本教程面向希望为 Claude Code 构建自定义 MCP(Model Context Protocol)服务器的开发者。学完本教程后,你将掌握 MCP 协议的三大原语(Tools、Resources、Prompts)、2025-06-18 规范新增特性(Elicitation、Structured Output、OAuth 2.1)、以及如何用 TypeScript 和 Python(FastMCP 3.x)两种语言实现完整的 MCP 服务器,并将其接入 Claude Code 的完整工作流。
适用人群:有基本编程经验、已使用过 Claude Code、希望扩展 Claude Code 能力边界的开发者。
Model Context Protocol(模型上下文协议)是 Anthropic 发布的开放协议,定义了 AI 模型与外部工具、数据源之间的标准化通信方式。MCP 的设计理念类似"AI 的 USB-C"——一种通用的连接标准,让任何 AI 客户端都能与任何工具服务器对接。

图表 1
MCP 服务器暴露三种类型的能力给客户端:
| 原语 | 用途 | 特征 | 典型场景 |
|---|---|---|---|
| Tools | 可调用的函数 | 模型控制、有副作用 | 查询数据库、调用API、执行命令 |
| Resources | 可读取的数据源 | 只读、应用控制 | 文件内容、数据库记录、配置信息 |
| Prompts | 可复用的提示模板 | 用户控制 | 标准化的工作流模板、角色设定 |
何时用 Tools vs Resources? - 如果操作会改变状态(写入、删除、发送)→ 用 Tool - 如果只是读取数据(查询、获取、列举)→ 用 Resource - 如果需要标准化一段提示让用户选择使用 → 用 Prompt
MCP 支持两种传输方式:

图表 2
2025-06-18 规范的重大更新:
- Elicitation:服务器可暂停工具执行,向用户请求输入(人机协作)
- Structured Output:工具可返回结构化内容(文本 + 图片 + 音频等)
- Tool Annotations:工具可声明 readOnlyHint、destructiveHint 等元数据
- OAuth 2.1 增强:远程服务器的标准化认证流程
# 创建项目目录
mkdir my-mcp-server && cd my-mcp-server
# 初始化 npm 项目
npm init -y
# 安装 MCP TypeScript SDK(当前最新 v1.29.x)
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx
# 初始化 TypeScript 配置
npx tsc --init
在 tsconfig.json 中确认以下配置:
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
}
}
创建 src/index.ts:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// 创建服务器实例
const server = new McpServer({
name: "my-first-mcp-server",
version: "1.0.0",
});
// 注册一个 Tool
server.tool(
"get_weather", // 工具名称
"获取指定城市的天气信息", // 工具描述
{ city: z.string().describe("城市名称") }, // 参数 schema
async ({ city }) => {
// 这里是工具的实际逻辑
const weatherData = {
city,
temperature: "22°C",
condition: "晴",
humidity: "45%",
};
return {
content: [
{
type: "text",
text: JSON.stringify(weatherData, null, 2),
},
],
};
}
);
// 注册一个 Resource
server.resource(
"config", // 资源名称
"config://app", // 资源 URI
async (uri) => {
return {
contents: [
{
uri: uri.href,
text: JSON.stringify({ version: "1.0", env: "development" }),
},
],
};
}
);
// 注册一个 Prompt
server.prompt(
"code-review", // Prompt 名称
"代码审查模板", // 描述
{ code: z.string().describe("待审查的代码") },
async ({ code }) => {
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `请审查以下代码,关注安全性、性能和可维护性:\n\n${code}`,
},
},
],
};
}
);
// 启动服务器
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP Server started on stdio"); // 注意:用 stderr 输出日志
}
main().catch(console.error);
更新 package.json:
{
"type": "module",
"scripts": {
"build": "tsc",
"dev": "tsx src/index.ts",
"start": "node dist/index.js"
}
}
stdout vs stderr:MCP 协议通过 stdio 传输 JSON-RPC 消息,所以 console.log() 会干扰协议通信。所有日志必须输出到 stderr:
console.error("这条日志不会干扰 MCP 协议"); // ✓ 正确
console.log("这条会破坏 MCP 协议"); // ✗ 错误
Zod Schema 自动转换:SDK 会自动将 Zod schema 转换为 JSON Schema,Claude 端会据此理解参数含义和类型约束。
Tool 返回格式:所有 Tool 必须返回 { content: [...] } 结构,content 数组中可包含多个内容块(text、image、resource)。
使用 MCP Inspector(官方调试工具)进行测试:
# 安装并运行 Inspector
npx @modelcontextprotocol/inspector tsx src/index.ts
Inspector 会打开一个浏览器界面,你可以: - 查看 Tools/Resources/Prompts 列表 - 手动调用 Tool 并查看返回结果 - 检查 JSON-RPC 请求/响应 - 验证 Schema 定义是否正确
Python 生态有两个层次的 MCP SDK:
- mcp 官方 SDK:底层、灵活但代码量大
- fastmcp 3.x:高层封装,用装饰器快速定义 Tools/Resources/Prompts
对于大多数场景,FastMCP 的开发效率更高。
# 创建项目
mkdir my-python-mcp && cd my-python-mcp
# 创建虚拟环境
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# 安装 FastMCP
pip install fastmcp
创建 server.py:
from fastmcp import FastMCP
import json
from datetime import datetime
# 创建服务器实例
mcp = FastMCP("my-python-server")
# ============ Tools ============
@mcp.tool()
def search_docs(query: str, max_results: int = 5) -> str:
"""搜索技术文档
Args:
query: 搜索关键词
max_results: 最大返回结果数(默认5)
"""
# 模拟搜索逻辑
results = [
{"title": f"文档{i}: {query} 相关内容", "relevance": 0.95 - i * 0.1}
for i in range(min(max_results, 10))
]
return json.dumps(results, ensure_ascii=False, indent=2)
@mcp.tool()
def calculate(expression: str) -> str:
"""安全计算数学表达式
Args:
expression: 数学表达式字符串,如 "2 + 3 * 4"
"""
# 安全的数学计算 - 只允许基本运算符
allowed_chars = set("0123456789+-*/().% ")
if not all(c in allowed_chars for c in expression):
return "错误:表达式包含不允许的字符"
try:
result = eval(expression) # 在输入已验证的情况下使用
return f"{expression} = {result}"
except Exception as e:
return f"计算错误:{e}"
@mcp.tool()
def create_task(title: str, description: str = "", priority: str = "medium") -> str:
"""创建新任务
Args:
title: 任务标题
description: 任务描述
priority: 优先级 (low/medium/high)
"""
task = {
"id": f"TASK-{datetime.now().strftime('%Y%m%d%H%M%S')}",
"title": title,
"description": description,
"priority": priority,
"status": "created",
"created_at": datetime.now().isoformat(),
}
return json.dumps(task, ensure_ascii=False, indent=2)
# ============ Resources ============
@mcp.resource("config://app")
def get_app_config() -> str:
"""获取应用配置"""
config = {
"app_name": "My Python MCP Server",
"version": "1.0.0",
"environment": "development",
"features": ["search", "calculate", "task_management"],
}
return json.dumps(config, ensure_ascii=False, indent=2)
@mcp.resource("docs://api/{endpoint}")
def get_api_docs(endpoint: str) -> str:
"""获取 API 文档"""
docs = {
"search_docs": "搜索技术文档,参数: query(str), max_results(int)",
"calculate": "计算数学表达式,参数: expression(str)",
"create_task": "创建任务,参数: title(str), description(str), priority(str)",
}
return json.dumps(
docs.get(endpoint, f"未找到 {endpoint} 的文档"),
ensure_ascii=False
)
# ============ Prompts ============
@mcp.prompt()
def debug_helper(error_message: str, language: str = "python") -> str:
"""调试辅助提示模板
Args:
error_message: 错误信息
language: 编程语言
"""
return f"""你是一个 {language} 调试专家。请分析以下错误并给出解决方案:
错误信息:
{error_message}
请按以下格式回答:
1. 错误原因分析
2. 可能的修复方案(从最可能到最不可能排序)
3. 预防措施"""
@mcp.prompt()
def code_review_template(code: str, focus: str = "general") -> str:
"""代码审查提示模板"""
focus_areas = {
"general": "整体代码质量、可读性、最佳实践",
"security": "安全漏洞、输入验证、权限控制",
"performance": "性能瓶颈、时间复杂度、内存使用",
}
return f"""请审查以下代码,重点关注:{focus_areas.get(focus, focus_areas['general'])}
```{focus}
{code}
请提供: 1. 发现的问题(按严重程度排序) 2. 改进建议 3. 修改后的代码示例"""
if name == "main": mcp.run()
### 3.4 运行 FastMCP 服务器
```bash
# stdio 模式(Claude Code 默认使用此模式)
fastmcp run server.py
# 或者开发调试模式
fastmcp dev server.py
# 指定传输方式
fastmcp run server.py --transport stdio
claude mcp add 命令Claude Code 提供了专用的 MCP 管理命令:
# 添加 stdio 模式的本地 MCP 服务器(TypeScript)
claude mcp add my-tools -- npx tsx /path/to/src/index.ts
# 添加 stdio 模式的本地 MCP 服务器(Python)
claude mcp add my-python-tools -- fastmcp run /path/to/server.py
# 添加远程 MCP 服务器(Streamable HTTP)
claude mcp add --transport http http://localhost:3000/mcp
# 指定作用域
claude mcp add --scope project my-tools -- npx tsx ./src/index.ts
claude mcp add --scope user my-tools -- npx tsx ~/mcp-servers/my-server/src/index.ts

图表 3
作用域选择指南:
- user:个人通用工具(如搜索引擎、个人日历)
- project:项目特定工具(如项目数据库、CI/CD 工具)
- 优先使用 project scope,让项目配置可移植
你也可以直接编辑配置文件。用户级配置在 ~/.claude/settings.json,项目级配置在项目根目录的 .mcp.json:
{
"mcpServers": {
"my-local-server": {
"command": "npx",
"args": ["tsx", "/path/to/src/index.ts"],
"env": {
"API_KEY": "your-api-key"
}
},
"my-remote-server": {
"url": "http://localhost:3000/mcp",
"headers": {
"Authorization": "Bearer your-token"
}
},
"my-python-server": {
"command": "fastmcp",
"args": ["run", "/path/to/server.py"],
"env": {
"PYTHONUNBUFFERED": "1"
}
}
}
}
# 列出所有 MCP 服务器
claude mcp list
# 查看某个服务器的详细信息
claude mcp get my-tools
# 移除服务器
claude mcp remove my-tools
# 重置服务器连接
claude mcp reset
添加服务器后,在 Claude Code 对话中直接使用:
> 帮我搜索关于 React hooks 的技术文档
# Claude 会自动调用 search_docs tool
> 当前应用配置是什么?
# Claude 会读取 config://app resource
> 用代码审查模板帮我检查这段代码
# Claude 会使用 code-review prompt
Claude Code 的 /mcp 面板可以查看所有已连接的服务器状态和可用工具数量。
2025-06-18 规范引入了工具注解,让你的工具声明自身的行为特征:
// TypeScript SDK 示例
server.tool(
"delete_database",
"删除数据库",
{ db_name: z.string() },
{ annotations: {
readOnlyHint: false, // 非只读,会修改状态
destructiveHint: true, // 破坏性操作
idempotentHint: false, // 非幂等
openWorldHint: false, // 不访问外部网络
}},
async ({ db_name }) => {
// 删除逻辑
return { content: [{ type: "text", text: `已删除数据库: ${db_name}` }] };
}
);
# FastMCP Python 示例
from fastmcp import FastMCP
from mcp.types import ToolAnnotations
mcp = FastMCP("annotated-server")
@mcp.tool(annotations=ToolAnnotations(
readOnlyHint=True,
destructiveHint=False,
idempotentHint=True,
openWorldHint=False,
))
def query_user(user_id: str) -> str:
"""查询用户信息(只读操作)"""
return json.dumps({"user_id": user_id, "name": "张三"})
注解帮助 Claude 在调用前评估风险,对破坏性操作会额外请求用户确认。
长时间运行的操作可以报告进度:
server.tool(
"process_large_file",
"处理大文件",
{ path: z.string() },
async ({ path }, { sendNotification }) => {
const totalSteps = 100;
for (let i = 0; i < totalSteps; i++) {
// 执行处理步骤...
await sendNotification({
method: "notifications/progress",
params: {
progress: i + 1,
total: totalSteps,
progressToken: "file-processing",
},
});
}
return { content: [{ type: "text", text: "处理完成" }] };
}
);
2025-06-18 规范允许工具返回多种类型的内容:
server.tool(
"analyze_chart",
"分析图表并返回描述和图片",
{ chart_type: z.string() },
async ({ chart_type }) => {
return {
content: [
{
type: "text",
text: `分析结果:这是一个${chart_type}图表,显示上升趋势...`,
},
{
type: "image",
data: base64EncodedImage,
mimeType: "image/png",
},
{
type: "resource",
resource: {
uri: "analysis://full-report",
text: "完整分析报告内容...",
},
},
],
};
}
);
Elicitation 是 2025-06-18 规范的重磅特性,允许服务器在工具执行过程中暂停并请求用户输入:
// 概念示例:删除前确认
server.tool(
"safe_delete",
"安全删除(需要用户确认)",
{ file_path: z.string() },
async ({ file_path }, { elicitInput }) => {
// 请求用户确认
const confirmation = await elicitInput({
message: `确认删除文件 ${file_path}?此操作不可撤销。`,
requestedSchema: {
type: "object",
properties: {
confirm: { type: "boolean", title: "确认删除" },
reason: { type: "string", title: "删除原因(可选)" },
},
required: ["confirm"],
},
});
if (!confirmation.confirm) {
return { content: [{ type: "text", text: "操作已取消" }] };
}
// 执行删除...
return { content: [{ type: "text", text: `已删除: ${file_path}` }] };
}
);

图表 4
下面构建一个完整的、可运行的 MCP 服务器,管理本地 Markdown 知识库。
md-knowledge-mcp/
├── package.json
├── tsconfig.json
├── src/
│ └── index.ts
└── knowledge/ # Markdown 知识库目录
├── getting-started.md
└── api-reference.md
src/index.ts:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import fs from "fs/promises";
import path from "path";
// 知识库根目录(可通过环境变量配置)
const KNOWLEDGE_DIR = process.env.KNOWLEDGE_DIR || "./knowledge";
const server = new McpServer({
name: "md-knowledge-server",
version: "1.0.0",
});
// ============ Tools ============
server.tool(
"search_notes",
"在知识库中搜索包含关键词的笔记",
{
query: z.string().describe("搜索关键词"),
max_results: z.number().optional().default(10).describe("最大返回数量"),
},
async ({ query, max_results }) => {
try {
const files = await fs.readdir(KNOWLEDGE_DIR);
const mdFiles = files.filter((f) => f.endsWith(".md"));
const results: Array<{ file: string; matches: string[]; preview: string }> = [];
for (const file of mdFiles) {
if (results.length >= max_results) break;
const content = await fs.readFile(
path.join(KNOWLEDGE_DIR, file),
"utf-8"
);
const lines = content.split("\n");
const matches = lines.filter((line) =>
line.toLowerCase().includes(query.toLowerCase())
);
if (matches.length > 0) {
results.push({
file,
matches: matches.slice(0, 3),
preview: lines.slice(0, 5).join("\n"),
});
}
}
return {
content: [
{
type: "text",
text:
results.length > 0
? JSON.stringify(results, null, 2)
: `未找到包含 "${query}" 的笔记`,
},
],
};
} catch (error: any) {
return {
content: [{ type: "text", text: `搜索失败: ${error.message}` }],
isError: true,
};
}
}
);
server.tool(
"create_note",
"创建新的 Markdown 笔记",
{
title: z.string().describe("笔记标题(将作为文件名)"),
content: z.string().describe("笔记内容(Markdown 格式)"),
tags: z.array(z.string()).optional().describe("标签列表"),
},
{ annotations: { readOnlyHint: false, destructiveHint: false } },
async ({ title, content, tags }) => {
try {
const fileName = title.replace(/[^a-zA-Z0-9\u4e00-\u9fa5-_]/g, "-") + ".md";
const filePath = path.join(KNOWLEDGE_DIR, fileName);
const frontmatter = [
"---",
`title: ${title}`,
`created: ${new Date().toISOString()}`,
tags ? `tags: [${tags.join(", ")}]` : "",
"---",
"",
].join("\n");
await fs.writeFile(filePath, frontmatter + content, "utf-8");
return {
content: [{ type: "text", text: `笔记已创建: ${fileName}` }],
};
} catch (error: any) {
return {
content: [{ type: "text", text: `创建失败: ${error.message}` }],
isError: true,
};
}
}
);
server.tool(
"update_note",
"更新已有笔记(追加内容)",
{
filename: z.string().describe("文件名"),
new_content: z.string().describe("要追加的内容"),
},
{ annotations: { readOnlyHint: false, destructiveHint: false } },
async ({ filename, new_content }) => {
try {
const filePath = path.join(KNOWLEDGE_DIR, filename);
const existing = await fs.readFile(filePath, "utf-8");
const updated = existing + "\n\n" + new_content;
await fs.writeFile(filePath, updated, "utf-8");
return {
content: [{ type: "text", text: `笔记已更新: ${filename}` }],
};
} catch (error: any) {
return {
content: [{ type: "text", text: `更新失败: ${error.message}` }],
isError: true,
};
}
}
);
// ============ Resources ============
server.resource("notes://list", async (uri) => {
try {
const files = await fs.readdir(KNOWLEDGE_DIR);
const mdFiles = files.filter((f) => f.endsWith(".md"));
const listing = mdFiles.map(async (f) => {
const stat = await fs.stat(path.join(KNOWLEDGE_DIR, f));
return { name: f, size: stat.size, modified: stat.mtime.toISOString() };
});
return {
contents: [
{
uri: uri.href,
text: JSON.stringify(await Promise.all(listing), null, 2),
},
],
};
} catch (error: any) {
return {
contents: [{ uri: uri.href, text: `读取失败: ${error.message}` }],
};
}
});
server.resource("notes://{filename}", async (uri, { filename }) => {
try {
const filePath = path.join(KNOWLEDGE_DIR, filename as string);
const content = await fs.readFile(filePath, "utf-8");
return {
contents: [{ uri: uri.href, text: content }],
};
} catch (error: any) {
return {
contents: [{ uri: uri.href, text: `读取失败: ${error.message}` }],
};
}
});
// ============ Prompts ============
server.prompt(
"summarize-notes",
"总结知识库笔记",
{ topic: z.string().describe("要总结的主题") },
async ({ topic }) => {
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `请搜索知识库中关于「${topic}」的所有笔记,并生成一份结构化的总结报告。包括:1) 核心概念 2) 关键要点 3) 相关引用`,
},
},
],
};
}
);
// ============ 启动 ============
async function main() {
// 确保知识库目录存在
await fs.mkdir(KNOWLEDGE_DIR, { recursive: true });
const transport = new StdioServerTransport();
await server.connect(transport);
console.error(`Knowledge MCP Server started, dir: ${KNOWLEDGE_DIR}`);
}
main().catch(console.error);
# 构建项目
npm run build
# 注册到 Claude Code(项目级)
claude mcp add --scope project knowledge-base -- node /path/to/md-knowledge-mcp/dist/index.js
# 或使用 tsx 直接运行
claude mcp add --scope project knowledge-base -- npx tsx /path/to/md-knowledge-mcp/src/index.ts
# 指定知识库目录
claude mcp add --scope project knowledge-base -e KNOWLEDGE_DIR=/path/to/my-notes -- npx tsx /path/to/md-knowledge-mcp/src/index.ts
在 Claude Code 中:
> 搜索知识库中关于 "API设计" 的笔记
# 调用 search_notes tool
> 创建一个新笔记,标题是"RESTful API 最佳实践",内容是关于 HTTP 方法的使用
# 调用 create_note tool
> 列出知识库中的所有笔记
# 读取 notes://list resource
> 帮我总结关于"数据库"主题的所有笔记
# 使用 summarize-notes prompt
MCP 工具的错误应通过结构化的错误响应返回,而非抛出异常:
// ✓ 正确:返回错误信息
return {
content: [{ type: "text", text: `查询失败: ${error.message}` }],
isError: true, // 标记为错误
};
// ✗ 错误:直接抛出异常可能导致服务器崩溃
throw new Error("查询失败");
// 所有日志输出到 stderr
function log(level: string, message: string, data?: any) {
console.error(JSON.stringify({
level,
message,
timestamp: new Date().toISOString(),
...(data && { data }),
}));
}
server.tool("my-tool", "示例工具", { input: z.string() }, async ({ input }) => {
log("info", "工具调用开始", { input });
try {
const result = await doSomething(input);
log("info", "工具调用成功", { result });
return { content: [{ type: "text", text: result }] };
} catch (error: any) {
log("error", "工具调用失败", { error: error.message });
return { content: [{ type: "text", text: error.message }], isError: true };
}
});
import { z } from "zod";
// Zod 自动处理类型验证
server.tool(
"query_database",
"查询数据库",
{
table: z.string().min(1).max(64).regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/),
limit: z.number().int().min(1).max(1000).default(100),
offset: z.number().int().min(0).default(0),
},
async ({ table, limit, offset }) => {
// 参数已经过 Zod 验证
// ...
}
);
# Dockerfile
FROM node:20-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
# 非 root 用户
USER node
EXPOSE 3000
CMD ["node", "dist/index.js"]
将 stdio 服务器改造为支持远程访问:
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import express from "express";
const app = express();
app.use(express.json());
app.post("/mcp", async (req, res) => {
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
});
app.listen(3000, () => {
console.error("MCP Server listening on port 3000");
});
然后在 Claude Code 中注册:
claude mcp add --transport http http://your-server:3000/mcp

图表 5
关键安全原则: 1. 永远不要信任 AI 生成的参数——在工具内部进行完整的输入验证 2. 破坏性操作使用 Tool Annotations——让 Claude 在调用前提示用户确认 3. 敏感数据通过环境变量传递——不要在代码中硬编码 API Key 4. 远程服务器必须使用 HTTPS——防止中间人攻击 5. 限制文件系统访问范围——只允许访问指定目录

图表 6
| 操作 | 命令 |
|---|---|
| 创建 TS 服务器 | npm init -y && npm i @modelcontextprotocol/sdk zod |
| 创建 Python 服务器 | pip install fastmcp |
| 调试 TS 服务器 | npx @modelcontextprotocol/inspector npx tsx src/index.ts |
| 调试 Python 服务器 | fastmcp dev server.py |
| 注册到 Claude Code | claude mcp add <name> -- <command> |
| 查看已注册服务器 | claude mcp list |
| 查看服务器详情 | claude mcp get <name> |
| 移除服务器 | claude mcp remove <name> |
| 查看 MCP 面板 | Claude Code 中输入 /mcp |
症状:claude mcp list 显示服务器但工具不可用。
排查步骤:
1. 手动运行服务器命令确认无报错:npx tsx src/index.ts
2. 检查 stderr 输出是否有错误信息
3. 确认 console.log() 没有被使用(必须用 console.error())
4. 检查 Node.js 版本 >= 18
原因:Zod schema 与实际参数不匹配。
解决:确保 Zod schema 描述完整,.describe() 为每个字段添加描述:
{
// ✓ 好
name: z.string().min(1).describe("用户名,不能为空"),
// ✗ 差:缺少描述和约束
name: z.string(),
}
排查:
1. 确认服务器使用 Streamable HTTP 传输(非旧的 SSE)
2. 检查防火墙和网络连通性
3. 确认 URL 路径正确(通常是 /mcp)
4. 使用 curl -X POST http://server:port/mcp 测试连通性
解决:使用 -e 参数或 env 配置:
claude mcp add -e API_KEY=xxx -e DB_URL=xxx my-server -- npx tsx src/index.ts
或配置文件中:
{
"mcpServers": {
"my-server": {
"command": "npx",
"args": ["tsx", "src/index.ts"],
"env": { "API_KEY": "xxx" }
}
}
}
| 维度 | 评估 |
|---|---|
| 适合训练营类型 | AI 工具开发、DevOps 自动化、企业 AI 集成 |
| 建议教学时长 | 4-6 小时(含动手实验) |
| 难度等级 | 中级(需要编程基础,不需要 AI/ML 背景) |
| 实验环境要求 | Node.js 18+ 或 Python 3.10+、Claude Code CLI、Docker(可选) |
| 可拆分模块 | 基础概念(1h)+ TypeScript 实战(1.5h)+ Python 实战(1.5h)+ 部署与安全(1h)+ 综合练习(1h) |
[!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 等场景全覆盖。
