mirror of
https://github.com/alibaba/higress.git
synced 2026-05-22 19:57:29 +08:00
248 lines
7.1 KiB
Markdown
248 lines
7.1 KiB
Markdown
# MCP Server Implementation Guide
|
|
|
|
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
|
|
├── server/
|
|
│ └── server.go # Server configuration and parsing
|
|
└── tools/
|
|
└── my_tool.go # Tool implementation
|
|
```
|
|
|
|
## Server Configuration
|
|
|
|
The server configuration defines the parameters needed for the server to function. For example:
|
|
|
|
```go
|
|
// server/server.go
|
|
package server
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
|
|
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
|
|
)
|
|
|
|
// Define your server configuration structure
|
|
type MyMCPServer struct {
|
|
ApiKey string `json:"apiKey"`
|
|
// Add other configuration fields as needed
|
|
}
|
|
|
|
// Validate the configuration
|
|
func (s MyMCPServer) ConfigHasError() error {
|
|
if s.ApiKey == "" {
|
|
return errors.New("missing api key")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Parse configuration from JSON
|
|
func ParseFromConfig(configBytes []byte, server *MyMCPServer) error {
|
|
return json.Unmarshal(configBytes, server)
|
|
}
|
|
|
|
// Parse configuration from HTTP request
|
|
func ParseFromRequest(ctx wrapper.HttpContext, server *MyMCPServer) error {
|
|
return ctx.ParseMCPServerConfig(server)
|
|
}
|
|
```
|
|
|
|
## Tool Implementation
|
|
|
|
Each tool should be implemented as a struct with the following methods:
|
|
|
|
1. `Description()`: Returns a description of the tool
|
|
2. `InputSchema()`: Returns the JSON schema for the tool's input parameters
|
|
3. `Create()`: Creates a new instance of the tool with the provided parameters
|
|
4. `Call()`: Executes the tool's functionality
|
|
|
|
Example:
|
|
|
|
```go
|
|
// tools/my_tool.go
|
|
package tools
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"my-mcp-server/server"
|
|
|
|
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
|
|
)
|
|
|
|
// 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 wrapper.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) wrapper.MCPTool[server.MyMCPServer] {
|
|
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 wrapper.HttpContext, config server.MyMCPServer) error {
|
|
// Validate configuration
|
|
err := server.ParseFromRequest(ctx, &config)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = config.ConfigHasError()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Implement your tool's logic here
|
|
// ...
|
|
|
|
// Return results
|
|
ctx.SendMCPToolTextResult(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:
|
|
|
|
```go
|
|
// main.go
|
|
package main
|
|
|
|
import (
|
|
"my-mcp-server/server"
|
|
"my-mcp-server/tools"
|
|
|
|
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
|
|
)
|
|
|
|
func main() {}
|
|
|
|
func init() {
|
|
wrapper.SetCtx(
|
|
"my-mcp-server", // Server name
|
|
wrapper.ParseRawConfig(server.ParseFromConfig),
|
|
wrapper.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:
|
|
|
|
```bash
|
|
# Add the required dependency with the specific version tag
|
|
go get github.com/alibaba/higress/plugins/wasm-go@wasm-go-1.24
|
|
```
|
|
|
|
## Building the WASM Binary
|
|
|
|
To compile your Go code into a WebAssembly (WASM) file, use the following command:
|
|
|
|
```bash
|
|
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 server
|
|
- `make build-image`: Builds a Docker image containing your MCP server
|
|
- `make build-push`: Builds and pushes the Docker image to a registry
|
|
- `make clean`: Removes build artifacts
|
|
- `make help`: Shows available targets and variables
|
|
|
|
You can customize the build by setting the following variables:
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```go
|
|
// tools/my_tool_test.go
|
|
package tools
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"testing"
|
|
)
|
|
|
|
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")
|
|
}
|
|
}
|
|
```
|