MCP 与 Agent 生态 / MCP Server 开发实战
CHAPTER 06 · TOPIC 02

MCP Server 开发实战

理解了 MCP 协议的原理后,本章进入实战——如何从零开发一个 MCP Server。我们将使用 Python SDK 构建一个完整的 MCP Server,涵盖工具(Tools)、资源(Resources)和提示词模板(Prompts)的开发,并讲解调试和部署。

一句话理解

理解了 MCP 协议的原理后,本章进入实战——如何从零开发一个 MCP Server。我们将使用 Python SDK 构建一个完整的 MCP Server,涵盖工具(Tools)、资源(Resources)和提示词模板(Prompts)的开发,并讲解调试和部署。

阅读前置

建议先完成第 05 章

本文关注

开发环境搭建、Python SDK 开发 MCP Server、配置与集成

所在知识层

连接协议 · MCP 与 Agent 生态

文章导航
主教学视觉MCP Server 开发实战 · 知识结构

点击图中节点可定位到对应正文。

核心主题关系与流向

引言

理解了 MCP 协议的原理后,本章进入实战——如何从零开发一个 MCP Server。我们将使用 Python SDK 构建一个完整的 MCP Server,涵盖工具(Tools)、资源(Resources)和提示词模板(Prompts)的开发,并讲解调试和部署。


1. 开发环境搭建

1.1 安装 SDK

BASH
# Python SDK
pip install mcp

# TypeScript SDK(二选一)
npm install @modelcontextprotocol/sdk

# 辅助工具
pip install mcp[cli]  # MCP 开发调试 CLI

1.2 项目结构

语义 SVG 重绘MCP Server 开发实战

根据原图的箭头、并列、分层与循环关系选择对应图形;可展开核对原文结构。

输入与上下文my-mcp-server/系统核心server.py 主服务文件tools/ 工具实现init.py工具、结果与反馈search.py 搜索工analytics.py 分析工具
查看原文结构
my-mcp-server/
├── server.py          # 主服务文件
├── tools/             # 工具实现
│   ├── __init__.py
│   ├── search.py      # 搜索工具
│   └── analytics.py   # 分析工具
├── resources/         # 资源实现
│   ├── __init__.py
│   └── data.py        # 数据资源
├── prompts/           # 提示词模板
│   ├── __init__.py
│   └── templates.py
├── requirements.txt
└── mcp-config.json    # MCP 配置文件

2. Python SDK 开发 MCP Server

2.1 基础 Server 框架

语义 SVG 重绘MCP Server 开发实战 · 结构 1

根据原图的箭头、并列、分层与循环关系选择对应图形;可展开核对原文结构。

输入与上下文@server.listtools()系统核心async def listtools()list Tool :"""返回所有可用工具的列表"""工具、结果与反馈returnTool(
查看原文结构
@server.list_tools()
async def list_tools() -> list[Tool]:
    """返回所有可用工具的列表"""
    return [
        Tool(
            name="query_data",
            description="查询数据分析结果。当需要获取特定指标或统计数据时使用此工具。",
            inputSchema={
                "type": "object",
                "properties": {
                    "metric": {
                        "type": "string",
                        "description": "要查询的指标名称,如 'revenue', 'users', 'conversion'",
                        "enum": ["revenue", "users", "conversion", "retention"]
                    },
                    "time_range": {
                        "type": "string",
                        "description": "时间范围",
                        "enum": ["today", "week", "month", "quarter", "year"]
                    },
                    "filters": {
                        "type": "object",
                        "description": "可选的过滤条件",
                        "properties": {
                            "region": {"type": "string"},
                            "product": {"type": "string"}
                        }
                    }
                },
                "required": ["metric", "time_range"]
            }
        ),
        Tool(
            name="generate_report",
            description="生成数据分析报告。支持多种格式和详细程度。",
            inputSchema={
                "type": "object",
                "properties": {
                    "report_type": {
                        "type": "string",
                        "enum": ["daily", "weekly", "monthly", "custom"]
                    },
                    "format": {
                        "type": "string",
                        "enum": ["text", "markdown", "json"],
                        "default": "markdown"
                    },
                    "include_charts": {
                        "type": "boolean",
                        "default": True
                    }
                },
                "required": ["report_type"]
            }
        )
    ]
语义 SVG 重绘MCP Server 开发实战 · 结构 2

根据原图的箭头、并列、分层与循环关系选择对应图形;可展开核对原文结构。

输入与上下文@server.calltool()系统核心async def calltool(name: …list TextContent :"""处理工具调用请求"""工具、结果与反馈
查看原文结构
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
    """处理工具调用请求"""
语义 SVG 重绘MCP Server 开发实战 · 结构 3

根据原图的箭头、并列、分层与循环关系选择对应图形;可展开核对原文结构。

查看原文结构
@server.list_resources()
async def list_resources() -> list[Resource]:
    """返回所有可用资源的列表"""
    return [
        Resource(
            uri="data://metrics/overview",
            name="数据概览",
            description="所有核心指标的概览数据",
            mimeType="application/json"
        ),
        Resource(
            uri="data://config/settings",
            name="系统配置",
            description="当前数据分析系统的配置信息",
            mimeType="application/json"
        )
    ]
语义 SVG 重绘MCP Server 开发实战 · 结构 4

根据原图的箭头、并列、分层与循环关系选择对应图形;可展开核对原文结构。

查看原文结构
@server.list_resource_templates()
async def list_resource_templates() -> list[ResourceTemplate]:
    """返回动态资源模板"""
    return [
        ResourceTemplate(
            uriTemplate="data://metrics/{metric_name}",
            name="指标详情",
            description="获取指定指标的详细数据",
            mimeType="application/json"
        )
    ]
语义 SVG 重绘MCP Server 开发实战 · 结构 5

根据原图的箭头、并列、分层与循环关系选择对应图形;可展开核对原文结构。

查看原文结构
@server.read_resource()
async def read_resource(uri: str) -> str:
    """读取资源内容"""
    if uri == "data://metrics/overview":
        return json.dumps(get_overview_data())
    elif uri.startswith("data://metrics/"):
        metric_name = uri.split("/")[-1]
        return json.dumps(get_metric_detail(metric_name))
    else:
        raise ValueError(f"未知资源: {uri}")
语义 SVG 重绘MCP Server 开发实战 · 结构 6

根据原图的箭头、并列、分层与循环关系选择对应图形;可展开核对原文结构。

输入与上下文@server.listprompts()系统核心async def listprompts()list Prompt :return工具、结果与反馈Prompt(name="analyzetrend",
查看原文结构
@server.list_prompts()
async def list_prompts() -> list[Prompt]:
    return [
        Prompt(
            name="analyze_trend",
            description="分析数据趋势并提供洞察",
            arguments=[
                PromptArgument(
                    name="metric",
                    description="要分析的指标",
                    required=True
                ),
                PromptArgument(
                    name="period",
                    description="分析周期(如 7d, 30d, 90d)",
                    required=True
                )
            ]
        )
    ]
语义 SVG 重绘MCP Server 开发实战 · 结构 7

根据原图的箭头、并列、分层与循环关系选择对应图形;可展开核对原文结构。

输入与上下文@server.getprompt()系统核心async def getprompt(name:…dict:if name == "analyzetrend"…工具、结果与反馈return"messages":
查看原文结构
@server.get_prompt()
async def get_prompt(name: str, arguments: dict) -> dict:
    if name == "analyze_trend":
        return {
            "messages": [
                PromptMessage(
                    role="user",
                    content=TextContent(
                        type="text",
                        text=f"""请分析 {arguments['metric']} 指标在最近 {arguments['period']} 的趋势:
语义 SVG 重绘MCP Server 开发实战 · 结构 8

根据原图的箭头、并列、分层与循环关系选择对应图形;可展开核对原文结构。

async def handleque…str:"""查询数据的实际实现"""metric = arguments …timerange = argumen…filters = arguments…
查看原文结构
async def handle_query_data(arguments: dict) -> str:
    """查询数据的实际实现"""
    metric = arguments["metric"]
    time_range = arguments["time_range"]
    filters = arguments.get("filters", {})
语义 SVG 重绘MCP Server 开发实战 · 结构 9

根据原图的箭头、并列、分层与循环关系选择对应图形;可展开核对原文结构。

async def handlegen…str:"""生成报告的实际实现"""reporttype = argume…fmt = arguments.get…
查看原文结构
async def handle_generate_report(arguments: dict) -> str:
    """生成报告的实际实现"""
    report_type = arguments["report_type"]
    fmt = arguments.get("format", "markdown")

2.2 TypeScript SDK 实现

语义 SVG 重绘MCP Server 开发实战 · 结构 1

根据原图的箭头、并列、分层与循环关系选择对应图形;可展开核对原文结构。

查看原文结构
// 注册工具列表
server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [
    {
      name: "query_data",
      description: "查询数据分析结果",
      inputSchema: {
        type: "object",
        properties: {
          metric: { type: "string", enum: ["revenue", "users", "conversion"] },
          time_range: { type: "string", enum: ["today", "week", "month"] },
        },
        required: ["metric", "time_range"],
      },
    },
  ],
}));
语义 SVG 重绘MCP Server 开发实战 · 结构 2

根据原图的箭头、并列、分层与循环关系选择对应图形;可展开核对原文结构。

输入与上下文// 处理工具调用系统核心server.setRequestHandler(…const name, arguments: ar…工具、结果与反馈
查看原文结构
// 处理工具调用
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

3. 配置与集成

3.1 Claude Desktop 配置

JSON
// claude_desktop_config.json
{
  "mcpServers": {
    "my-data-server": {
      "command": "python",
      "args": ["path/to/server.py"],
      "env": {
        "DATABASE_URL": "postgresql://localhost:5432/analytics",
        "API_KEY": "your-api-key"
      }
    },
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/project"]
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_TOKEN": "ghp_xxxx"
      }
    }
  }
}

3.2 多 Server 协同

语义 SVG 重绘MCP Server 开发实战 · 结构 1

根据原图的箭头、并列、分层与循环关系选择对应图形;可展开核对原文结构。

输入与上下文Claude Desktop · Client 1…系统核心Client 2 · GitHub · Serve…Client 3 · File · Server工具、结果与反馈
查看原文结构
┌──────────────────────────────────────────────┐
│              Claude Desktop                  │
│                                              │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐     │
│  │ Client 1 │  │ Client 2 │  │ Client 3 │     │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘     │
└───────┼─────────────┼─────────────┼──────────┘
        │             │             │
   ┌────┴────┐  ┌────┴────┐  ┌────┴────┐
   │Database │  │ GitHub  │  │ File    │
   │ Server  │  │ Server  │  │ Server  │
   └─────────┘  └─────────┘  └─────────┘
语义 SVG 重绘MCP Server 开发实战 · 结构 2

根据原图的箭头、并列、分层与循环关系选择对应图形;可展开核对原文结构。

输入与上下文Claude 可以跨 Server 工作:系统核心"查看 GitHub 上的 Issue,查询数据库…GitHub Server 获取 IssueDatabase Server 查询数据工具、结果与反馈Filesystem Server 写入文件
查看原文结构
Claude 可以跨 Server 工作:
"查看 GitHub 上的 Issue,查询数据库中的相关数据,把分析结果写入报告文件"
  → GitHub Server 获取 Issue
  → Database Server 查询数据
  → Filesystem Server 写入文件

4. 调试与测试

4.1 MCP Inspector

BASH
# 使用 MCP Inspector 调试 Server
npx @modelcontextprotocol/inspector python server.py

#  Inspector 提供:
# - 工具列表和手动调用
# - 资源浏览和读取
# - 提示词模板测试
# - 消息日志查看

4.2 单元测试

PYTHON
import pytest
from mcp.testing import MockClient

@pytest.fixture
async def client():
    """创建测试用的 Mock Client"""
    return MockClient("server.py")

@pytest.mark.asyncio
async def test_list_tools(client):
    """测试工具列表"""
    tools = await client.list_tools()
    assert len(tools) >= 2
    tool_names = [t.name for t in tools]
    assert "query_data" in tool_names
    assert "generate_report" in tool_names

@pytest.mark.asyncio
async def test_query_data(client):
    """测试数据查询工具"""
    result = await client.call_tool("query_data", {
        "metric": "revenue",
        "time_range": "month"
    })
    assert not result.isError
    assert "revenue" in result.content[0].text.lower()

@pytest.mark.asyncio
async def test_invalid_metric(client):
    """测试无效指标的错误处理"""
    result = await client.call_tool("query_data", {
        "metric": "invalid_metric",
        "time_range": "month"
    })
    assert result.isError

@pytest.mark.asyncio
async def test_resources(client):
    """测试资源读取"""
    resources = await client.list_resources()
    assert len(resources) > 0
    
    content = await client.read_resource("data://metrics/overview")
    assert "revenue" in content or "users" in content

5. 高级特性

5.1 工具进度通知

语义 SVG 重绘MCP Server 开发实战

根据原图的箭头、并列、分层与循环关系选择对应图形;可展开核对原文结构。

输入与上下文@server.calltool()系统核心async def calltool(name: …list TextContent :if name == "longrunningan…工具、结果与反馈发送进度通知await server.sendprogress…
查看原文结构
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
    if name == "long_running_analysis":
        # 发送进度通知
        await server.send_progress("正在连接数据库...")
        data = await fetch_data()

5.2 资源订阅(变更通知)

PYTHON
# 客户端订阅资源变更
@server.subscribe_resource()
async def handle_subscribe(uri: str):
    """当客户端订阅某个资源时"""
    # 注册变更通知
    database.on_change(uri, lambda: server.send_resource_updated(uri))

# 当数据变更时,自动通知所有订阅者
async def on_data_change(table: str):
    uri = f"data://metrics/{table}"
    await server.send_notification(
        "notifications/resources/updated",
        {"uri": uri}
    )

5.3 采样能力(Server 请求 LLM)

PYTHON
# Server 可以请求 Host 的 LLM 能力(需要 Host 支持)
async def smart_tool_selection(task: str):
    """让 LLM 帮助选择最合适的工具组合"""
    result = await server.create_message(
        messages=[{
            "role": "user",
            "content": {
                "type": "text",
                "text": f"任务:{task}\n请从可用工具中选择最合适的执行方案"
            }
        }],
        max_tokens=500
    )
    return result

6. 部署方案

6.1 本地部署(stdio)

JSON
// 配置文件中直接使用
{
  "mcpServers": {
    "local-server": {
      "command": "python",
      "args": ["/path/to/server.py"]
    }
  }
}

6.2 远程部署(HTTP + SSE)

PYTHON
from mcp.server.sse import SseServerTransport
from starlette.applications import Starlette
from starlette.routing import Route

# 创建 SSE 传输
sse = SseServerTransport("/mcp/")

async def handle_sse(request):
    async with sse.connect_sse(request.scope, request.receive, request._send) as streams:
        await server.run(streams[0], streams[1], server.create_initialization_options())

async def handle_message(request):
    await sse.handle_post_message(request.scope, request.receive, request._send)

app = Starlette(routes=[
    Route("/mcp/sse", endpoint=handle_sse),
    Route("/mcp/messages", endpoint=handle_message, methods=["POST"]),
])

# 部署
# uvicorn server_http:app --host 0.0.0.0 --port 8080

6.3 Docker 部署

DOCKERFILE
FROM python:3.12-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# stdio 模式
CMD ["python", "server.py"]
JSON
// Docker 方式配置
{
  "mcpServers": {
    "docker-server": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "my-mcp-server"],
      "env": {
        "DATABASE_URL": "postgresql://host.docker.internal:5432/analytics"
      }
    }
  }
}

7. 本章小结

维度要点
SDK 选择Python SDK(快速开发)/ TypeScript SDK(生态兼容)
核心步骤定义工具/资源/提示词 → 实现处理逻辑 → 配置启动
工具描述越详细越好,直接影响 LLM 的选择准确性
调试MCP Inspector + 单元测试
部署stdio(本地)/ HTTP+SSE(远程)/ Docker(容器化)
安全最小权限、沙箱隔离、用户确认

相关章节


延伸阅读

  • MCP Python SDK: github.com/modelcontextprotocol/python-sdk
  • MCP TypeScript SDK: github.com/modelcontextprotocol/typescript-sdk
  • MCP Server 示例库: github.com/modelcontextprotocol/servers
  • MCP Inspector: github.com/modelcontextprotocol/inspector