Get Started
Prerequisites
Before you begin, ensure you have the following installed:
- Go: You need a recent version of Go installed on your system. Go version 1.18 or later is recommended as it includes support for generics, which are used in some parts of the
gomcp
library. You can download and install Go from the official Go website: https://golang.org/dl/ - A Go Project: You should have an existing Go project or create a new one. If you’re creating a new project, initialize a Go module:
go mod init your_module_name
Installing GoMCP
To add the gomcp
library to your Go project, open your terminal or command prompt, navigate to your project’s root directory, and run the following command:
go get github.com/localrivet/gomcp
This command will download the gomcp
library and its dependencies and add them to your project’s go.mod
file.
Importing the Library
Once installed, you can import the necessary packages in your Go code to start building MCP servers or clients:
import (
"github.com/localrivet/gomcp/client" // For building MCP clients
"github.com/localrivet/gomcp/server" // For building MCP servers
"github.com/localrivet/gomcp/protocol" // For MCP message types and structures
// You may also need to import specific transport packages, e.g.:
// "github.com/localrivet/gomcp/transport/stdio"
// "github.com/localrivet/gomcp/transport/sse"
// "github.com/localrivet/gomcp/transport/websocket"
)
Quickstart
This guide provides a quick introduction to building a minimal GoMCP server and client that communicate using the standard input/output (stdio) transport. This will give you a basic understanding of how to get started with the library.
Your First MCP Server
Let’s create a simple MCP server that registers a basic “echo” tool. This tool will simply return the input text it receives.
Create a new file (e.g., server/main.go
) and add the following code:
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/localrivet/gomcp/protocol"
"github.com/localrivet/gomcp/server"
"github.com/localrivet/gomcp/util/schema" // Helper for argument schema
)
// Define the arguments the echo tool expects
type EchoArgs struct {
Input string `json:"input" description:"Text to echo back"`
}
// Define the handler function for the echo tool
func handleEchoTool(ctx context.Context, progressToken *protocol.ProgressToken, arguments any) (content []protocol.Content, isError bool) {
// Use the schema helper to parse and validate arguments
args, errContent, isErr := schema.HandleArgs[EchoArgs](arguments)
if isErr {
// Return the error content generated by HandleArgs
return errContent, true
}
// Log the tool execution (optional)
log.Printf("Echo tool received input: %s", args.Input)
// Prepare the result content
resultContent := []protocol.Content{
protocol.TextContent{
Type: "text",
Text: "Echo: " + args.Input,
},
}
// Return the result and indicate no error
return resultContent, false
}
func main() {
// Configure logger (optional, defaults to stderr)
log.SetOutput(os.Stderr)
log.SetFlags(log.Ltime | log.Lshortfile)
log.Println("Starting Minimal MCP Server...")
// Create the core server instance
// Provide a name and default options
srv := server.NewServer("MyMinimalEchoServer", server.ServerOptions{})
// Define the metadata for the echo tool
echoTool := protocol.Tool{
Name: "echo",
Description: "Echoes back the input text.",
InputSchema: schema.FromStruct(EchoArgs{}), // Generate schema from the struct
}
// Register the echo tool with its handler function
err := srv.RegisterTool(echoTool, handleEchoTool)
if err != nil {
log.Fatalf("Failed to register tool: %v", err)
}
log.Printf("Registered tool: %s", echoTool.Name)
// Start the server using the built-in stdio handler.
// This blocks until the server exits (e.g., EOF on stdin or error).
log.Println("Server setup complete. Listening on stdio...")
if err := server.ServeStdio(srv); err != nil {
log.Fatalf("Server exited with error: %v", err)
}
log.Println("Server shutdown complete.")
}
Your First MCP Client
Now, let’s create a simple MCP client that connects to our server via stdio, lists the available tools, and calls the “echo” tool.
Create a new file (e.g., client/main.go
) and add the following code:
package main
import (
"context"
"log"
"os"
"time"
"github.com/localrivet/gomcp/client"
"github.com/localrivet/gomcp/protocol"
)
func main() {
// Configure logger (optional)
log.SetOutput(os.Stderr)
log.SetFlags(log.Ltime | log.Lshortfile)
log.Println("Starting Simple Stdio MCP Client...")
// Create a client instance for the stdio transport
// NewStdioClient handles the underlying transport setup
clt, err := client.NewStdioClient("MyMinimalEchoClient", client.ClientOptions{})
if err != nil {
log.Fatalf("Failed to create stdio client: %v", err)
}
// Ensure the client connection is closed when main exits
defer clt.Close()
// Use a context for the connection and requests
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// Connect to the server and perform the initialization handshake
log.Println("Connecting to server via stdio...")
err = clt.Connect(ctx)
if err != nil {
log.Fatalf("Failed to connect and initialize with server: %v", err)
}
log.Printf("Connected to server: %s (Version: %s)", clt.ServerInfo().Name, clt.ServerInfo().Version)
// --- Client is now ready to make requests ---
// Example: List available tools from the server
log.Println("Listing available tools...")
toolsResult, err := clt.ListTools(ctx, protocol.ListToolsRequestParams{})
if err != nil {
log.Printf("Error listing tools: %v", err)
} else {
log.Printf("Available tools (%d):", len(toolsResult.Tools))
for _, tool := range toolsResult.Tools {
log.Printf("- %s: %s", tool.Name, tool.Description)
}
}
// Example: Call the "echo" tool
log.Println("Calling 'echo' tool...")
callToolParams := protocol.CallToolParams{
Name: "echo",
Arguments: map[string]interface{}{
"input": "Hello from the client!",
},
}
callToolResult, err := clt.CallTool(ctx, callToolParams)
if err != nil {
log.Printf("Error calling tool 'echo': %v", err)
} else {
log.Println("Tool 'echo' returned content:")
for _, content := range callToolResult.Content {
// Assuming TextContent for this example
if textContent, ok := content.(protocol.TextContent); ok {
log.Printf("- %s: %s", textContent.Type, textContent.Text)
} else {
log.Printf("- Received content of type: %s", content.GetContentType())
}
}
if callToolResult.IsError != nil && *callToolResult.IsError {
log.Println("Tool execution reported an error.")
}
}
log.Println("Client operations finished.")
}
Running the Example
To run this minimal server and client and see them communicate:
- Save the server code as
server/main.go
and the client code asclient/main.go
within your Go project. - Navigate to your project’s root directory in your terminal.
- Run
go mod tidy
to ensure dependencies are fetched. - Pipe the output of the client directly into the input of the server:You should see output from both the client and the server demonstrating the MCP handshake, tool listing, and the echo tool call.
go run client/main.go | go run server/main.go
Next Steps
You have successfully built and run a minimal GoMCP server and client. To learn more, explore the detailed guides: