📚 目录

  1. 前言:为什么需要 MCP Server

  2. 核心概念:MCP 协议与工具调用

  3. 系统架构:从用户到工具的完整路径

  4. 代码实现:构建加法 MCP Server

  5. 完整调用流程:解密 LLM 如何使用工具

  6. 关键洞察:LLM 推理与工具编排

  7. 最佳实践与常见问题

  8. 总结与展望


1. 前言:为什么需要 MCP Server

1.1 AI Agent 的局限性

大型语言模型(LLM)虽然强大,但存在固有局限:

局限

说明

示例

知识截止

训练数据有时间限制

无法获取实时股票价格

计算能力

推理过程中不做精确计算

9867 × 8734

 可能计算错误

外部交互

无法主动访问外部系统

不能读取文件、调用 API

工具操作

无法执行系统命令

不能运行 Python 代码、操作数据库

1.2 MCP:连接 AI 与工具的桥梁

MCP (Model Context Protocol) 是 Anthropic 开发的开放协议,用于让 AI Agent 安全、标准化地调用外部工具。

没有 MCP:
  用户 → LLM → 文本响应 ❌ (无法执行操作)

有了 MCP:
  用户 → LLM → 工具调用 → 执行 → 结果 → LLM → 响应 ✅

1.3 本文目标

通过构建一个最简单但完整的 MCP Server(加法服务),我们将深入理解:

  • ✅ MCP 协议的工作原理
  • ✅ HTTP 传输与 JSON-RPC 2.0 规范
  • ✅ Claude Code 如何发现和调用工具
  • ✅ LLM 如何"知道"该用哪个工具 ⭐ 核心问题

  • ✅ 多步骤工具编排的实现机制

2. 核心概念:MCP 协议与工具调用

2.1 MCP 协议栈

┌──────────────────────────────────────┐
│         应用层 (Application)         │
│   Claude Code / 其他 AI Agent        │
└─────────────┬────────────────────────┘
              │
┌─────────────┴────────────────────────┐
│         协议层 (Protocol)            │
│   JSON-RPC 2.0 + MCP 扩展            │
│   • initialize                       │
│   • tools/list                       │
│   • tools/call                       │
└─────────────┬────────────────────────┘
              │
┌─────────────┴────────────────────────┐
│         传输层 (Transport)           │
│   HTTP (本文) / stdio / WebSocket    │
└─────────────┬────────────────────────┘
              │
┌─────────────┴────────────────────────┐
│         工具层 (Tools)               │
│   Python / JavaScript / Bash / ...   │
└──────────────────────────────────────┘

2.2 核心方法

方法

作用

调用时机

initialize

握手协商

Claude Code 启动时

tools/list

列出所有工具

初始化后立即调用 ⭐

tools/call

执行具体工具

LLM 决策需要使用工具时

2.3 工具定义规范

{
    "name": "add",  # 工具唯一标识符
    "description": "Add two numbers together",  # 功能描述 ⭐ LLM 看这个
    "inputSchema": {  # JSON Schema 定义参数
        "type": "object",
        "properties": {
            "a": {"type": "number", "description": "第一个数"},
            "b": {"type": "number", "description": "第二个数"}
        },
        "required": ["a", "b"]
    }
}

关键点

  • description

     是 LLM 理解工具用途的唯一信息

  • inputSchema

     定义了参数结构,LLM 根据它生成参数

  • 描述越清晰,LLM 越容易正确使用

3. 系统架构:从用户到工具的完整路径

3.1 整体架构

┌─────────────────────────────────────────────────────────────────┐
│                         用户交互层                                │
│                    👤 Terminal / Shell                          │
│                   $ claude "add 10+13+12"                       │
└────────────────────────────┬────────────────────────────────────┘
                             │
                             ▼
┌─────────────────────────────────────────────────────────────────┐
│                      Claude Code CLI                            │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │
│  │ 会话管理      │  │ 配置加载      │  │ 权限控制      │          │
│  │ Session      │  │ .mcp.json    │  │ Permission   │          │
│  └──────────────┘  └──────────────┘  └──────────────┘          │
└────────────────────────────┬────────────────────────────────────┘
                             │
                             ▼
┌─────────────────────────────────────────────────────────────────┐
│                       Agent Loop 循环                            │
│  ┌────────────────────────────────────────────────────────┐    │
│  │  接收请求 → LLM推理 → 工具调用 → 结果处理 → 生成响应   │    │
│  └────────────────────────────────────────────────────────┘    │
└───────┬─────────────────────────────────┬───────────────────────┘
        │                                 │
        │                                 │
        ▼                                 ▼
┌──────────────────┐            ┌──────────────────────────────┐
│   LLM 推理层      │            │   MCP 协议层                  │
│                  │            │                              │
│  ┌────────────┐  │            │  ┌────────────────────────┐ │
│  │Claude API  │  │            │  │  HTTP Transport        │ │
│  │🧠 Sonnet   │  │◄───────────┤  │  JSON-RPC 2.0          │ │
│  │  4.5       │  │  工具响应   │  │                        │ │
│  └────────────┘  │            │  │  ┌──────────────────┐ │ │
│                  │            │  │  │ SSE EventStream  │ │ │
│  • 分析用户意图   │            │  │  │ /sse endpoint    │ │ │
│  • 决定工具调用   │            │  │  │ 握手协商          │ │ │
│  • 整合返回结果   │            │  │  └──────────────────┘ │ │
│                  │  工具调用   │  │                        │ │
│                  ├───────────►│  │  POST /              │ │
│                  │            │  │  调用工具              │ │
└──────────────────┘            │  └────────────────────────┘ │
                                └────────┬─────────────────────┘
                                         │
                                         ▼
                            ┌───────────────────────┐
                            │  add-server MCP       │
                            │  🔧 HTTP Server       │
                            ├───────────────────────┤
                            │                       │
                            │  Flask Web Server     │
                            │  • Host: 0.0.0.0      │
                            │  • Port: 8080         │
                            │  • CORS: Enabled      │
                            │                       │
                            │  MCP 端点:             │
                            │  ┌─────────────────┐ │
                            │  │ GET  /sse       │ │
                            │  │ POST /          │ │
                            │  │ GET  /health    │ │
                            │  └─────────────────┘ │
                            │                       │
                            │  提供工具:             │
                            │  ┌─────────────────┐ │
                            │  │ 📐 add(a, b)    │ │
                            │  │                 │ │
                            │  │ 输入:            │ │
                            │  │  • a: number    │ │
                            │  │  • b: number    │ │
                            │  │                 │ │
                            │  │ 输出:            │ │
                            │  │  result = a + b │ │
                            │  └─────────────────┘ │
                            │                       │
                            │  实现文件:             │
                            │  add_mcp_server.py    │
                            └───────────────────────┘
                                         │
                                         ▼
                            ┌────────────────────────┐
                            │   Python Runtime       │
                            │   执行加法运算          │
                            └────────────────────────┘

3.2 关键组件职责

组件

职责

关键点

Claude Code

会话管理、配置加载

读取 .mcp.json 发现服务

LLM (Sonnet 4.5)

理解意图、决策工具调用

⭐ 不直接看代码,只看工具描述

MCP 协议层

标准化通信

JSON-RPC 2.0 + HTTP/SSE

add-server

实现具体工具

Flask 服务器 + Python 逻辑


4. 代码实现:构建加法 MCP Server

4.1 项目结构

add-server/
├── add_mcp_server_http.py    # 主服务器代码
├── requirements.txt           # 依赖: Flask, flask-cors
└── README.md                  # 说明文档

4.2 核心代码解析

4.2.1 服务器初始化
from flask import Flask, request, jsonify, Response
from flask_cors import CORS

app = Flask(__name__)
CORS(app)  # 允许跨域(Claude Code 可能从不同域访问)

# 服务器元信息
SERVER_INFO = {
    "name": "add-server",
    "version": "1.0.0"
}

# 工具定义 ⭐ 这是 LLM 看到的唯一信息
TOOLS = [
    {
        "name": "add",
        "description": "Add two numbers together and return the result",
        "inputSchema": {
            "type": "object",
            "properties": {
                "a": {"type": "number", "description": "The first number"},
                "b": {"type": "number", "description": "The second number"}
            },
            "required": ["a", "b"]
        }
    }
]

关键点

  • TOOLS

     列表定义了所有可用工具

  • description必须清晰

    ,LLM 靠它理解工具用途

  • inputSchema

     使用 JSON Schema 标准

4.2.2 服务发现端点(SSE)
@app.route('/sse', methods=['GET'])
def sse_endpoint():
    """
    SSE 端点 - 告诉客户端 JSON-RPC 端点的 URL

    工作流程:
    1. Claude Code 启动时访问 /sse
    2. 服务器返回 endpoint 事件,包含 JSON-RPC URL
    3. 客户端后续所有请求发送到该 URL
    """
    def generate():
        endpoint_data = json.dumps({"url": "http://localhost:8080"})
        yieldf"event: endpoint\n"
        yieldf"data: {endpoint_data}\n\n"

    return Response(
        generate(),
        mimetype='text/event-stream',
        headers={
            'Cache-Control': 'no-cache',
            'Connection': 'keep-alive'
        }
    )

为什么需要 SSE?

  • HTTP 传输的 MCP Server 需要服务发现机制
  • SSE 允许服务器主动推送端点信息
  • 客户端只需知道 /sse 即可动态发现 JSON-RPC 端点

4.2.3 主请求处理器
@app.route('/', methods=['POST'])
def handle_request():
    message = request.get_json()
    msg_id = message.get("id")
    method = message.get("method")
    params = message.get("params", {})

    # ============================================================
    # 方法 1: initialize - 握手
    # ============================================================
    if method == "initialize":
        return jsonify({
            "jsonrpc": "2.0",
            "id": msg_id,
            "result": {
                "protocolVersion": "2024-11-05",
                "capabilities": {"tools": {}},  # 声明支持工具
                "serverInfo": SERVER_INFO
            }
        })

    # ============================================================
    # 方法 2: tools/list - 列出工具 ⭐ 关键方法
    # ============================================================
    elif method == "tools/list":
        return jsonify({
            "jsonrpc": "2.0",
            "id": msg_id,
            "result": {"tools": TOOLS}  # 返回工具定义
        })

    # ============================================================
    # 方法 3: tools/call - 执行工具
    # ============================================================
    elif method == "tools/call":
        tool_name = params.get("name")
        arguments = params.get("arguments", {})

        if tool_name == "add":
            a = arguments.get("a")
            b = arguments.get("b")
            result = float(a) + float(b)

            return jsonify({
                "jsonrpc": "2.0",
                "id": msg_id,
                "result": {
                    "content": [
                        {
                            "type": "text",
                            "text": f"The sum of {a} and {b} is {result}"
                        }
                    ]
                }
            })
        else:
            # 工具未找到
            return jsonify({
                "jsonrpc": "2.0",
                "id": msg_id,
                "error": {
                    "code": -32601,
                    "message": f"Tool not found: {tool_name}"
                }
            }), 404

代码亮点

  • ✅ 标准 JSON-RPC 2.0 格式
  • ✅ 清晰的错误处理
  • ✅ 结构化的响应格式
4.2.4 健康检查(可选但推荐)
@app.route('/health', methods=['GET'])
def health_check():
    """简单的健康检查,便于监控和调试"""
    return jsonify({
        "status": "healthy",
        "server": SERVER_INFO
    })

4.3 启动服务器

if __name__ == '__main__':
    print("🚀 Starting Add MCP Server")
    print(f"📍 URL: http://localhost:8080")
    print(f"🔧 Available tools: add")

    app.run(host='0.0.0.0', port=8080, debug=True)

运行命令

# 安装依赖
pip install flask flask-cors

# 启动服务器
python3 add_mcp_server_http.py

5. 完整调用流程:解密 LLM 如何使用工具

5.1 配置 Claude Code

创建或编辑 ~/.mcp.json

{
  "mcpServers": {
    "add-server": {
      "type": "http",
      "url": "http://localhost:8080"
    }
  }
}

5.2 启动时的初始化流程

┌─────────────────────────────────────────────────────────────────┐
│                    Claude Code 启动流程                          │
└─────────────────────────────────────────────────────────────────┘

1️⃣ 读取配置文件 (.mcp.json)
   ↓
   发现 add-server: {"type": "http", "url": "http://localhost:8080"}

2️⃣ 建立连接 - 服务发现 (SSE)
   ↓
   GET http://localhost:8080/sse
   ←─────────────────────────────────
   event: endpoint
   data: {"url": "http://localhost:8080"}

3️⃣ 初始化连接 (initialize)
   ↓
   POST http://localhost:8080/
   {
     "jsonrpc": "2.0",
     "id": 1,
     "method": "initialize"
   }
   ←─────────────────────────────────
   {
     "result": {
       "protocolVersion": "2024-11-05",
       "capabilities": {"tools": {}},
       "serverInfo": {
         "name": "add-server",
         "version": "1.0.0"
       }
     }
   }

4️⃣ 获取工具列表 (tools/list) ⭐ 关键步骤
   ↓
   POST http://localhost:8080/
   {
     "jsonrpc": "2.0",
     "id": 2,
     "method": "tools/list"
   }
   ←─────────────────────────────────
   {
     "result": {
       "tools": [
         {
           "name": "add",
           "description": "Add two numbers together and return the result",
           "inputSchema": {
             "type": "object",
             "properties": {
               "a": {"type": "number", "description": "The first number"},
               "b": {"type": "number", "description": "The second number"}
             },
             "required": ["a", "b"]
           }
         }
       ]
     }
   }

5️⃣ 工具信息传递给 LLM ⭐⭐⭐ 核心机制
   ↓
   Claude Code 将工具信息包含在系统提示中发送给 Claude API

   System Prompt (简化版):
   """
   You have access to the following tools:

   Tool: add
   Description: Add two numbers together and return the result
   Parameters:
     - a (number): The first number
     - b (number): The second number

   When you need to add numbers, call this tool by outputting:
   <tool_call>
     <name>add</name>
     <arguments>
       {"a": 10, "b": 13}
     </arguments>
   </tool_call>
   """

关键理解

  • LLM 从未见过 MCP Server 的代码

  • LLM 只看到tools/list 返回的工具描述

  • 工具描述就是 LLM 的"使用说明书"

5.3 用户请求的执行流程

场景:用户输入 "add 10+13+12"

┌─────────────────────────────────────────────────────────────────┐
│                    用户请求执行流程                              │
└─────────────────────────────────────────────────────────────────┘

6️⃣ 用户发送请求
   ↓
   User: "add 10+13+12"

7️⃣ LLM 推理决策 ⭐⭐⭐ 最关键的步骤
   ↓
   Claude API 的思考过程:

   输入:
   - 用户消息: "add 10+13+12"
   - 可用工具: add(a, b)
   - 工具描述: "Add two numbers together"

   推理:
   "用户要计算 10+13+12 的和
    我有一个 add 工具,但它只能加两个数
    所以我需要调用两次:
    - 第一次: add(10, 13) → 得到 23
    - 第二次: add(23, 12) → 得到最终结果"

   决策:
   调用 add 工具两次(串行)

8️⃣ Claude Code 执行工具调用 (第一次)
   ↓
   POST http://localhost:8080/
   {
     "jsonrpc": "2.0",
     "id": 3,
     "method": "tools/call",
     "params": {
       "name": "add",
       "arguments": {"a": 10, "b": 13}
     }
   }
   ←─────────────────────────────────
   {
     "result": {
       "content": [
         {"type": "text", "text": "The sum of 10 and 13 is 23.0"}
       ]
     }
   }

9️⃣ Claude Code 执行工具调用 (第二次)
   ↓
   LLM 收到第一次结果后,继续推理:
   "现在我知道 10+13=23,接下来计算 23+12"

   POST http://localhost:8080/
   {
     "jsonrpc": "2.0",
     "id": 4,
     "method": "tools/call",
     "params": {
       "name": "add",
       "arguments": {"a": 23.0, "b": 12}
     }
   }
   ←─────────────────────────────────
   {
     "result": {
       "content": [
         {"type": "text", "text": "The sum of 23.0 and 12 is 35.0"}
       ]
     }
   }

🔟 LLM 整合结果并生成最终响应
   ↓
   Claude API 收到两次工具调用结果后:

   "根据工具调用结果:
    - 第一步: 10 + 13 = 23
    - 第二步: 23 + 12 = 35
    因此,10 + 13 + 12 = 35"

   生成用户友好的响应:
   "## 计算结果

   我使用 add 工具进行了计算:

   **步骤 1**: 10 + 13 = **23**
   **步骤 2**: 23 + 12 = **35**

   **最终答案**: 10 + 13 + 12 = **35** ✓"

1️⃣1️⃣ 结果返回给用户
   ↓
   User 看到完整的计算过程和结果

6. 关键洞察:LLM 推理与工具编排

6.1 LLM 如何"知道"使用哪个工具?

这是最关键的问题。答案分为三个层次:

层次 1:工具描述是唯一依据
# ❌ LLM 看不到这些
def add(a, b):
    """这个函数计算两个数的和"""  # 代码注释
    return a + b

# ✅ LLM 只看到这个
{
    "name": "add",
    "description": "Add two numbers together and return the result",  # ⭐
    "inputSchema": {...}
}

实验验证

# 测试 1: 模糊描述
{
    "name": "add",
    "description": "Does something with numbers",  # ❌ 太模糊
}
# 结果: LLM 不确定何时使用

# 测试 2: 清晰描述
{
    "name": "add",
    "description": "Add two numbers together and return the sum",  # ✅ 清晰
}
# 结果: LLM 正确使用
层次 2:上下文匹配算法

LLM 内部的决策过程(简化模型):

输入: "add 10+13+12"

步骤 1: 理解用户意图
  → "用户想要计算数字之和"

步骤 2: 遍历所有可用工具
  tools = [
    {"name": "add", "description": "Add two numbers together"},
    {"name": "multiply", "description": "Multiply two numbers"},
    ...
  ]

步骤 3: 相关性评分
for tool in tools:
    score = similarity(user_intent, tool.description)

  结果:
    add: 0.95  ⭐ 最匹配
    multiply: 0.15
    ...

步骤 4: 参数生成
  根据 inputSchema 和上下文生成参数

  schema = {"a": number, "b": number}
  context = "10+13+12"

  推理: "需要分两步执行"
  call_1: add(10, 13)
  call_2: add(result_1, 12)
层次 3:多工具编排策略

LLM 具备规划能力

场景: 用户要求 "计算 (10+5) × 3"

可用工具: add(a, b), multiply(a, b)

LLM 的执行计划:
1.add(10, 5) → result1 = 15
2. multiply(result1, 3) → result2 = 45
3. 返回 result2

关键能力:
  ✅ 识别依赖关系 (步骤 2 依赖步骤 1)
  ✅ 中间变量传递 (result1)
  ✅ 正确的执行顺序

6.2 为什么 LLM 能做到这些?

能力

来源

示例

语义理解

预训练语料库

"add" 和 "sum" 语义相近

指令遵循

RLHF 微调

理解工具调用格式

规划能力

Chain-of-Thought

多步骤推理

参数推断

Schema 理解 + 上下文

从 "10+13" 推断 a=10, b=13

6.3 实验:改变描述的影响

# 实验对照组
EXPERIMENT_TOOLS = [
    # 版本 A: 精确描述
    {
        "name": "add",
        "description": "Add two numbers together and return their sum"
    },

    # 版本 B: 模糊描述
    {
        "name": "add",
        "description": "Process numbers"# ❌ 太模糊
    },

    # 版本 C: 误导性描述
    {
        "name": "add",
        "description": "Multiply two numbers"# ❌ 描述错误
    }
]

# 测试结果
用户输入: "What is 5 + 3?"

版本 A: ✅ 正确调用 add(5, 3)
版本 B: ❌ 不确定,可能不调用或调用错误工具
版本 C: ❌ 可能调用其他工具或产生困惑

结论:工具描述的质量直接决定 LLM 的使用效果。


7. 最佳实践与常见问题

7.1 工具描述最佳实践

✅ 好的描述
{
    "name": "send_email",
    "description": """
    Send an email to a recipient with a subject and body.

    Use this when the user wants to:
    - Send an email
    - Email someone
    - Compose and send a message

    Note: Requires valid email address format.
    """
}

特点:

  • ✅ 清晰的功能说明
  • ✅ 列出使用场景
  • ✅ 说明重要约束
❌ 差的描述
{
    "name": "send_email",
    "description": "Sends email"  # ❌ 太简短,信息不足
}

7.2 参数 Schema 设计

✅ 完善的 Schema
{
    "inputSchema": {
        "type": "object",
        "properties": {
            "to": {
                "type": "string",
                "description": "Recipient email address (e.g., user@example.com)",
                "pattern": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
            },
            "subject": {
                "type": "string",
                "description": "Email subject line",
                "minLength": 1,
                "maxLength": 200
            },
            "body": {
                "type": "string",
                "description": "Email body content (plain text or HTML)"
            }
        },
        "required": ["to", "subject", "body"]
    }
}

特点:

  • ✅ 详细的字段描述
  • ✅ 数据验证规则
  • ✅ 示例格式

7.3 错误处理

✅ 友好的错误消息
try:
    result = perform_action(params)
    return {
        "content": [{"type": "text", "text": f"Success: {result}"}]
    }
except ValueError as e:
    return {
        "content": [
            {
                "type": "text",
                "text": f"Error: Invalid input - {str(e)}\n\n"
                        f"Please provide valid numbers."
            }
        ],
        "isError": True# 标记为错误响应
    }

7.4 常见问题

Q1: LLM 没有调用我的工具?

可能原因

  1. 工具描述不清晰 → 改进 description

  2. 用户意图不明确 → 提示用户更明确的表达
  3. 有更匹配的其他工具 → 检查工具冲突

调试方法

# 查看 Claude Code 日志
claude --debug "test my tool"

# 手动测试工具
curl -X POST http://localhost:8080/ \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/list"
  }'
Q2: 工具调用参数错误?

可能原因

  1. inputSchema

     定义不清晰

  2. 参数描述缺失
  3. 类型定义错误

解决方案

# ✅ 添加更多上下文
"properties": {
    "amount": {
        "type": "number",
        "description": "Amount in USD (e.g., 10.50 for $10.50)",  # ⭐ 示例
        "minimum": 0,
        "maximum": 10000
    }
}
Q3: 如何支持复杂返回类型?
# 支持多种内容类型
return {
    "content": [
        {"type": "text", "text": "Here are the results:"},
        {"type": "image", "data": base64_image, "mimeType": "image/png"},
        {"type": "resource", "uri": "file:///path/to/file"}
    ]
}

8. 总结与展望

8.1 核心要点回顾

概念

关键理解

MCP 协议

标准化 AI 与工具的通信协议

工具描述

LLM 理解工具的唯一依据 ⭐

JSON-RPC 2.0

底层通信格式

工具编排

LLM 具备多步骤规划能力

参数推断

LLM 从上下文推断工具参数

8.2 实现 MCP Server 的三个层次

层次 1: 最小实现 (本文示例)
  ├─ 单个工具
  ├─ 基本错误处理
  └─ HTTP 传输

层次 2: 生产级实现
  ├─ 多个工具
  ├─ 完善的验证
  ├─ 日志和监控
  ├─ 认证授权
  └─ 性能优化

层次 3: 企业级实现
  ├─ 工具发现与注册
  ├─ 版本管理
  ├─ 分布式部署
  ├─ 工具组合与链式调用
  └─ 安全沙箱

8.3 从加法到复杂工具

渐进式学习路径

1. add(a, b)           → 理解基本原理
   ↓
2. calculator(expr)    → 解析复杂输入
   ↓
3. database_query()    → 外部系统集成
   ↓
4. code_execution()    → 安全执行代码
   ↓
5. workflow_engine()   → 多工具编排
🌟 生态系统

9. 实战练习

练习 1: 扩展加法服务器

在 add-server 基础上添加:

  • ✅ subtract(a, b) - 减法

  • ✅ multiply(a, b) - 乘法

  • ✅ divide(a, b) - 除法(处理除零)

练习 2: 构建文件操作 MCP Server

实现:

  • ✅ read_file(path) - 读取文件

  • ✅ write_file(path, content) - 写入文件

  • ✅ list_directory(path) - 列出目录

练习 3: API 集成 MCP Server

实现:

  • ✅ get_weather(city) - 获取天气

  • ✅ search_github(query) - 搜索仓库

  • ✅ translate_text(text, target_lang) - 翻译


10. 资源与参考

官方文档

  • MCP 协议规范

  • Claude Code 文档

  • JSON-RPC 2.0 规范

示例代码

  • 本文完整代码

  • MCP Python SDK

  • 社区 MCP Server 集合

社区

  • MCP Discord

  • Claude Code 论坛


附录:完整代码清单

A.1 add_mcp_server_http.py

#!/usr/bin/env python3
"""
完整的 MCP Server 实现 - 加法服务
详细注释版本
"""
import json
from flask import Flask, request, jsonify, Response
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

SERVER_INFO = {
    "name": "add-server",
    "version": "1.0.0"
}

TOOLS = [
    {
        "name": "add",
        "description": "Add two numbers together and return the result",
        "inputSchema": {
            "type": "object",
            "properties": {
                "a": {"type": "number", "description": "The first number"},
                "b": {"type": "number", "description": "The second number"}
            },
            "required": ["a", "b"]
        }
    }
]

@app.route('/sse', methods=['GET'])
def sse_endpoint():
    def generate():
        endpoint_data = json.dumps({"url": "http://localhost:8080"})
        yieldf"event: endpoint\n"
        yieldf"data: {endpoint_data}\n\n"

    return Response(
        generate(),
        mimetype='text/event-stream',
        headers={
            'Cache-Control': 'no-cache',
            'X-Accel-Buffering': 'no',
            'Connection': 'keep-alive'
        }
    )

@app.route('/', methods=['POST'])
def handle_request():
    try:
        message = request.get_json()
        ifnot message:
            return jsonify({
                "jsonrpc": "2.0",
                "id": None,
                "error": {"code": -32700, "message": "Parse error"}
            }), 400

        msg_id = message.get("id")
        method = message.get("method")
        params = message.get("params", {})

        if method == "initialize":
            return jsonify({
                "jsonrpc": "2.0",
                "id": msg_id,
                "result": {
                    "protocolVersion": "2024-11-05",
                    "capabilities": {"tools": {}},
                    "serverInfo": SERVER_INFO
                }
            })

        elif method == "tools/list":
            return jsonify({
                "jsonrpc": "2.0",
                "id": msg_id,
                "result": {"tools": TOOLS}
            })

        elif method == "tools/call":
            tool_name = params.get("name")
            arguments = params.get("arguments", {})

            if tool_name == "add":
                try:
                    a = arguments.get("a")
                    b = arguments.get("b")

                    if a isNoneor b isNone:
                        return jsonify({
                            "jsonrpc": "2.0",
                            "id": msg_id,
                            "error": {
                                "code": -32602,
                                "message": "Both 'a' and 'b' required"
                            }
                        }), 400

                    result = float(a) + float(b)

                    return jsonify({
                        "jsonrpc": "2.0",
                        "id": msg_id,
                        "result": {
                            "content": [
                                {
                                    "type": "text",
                                    "text": f"The sum of {a} and {b} is {result}"
                                }
                            ]
                        }
                    })

                except (ValueError, TypeError) as e:
                    return jsonify({
                        "jsonrpc": "2.0",
                        "id": msg_id,
                        "error": {
                            "code": -32602,
                            "message": f"Invalid parameters: {str(e)}"
                        }
                    }), 400

            else:
                return jsonify({
                    "jsonrpc": "2.0",
                    "id": msg_id,
                    "error": {
                        "code": -32601,
                        "message": f"Tool not found: {tool_name}"
                    }
                }), 404

        else:
            return jsonify({
                "jsonrpc": "2.0",
                "id": msg_id,
                "error": {
                    "code": -32601,
                    "message": f"Method not found: {method}"
                }
            }), 404

    except Exception as e:
        return jsonify({
            "jsonrpc": "2.0",
            "id": None,
            "error": {
                "code": -32603,
                "message": f"Internal error: {str(e)}"
            }
        }), 500

@app.route('/health', methods=['GET'])
def health_check():
    return jsonify({"status": "healthy", "server": SERVER_INFO})

if __name__ == '__main__':
    print("=" * 70)
    print("🚀 Starting Add MCP Server")
    print("=" * 70)
    print(f"📍 URL: http://localhost:8080")
    print(f"📋 Server: {SERVER_INFO['name']} v{SERVER_INFO['version']}")
    print(f"🔧 Available tools: {', '.join([t['name'] for t in TOOLS])}")
    print("=" * 70)
    print("\n🔗 Endpoints:")
    print("   GET  /health  - Health check")
    print("   GET  /sse     - Service discovery")
    print("   POST /        - JSON-RPC requests")
    print("\n⏳ Starting server...\n")

    app.run(host='0.0.0.0', port=8080, debug=True)

A.2 requirements.txt

Flask==3.0.0
flask-cors==4.0.0

A.3 测试脚本

#!/bin/bash
# test_mcp_server.sh

echo"🧪 Testing MCP Server..."

echo"\n1️⃣ Health Check:"
curl -s http://localhost:8080/health | jq

echo"\n2️⃣ Initialize:"
curl -s -X POST http://localhost:8080/ \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize"}' | jq

echo"\n3️⃣ Tools List:"
curl -s -X POST http://localhost:8080/ \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | jq

echo"\n4️⃣ Call Add Tool:"
curl -s -X POST http://localhost:8080/ \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"add","arguments":{"a":10,"b":13}}}' | jq

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐