<!-- title: MCP Server开发调试：构建到验证全链路 -->

## 概述

本教程面向希望构建自定义 MCP Server 并掌握完整开发调试流程的开发者。你将从零搭建一个 TypeScript MCP Server，掌握双传输层配置、Tool/Resource/Prompt 注册、结构化输出、进度通知、日志追踪等核心能力，并学会使用 MCP Inspector 进行可视化调试，最终连接 Claude Code 完成端到端验证。

**适合人群**：有 TypeScript 基础、了解 Claude Code 基本用法的开发者

**学习目标**：
- 掌握 `@modelcontextprotocol/server` SDK 的完整 API
- 理解 stdio 与 Streamable HTTP 两种传输模式的选型与实现
- 使用 MCP Inspector 进行可视化调试与协议级验证
- 构建一个具备生产级特性的 MCP Server 并接入 Claude Code

## 前置条件

| 工具 | 最低版本 | 说明 |
|------|---------|------|
| Node.js | 22.7.5+ | MCP Inspector 需要 |
| npm/pnpm | 最新版 | 包管理 |
| TypeScript | 5.x | 类型安全 |
| Claude Code | 最新版 | 端到端验证 |
| Git | 2.x | 版本控制 |

## MCP Server 开发架构全景

一个 MCP Server 的生命周期由三层组成：

```mermaid
graph TB
    subgraph Client["客户端层"]
        CC["Claude Code"]
        CD["Claude Desktop"]
        MI["MCP Inspector"]
    end

    subgraph Transport["传输层"]
        STDIO["stdio<br/>本地进程通信"]
        HTTP["Streamable HTTP<br/>远程网络通信"]
    end

    subgraph Server["服务层"]
        MCP["McpServer"]
        TOOLS["Tools<br/>可调用操作"]
        RES["Resources<br/>只读数据"]
        PROMPT["Prompts<br/>交互模板"]
        LOG["Logging<br/>结构化日志"]
        PROG["Progress<br/>进度通知"]
    end

    Client --> Transport
    Transport --> Server
    MCP --> TOOLS
    MCP --> RES
    MCP --> PROMPT
    MCP --> LOG
    MCP --> PROG
```

核心决策点：**stdio 用于本地工具（Claude Code / Desktop 直接启动子进程），Streamable HTTP 用于远程服务（网络可达、支持多客户端）**。

## 第一步：项目初始化与 SDK 配置

### 1.1 创建项目脚手架

```bash
mkdir mcp-repo-analyzer && cd mcp-repo-analyzer
npm init -y
npm install @modelcontextprotocol/server@latest @modelcontextprotocol/node@latest zod
npm install -D typescript @types/node
```

### 1.2 TypeScript 配置

创建 `tsconfig.json`：

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"]
}
```

### 1.3 package.json 脚本

```json
{
  "name": "mcp-repo-analyzer",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "build": "tsc",
    "dev": "tsc --watch",
    "start": "node build/index.js",
    "inspect": "npx @modelcontextprotocol/inspector node build/index.js"
  }
}
```

**预期结果**：项目结构如下，`npm run build` 可正常编译。

```
mcp-repo-analyzer/
├── src/
│   └── index.ts
├── build/
├── package.json
└── tsconfig.json
```

**常见问题**：

| 问题 | 原因 | 解决 |
|------|------|------|
| `Cannot find module '@modelcontextprotocol/server'` | SDK 包名变更 | 确认安装 `@modelcontextprotocol/server` |
| `Module build failed` | `"type": "module"` 缺失 | package.json 中添加 `"type": "module"` |
| Zod import 报错 | 版本不匹配 | 使用 `zod/v4` 路径导入 |

## 第二步：双传输层实现

MCP SDK 提供两种传输机制。开发阶段同时支持两者，通过环境变量切换。

```typescript
// src/index.ts
import { randomUUID } from 'node:crypto';
import { McpServer } from '@modelcontextprotocol/server';
import { StdioServerTransport } from '@modelcontextprotocol/server/stdio';
import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node';
import { createMcpExpressApp } from '@modelcontextprotocol/express';

const TRANSPORT = process.env.MCP_TRANSPORT || 'stdio';

export function createServer(): McpServer {
  const server = new McpServer(
    { name: 'repo-analyzer', version: '1.0.0' },
    {
      instructions: 'Git仓库分析工具。始终先调用 list_branches 获取分支列表，再调用 analyze_repo 进行分析。结果最多返回 100 条。'
    }
  );

  // Tools、Resources、Prompts 在这里注册...
  registerTools(server);
  registerResources(server);
  registerPrompts(server);

  return server;
}

async function main() {
  const server = createServer();

  if (TRANSPORT === 'http') {
    // Streamable HTTP 模式：远程访问
    const app = createMcpExpressApp();
    const transport = new NodeStreamableHTTPServerTransport({
      sessionIdGenerator: () => randomUUID()
    });
    await server.connect(transport);
    app.listen(3000, () => {
      console.error('MCP Server running on http://localhost:3000/mcp');
    });
  } else {
    // stdio 模式：本地进程通信
    const transport = new StdioServerTransport();
    await server.connect(transport);
  }
}

main().catch(console.error);
```

**关键要点**：

- `createMcpExpressApp()` 自动启用 DNS rebinding 防护（Host header 校验）
- `sessionIdGenerator` 返回函数则启用有状态会话，设为 `undefined` 则无状态
- stdio 模式下 `console.log` 会干扰协议通信，必须使用 `console.error` 输出调试信息

```mermaid
flowchart LR
    subgraph 开发阶段
        A["npm run inspect<br/>MCP Inspector调试"] --> B["stdio传输"]
    end
    subgraph 部署阶段
        C["远程客户端访问"] --> D["Streamable HTTP传输"]
    end
    B --> E["同一个McpServer实例"]
    D --> E
```

## 第三步：注册 Tool、Resource 与 Prompt

### 3.1 Tool：带结构化输出的工具注册

```typescript
// src/tools.ts
import { McpServer } from '@modelcontextprotocol/server';
import type { CallToolResult } from '@modelcontextprotocol/server';
import * as z from 'zod/v4';
import { execSync } from 'node:child_process';

export function registerTools(server: McpServer): void {
  // 工具1：分析仓库文件统计
  server.registerTool(
    'analyze_repo',
    {
      title: '仓库分析',
      description: '分析 Git 仓库的文件统计、语言分布和提交活跃度',
      inputSchema: z.object({
        path: z.string().describe('仓库本地路径'),
        branch: z.string().default('main').describe('目标分支')
      }),
      outputSchema: z.object({
        totalFiles: z.number(),
        languages: z.record(z.string(), z.number()),
        recentCommits: z.number()
      }),
      annotations: {
        readOnlyHint: true,
        idempotentHint: true
      }
    },
    async ({ path, branch }): Promise<CallToolResult> => {
      try {
        const fileCount = execSync(
          `git -C "${path}" ls-tree -r --name-only ${branch} | wc -l`,
          { encoding: 'utf-8' }
        ).trim();

        const langStats = execSync(
          `git -C "${path}" ls-tree -r --name-only ${branch} | sed 's/.*\\.//' | sort | uniq -c | sort -rn | head -10`,
          { encoding: 'utf-8' }
        ).trim();

        const output = {
          totalFiles: parseInt(fileCount),
          languages: parseLangStats(langStats),
          recentCommits: 0
        };

        return {
          content: [{ type: 'text', text: JSON.stringify(output, null, 2) }],
          structuredContent: output
        };
      } catch (error) {
        return {
          content: [{
            type: 'text',
            text: `分析失败: ${error instanceof Error ? error.message : String(error)}`
          }],
          isError: true
        };
      }
    }
  );

  // 工具2：分支列表（带 ResourceLink 输出）
  server.registerTool(
    'list_branches',
    {
      title: '分支列表',
      description: '列出仓库所有分支',
      inputSchema: z.object({
        path: z.string().describe('仓库本地路径')
      }),
      annotations: {
        readOnlyHint: true
      }
    },
    async ({ path }): Promise<CallToolResult> => {
      const branches = execSync(
        `git -C "${path}" branch -a --format='%(refname:short)'`,
        { encoding: 'utf-8' }
      ).trim().split('\n');

      const links = branches.map(b => ({
        type: 'resource_link' as const,
        uri: `repo://${path}/branch/${b.trim()}`,
        name: b.trim(),
        mimeType: 'text/plain'
      }));

      return { content: links };
    }
  );
}

function parseLangStats(raw: string): Record<string, number> {
  const result: Record<string, number> = {};
  for (const line of raw.split('\n')) {
    const match = line.match(/^\s*(\d+)\s+(\w+)/);
    if (match) result[match[2]] = parseInt(match[1]);
  }
  return result;
}
```

**Tool 注册三要素**：

1. **`inputSchema`**（Zod v4）：定义入参，SDK 自动生成 JSON Schema
2. **`outputSchema`**（可选）：声明结构化返回类型，启用 `structuredContent` 字段
3. **`annotations`**（推荐）：向客户端暗示工具行为（只读、幂等、破坏性）

**注意**：定义 `structuredContent` 的类型时，使用 `type` 别名而非 `interface`，因为 interface 缺少隐式索引签名。

### 3.2 Resource：只读数据暴露

```typescript
// src/resources.ts
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/server';
import * as z from 'zod/v4';
import { execSync } from 'node:child_process';
import { completable } from '@modelcontextprotocol/server';

export function registerResources(server: McpServer): void {
  // 静态资源：仓库配置
  server.registerResource(
    'repo-config',
    'config://repo-analyzer',
    {
      title: '分析器配置',
      description: '当前仓库分析器的配置信息',
      mimeType: 'application/json'
    },
    async (uri) => ({
      contents: [{
        uri: uri.href,
        text: JSON.stringify({
          version: '1.0.0',
          maxResults: 100,
          supportedAnalysis: ['file-stats', 'branch-list', 'commit-log']
        })
      }]
    })
  );

  // 动态资源模板：分支提交日志
  server.registerResource(
    'branch-log',
    new ResourceTemplate('repo://{path}/branch/{branch}', {
      list: async () => ({
        resources: [
          { uri: 'repo:///home/user/my-project/branch/main', name: 'main' },
          { uri: 'repo:///home/user/my-project/branch/develop', name: 'develop' }
        ]
      })
    }),
    {
      title: '分支提交日志',
      description: '指定分支的最近提交记录',
      mimeType: 'text/plain'
    },
    async (uri, { path, branch }) => {
      const log = execSync(
        `git -C "${decodeURIComponent(path)}" log --oneline -20 ${branch}`,
        { encoding: 'utf-8' }
      );
      return {
        contents: [{ uri: uri.href, text: log }]
      };
    }
  );
}
```

### 3.3 Prompt：交互模板与参数补全

```typescript
// src/prompts.ts
import { McpServer, completable } from '@modelcontextprotocol/server';
import * as z from 'zod/v4';

export function registerPrompts(server: McpServer): void {
  server.registerPrompt(
    'review-repo',
    {
      title: '仓库审查',
      description: '对指定仓库进行全面的代码审查分析',
      argsSchema: z.object({
        path: z.string().describe('仓库路径'),
        focus: completable(
          z.string().describe('审查重点'),
          (value) => ['security', 'performance', 'architecture', 'testing']
            .filter(f => f.startsWith(value))
        )
      })
    },
    ({ path, focus }) => ({
      messages: [{
        role: 'user' as const,
        content: {
          type: 'text' as const,
          text: `请对仓库 ${path} 进行${focus || '全面'}审查。先调用 list_branches 获取分支列表，再调用 analyze_repo 分析文件结构。`
        }
      }]
    })
  );
}
```

`completable()` 包装器为客户端提供自动补全建议，用户在输入参数时会看到候选列表。

## 第四步：高级特性——日志、进度与注解

### 4.1 结构化日志

```typescript
// 启用 logging 能力
const server = new McpServer(
  { name: 'repo-analyzer', version: '1.0.0' },
  { capabilities: { logging: {} } }
);

// 在工具处理器中使用
server.registerTool(
  'analyze_repo',
  { /* ... */ },
  async ({ path }, ctx) => {
    await ctx.mcpReq.log('info', `开始分析仓库: ${path}`);

    // ... 执行分析 ...

    await ctx.mcpReq.log('debug', `文件统计完成，共 ${count} 个文件`);
    return { content: [{ type: 'text', text: '...' }] };
  }
);
```

日志级别从低到高：`debug` → `info` → `notice` → `warning` → `error` → `critical`。客户端可通过 `logging/setLevel` 控制接收的最低级别。

### 4.2 进度通知

长时间运行的工具应报告进度：

```typescript
server.registerTool(
  'deep_scan',
  {
    description: '深度扫描仓库所有文件',
    inputSchema: z.object({ path: z.string() })
  },
  async ({ path }, ctx) => {
    const files = getFiles(path);
    const progressToken = ctx.mcpReq._meta?.progressToken;

    for (let i = 0; i < files.length; i++) {
      await processFile(files[i]);

      if (progressToken !== undefined) {
        await ctx.mcpReq.notify({
          method: 'notifications/progress',
          params: {
            progressToken,
            progress: i + 1,
            total: files.length,
            message: `已处理: ${files[i]}`
          }
        });
      }
    }

    return { content: [{ type: 'text', text: `扫描完成: ${files.length} 个文件` }] };
  }
);
```

**关键约束**：`progress` 必须递增；`total` 和 `message` 可选；客户端不提供 `progressToken` 时跳过通知。

### 4.3 错误处理策略

```typescript
// 工具级错误：LLM 可见，可自我纠正
return {
  content: [{ type: 'text', text: `分析失败: ${errorMessage}` }],
  isError: true
};

// 未捕获异常：SDK 自动包装为 isError: true
// 但显式 try/catch 可以控制错误消息内容
```

```mermaid
flowchart TD
    A["Tool被调用"] --> B{"执行成功?"}
    B -->|是| C["返回 content + structuredContent"]
    B -->|否| D{"isError: true?"}
    D -->|是| E["LLM可见错误<br/>可自我纠正重试"]
    D -->|抛异常| F["SDK自动包装<br/>为 isError: true"]
    C --> G["outputSchema验证"]
    E --> H["跳过outputSchema验证"]
    F --> H
```

## 第五步：MCP Inspector 调试全流程

MCP Inspector 是官方可视化调试工具，能直接与你的 Server 交互、查看协议消息、测试所有原语。

### 5.1 启动 Inspector

```bash
# 编译项目
npm run build

# 方式1：直接启动（stdio模式）
npx @modelcontextprotocol/inspector node build/index.js

# 方式2：带环境变量
npx @modelcontextprotocol/inspector -e API_KEY=xxx -e DEBUG=true -- node build/index.js

# 方式3：自定义端口
CLIENT_PORT=8080 SERVER_PORT=9000 npx @modelcontextprotocol/inspector node build/index.js
```

启动后控制台输出：

```
🔑 Session token: 3a1c267fad21f7150b7d624c160b7f09...

🔗 Open inspector with token pre-filled:
   http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=3a1c267f...
```

浏览器自动打开 Inspector UI（端口 6274 是 MCPI 客户端，6277 是 MCPP 代理）。

### 5.2 Inspector 调试界面功能

| 面板 | 功能 | 用途 |
|------|------|------|
| **Tools** | 列出所有注册工具、表单填写参数、执行并查看返回 | 验证工具逻辑和输出格式 |
| **Resources** | 浏览静态资源和动态模板、读取内容 | 验证资源 URI 和内容正确性 |
| **Prompts** | 选择 Prompt 模板、填写参数、预览消息 | 验证模板渲染和补全功能 |
| **Notifications** | 实时显示服务端日志和进度通知 | 追踪日志级别和进度报告 |
| **History** | 查看所有 JSON-RPC 请求/响应 | 协议级调试 |

### 5.3 调试工作流

```mermaid
sequenceDiagram
    participant Dev as 开发者
    participant Ins as MCP Inspector
    participant Proxy as MCP Proxy(6277)
    participant Srv as 你的MCP Server

    Dev->>Ins: 浏览器打开 localhost:6274
    Ins->>Proxy: 连接(stdio启动Server)
    Proxy->>Srv: spawn子进程
    Srv-->>Proxy: initialize响应
    Proxy-->>Ins: 展示Tools/Resources/Prompts列表

    Dev->>Ins: 选择Tool，填写参数
    Ins->>Proxy: tools/call请求
    Proxy->>Srv: 转发JSON-RPC
    Srv-->>Proxy: 返回结果
    Proxy-->>Ins: 显示结果+结构化输出

    Dev->>Ins: 查看Notifications面板
    Note over Ins,Srv: 实时显示log/progress通知
```

### 5.4 配置导出

Inspector 提供一键导出配置，用于接入 Claude Code：

点击 **"Server Entry"** 按钮获取单条配置：

```json
{
  "command": "node",
  "args": ["build/index.js"],
  "env": {
    "DEBUG": "true"
  }
}
```

点击 **"Servers File"** 按钮获取完整配置文件：

```json
{
  "mcpServers": {
    "repo-analyzer": {
      "command": "node",
      "args": ["/absolute/path/to/build/index.js"],
      "env": {
        "DEBUG": "true"
      }
    }
  }
}
```

### 5.5 Docker 运行 Inspector

```bash
docker run --rm \
  -p 127.0.0.1:6274:6274 \
  -p 127.0.0.1:6277:6277 \
  -e HOST=0.0.0.0 \
  -e MCP_AUTO_OPEN_ENABLED=false \
  ghcr.io/modelcontextprotocol/inspector:latest
```

然后手动在 UI 中配置 Server 连接参数。

## 第六步：连接 Claude Code 端到端验证

### 6.1 添加 MCP Server 到 Claude Code

```bash
# 方式1：命令行添加
claude mcp add repo-analyzer node /absolute/path/to/build/index.js

# 方式2：JSON配置添加
claude mcp add-json repo-analyzer '{"command":"node","args":["/absolute/path/to/build/index.js"]}'

# 方式3：项目级 .mcp.json 文件
```

项目根目录创建 `.mcp.json`：

```json
{
  "mcpServers": {
    "repo-analyzer": {
      "command": "node",
      "args": ["./build/index.js"],
      "env": {}
    }
  }
}
```

### 6.2 配置层级

```mermaid
graph TD
    A["项目级 .mcp.json<br/>仅当前项目可见"] --> B["用户级 ~/.claude.json<br/>所有项目共享"]
    B --> C["命令行 claude mcp add<br/>快速临时添加"]
    C --> D["优先级：项目级 > 用户级"]

    style A fill:#4CAF50,color:#fff
    style B fill:#2196F3,color:#fff
    style C fill:#FF9800,color:#fff
```

### 6.3 验证清单

在 Claude Code 中逐项验证：

```bash
# 1. 确认 Server 已注册
claude mcp list

# 2. 检查特定 Server 详情
claude mcp get repo-analyzer

# 3. 在对话中测试
claude "用 repo-analyzer 分析当前仓库的文件分布"
```

**验证检查表**：

| 检查项 | 命令/操作 | 预期结果 |
|--------|----------|---------|
| Server 注册 | `claude mcp list` | 显示 repo-analyzer |
| Tool 发现 | 对话中提及分析 | Claude 调用 analyze_repo |
| Resource 访问 | "查看分析器配置" | 返回配置 JSON |
| Prompt 模板 | "审查仓库" | 展示 review-repo 模板 |
| 错误恢复 | 故意传错路径 | Claude 自我纠正 |
| 日志输出 | Inspector 查看 | 显示 info/debug 级日志 |

### 6.4 移除与重置

```bash
# 移除特定 Server
claude mcp remove repo-analyzer

# 重置所有 MCP 配置（谨慎使用）
claude mcp reset
```

## 完整实战项目：代码仓库分析器

将上述所有模块整合为一个完整可运行的项目。

### 项目结构

```
mcp-repo-analyzer/
├── src/
│   ├── index.ts          # 入口 + 双传输层
│   ├── tools.ts          # Tool 注册
│   ├── resources.ts      # Resource 注册
│   ├── prompts.ts        # Prompt 注册
│   └── utils.ts          # Git 命令工具函数
├── build/                # 编译输出
├── .mcp.json             # Claude Code 集成配置
├── package.json
└── tsconfig.json
```

### 工具函数模块

```typescript
// src/utils.ts
import { execSync } from 'node:child_process';

export function gitCommand(repoPath: string, args: string): string {
  try {
    return execSync(`git -C "${repoPath}" ${args}`, {
      encoding: 'utf-8',
      timeout: 10000,
      maxBuffer: 1024 * 1024
    }).trim();
  } catch (error) {
    throw new Error(
      `Git命令执行失败: git ${args}\n${error instanceof Error ? error.message : String(error)}`
    );
  }
}

export function safeParseInt(value: string, fallback = 0): number {
  const num = parseInt(value, 10);
  return isNaN(num) ? fallback : num;
}
```

### 完整入口文件

```typescript
// src/index.ts
import { randomUUID } from 'node:crypto';
import { McpServer } from '@modelcontextprotocol/server';
import { StdioServerTransport } from '@modelcontextprotocol/server/stdio';
import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node';
import { createMcpExpressApp } from '@modelcontextprotocol/express';
import { registerTools } from './tools.js';
import { registerResources } from './resources.js';
import { registerPrompts } from './prompts.js';

const TRANSPORT = process.env.MCP_TRANSPORT || 'stdio';

function createServer(): McpServer {
  const server = new McpServer(
    { name: 'repo-analyzer', version: '1.0.0' },
    {
      capabilities: { logging: {} },
      instructions: [
        'Git仓库分析工具。',
        '工作流：先调用 list_branches 获取分支列表，再调用 analyze_repo 进行分析。',
        '所有路径参数必须是绝对路径。',
        '结果最多返回 100 条记录。'
      ].join(' ')
    }
  );

  registerTools(server);
  registerResources(server);
  registerPrompts(server);

  return server;
}

async function main() {
  const server = createServer();

  if (TRANSPORT === 'http') {
    const app = createMcpExpressApp();
    const transport = new NodeStreamableHTTPServerTransport({
      sessionIdGenerator: () => randomUUID()
    });
    await server.connect(transport);
    app.listen(3000, () => {
      console.error('[repo-analyzer] Streamable HTTP running on :3000/mcp');
    });
  } else {
    const transport = new StdioServerTransport();
    await server.connect(transport);
    console.error('[repo-analyzer] stdio transport connected');
  }
}

main().catch((err) => {
  console.error('Fatal:', err);
  process.exit(1);
});
```

### 编译与测试

```bash
# 编译
npm run build

# 本地 Inspector 调试
npm run inspect

# 在 Inspector 中：
# 1. 查看 Tools 面板 → 应显示 analyze_repo 和 list_branches
# 2. 测试 list_branches → 传入有效 Git 仓库路径
# 3. 测试 analyze_repo → 查看结构化输出
# 4. 查看 Resources 面板 → 点击 config://repo-analyzer
# 5. 查看 Prompts 面板 → 测试 review-repo，体验参数补全

# 连接 Claude Code
claude mcp add repo-analyzer node $(pwd)/build/index.js
claude "用 repo-analyzer 工具分析 /path/to/your/repo 仓库"
```

## 常见问题与解决方案

### Q1：Inspector 无法连接 Server

**现象**：Inspector UI 显示连接错误。

**排查路径**：

```mermaid
flowchart TD
    A["Inspector连接失败"] --> B{"编译是否成功?"}
    B -->|否| C["运行 npm run build 检查错误"]
    B -->|是| D{"Node版本≥22.7.5?"}
    D -->|否| E["升级Node.js"]
    D -->|是| F{"路径是否正确?"}
    F -->|否| G["使用绝对路径"]
    F -->|是| H["查看Proxy控制台日志"]
    C --> I["修复编译错误后重试"]
    E --> I
    G --> I
    H --> J["检查Server stderr输出"]
```

### Q2：Tool 返回结果被截断

**原因**：`maxBuffer` 限制或 Git 仓库过大。

**解决**：

```typescript
// 增大 buffer 限制
execSync(command, { maxBuffer: 10 * 1024 * 1024 }); // 10MB

// 或限制输出行数
const result = execSync(command).toString().split('\n').slice(0, 100).join('\n');
```

### Q3：Claude Code 中 MCP Server 不响应

```bash
# 检查 Server 是否在列表中
claude mcp list

# 查看 Server 详情（包括错误信息）
claude mcp get repo-analyzer

# 手动测试 Server
node build/index.js
# 然后发送 JSON-RPC 初始化请求到 stdin
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | node build/index.js
```

### Q4：Streamable HTTP 模式 DNS 防护问题

绑定 `0.0.0.0` 时需配置允许的主机列表：

```typescript
const app = createMcpExpressApp({
  host: '0.0.0.0',
  allowedHosts: ['localhost', '127.0.0.1', 'your-domain.com']
});
```

### Q5：`outputSchema` 验证失败

当 `isError: true` 时，输出 schema 验证会被跳过。确保成功路径的返回值与声明的 schema 匹配：

```typescript
// 使用 type 而非 interface
type AnalysisResult = { totalFiles: number; languages: Record<string, number> };
// 而不是 interface AnalysisResult { ... }
```

## 开发调试完整流程图

```mermaid
flowchart TB
    subgraph 开发["开发阶段"]
        A["编写 TypeScript 代码"] --> B["npm run build"]
        B --> C{"编译成功?"}
        C -->|否| A
        C -->|是| D["npm run inspect"]
    end

    subgraph 调试["Inspector调试"]
        D --> E["Tools面板测试"]
        E --> F{"功能正确?"}
        F -->|否| A
        F -->|是| G["Resources面板验证"]
        G --> H{"数据正确?"}
        H -->|否| A
        H -->|是| I["Prompts面板测试"]
        I --> J{"模板正确?"}
        J -->|否| A
        J -->|是| K["导出配置"]
    end

    subgraph 集成["Claude Code集成"]
        K --> L["claude mcp add"]
        L --> M["对话测试"]
        M --> N{"端到端通过?"}
        N -->|否| O["检查 claude mcp get 错误日志"]
        O --> A
        N -->|是| P["完成✓"]
    end

    style P fill:#4CAF50,color:#fff
```

## 延伸阅读

| 资源 | 说明 |
|------|------|
| [MCP TypeScript SDK Server Guide](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/server.md) | 官方完整 API 参考 |
| [MCP Inspector GitHub](https://github.com/modelcontextprotocol/inspector) | Inspector 源码与使用文档 |
| [Claude Code MCP Documentation](https://code.claude.com/docs/en/mcp) | Claude Code MCP 集成官方文档 |
| [MCP Specification](https://modelcontextprotocol.io/specification/latest) | 协议规范全文 |
| [MCP Debugging Guide](https://modelcontextprotocol.io/docs/tools/debugging) | 官方调试指南 |

## 训练营适用性评估

| 维度 | 评估 |
|------|------|
| **适合训练营** | 全栈开发训练营、AI 工具链训练营、DevOps 自动化训练营 |
| **教学时长** | 3-4 小时（含动手实操） |
| **难度级别** | 中级（需要 TypeScript 和 CLI 基础） |
| **前置课程** | Claude Code 入门篇 + Skill 开发实战 |
| **后续课程** | MCP Server 部署与运维、多 MCP 聚合网关 |
| **所需设备** | 学生需自带笔记本，预装 Node.js 22+ 和 Git |

---

## 参考来源

1. [Building MCP Servers — TypeScript SDK Official Guide](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/server.md) — 官方 TypeScript SDK 服务端构建完整 API 文档，涵盖 Tool/Resource/Prompt/Logging/Progress/Elicitation 全部特性
2. [MCP Inspector GitHub Repository](https://github.com/modelcontextprotocol/inspector) — MCP Inspector 官方仓库，包含安装、架构、Docker 部署和安全认证说明
3. [Connect Claude Code to tools via MCP](https://code.claude.com/docs/en/mcp) — Claude Code 官方 MCP 集成文档，覆盖配置层级、传输类型和故障排查
4. [MCP Debugging Guide](https://modelcontextprotocol.io/docs/tools/debugging) — 官方调试工具概览，包含 Inspector、日志、网络分析等多层调试策略
5. [How to Build an MCP Server with Claude: Complete Tutorial 2026](https://dev.to/kalyna_pro/how-to-build-an-mcp-server-with-claude-complete-tutorial-2026-3c26) — 社区实战教程，提供端到端的 MCP Server 构建和测试流程

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
