数学计算服务

一个基于Go语言实现的MCP协议服务器,提供加法等数学运算功能。

  • by ams0
  • Bicep
  • 本地部署
  • 1 星标
  • 更新于
在 GitHub 查看 ams0/mcp-demo-go

使用说明

MCP演示Go服务器

用Go编写的演示模型上下文协议(MCP)服务器,提供数学运算作为工具。

概述

此MCP服务器实现了一个可以添加两个整数的简单计算器工具。它演示了使用以下工具构建MCP服务器的核心概念 mcp走 图书馆。

服务器信息:

  • 名字:演示开始
  • 版本: 0.0.1
  • 协议版本: 2024-11-05

特性

可用工具

add

将两个整数相加。

参数:

  • a (数字,必填):第一个整数
  • b (数字,必填):第二个整数

退货: 总和为文本

例子:

{
  "name": "add",
  "arguments": {
    "a": 5,
    "b": 3
  }
}

结果: 8

先决条件

  • 达到1.21或更高
  • Node.js和npm(用于MCP检查器)

安装

1.克隆或导航到存储库

cd /Users/alessandro/repos/labs/mcp/mcp-demo-go

2.安装依赖项

go mod download

3.构建服务器

go build -o mcp-demo-go main.go

可执行文件 mcp-demo-go 将在当前目录中创建。

用法

方法1:MCP检查员(建议用于测试)

MCP检查器提供了一个可视化的web界面,用于与您的MCP服务器进行交互。

npx @modelcontextprotocol/inspector ./mcp-demo-go

这将:

  1. 启动本地web服务器(通常在http://localhost:5173)
  2. 启动您的MCP服务器
  3. 打开一个带有交互式UI的浏览器,您可以在其中:
    • 查看所有可用工具
    • 请参阅工具说明和参数
    • 具有自定义输入的测试工具
    • 实时查看响应

方法2:与Claude Desktop集成

要将此MCP服务器与Claude Desktop一起使用,请将其添加到配置文件中。

地点: ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)

配置:

{
  "mcpServers": {
    "demo-go": {
      "command": "/Users/alessandro/repos/labs/mcp/mcp-demo-go/mcp-demo-go"
    }
  }
}

添加配置后:

  1. 重新启动克劳德桌面
  2. 服务器将自动连接
  3. 克劳德将有权访问 add 工具

方法3:使用JSON-RPC进行手动测试

您可以通过stdio使用JSON-RPC消息手动与服务器交互。

创建测试脚本(test_mcp.py):

#!/usr/bin/env python3
import json
import subprocess

def send_request(proc, request):
    request_str = json.dumps(request) + "\n"
    proc.stdin.write(request_str.encode())
    proc.stdin.flush()
    
    response_line = proc.stdout.readline().decode()
    if response_line:
        return json.loads(response_line)
    return None

# Start the MCP server
proc = subprocess.Popen(
    ['./mcp-demo-go'],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE
)

try:
    # Initialize
    init_request = {
        "jsonrpc": "2.0",
        "id": 1,
        "method": "initialize",
        "params": {
            "protocolVersion": "2024-11-05",
            "capabilities": {},
            "clientInfo": {"name": "test-client", "version": "1.0.0"}
        }
    }
    response = send_request(proc, init_request)
    print("Initialize:", json.dumps(response, indent=2))
    
    # Send initialized notification
    initialized = {"jsonrpc": "2.0", "method": "notifications/initialized"}
    proc.stdin.write((json.dumps(initialized) + "\n").encode())
    proc.stdin.flush()
    
    # List tools
    list_request = {
        "jsonrpc": "2.0",
        "id": 2,
        "method": "tools/list",
        "params": {}
    }
    response = send_request(proc, list_request)
    print("\nTools:", json.dumps(response, indent=2))
    
    # Call add tool
    call_request = {
        "jsonrpc": "2.0",
        "id": 3,
        "method": "tools/call",
        "params": {
            "name": "add",
            "arguments": {"a": 10, "b": 20}
        }
    }
    response = send_request(proc, call_request)
    print("\nResult:", json.dumps(response, indent=2))
    
finally:
    proc.terminate()
    proc.wait()

运行测试:

python3 test_mcp.py

方法4:使用curl(用于单个消息)

# Start the server
./mcp-demo-go &
SERVER_PID=$!

# Initialize
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | ./mcp-demo-go

# List tools
echo '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' | ./mcp-demo-go

# Clean up
kill $SERVER_PID

发展

项目结构

mcp-demo-go/
├── main.go           # Main server implementation
├── go.mod            # Go module dependencies
├── go.sum            # Dependency checksums
├── mcp-demo-go       # Compiled binary
└── README.md         # This file

添加新工具

要添加新工具,请按照以下模式操作 main.go:

mcpServer.AddTool(
    mcp.NewTool("tool_name",
        mcp.WithDescription("Description of what the tool does"),
        mcp.WithString("param1",
            mcp.Description("Description of parameter"),
            mcp.Required(),
        ),
    ),
    func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
        args := req.GetArguments()
        param1 := args["param1"].(string)
        
        // Your tool logic here
        
        return &mcp.CallToolResult{
            Content: []mcp.Content{
                mcp.TextContent{
                    Type: "text",
                    Text: "result",
                },
            },
        }, nil
    },
)

参数类型

mcp-go库支持各种参数类型:

  • mcp.WithString() -字符串参数
  • mcp.WithNumber() -数字参数
  • mcp.WithBoolean() -布尔参数
  • mcp.WithArray() -数组参数
  • mcp.WithObject() -对象参数

建筑

# Build for current platform
go build -o mcp-demo-go main.go

# Build for specific platform
GOOS=linux GOARCH=amd64 go build -o mcp-demo-go-linux main.go
GOOS=darwin GOARCH=arm64 go build -o mcp-demo-go-macos main.go
GOOS=windows GOARCH=amd64 go build -o mcp-demo-go.exe main.go

构建Docker镜像(多平台)

# Set your registry and image details
REGISTRY=ghcr.io/ams0
IMAGE=mcp-demo-go
TAG=latest

# Build and push multi-platform image (macOS with Docker Desktop)
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t $REGISTRY/$IMAGE:$TAG \
  --push .

注: 多平台构建需要Docker Buildx。在带有Docker Desktop的macOS上,这是默认启用的。

在发展中奔跑

# Run without building
go run main.go

# Run with race detector
go run -race main.go

MCP协议

该服务器实现了模型上下文协议,该协议允许AI助手和外部工具通过stdio上的JSON-RPC进行通信。

关键概念

  1. 初始化:客户端和服务器交换功能
  2. 工具:AI可以调用的函数
  3. JSON-RPC:用于所有消息的通信协议
  4. 标准运输:通过标准输入/输出交换消息

消息流

Client                          Server
  |                               |
  |---initialize----------------->|
  |<--capabilities----------------|
  |                               |
  |---notifications/initialized-->|
  |                               |
  |---tools/list----------------->|
  |<--tool definitions-----------|
  |                               |
  |---tools/call----------------->|
  |<--result---------------------|

故障排除

服务器未启动

  • 确保二进制文件具有执行权限: chmod +x mcp-demo-go
  • 检查端口5173是否未使用(用于MCP检查器)
  • 验证Go版本: go version

工具未出现在Claude Desktop中

  • 检查配置文件路径是否正确
  • 确保使用二进制文件的绝对路径
  • 配置更改后重新启动Claude Desktop
  • 检查Claude Desktop日志是否有错误

JSON-RPC错误

  • 确保消息的JSON格式正确
  • 每条消息必须以换行符结尾
  • 验证协议版本是否匹配(2024-11-05)

资源

APIM故障排除(容器应用程序后端)

如果APIM调用超时,但直接调用容器应用程序FQDN有效,请按如下方式配置APIM:

  • 后端 serviceUrl: https://mcp-demo-go.graywave-b3e914df.swedencentral.azurecontainerapps.io (公共FQDN,没有尾随斜线,没有 /mcp).
  • API path:空("")所以 /api/joke 地图干净利落。
  • 操作: GET /api/joke (后端路径 /api/joke);对于MCP JSON-RPC,添加 POST /mcp (后端路径 /mcp).
  • 产品:确保API位于与您的订阅密钥匹配的产品中,并且订阅处于活动状态。

通过APIM进行测试(用您的密钥替换):

curl -i --max-time 15 \
    -H "Ocp-Apim-Subscription-Key: <your key>" \
    https://aigwcloud.azure-api.net/api/joke

APIM+入口ID(JWT)身份验证

通过Entra ID和APIM保护此API的示例工作设置:

  • APIM serviceUrl: https://mcp-demo-go.graywave-b3e914df.swedencentral.azurecontainerapps.io (没有尾随斜线,没有 /mcp).
  • API URL后缀: entraid ⇒ 公有 https://aigwcloud.azure-api.net/entraid.
  • 操作: GET /api/joke (后端路径 /api/joke);添加 POST /mcp 如果需要,可以使用JSON-RPC。
  • 订阅:可选;如果禁用,则只需要JWT。如果启用,则发送JWT和订阅密钥。
  • Entra应用程序(API资源): api://5e52ac77-93a5-49aa-923d-a1cdeb3e7cbf 作为观众。

用于验证的入站策略(APIM):

<inbound>
    <base />
    <validate-jwt header-name="Authorization"
                                failed-validation-httpcode="401"
                                failed-validation-error-message="Unauthorized">
        <openid-config url="https://login.microsoftonline.com/2f88d75e-5ed4-41c4-9556-e627fd1ee262/v2.0/.well-known/openid-configuration" />
        <audiences>
            <audience>api://5e52ac77-93a5-49aa-923d-a1cdeb3e7cbf</audience>
        </audiences>
        <issuers>
            <issuer>https://sts.windows.net/2f88d75e-5ed4-41c4-9556-e627fd1ee262/</issuer>
        </issuers>
    </validate-jwt>
</inbound>

获取令牌(基于范围):

API_APP_ID=5e52ac77-93a5-49aa-923d-a1cdeb3e7cbf
TOKEN=$(az account get-access-token --scope api://$API_APP_ID/.default --query accessToken -o tsv)

通过APIM致电(仅限JWT):

curl -i --max-time 15 \
    -H "Authorization: Bearer $TOKEN" \
    https://aigwcloud.azure-api.net/entraid/api/joke

如果需要订阅,请添加: -H "Ocp-Apim-Subscription-Key: <key>".

许可证

这是一个用于学习目的的示范项目。

贡献

欢迎通过以下方式扩展此演示:

  • 添加更多的数学运算(减法、乘法、除法)
  • 对边缘情况实施错误处理
  • 添加输入验证
  • 创建更复杂的工具

示例扩展:添加乘法工具

mcpServer.AddTool(
    mcp.NewTool("multiply",
        mcp.WithDescription("Multiply two numbers"),
        mcp.WithNumber("a",
            mcp.Description("First number"),
            mcp.Required(),
        ),
        mcp.WithNumber("b",
            mcp.Description("Second number"),
            mcp.Required(),
        ),
    ),
    func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
        args := req.GetArguments()
        a, ok1 := args["a"].(float64)
        b, ok2 := args["b"].(float64)
        if !ok1 || !ok2 {
            return mcp.NewToolResultError("Invalid arguments"), nil
        }
        product := a * b
        return &mcp.CallToolResult{
            Content: []mcp.Content{
                mcp.TextContent{
                    Type: "text",
                    Text: strconv.FormatFloat(product, 'f', -1, 64),
                },
            },
        }, nil
    },
)

问题?

关于以下问题:

  • MCP协议:参见 MCP文件
  • Go SDK:参见 mcp转到GitHub
  • 此演示:打开一个问题或修改代码,边做边学!