MCP Server Implementation Guide
Background
Higress, as an Envoy-based API gateway, supports hosting MCP Servers through its plugin mechanism. MCP (Model Context Protocol) is essentially an AI-friendly API that enables AI Agents to more easily call various tools and services. Higress provides unified capabilities for authentication, authorization, rate limiting, and observability for tool calls, simplifying the development and deployment of AI applications.
By hosting MCP Servers with Higress, you can achieve:
- Unified authentication and authorization mechanisms, ensuring the security of AI tool calls
- Fine-grained rate limiting to prevent abuse and resource exhaustion
- Comprehensive audit logs recording all tool call behaviors
- Rich observability for monitoring the performance and health of tool calls
- Simplified deployment and management through Higress's plugin mechanism for quickly adding new MCP Servers
This guide explains how to implement a Model Context Protocol (MCP) server using the Higress WASM Go SDK. MCP servers provide tools and resources that extend the capabilities of AI assistants.
Overview
An MCP server is a standalone application that communicates with AI assistants through the Model Context Protocol. It can provide:
- Tools: Functions that can be called by the AI to perform specific tasks
- Resources: Data that can be accessed by the AI
Note
: MCP server plugins require Higress version 2.1.0 or higher to be used.
Project Structure
A typical MCP server project has the following structure:
my-mcp-server/
├── go.mod # Go module definition
├── go.sum # Go module checksums
├── main.go # Entry point that registers tools and resources
└── tools/
└── my_tool.go # Tool implementation
Server Configuration
Define a configuration structure for your MCP server to store settings like API keys:
// config/config.go
package config
type MyServerConfig struct {
ApiKey string `json:"apiKey"`
}
Tool Implementation
Each tool should be implemented as a struct with the following methods:
Description(): Returns a description of the toolInputSchema(): Returns the JSON schema for the tool's input parametersCreate(): Creates a new instance of the tool with the provided parametersCall(): Executes the tool's functionality
Example:
// tools/my_tool.go
package tools
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"my-mcp-server/config"
"github.com/alibaba/higress/plugins/wasm-go/pkg/mcp/server"
"github.com/alibaba/higress/plugins/wasm-go/pkg/mcp/utils"
)
// Define your tool structure with input parameters
type MyTool struct {
Param1 string `json:"param1" jsonschema_description:"Description of param1" jsonschema:"example=example value"`
Param2 int `json:"param2,omitempty" jsonschema_description:"Description of param2" jsonschema:"default=5"`
}
// Description returns the description field for the MCP tool definition.
// This corresponds to the "description" field in the MCP tool JSON response,
// which provides a human-readable explanation of the tool's purpose and usage.
func (t MyTool) Description() string {
return `Detailed description of what this tool does and when to use it.`
}
// InputSchema returns the inputSchema field for the MCP tool definition.
// This corresponds to the "inputSchema" field in the MCP tool JSON response,
// which defines the JSON Schema for the tool's input parameters, including
// property types, descriptions, and required fields.
func (t MyTool) InputSchema() map[string]any {
return server.ToInputSchema(&MyTool{})
}
// Create instantiates a new tool instance based on the input parameters
// from an MCP tool call. It deserializes the JSON parameters into a struct,
// applying default values for optional fields, and returns the configured tool instance.
func (t MyTool) Create(params []byte) server.Tool {
myTool := &MyTool{
Param2: 5, // Default value
}
json.Unmarshal(params, &myTool)
return myTool
}
// Call implements the core logic for handling an MCP tool call. This method is executed
// when the tool is invoked through the MCP framework. It processes the configured parameters,
// makes any necessary API requests, and formats the results to be returned to the caller.
func (t MyTool) Call(ctx server.HttpContext, s server.Server) error {
// Get server configuration
serverConfig := &config.MyServerConfig{}
s.GetConfig(serverConfig)
if serverConfig.ApiKey == "" {
return errors.New("missing api key in server configuration")
}
// Implement your tool's logic here
// ...
// Return results
utils.SendMCPToolTextResult(ctx, fmt.Sprintf("Result: %s, %d", t.Param1, t.Param2))
return nil
}
Main Entry Point
The main.go file is the entry point for your MCP server. It registers your tools and resources:
// main.go
package main
import (
"my-mcp-server/tools"
"github.com/alibaba/higress/plugins/wasm-go/pkg/mcp/server"
)
func main() {}
func init() {
myMCPServer := &server.MCPServer{}
server.Load(server.AddMCPServer(
"my-mcp-server", // Server name
myMCPServer.AddMCPTool("my_tool", &tools.MyTool{}), // Register tools
// Add more tools as needed
))
}
Dependencies
Your MCP server must use a specific version of the wasm-go SDK that supports Go 1.24's WebAssembly compilation features:
# Add the required dependency
go get github.com/alibaba/higress/plugins/wasm-go
Make sure your go.mod file specifies Go 1.24:
module my-mcp-server
go 1.24
require (
github.com/alibaba/higress/plugins/wasm-go v1.4.4-0.20250324133957-dab499f6ade6
// other dependencies
)
Building the WASM Binary
To compile your Go code into a WebAssembly (WASM) file, use the following command:
GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o main.wasm main.go
This command sets the target operating system to wasip1 (WebAssembly System Interface) and architecture to wasm (WebAssembly), then builds your code as a C-shared library and outputs it as main.wasm.
Using the Makefile
A Makefile is provided to simplify the build process. It includes the following targets:
make build: Builds the WASM binary for your MCP servermake build-image: Builds a Docker image containing your MCP servermake build-push: Builds and pushes the Docker image to a registrymake clean: Removes build artifactsmake help: Shows available targets and variables
You can customize the build by setting the following variables:
# Build with a custom server name
make SERVER_NAME=my-mcp-server build
# Build with a custom registry
make REGISTRY=my-registry.example.com/ build-image
# Build with a specific version tag
make SERVER_VERSION=1.0.0 build-image
Testing
You can create unit tests for your tools to verify their functionality:
// tools/my_tool_test.go
package tools
import (
"encoding/json"
"fmt"
"testing"
)
// TestMyToolInputSchema tests the InputSchema method of MyTool
// to verify that the JSON schema configuration is correct.
func TestMyToolInputSchema(t *testing.T) {
myTool := MyTool{}
schema := myTool.InputSchema()
schemaJSON, err := json.MarshalIndent(schema, "", " ")
if err != nil {
t.Fatalf("Failed to marshal schema to JSON: %v", err)
}
fmt.Printf("MyTool InputSchema:\n%s\n", string(schemaJSON))
if len(schema) == 0 {
t.Error("InputSchema returned an empty schema")
}
}
