> ## Documentation Index
> Fetch the complete documentation index at: https://learn.orbexa.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 从零构建MCP Server开发教程

> 从零构建MCP Server完整开发教程，提供TypeScript与Python双语言分步实现指南。涵盖工具定义与inputSchema参数验证、structuredContent结构化响应及Streamable HTTP远程部署配置，附带可运行的天气查询示例代码与MCP Inspector调试技巧

# 构建 MCP Server

## 4.1 开发环境准备

### TypeScript (推荐)

```bash theme={null}
mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk
npm install -D typescript @types/node
npx tsc --init
```

### Python

```bash theme={null}
mkdir my-mcp-server && cd my-mcp-server
pip install mcp
```

## 4.2 TypeScript完整示例

一个提供天气查询工具的MCP Server:

```typescript theme={null}
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

// 创建Server实例
const server = new McpServer({
  name: "weather-server",
  version: "1.0.0"
});

// 定义工具
server.tool(
  "get_weather",          // 工具名
  "获取指定城市的当前天气",  // 描述
  {                        // 输入参数Schema
    city: {
      type: "string",
      description: "城市名称"
    }
  },
  async ({ city }) => {    // 执行函数
    // 这里调用你的天气API
    const weather = await fetchWeather(city);
    return {
      content: [{
        type: "text",
        text: `${city}当前天气: ${weather.temp}°C, ${weather.condition}`
      }]
    };
  }
);

// 启动（stdio传输）
const transport = new StdioServerTransport();
await server.connect(transport);
```

### 多工具Server（含outputSchema和structuredContent）

协议版本 `2025-11-25` 支持 `outputSchema` 定义工具的结构化输出格式，并通过 `structuredContent` 返回结构化数据：

```typescript theme={null}
const server = new McpServer({
  name: "commerce-server",
  version: "1.0.0"
});

// 工具1: 搜索商品（含outputSchema）
server.tool(
  "search_products",
  "搜索商品目录",
  {
    query: { type: "string", description: "搜索关键词" },
    category: { type: "string", description: "商品分类（可选）" },
    limit: { type: "number", description: "返回数量，默认10" }
  },
  async ({ query, category, limit = 10 }) => {
    const results = await db.products.search(query, { category, limit });
    const data = {
      products: results.map(p => ({
        name: p.name, sku: p.sku, price: p.price, inStock: p.inventory > 0
      })),
      total: results.totalCount
    };
    return {
      content: [{
        type: "text",
        text: JSON.stringify(data, null, 2)
      }],
      // structuredContent: 供程序化处理（当定义了outputSchema时）
      structuredContent: data
    };
  }
);

// 工具2: 查询库存
server.tool(
  "check_inventory",
  "查询商品实时库存",
  {
    sku: { type: "string", description: "商品SKU" }
  },
  async ({ sku }) => {
    const inventory = await db.inventory.getBySku(sku);
    if (!inventory) {
      return {
        content: [{ type: "text", text: `SKU ${sku} 不存在` }],
        isError: true
      };
    }
    return {
      content: [{
        type: "text",
        text: `SKU ${sku}: ${inventory.quantity}件 (${inventory.warehouse}仓)`
      }]
    };
  }
);

// 工具3: 查询订单
server.tool(
  "get_order",
  "查询订单状态",
  {
    orderId: { type: "string", description: "订单号" }
  },
  async ({ orderId }) => {
    const order = await db.orders.getById(orderId);
    if (!order) {
      return {
        content: [{ type: "text", text: `订单 ${orderId} 不存在` }],
        isError: true
      };
    }
    return {
      content: [{
        type: "text",
        text: JSON.stringify({
          id: order.id,
          status: order.status,
          items: order.items.length,
          total: order.total,
          tracking: order.trackingNumber
        }, null, 2)
      }]
    };
  }
);
```

## 4.3 Python完整示例

```python theme={null}
from mcp.server import Server
from mcp.server.stdio import stdio_server
import mcp.types as types

server = Server("commerce-server")

@server.list_tools()
async def list_tools() -> list[types.Tool]:
    return [
        types.Tool(
            name="search_products",
            description="搜索商品目录",
            inputSchema={
                "type": "object",
                "properties": {
                    "query": {"type": "string", "description": "搜索关键词"},
                    "limit": {"type": "number", "description": "返回数量"}
                },
                "required": ["query"]
            }
        ),
        types.Tool(
            name="check_inventory",
            description="查询商品实时库存",
            inputSchema={
                "type": "object",
                "properties": {
                    "sku": {"type": "string", "description": "商品SKU"}
                },
                "required": ["sku"]
            }
        )
    ]

@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
    if name == "search_products":
        results = await search_products(
            arguments["query"],
            arguments.get("limit", 10)
        )
        return [types.TextContent(
            type="text",
            text=json.dumps(results, ensure_ascii=False)
        )]
    elif name == "check_inventory":
        inventory = await get_inventory(arguments["sku"])
        return [types.TextContent(
            type="text",
            text=f"SKU {arguments['sku']}: {inventory['quantity']}件"
        )]

async def main():
    async with stdio_server() as (read_stream, write_stream):
        await server.run(read_stream, write_stream)

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())
```

## 4.4 暴露Resources

除了工具，Server还可以暴露数据资源：

```typescript theme={null}
// 暴露商品分类作为资源
server.resource(
  "commerce://catalog/categories",
  "商品分类",
  "application/json",
  async () => {
    const categories = await db.categories.getAll();
    return JSON.stringify(categories, null, 2);
  }
);

// 暴露公司信息作为资源
server.resource(
  "commerce://company/info",
  "公司信息",
  "text/markdown",
  async () => {
    return `# 公司名\n\n> 一句话描述\n\n## 主营业务\n...`;
  }
);
```

## 4.5 Streamable HTTP Server

远程部署时使用Streamable HTTP传输：

```typescript theme={null}
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import express from "express";

const app = express();
app.use(express.json());

const server = new McpServer({
  name: "my-remote-server",
  version: "1.0.0"
});

// 注册工具（同上）...

// 创建Streamable HTTP传输
const transport = new StreamableHTTPServerTransport({
  endpoint: "/mcp"
});

// 挂载到Express
app.post("/mcp", transport.handlePost.bind(transport));
app.get("/mcp", transport.handleGet.bind(transport));

await server.connect(transport);

app.listen(3000, () => {
  console.error("MCP Server (Streamable HTTP) running on port 3000");
});
```

## 4.6 测试和调试

### MCP Inspector

官方提供的调试工具：

```bash theme={null}
npx @modelcontextprotocol/inspector node dist/index.js
```

Inspector会启动一个Web界面，让你交互式地测试每个工具。你可以：

* 查看Server暴露的所有工具、资源、提示词
* 手动输入参数执行工具
* 查看JSON-RPC请求和响应的原始数据
* 验证inputSchema和outputSchema

### 在Claude Desktop中测试

编辑Claude Desktop配置文件：

**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`

```json theme={null}
{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["D:/path/to/my-server/dist/index.js"]
    }
  }
}
```

重启Claude Desktop，在对话中尝试使用你的工具。

## 4.7 常见错误

| 错误                      | 原因                          | 修复                       |
| ----------------------- | --------------------------- | ------------------------ |
| Server启动后无响应            | `console.log` 输出到stdout干扰协议 | 日志输出到stderr              |
| 工具不出现                   | `tools/list` 返回为空           | 检查工具注册代码                 |
| 参数验证失败                  | inputSchema和实际参数不匹配         | 检查JSON Schema定义          |
| 连接超时                    | Server进程没有正确启动              | 检查command和args配置         |
| `structuredContent` 被忽略 | 未定义 `outputSchema`          | 添加outputSchema或只用content |
| 初始化失败                   | 协议版本不匹配                     | 确认Client和Server使用兼容的版本   |

<Warning>
  **stdio Server绝对不能用 `console.log`**。stdout是协议通道，任何非JSON-RPC的输出都会破坏通信。用 `console.error` 或写文件日志。
</Warning>

***

**下一章**: [商务MCP Server](/zh/book-5/ch5-commerce-server) — 电商场景的MCP Server设计模式
