Go Quickstart (Local)

How to get started running Toolbox locally with Go, PostgreSQL, and orchestration frameworks such as LangChain Go, GenkitGo, Go GenAI and OpenAI Go.

Before you begin

This guide assumes you have already done the following:

  1. Installed Go (v1.24.2 or higher).
  2. Installed PostgreSQL 16+ and the psql client.

Cloud Setup (Optional)

If you plan to use Google Cloud’s Vertex AI with your agent (e.g., using vertexai=True or a Google GenAI model), follow these one-time setup steps for local development:

  1. Install the Google Cloud CLI

  2. Set up Application Default Credentials (ADC)

  3. Set your project and enable Vertex AI

    gcloud config set project YOUR_PROJECT_ID
    gcloud services enable aiplatform.googleapis.com
    

Step 1: Set up your database

In this section, we will create a database, insert some data that needs to be accessed by our agent, and create a database user for Toolbox to connect with.

  1. Connect to postgres using the psql command:

    psql -h 127.0.0.1 -U postgres
    

    Here, postgres denotes the default postgres superuser.

    Info

    Having trouble connecting?

    • Password Prompt: If you are prompted for a password for the postgres user and do not know it (or a blank password doesn’t work), your PostgreSQL installation might require a password or a different authentication method.
    • FATAL: role "postgres" does not exist: This error means the default postgres superuser role isn’t available under that name on your system.
    • Connection refused: Ensure your PostgreSQL server is actually running. You can typically check with sudo systemctl status postgresql and start it with sudo systemctl start postgresql on Linux systems.

    Common Solution

    For password issues or if the postgres role seems inaccessible directly, try switching to the postgres operating system user first. This user often has permission to connect without a password for local connections (this is called peer authentication).

    sudo -i -u postgres
    psql -h 127.0.0.1
    

    Once you are in the psql shell using this method, you can proceed with the database creation steps below. Afterwards, type \q to exit psql, and then exit to return to your normal user shell.

    If desired, once connected to psql as the postgres OS user, you can set a password for the postgres database user using: ALTER USER postgres WITH PASSWORD 'your_chosen_password';. This would allow direct connection with -U postgres and a password next time.

  2. Create a new database and a new user:

    Tip

    For a real application, it’s best to follow the principle of least permission and only grant the privileges your application needs.

      CREATE USER toolbox_user WITH PASSWORD 'my-password';
    
      CREATE DATABASE toolbox_db;
      GRANT ALL PRIVILEGES ON DATABASE toolbox_db TO toolbox_user;
    
      ALTER DATABASE toolbox_db OWNER TO toolbox_user;
    
  3. End the database session:

    \q
    

    (If you used sudo -i -u postgres and then psql, remember you might also need to type exit after \q to leave the postgres user’s shell session.)

  4. Connect to your database with your new user:

    psql -h 127.0.0.1 -U toolbox_user -d toolbox_db
    
  5. Create a table using the following command:

    CREATE TABLE hotels(
      id            INTEGER NOT NULL PRIMARY KEY,
      name          VARCHAR NOT NULL,
      location      VARCHAR NOT NULL,
      price_tier    VARCHAR NOT NULL,
      checkin_date  DATE    NOT NULL,
      checkout_date DATE    NOT NULL,
      booked        BIT     NOT NULL
    );
    
  6. Insert data into the table.

    INSERT INTO hotels(id, name, location, price_tier, checkin_date, checkout_date, booked)
    VALUES
      (1, 'Hilton Basel', 'Basel', 'Luxury', '2024-04-22', '2024-04-20', B'0'),
      (2, 'Marriott Zurich', 'Zurich', 'Upscale', '2024-04-14', '2024-04-21', B'0'),
      (3, 'Hyatt Regency Basel', 'Basel', 'Upper Upscale', '2024-04-02', '2024-04-20', B'0'),
      (4, 'Radisson Blu Lucerne', 'Lucerne', 'Midscale', '2024-04-24', '2024-04-05', B'0'),
      (5, 'Best Western Bern', 'Bern', 'Upper Midscale', '2024-04-23', '2024-04-01', B'0'),
      (6, 'InterContinental Geneva', 'Geneva', 'Luxury', '2024-04-23', '2024-04-28', B'0'),
      (7, 'Sheraton Zurich', 'Zurich', 'Upper Upscale', '2024-04-27', '2024-04-02', B'0'),
      (8, 'Holiday Inn Basel', 'Basel', 'Upper Midscale', '2024-04-24', '2024-04-09', B'0'),
      (9, 'Courtyard Zurich', 'Zurich', 'Upscale', '2024-04-03', '2024-04-13', B'0'),
      (10, 'Comfort Inn Bern', 'Bern', 'Midscale', '2024-04-04', '2024-04-16', B'0');
    
  7. End the database session:

    \q
    

Step 2: Install and configure Toolbox

In this section, we will download Toolbox, configure our tools in a tools.yaml, and then run the Toolbox server.

  1. Download the latest version of Toolbox as a binary:

    Tip

    Select the correct binary corresponding to your OS and CPU architecture.

    export OS="linux/amd64" # one of linux/amd64, darwin/arm64, darwin/amd64, or windows/amd64
    curl -O https://storage.googleapis.com/genai-toolbox/v0.12.0/$OS/toolbox
    
  2. Make the binary executable:

    chmod +x toolbox
    
  3. Write the following into a tools.yaml file. Be sure to update any fields such as user, password, or database that you may have customized in the previous step.

    Tip

    In practice, use environment variable replacement with the format ${ENV_NAME} instead of hardcoding your secrets into the configuration file.

    sources:
      my-pg-source:
        kind: postgres
        host: 127.0.0.1
        port: 5432
        database: toolbox_db
        user: ${USER_NAME}
        password: ${PASSWORD}
    tools:
      search-hotels-by-name:
        kind: postgres-sql
        source: my-pg-source
        description: Search for hotels based on name.
        parameters:
          - name: name
            type: string
            description: The name of the hotel.
        statement: SELECT * FROM hotels WHERE name ILIKE '%' || $1 || '%';
      search-hotels-by-location:
        kind: postgres-sql
        source: my-pg-source
        description: Search for hotels based on location.
        parameters:
          - name: location
            type: string
            description: The location of the hotel.
        statement: SELECT * FROM hotels WHERE location ILIKE '%' || $1 || '%';
      book-hotel:
        kind: postgres-sql
        source: my-pg-source
        description: >-
           Book a hotel by its ID. If the hotel is successfully booked, returns a NULL, raises an error if not.
        parameters:
          - name: hotel_id
            type: string
            description: The ID of the hotel to book.
        statement: UPDATE hotels SET booked = B'1' WHERE id = $1;
      update-hotel:
        kind: postgres-sql
        source: my-pg-source
        description: >-
          Update a hotel's check-in and check-out dates by its ID. Returns a message
          indicating  whether the hotel was successfully updated or not.
        parameters:
          - name: hotel_id
            type: string
            description: The ID of the hotel to update.
          - name: checkin_date
            type: string
            description: The new check-in date of the hotel.
          - name: checkout_date
            type: string
            description: The new check-out date of the hotel.
        statement: >-
          UPDATE hotels SET checkin_date = CAST($2 as date), checkout_date = CAST($3
          as date) WHERE id = $1;
      cancel-hotel:
        kind: postgres-sql
        source: my-pg-source
        description: Cancel a hotel by its ID.
        parameters:
          - name: hotel_id
            type: string
            description: The ID of the hotel to cancel.
        statement: UPDATE hotels SET booked = B'0' WHERE id = $1;
    toolsets:
      my-toolset:
        - search-hotels-by-name
        - search-hotels-by-location
        - book-hotel
        - update-hotel
        - cancel-hotel
    

    For more info on tools, check out the Resources section of the docs.

  4. Run the Toolbox server, pointing to the tools.yaml file created earlier:

    ./toolbox --tools-file "tools.yaml"
    

    Note

    Toolbox enables dynamic reloading by default. To disable, use the
    `--disable-reload` flag.
    

Step 3: Connect your agent to Toolbox

In this section, we will write and run an agent that will load the Tools from Toolbox.

  1. Initialize a go module:

    go mod init main
    
  2. In a new terminal, install the SDK.

    go get github.com/googleapis/mcp-toolbox-sdk-go
    
  3. Create a new file named hotelagent.go and copy the following code to create an agent:

    package main
    
    import (
    	"context"
    	"encoding/json"
    	"fmt"
    	"log"
    	"os"
    
    	"github.com/googleapis/mcp-toolbox-sdk-go/core"
    	"github.com/tmc/langchaingo/llms"
    	"github.com/tmc/langchaingo/llms/googleai"
    )
    
    // ConvertToLangchainTool converts a generic core.ToolboxTool into a LangChainGo llms.Tool.
    func ConvertToLangchainTool(toolboxTool *core.ToolboxTool) llms.Tool {
    
    	// Fetch the tool's input schema
    	inputschema, err := toolboxTool.InputSchema()
    	if err != nil {
    		return llms.Tool{}
    	}
    
    	var paramsSchema map[string]any
    	_ = json.Unmarshal(inputschema, &paramsSchema)
    
    	// Convert into LangChain's llms.Tool
    	return llms.Tool{
    		Type: "function",
    		Function: &llms.FunctionDefinition{
    			Name:        toolboxTool.Name(),
    			Description: toolboxTool.Description(),
    			Parameters:  paramsSchema,
    		},
    	}
    }
    
    const systemPrompt = `
    You're a helpful hotel assistant. You handle hotel searching, booking, and
    cancellations. When the user searches for a hotel, mention its name, id,
    location and price tier. Always mention hotel ids while performing any
    searches. This is very important for any operations. For any bookings or
    cancellations, please provide the appropriate confirmation. Be sure to
    update checkin or checkout dates if mentioned by the user.
    Don't ask for confirmations from the user.
    `
    
    var queries = []string{
    	"Find hotels in Basel with Basel in its name.",
    	"Can you book the hotel Hilton Basel for me?",
    	"Oh wait, this is too expensive. Please cancel it.",
    	"Please book the Hyatt Regency instead.",
    	"My check in dates would be from April 10, 2024 to April 19, 2024.",
    }
    
    func main() {
    	genaiKey := os.Getenv("GOOGLE_API_KEY")
    	toolboxURL := "http://localhost:5000"
    	ctx := context.Background()
    
    	// Initialize the Google AI client (LLM).
    	llm, err := googleai.New(ctx, googleai.WithAPIKey(genaiKey), googleai.WithDefaultModel("gemini-1.5-flash"))
    	if err != nil {
    		log.Fatalf("Failed to create Google AI client: %v", err)
    	}
    
    	// Initialize the MCP Toolbox client.
    	toolboxClient, err := core.NewToolboxClient(toolboxURL)
    	if err != nil {
    		log.Fatalf("Failed to create Toolbox client: %v", err)
    	}
    
    	// Load the tool using the MCP Toolbox SDK.
    	tools, err := toolboxClient.LoadToolset("my-toolset", ctx)
    	if err != nil {
    		log.Fatalf("Failed to load tools: %v\nMake sure your Toolbox server is running and the tool is configured.", err)
    	}
    
    	toolsMap := make(map[string]*core.ToolboxTool, len(tools))
    
    	langchainTools := make([]llms.Tool, len(tools))
    	// Convert the loaded ToolboxTools into the format LangChainGo requires.
    	for i, tool := range tools {
    		langchainTools[i] = ConvertToLangchainTool(tool)
    		toolsMap[tool.Name()] = tool
    	}
    
    	// Start the conversation history.
    	messageHistory := []llms.MessageContent{
    		llms.TextParts(llms.ChatMessageTypeSystem, systemPrompt),
    	}
    
    	for _, query := range queries {
    		messageHistory = append(messageHistory, llms.TextParts(llms.ChatMessageTypeHuman, query))
    
    		// Make the first call to the LLM, making it aware of the tool.
    		resp, err := llm.GenerateContent(ctx, messageHistory, llms.WithTools(langchainTools))
    		if err != nil {
    			log.Fatalf("LLM call failed: %v", err)
    		}
    		respChoice := resp.Choices[0]
    
    		assistantResponse := llms.TextParts(llms.ChatMessageTypeAI, respChoice.Content)
    		for _, tc := range respChoice.ToolCalls {
    			assistantResponse.Parts = append(assistantResponse.Parts, tc)
    		}
    		messageHistory = append(messageHistory, assistantResponse)
    
    		// Process each tool call requested by the model.
    		for _, tc := range respChoice.ToolCalls {
    			toolName := tc.FunctionCall.Name
    			tool := toolsMap[toolName]
    			var args map[string]any
    			if err := json.Unmarshal([]byte(tc.FunctionCall.Arguments), &args); err != nil {
    				log.Fatalf("Failed to unmarshal arguments for tool '%s': %v", toolName, err)
    			}
    			toolResult, err := tool.Invoke(ctx, args)
    			if err != nil {
    				log.Fatalf("Failed to execute tool '%s': %v", toolName, err)
    			}
    			if toolResult == "" || toolResult == nil {
    				toolResult = "Operation completed successfully with no specific return value."
    			}
    
    			// Create the tool call response message and add it to the history.
    			toolResponse := llms.MessageContent{
    				Role: llms.ChatMessageTypeTool,
    				Parts: []llms.ContentPart{
    					llms.ToolCallResponse{
    						Name:    toolName,
    						Content: fmt.Sprintf("%v", toolResult),
    					},
    				},
    			}
    			messageHistory = append(messageHistory, toolResponse)
    		}
    		finalResp, err := llm.GenerateContent(ctx, messageHistory)
    		if err != nil {
    			log.Fatalf("Final LLM call failed after tool execution: %v", err)
    		}
    
    		// Add the final textual response from the LLM to the history
    		messageHistory = append(messageHistory, llms.TextParts(llms.ChatMessageTypeAI, finalResp.Choices[0].Content))
    
    		fmt.Println(finalResp.Choices[0].Content)
    
    	}
    
    }
    package main
    
    import (
    	"context"
    	"fmt"
    	"log"
    
    	"github.com/googleapis/mcp-toolbox-sdk-go/core"
    	"github.com/googleapis/mcp-toolbox-sdk-go/tbgenkit"
    
    	"github.com/firebase/genkit/go/ai"
    	"github.com/firebase/genkit/go/genkit"
    	"github.com/firebase/genkit/go/plugins/googlegenai"
    )
    
    const systemPrompt = `
    You're a helpful hotel assistant. You handle hotel searching, booking, and
    cancellations. When the user searches for a hotel, mention its name, id,
    location and price tier. Always mention hotel ids while performing any
    searches. This is very important for any operations. For any bookings or
    cancellations, please provide the appropriate confirmation. Be sure to
    update checkin or checkout dates if mentioned by the user.
    Don't ask for confirmations from the user.
    `
    
    var queries = []string{
    	"Find hotels in Basel with Basel in its name.",
    	"Can you book the hotel Hilton Basel for me?",
    	"Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.",
    	"My check in dates would be from April 10, 2024 to April 19, 2024.",
    }
    
    func main() {
    	ctx := context.Background()
    
    	// Create Toolbox Client
    	toolboxClient, err := core.NewToolboxClient("http://127.0.0.1:5000")
    	if err != nil {
    		log.Fatalf("Failed to create Toolbox client: %v", err)
    	}
    
    	// Load the tools using the MCP Toolbox SDK.
    	tools, err := toolboxClient.LoadToolset("my-toolset", ctx)
    	if err != nil {
    		log.Fatalf("Failed to load tools: %v\nMake sure your Toolbox server is running and the tool is configured.", err)
    	}
    
    	// Initialize Genkit
    	g, err := genkit.Init(ctx,
    		genkit.WithPlugins(&googlegenai.GoogleAI{}),
    		genkit.WithDefaultModel("googleai/gemini-1.5-flash"),
    	)
    	if err != nil {
    		log.Fatalf("Failed to init genkit: %v\n", err)
    	}
    
    	// Create a conversation history
    	conversationHistory := []*ai.Message{
    		ai.NewSystemTextMessage(systemPrompt),
    	}
    
    	// Convert your tool to a Genkit tool.
    	genkitTools := make([]ai.Tool, len(tools))
    	for i, tool := range tools {
    		newTool, err := tbgenkit.ToGenkitTool(tool, g)
    		if err != nil {
    			log.Fatalf("Failed to convert tool: %v\n", err)
    		}
    		genkitTools[i] = newTool
    	}
    
    	toolRefs := make([]ai.ToolRef, len(genkitTools))
    
    	for i, tool := range genkitTools {
    		toolRefs[i] = tool
    	}
    
    	for _, query := range queries {
    		conversationHistory = append(conversationHistory, ai.NewUserTextMessage(query))
    		response, err := genkit.Generate(ctx, g,
    			ai.WithMessages(conversationHistory...),
    			ai.WithTools(toolRefs...),
    			ai.WithReturnToolRequests(true),
    		)
    
    		if err != nil {
    			log.Fatalf("%v\n", err)
    		}
    		conversationHistory = append(conversationHistory, response.Message)
    
    		parts := []*ai.Part{}
    
    		for _, req := range response.ToolRequests() {
    			tool := genkit.LookupTool(g, req.Name)
    			if tool == nil {
    				log.Fatalf("tool %q not found", req.Name)
    			}
    
    			output, err := tool.RunRaw(ctx, req.Input)
    			if err != nil {
    				log.Fatalf("tool %q execution failed: %v", tool.Name(), err)
    			}
    
    			parts = append(parts,
    				ai.NewToolResponsePart(&ai.ToolResponse{
    					Name:   req.Name,
    					Ref:    req.Ref,
    					Output: output,
    				}))
    
    		}
    
    		if len(parts) > 0 {
    			resp, err := genkit.Generate(ctx, g,
    				ai.WithMessages(append(response.History(), ai.NewMessage(ai.RoleTool, nil, parts...))...),
    				ai.WithTools(toolRefs...),
    			)
    			if err != nil {
    				log.Fatal(err)
    			}
    			fmt.Println("\n", resp.Text())
    			conversationHistory = append(conversationHistory, resp.Message)
    		} else {
    			fmt.Println("\n", response.Text())
    		}
    
    	}
    
    }
    package main
    
    import (
    	"context"
    	"encoding/json"
    	"fmt"
    	"log"
    	"os"
    
    	"github.com/googleapis/mcp-toolbox-sdk-go/core"
    	"google.golang.org/genai"
    )
    
    // ConvertToGenaiTool translates a ToolboxTool into the genai.FunctionDeclaration format.
    func ConvertToGenaiTool(toolboxTool *core.ToolboxTool) *genai.Tool {
    
    	inputschema, err := toolboxTool.InputSchema()
    	if err != nil {
    		return &genai.Tool{}
    	}
    
    	var paramsSchema *genai.Schema
    	_ = json.Unmarshal(inputschema, &paramsSchema)
    	// First, create the function declaration.
    	funcDeclaration := &genai.FunctionDeclaration{
    		Name:        toolboxTool.Name(),
    		Description: toolboxTool.Description(),
    		Parameters:  paramsSchema,
    	}
    
    	// Then, wrap the function declaration in a genai.Tool struct.
    	return &genai.Tool{
    		FunctionDeclarations: []*genai.FunctionDeclaration{funcDeclaration},
    	}
    }
    
    func printResponse(resp *genai.GenerateContentResponse) {
    	for _, cand := range resp.Candidates {
    		if cand.Content != nil {
    			for _, part := range cand.Content.Parts {
    				fmt.Println(part.Text)
    			}
    		}
    	}
    }
    
    const systemPrompt = `
    You're a helpful hotel assistant. You handle hotel searching, booking, and
    cancellations. When the user searches for a hotel, mention its name, id,
    location and price tier. Always mention hotel ids while performing any
    searches. This is very important for any operations. For any bookings or
    cancellations, please provide the appropriate confirmation. Be sure to
    update checkin or checkout dates if mentioned by the user.
    Don't ask for confirmations from the user.
    `
    
    var queries = []string{
    	"Find hotels in Basel with Basel in its name.",
    	"Can you book the hotel Hilton Basel for me?",
    	"Oh wait, this is too expensive. Please cancel it.",
    	"Please book the Hyatt Regency instead.",
    	"My check in dates would be from April 10, 2024 to April 19, 2024.",
    }
    
    func main() {
    	// Setup
    	ctx := context.Background()
    	apiKey := os.Getenv("GOOGLE_API_KEY")
    	toolboxURL := "http://localhost:5000"
    
    	// Initialize the Google GenAI client using the explicit ClientConfig.
    	client, err := genai.NewClient(ctx, &genai.ClientConfig{
    		APIKey: apiKey,
    	})
    	if err != nil {
    		log.Fatalf("Failed to create Google GenAI client: %v", err)
    	}
    
    	// Initialize the MCP Toolbox client.
    	toolboxClient, err := core.NewToolboxClient(toolboxURL)
    	if err != nil {
    		log.Fatalf("Failed to create Toolbox client: %v", err)
    	}
    
    	// Load the tool using the MCP Toolbox SDK.
    	tools, err := toolboxClient.LoadToolset("my-toolset", ctx)
    	if err != nil {
    		log.Fatalf("Failed to load tools: %v\nMake sure your Toolbox server is running and the tool is configured.", err)
    	}
    
    	genAITools := make([]*genai.Tool, len(tools))
    	toolsMap := make(map[string]*core.ToolboxTool, len(tools))
    
    	for i, tool := range tools {
    		genAITools[i] = ConvertToGenaiTool(tool)
    		toolsMap[tool.Name()] = tool
    	}
    
    	// Set up the generative model with the available tool.
    	modelName := "gemini-2.0-flash"
    
    	// Create the initial content prompt for the model.
    	messageHistory := []*genai.Content{
    		genai.NewContentFromText(systemPrompt, genai.RoleUser),
    	}
    	config := &genai.GenerateContentConfig{
    		Tools: genAITools,
    		ToolConfig: &genai.ToolConfig{
    			FunctionCallingConfig: &genai.FunctionCallingConfig{
    				Mode: genai.FunctionCallingConfigModeAny,
    			},
    		},
    	}
    
    	for _, query := range queries {
    
    		messageHistory = append(messageHistory, genai.NewContentFromText(query, genai.RoleUser))
    
    		genContentResp, err := client.Models.GenerateContent(ctx, modelName, messageHistory, config)
    		if err != nil {
    			log.Fatalf("LLM call failed for query '%s': %v", query, err)
    		}
    
    		if len(genContentResp.Candidates) > 0 && genContentResp.Candidates[0].Content != nil {
    			messageHistory = append(messageHistory, genContentResp.Candidates[0].Content)
    		}
    
    		functionCalls := genContentResp.FunctionCalls()
    
    		toolResponseParts := []*genai.Part{}
    
    		for _, fc := range functionCalls {
    
    			toolToInvoke, found := toolsMap[fc.Name]
    			if !found {
    				log.Fatalf("Tool '%s' not found in loaded tools map. Check toolset configuration.", fc.Name)
    			}
    
    			toolResult, invokeErr := toolToInvoke.Invoke(ctx, fc.Args)
    			if invokeErr != nil {
    				log.Fatalf("Failed to execute tool '%s': %v", fc.Name, invokeErr)
    			}
    
    			// Enhanced Tool Result Handling (retained to prevent nil issues)
    			toolResultString := ""
    			if toolResult != nil {
    				jsonBytes, marshalErr := json.Marshal(toolResult)
    				if marshalErr == nil {
    					toolResultString = string(jsonBytes)
    				} else {
    					toolResultString = fmt.Sprintf("%v", toolResult)
    				}
    			}
    
    			responseMap := map[string]any{"result": toolResultString}
    
    			toolResponseParts = append(toolResponseParts, genai.NewPartFromFunctionResponse(fc.Name, responseMap))
    		}
    		// Add all accumulated tool responses for this turn to the message history.
    		toolResponseContent := genai.NewContentFromParts(toolResponseParts, "function")
    		messageHistory = append(messageHistory, toolResponseContent)
    
    		finalResponse, err := client.Models.GenerateContent(ctx, modelName, messageHistory, &genai.GenerateContentConfig{})
    		if err != nil {
    			log.Fatalf("Error calling GenerateContent (with function result): %v", err)
    		}
    
    		printResponse(finalResponse)
    		// Add the final textual response from the LLM to the history
    		if len(finalResponse.Candidates) > 0 && finalResponse.Candidates[0].Content != nil {
    			messageHistory = append(messageHistory, finalResponse.Candidates[0].Content)
    		}
    	}
    }
    package main
    
    import (
    	"context"
    	"encoding/json"
    	"log"
    	"fmt
    
    	"github.com/googleapis/mcp-toolbox-sdk-go/core"
    	openai "github.com/openai/openai-go"
    )
    
    // ConvertToOpenAITool converts a ToolboxTool into the go-openai library's Tool format.
    func ConvertToOpenAITool(toolboxTool *core.ToolboxTool) openai.ChatCompletionToolParam {
    	// Get the input schema
    	jsonSchemaBytes, err := toolboxTool.InputSchema()
    	if err != nil {
    		return openai.ChatCompletionToolParam{}
    	}
    
    	// Unmarshal the JSON bytes into FunctionParameters
    	var paramsSchema openai.FunctionParameters
    	if err := json.Unmarshal(jsonSchemaBytes, &paramsSchema); err != nil {
    		return openai.ChatCompletionToolParam{}
    	}
    
    	// Create and return the final tool parameter struct.
    	return openai.ChatCompletionToolParam{
    		Function: openai.FunctionDefinitionParam{
    			Name:        toolboxTool.Name(),
    			Description: openai.String(toolboxTool.Description()),
    			Parameters:  paramsSchema,
    		},
    	}
    }
    
    const systemPrompt = `
    You're a helpful hotel assistant. You handle hotel searching, booking, and
    cancellations. When the user searches for a hotel, mention its name, id,
    location and price tier. Always mention hotel ids while performing any
    searches. This is very important for any operations. For any bookings or
    cancellations, please provide the appropriate confirmation. Be sure to
    update checkin or checkout dates if mentioned by the user.
    Don't ask for confirmations from the user.
    `
    
    var queries = []string{
    	"Find hotels in Basel with Basel in its name.",
    	"Can you book the hotel Hilton Basel for me?",
    	"Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.",
    	"My check in dates would be from April 10, 2024 to April 19, 2024.",
    }
    
    func main() {
    	// Setup
    	ctx := context.Background()
    	toolboxURL := "http://localhost:5000"
    	openAIClient := openai.NewClient()
    
    	// Initialize the MCP Toolbox client.
    	toolboxClient, err := core.NewToolboxClient(toolboxURL)
    	if err != nil {
    		log.Fatalf("Failed to create Toolbox client: %v", err)
    	}
    
    	// Load the tools using the MCP Toolbox SDK.
    	tools, err := toolboxClient.LoadToolset("my-toolset", ctx)
    	if err != nil {
    		log.Fatalf("Failed to load tool : %v\nMake sure your Toolbox server is running and the tool is configured.", err)
    	}
    
    	openAITools := make([]openai.ChatCompletionToolParam, len(tools))
    	toolsMap := make(map[string]*core.ToolboxTool, len(tools))
    
    	for i, tool := range tools {
    		// Convert the Toolbox tool into the openAI FunctionDeclaration format.
    		openAITools[i] = ConvertToOpenAITool(tool)
    		// Add tool to a map for lookup later
    		toolsMap[tool.Name()] = tool
    
    	}
    
    	params := openai.ChatCompletionNewParams{
    		Messages: []openai.ChatCompletionMessageParamUnion{
    			openai.SystemMessage(systemPrompt),
    		},
    		Tools: openAITools,
    		Seed:  openai.Int(0),
    		Model: openai.ChatModelGPT4o,
    	}
    
    	for _, query := range queries {
    
    		params.Messages = append(params.Messages, openai.UserMessage(query))
    
    		// Make initial chat completion request
    		completion, err := openAIClient.Chat.Completions.New(ctx, params)
    		if err != nil {
    			panic(err)
    		}
    
    		toolCalls := completion.Choices[0].Message.ToolCalls
    
    		// Return early if there are no tool calls
    		if len(toolCalls) == 0 {
    			log.Println("No function call")
    		}
    
    		// If there was a function call, continue the conversation
    		params.Messages = append(params.Messages, completion.Choices[0].Message.ToParam())
    		for _, toolCall := range toolCalls {
    
    			toolName := toolCall.Function.Name
    			toolToInvoke := toolsMap[toolName]
    
    			var args map[string]any
    			err := json.Unmarshal([]byte(toolCall.Function.Arguments), &args)
    			if err != nil {
    				panic(err)
    			}
    
    			result, err := toolToInvoke.Invoke(ctx, args)
    			if err != nil {
    				log.Fatal("Could not invoke tool", err)
    			}
    
    			params.Messages = append(params.Messages, openai.ToolMessage(result.(string), toolCall.ID))
    		}
    
    		completion, err = openAIClient.Chat.Completions.New(ctx, params)
    		if err != nil {
    			panic(err)
    		}
    
    		params.Messages = append(params.Messages, openai.AssistantMessage(query))
    
    		fmt.println("\n", completion.Choices[0].Message.Content)
    
    	}
    
    }
  4. Ensure all dependencies are installed:

    go mod tidy
    
  5. Run your agent, and observe the results:

    go run hotelagent.go
    

Info

For more information, visit the Go SDK repo.