Model Context Protocol (MCP) Implementation
Overview
This package provides a go-zero integration for the Model Context Protocol (MCP) using the official go-sdk. It wraps the official MCP SDK to provide a seamless integration with go-zero's REST server framework.
Features
- Official SDK Integration: Built on top of the official Model Context Protocol Go SDK
- No SDK Import Required: Use
mcp.AddTool()directly without importing the official SDK - go-zero Integration: Seamlessly integrates with go-zero's REST server and configuration system
- Dual Transport Support:
- SSE (Server-Sent Events) transport for 2024-11-05 MCP spec
- Streamable HTTP transport for 2025-03-26 MCP spec
- CORS Support: Configurable CORS settings for cross-origin requests
- Type-Safe Tool Handlers: Generic tool handlers with automatic JSON schema generation
- Prompts and Resources: Full support for MCP prompts and resources
- Request Metadata Bridge: Optional request metadata extraction into handler context
Quick Start
1. Installation
go get github.com/zeromicro/go-zero
Note: The official MCP SDK is a transitive dependency and will be installed automatically. You don't need to import it directly in your code.
2. Configuration
Create a configuration file config.yaml:
name: my-mcp-server
host: localhost
port: 8080
mcp:
name: my-mcp-server
version: 1.0.0
useStreamable: false # Use SSE transport (default), set to true for Streamable HTTP
sseEndpoint: /sse
messageEndpoint: /message
sseTimeout: 24h
messageTimeout: 30s
cors:
- http://localhost:3000
3. Create Your Server
package main
import (
"context"
"log"
"github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/mcp"
)
type GreetArgs struct {
Name string `json:"name" jsonschema:"description=Name of the person to greet"`
}
func main() {
// Load configuration
var c mcp.McpConf
conf.MustLoad("config.yaml", &c)
// Create MCP server
server := mcp.NewMcpServer(c)
// Register a tool with automatic schema generation using the SDK directly
tool := &mcp.Tool{
Name: "greet",
Description: "Greet someone by name",
}
handler := func(ctx context.Context, req *mcp.CallToolRequest, args GreetArgs) (*mcp.CallToolResult, any, error) {
return &mcp.CallToolResult{
Content: []mcp.Content{
&mcp.TextContent{Text: "Hello, " + args.Name + "!"},
},
}, nil, nil
}
// Register tool with type-safe generics - no need to import official SDK
mcp.AddTool(server, tool, handler)
// Start server
defer server.Stop()
server.Start()
}
Adding Tools
Tools are functions that the MCP client can call. The SDK automatically generates JSON schemas from your struct tags. Use sdkmcp.AddTool with the server's underlying SDK server:
type CalculateArgs struct {
Operation string `json:"operation" jsonschema:"enum=add,enum=subtract,enum=multiply,enum=divide"`
A float64 `json:"a" jsonschema:"description=First number"`
B float64 `json:"b" jsonschema:"description=Second number"`
}
tool := &mcp.Tool{
Name: "calculate",
Description: "Perform arithmetic operations",
}
handler := func(ctx context.Context, req *mcp.CallToolRequest, args CalculateArgs) (*mcp.CallToolResult, any, error) {
var result float64
switch args.Operation {
case "add":
result = args.A + args.B
case "subtract":
result = args.A - args.B
case "multiply":
result = args.A * args.B
case "divide":
if args.B == 0 {
return &mcp.CallToolResult{IsError: true}, nil, fmt.Errorf("division by zero")
}
result = args.A / args.B
}
return &mcp.CallToolResult{
Content: []mcp.Content{
&mcp.TextContent{Text: fmt.Sprintf("Result: %v", result)},
},
}, result, nil
}
// Register tool
mcp.AddTool(server, tool, handler)
Adding Prompts
Prompts provide reusable message templates:
prompt := &mcp.Prompt{
Name: "code-review",
Description: "Review code for best practices",
}
handler := func(ctx context.Context, req *sdkmcp.GetPromptRequest, args map[string]string) (*mcp.GetPromptResult, error) {
code := args["code"]
language := args["language"]
return &mcp.GetPromptResult{
Messages: []mcp.PromptMessage{
{
Role: "user",
Content: &mcp.TextContent{
Text: fmt.Sprintf("Please review this %s code:\n\n%s", language, code),
},
},
},
}, nil
}
server.AddPrompt(prompt, handler)
Adding Resources
Resources provide access to data that the model can read:
resource := &mcp.Resource{
URI: "file:///docs/readme.md",
Name: "README",
Description: "Project documentation",
MimeType: "text/markdown",
}
handler := func(ctx context.Context, req *sdkmcp.ReadResourceRequest, uri string) (*mcp.ReadResourceResult, error) {
content, err := os.ReadFile("README.md")
if err != nil {
return nil, err
}
return &mcp.ReadResourceResult{
Contents: []mcp.ResourceContents{
{
URI: uri,
MimeType: "text/markdown",
Text: string(content),
},
},
}, nil
}
server.AddResource(resource, handler)
Transport Options
SSE Transport (Default)
The SSE (Server-Sent Events) transport is the original MCP transport from the 2024-11-05 specification:
mcp:
useStreamable: false
sseEndpoint: /sse
Streamable HTTP Transport
The newer Streamable HTTP transport from the 2025-03-26 specification provides better connection management:
mcp:
useStreamable: true
messageEndpoint: /message
Request Metadata Bridge
For multi-tenant or request-context-aware tools, you can extract selected HTTP request metadata once at the transport boundary and read it from context.Context in handlers.
server := mcp.NewMcpServerWithOptions(c,
mcp.WithRequestMetadataExtractor(mcp.DefaultRequestMetadataExtractor),
)
handler := func(ctx context.Context, req *mcp.CallToolRequest, args SomeArgs) (*mcp.CallToolResult, any, error) {
tenant, _ := mcp.HeaderFromContext(ctx, "X-Tenant-Id")
traceID, _ := mcp.QueryFromContext(ctx, "trace")
scope, _ := mcp.PathFromContext(ctx, "scope")
_ = tenant
_ = traceID
_ = scope
return &mcp.CallToolResult{}, nil, nil
}
Available helpers:
RequestMetadataFromContext(ctx)HeaderFromContext(ctx, key)QueryFromContext(ctx, key)PathFromContext(ctx, key)
Configuration Options
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | Server name (required, from RestConf) | |
host |
string | Server host (required, from RestConf) | |
port |
int | Server port (required, from RestConf) | |
mcp.name |
string | MCP server name (defaults to name) |
|
mcp.version |
string | 1.0.0 |
Server version |
mcp.useStreamable |
bool | false |
Use Streamable HTTP transport instead of SSE |
mcp.sseEndpoint |
string | /sse |
SSE endpoint path |
mcp.messageEndpoint |
string | /message |
Message endpoint path |
mcp.sseTimeout |
duration | 24h |
SSE connection timeout |
mcp.messageTimeout |
duration | 30s |
Message processing timeout |
mcp.cors |
[]string | Allowed CORS origins |
Examples
See the adhoc/mcp directory for a complete working example.
Official SDK Documentation
For more details on the underlying MCP SDK, see:
License
This implementation follows the go-zero project license (MIT).