文章
MCP 入门教程:让 AI 连接你的工具和数据
MCP 入门教程:让 AI 连接你的工具和数据 一篇搞定:MCP 是什么、怎么用、怎么开发自己的 MCP Server 目录 一、核心概念 二、快速体验 MCP 三、使用现有 MCP Server 四、开发自己的 MCP...
MCP 入门教程:让 AI 连接你的工具和数据 #
一篇搞定:MCP 是什么、怎么用、怎么开发自己的 MCP Server
目录 #
一、核心概念 #
1.1 什么是 MCP? #
MCP = Model Context Protocol(模型上下文协议)
打个比方:
- AI 就像是一个「聪明的助手」,但它被困在房间里,看不到外面的世界
- MCP 就像是给这个助手开了「窗户」和「门」,让它能接触到外部的工具和数据
- 通过 MCP,AI 可以:读取文件、搜索网页、操作数据库、调用 API...
官方定义:
MCP 是一个开放协议,让 AI 助手能够安全地连接外部数据源和工具。
1.2 为什么需要 MCP? #
没有 MCP 之前的问题:
| 问题 | 说明 |
|---|---|
| 信息孤岛 | AI 无法访问你的本地文件、数据库、私有 API |
| 重复开发 | 每个 AI 应用都要自己实现工具集成 |
| 安全风险 | 给 AI 完全访问权限太危险 |
| 不互通 | Claude 能用的工具,GPT 用不了 |
MCP 的解决方案:
┌─────────────────────────────────────────────────┐
│ AI 应用 │
│ (Claude / Cursor / Windsurf...) │
└─────────────────────┬───────────────────────────┘
│ MCP 协议
┌─────────────┼─────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ 文件系统 │ │ 数据库 │ │ Web API │
│ Server │ │ Server │ │ Server │
└─────────┘ └─────────┘ └─────────┘MCP 的好处:
| 好处 | 说明 |
|---|---|
| 一次开发,到处使用 | 写一个 MCP Server,Claude、Cursor、Windsurf 都能用 |
| 安全可控 | 用户决定 AI 能访问什么,不能访问什么 |
| 标准化 | 统一的协议,不用每个工具单独适配 |
| 可组合 | 可以连接多个 MCP Server,组合使用 |
1.3 MCP 的核心概念 #
| 概念 | 英文 | 说明 | 类比 |
|---|---|---|---|
| MCP Host | Host | 运行 AI 的应用程序 | Claude Desktop、Cursor、Windsurf |
| MCP Client | Client | Host 内部的 MCP 客户端 | Claude 里的 MCP 连接器 |
| MCP Server | Server | 提供工具和数据的服务端 | 文件系统 Server、GitHub Server |
| Resource | Resource | 可读取的数据源 | 文件内容、数据库记录 |
| Tool | Tool | 可执行的函数 | 搜索文件、发送请求 |
| Prompt | Prompt | 预定义的提示词模板 | 「帮我分析这个文件」模板 |
1.4 MCP 能做什么? #
访问数据(Resources):
// AI 可以读取你的文件
读取文件内容 → "你好,这是 README.md 的内容..."
// AI 可以查询数据库
查询用户表 → [{ id: 1, name: "张三" }, ...]
// AI 可以获取网页内容
获取网页 → "这是页面内容..."执行操作(Tools):
// AI 可以帮你操作
创建文件 → "已创建 test.js"
发送请求 → "请求已发送,返回 200"
执行命令 → "命令执行成功"使用模板(Prompts):
// 预定义好的提示词模板
"分析代码" → 自动读取文件 + 专业分析
"生成文档" → 自动扫描代码 + 生成 README1.5 哪些应用支持 MCP? #
| 应用 | 支持状态 | 说明 |
|---|---|---|
| Claude Desktop | ✅ 官方支持 | Anthropic 官方应用 |
| Cursor | ✅ 支持 | AI 代码编辑器 |
| Windsurf | ✅ 支持 | Codeium 出品 |
| Zed | ✅ 支持 | 高性能编辑器 |
| OpenAI | 🔄 规划中 | 微软正在整合 |
| OpenClaw | ✅ 支持 | 你正在用的这个! |
二、快速体验 MCP #
2.1 Claude Desktop 配置 MCP #
第一步:安装 Claude Desktop
从 claude.ai/download 下载安装。
第二步:配置 MCP Server
Claude Desktop 的配置文件位置:
| 系统 | 路径 |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
第三步:添加文件系统 MCP
创建或编辑配置文件:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/你的用户名/Desktop",
"/Users/你的用户名/Documents"
]
}
}
}第四步:重启 Claude Desktop
关闭并重新打开 Claude Desktop。
第五步:测试 MCP
在 Claude 中输入:
请列出我桌面上的文件Claude 会询问是否允许访问文件系统,点击允许。然后你就能看到文件列表了!
2.2 配置多个 MCP Server #
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/你的用户名/projects"
]
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "你的GitHub Token"
}
},
"brave-search": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
"env": {
"BRAVE_API_KEY": "你的Brave API Key"
}
}
}
}2.3 在 Cursor 中使用 MCP #
配置步骤:
- 打开 Cursor 设置(
Cmd + ,) - 搜索
MCP - 点击
Edit MCP Settings - 添加配置:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"${workspaceFolder}"
]
}
}
}使用方式:
在 Cursor 的 Chat 面板中,AI 现在可以访问你的项目文件了。
三、使用现有 MCP Server #
3.1 官方 MCP Server 列表 #
| Server | 功能 | 安装方式 |
|---|---|---|
| filesystem | 文件系统访问 | @modelcontextprotocol/server-filesystem |
| github | GitHub 操作 | @modelcontextprotocol/server-github |
| brave-search | 网页搜索 | @modelcontextprotocol/server-brave-search |
| google-maps | 地图服务 | @modelcontextprotocol/server-google-maps |
| postgres | PostgreSQL 数据库 | @modelcontextprotocol/server-postgres |
| sqlite | SQLite 数据库 | @modelcontextprotocol/server-sqlite |
| slack | Slack 集成 | @modelcontextprotocol/server-slack |
| puppeteer | 浏览器自动化 | @modelcontextprotocol/server-puppeteer |
3.2 文件系统 MCP 详解 #
配置:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/path/to/allowed/dir1",
"/path/to/allowed/dir2"
]
}
}
}提供的工具:
| 工具 | 功能 | 示例 |
|---|---|---|
read_file |
读取文件内容 | 读取 README.md |
write_file |
写入文件 | 创建新文件 |
list_directory |
列出目录内容 | 查看文件夹结构 |
create_directory |
创建目录 | 新建文件夹 |
move_file |
移动/重命名文件 | 重命名文件 |
search_files |
搜索文件 | 查找 *.js 文件 |
get_file_info |
获取文件信息 | 查看文件大小、修改时间 |
使用示例:
用户:请帮我读取 package.json 文件
AI 调用 read_file → 返回文件内容
AI:这是你的 package.json 内容:
{
"name": "my-project",
"version": "1.0.0",
...
}3.3 GitHub MCP 详解 #
前提:需要 GitHub Personal Access Token
- 访问 github.com/settings/tokens
- 点击
Generate new token (classic) - 勾选需要的权限(repo、issues、pull_requests)
- 生成并保存 Token
配置:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "ghp_xxxxxxxxxxxx"
}
}
}
}提供的工具:
| 工具 | 功能 |
|---|---|
search_repositories |
搜索仓库 |
get_repository |
获取仓库信息 |
list_issues |
列出 Issue |
create_issue |
创建 Issue |
create_pull_request |
创建 PR |
fork_repository |
Fork 仓库 |
create_branch |
创建分支 |
push_files |
推送文件 |
使用示例:
用户:帮我搜索 React 相关的热门仓库
AI 调用 search_repositories → 返回结果
AI:找到以下热门 React 仓库:
1. facebook/react - 220k stars
2. reactjs/reactjs.org - 8.5k stars
...
用户:帮我给 facebook/react 创建一个 Issue
AI:好的,请告诉我 Issue 的标题和内容...3.4 数据库 MCP 详解 #
PostgreSQL 配置:
{
"mcpServers": {
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"DATABASE_URL": "postgresql://user:password@localhost:5432/mydb"
}
}
}
}SQLite 配置:
{
"mcpServers": {
"sqlite": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-sqlite",
"/path/to/database.db"
]
}
}
}使用示例:
用户:帮我查询用户表有多少条记录
AI 调用 query → SELECT COUNT(*) FROM users
AI:用户表共有 1,234 条记录。
用户:帮我查看最近注册的 5 个用户
AI:最近的 5 个用户是:
1. 张三 - 2024-03-20
2. 李四 - 2024-03-19
...3.5 Brave Search MCP 详解 #
前提:需要 Brave Search API Key
- 访问 brave.com/search/api
- 注册并创建 API Key
配置:
{
"mcpServers": {
"brave-search": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
"env": {
"BRAVE_API_KEY": "BSAxxxxxxxxxxxx"
}
}
}
}使用示例:
用户:帮我搜索 2024 年 React 最佳实践
AI 调用 brave_search → 返回搜索结果
AI:找到以下相关文章:
1. React Best Practices in 2024 - Medium
2. 10 React Patterns You Should Know - Dev.to
...四、开发自己的 MCP Server #
4.1 MCP Server 基础结构 #
最简 MCP Server:
// server.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
// 1. 创建 Server 实例
const server = new Server(
{ name: "my-mcp-server", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
// 2. 定义工具列表
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "hello",
description: "向用户打招呼",
inputSchema: {
type: "object",
properties: {
name: {
type: "string",
description: "用户名称",
},
},
required: ["name"],
},
},
],
};
});
// 3. 处理工具调用
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "hello") {
return {
content: [
{
type: "text",
text: `你好,${args.name}!欢迎使用 MCP!`,
},
],
};
}
throw new Error(`Unknown tool: ${name}`);
});
// 4. 启动 Server
const transport = new StdioServerTransport();
await server.connect(transport);4.2 创建一个实用的 MCP Server #
场景:创建一个天气查询 MCP Server
第一步:初始化项目
mkdir weather-mcp-server
cd weather-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node第二步:创建 Server 代码
// src/index.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
// 天气 API(模拟)
async function getWeather(city: string): Promise<string> {
// 实际项目中,这里应该调用真实的天气 API
// 比如 OpenWeatherMap、和风天气等
const mockData: Record<string, string> = {
"北京": "晴天,温度 18°C,空气质量良好",
"上海": "多云,温度 20°C,有轻微雾霾",
"广州": "小雨,温度 25°C,湿度较高",
"深圳": "晴天,温度 26°C,适合出行",
"成都": "阴天,温度 16°C,可能下雨",
};
return mockData[city] || `未找到 ${city} 的天气信息`;
}
// 创建 Server
const server = new Server(
{
name: "weather-mcp-server",
version: "1.0.0"
},
{
capabilities: {
tools: {}
}
}
);
// 定义输入 Schema
const GetWeatherSchema = z.object({
city: z.string().describe("城市名称,如:北京、上海"),
});
// 注册工具列表
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "get_weather",
description: "获取指定城市的天气信息",
inputSchema: {
type: "object",
properties: {
city: {
type: "string",
description: "城市名称,如:北京、上海、广州",
},
},
required: ["city"],
},
},
{
name: "list_cities",
description: "列出支持查询天气的城市",
inputSchema: {
type: "object",
properties: {},
},
},
],
};
});
// 处理工具调用
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case "get_weather": {
const { city } = GetWeatherSchema.parse(args);
const weather = await getWeather(city);
return {
content: [
{
type: "text",
text: `🌤️ ${city}天气:${weather}`,
},
],
};
}
case "list_cities": {
const cities = ["北京", "上海", "广州", "深圳", "成都"];
return {
content: [
{
type: "text",
text: `支持查询的城市:\n${cities.map(c => `- ${c}`).join("\n")}`,
},
],
};
}
default:
throw new Error(`Unknown tool: ${name}`);
}
});
// 启动 Server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Weather MCP Server started");
}
main().catch(console.error);第三步:配置 package.json
{
"name": "weather-mcp-server",
"version": "1.0.0",
"type": "module",
"bin": {
"weather-mcp-server": "./dist/index.js"
},
"scripts": {
"build": "tsc",
"start": "node dist/index.js"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0",
"zod": "^3.23.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"typescript": "^5.0.0"
}
}第四步:配置 TypeScript
// tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src/**/*"]
}第五步:构建和测试
# 构建
npm run build
# 本地测试
node dist/index.js
# 发布到 npm(可选)
npm publish第六步:在 Claude Desktop 中使用
{
"mcpServers": {
"weather": {
"command": "node",
"args": ["/path/to/weather-mcp-server/dist/index.js"]
}
}
}4.3 添加 Resources(数据源) #
Resources 让 AI 可以读取你提供的数据。
import {
ListResourcesRequestSchema,
ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
// 定义资源
const resources = new Map([
["config", JSON.stringify({ theme: "dark", language: "zh-CN" })],
["readme", "# My Project\n\n这是一个示例项目..."],
]);
// 注册资源列表
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: "config://app",
name: "应用配置",
description: "当前应用的配置信息",
mimeType: "application/json",
},
{
uri: "file://readme",
name: "README",
description: "项目说明文档",
mimeType: "text/markdown",
},
],
};
});
// 处理资源读取
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const { uri } = request.params;
if (uri === "config://app") {
return {
contents: [
{
uri,
mimeType: "application/json",
text: resources.get("config")!,
},
],
};
}
if (uri === "file://readme") {
return {
contents: [
{
uri,
mimeType: "text/markdown",
text: resources.get("readme")!,
},
],
};
}
throw new Error(`Unknown resource: ${uri}`);
});4.4 添加 Prompts(提示词模板) #
Prompts 让用户可以快速使用预定义的提示词。
import {
ListPromptsRequestSchema,
GetPromptRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
// 注册提示词列表
server.setRequestHandler(ListPromptsRequestSchema, async () => {
return {
prompts: [
{
name: "analyze_code",
description: "分析代码质量和潜在问题",
arguments: [
{
name: "file_path",
description: "要分析的文件路径",
required: true,
},
],
},
{
name: "generate_docs",
description: "为代码生成文档",
arguments: [
{
name: "file_path",
description: "要生成文档的文件路径",
required: true,
},
],
},
],
};
});
// 处理提示词请求
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case "analyze_code": {
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `请分析以下代码的质量和潜在问题:
文件:${args?.file_path}
请从以下维度进行分析:
1. 代码风格
2. 性能问题
3. 安全隐患
4. 可维护性
5. 改进建议`,
},
},
],
};
}
case "generate_docs": {
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `请为以下代码生成详细的文档:
文件:${args?.file_path}
文档应包括:
1. 功能描述
2. 参数说明
3. 返回值说明
4. 使用示例
5. 注意事项`,
},
},
],
};
}
default:
throw new Error(`Unknown prompt: ${name}`);
}
});五、实战场景 #
场景 1:公司内部 API MCP Server #
需求:让 AI 能访问公司内部 API
// company-api-mcp-server.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
const API_BASE = "https://api.company.com/v1";
// API 请求封装
async function apiRequest(
endpoint: string,
method: string = "GET",
body?: unknown
) {
const response = await fetch(`${API_BASE}${endpoint}`, {
method,
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.COMPANY_API_KEY}`,
},
body: body ? JSON.stringify(body) : undefined,
});
if (!response.ok) {
throw new Error(`API Error: ${response.status}`);
}
return response.json();
}
const server = new Server(
{ name: "company-api-server", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "get_user",
description: "获取用户信息",
inputSchema: {
type: "object",
properties: {
user_id: { type: "string", description: "用户ID" },
},
required: ["user_id"],
},
},
{
name: "list_orders",
description: "获取订单列表",
inputSchema: {
type: "object",
properties: {
status: {
type: "string",
description: "订单状态:pending/completed/cancelled",
},
limit: {
type: "number",
description: "返回数量,默认 10",
},
},
},
},
{
name: "create_task",
description: "创建任务",
inputSchema: {
type: "object",
properties: {
title: { type: "string", description: "任务标题" },
description: { type: "string", description: "任务描述" },
assignee: { type: "string", description: "负责人ID" },
},
required: ["title", "assignee"],
},
},
],
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case "get_user": {
const user = await apiRequest(`/users/${args.user_id}`);
return {
content: [{ type: "text", text: JSON.stringify(user, null, 2) }],
};
}
case "list_orders": {
const params = new URLSearchParams();
if (args.status) params.set("status", args.status as string);
if (args.limit) params.set("limit", String(args.limit));
const orders = await apiRequest(`/orders?${params}`);
return {
content: [{ type: "text", text: JSON.stringify(orders, null, 2) }],
};
}
case "create_task": {
const task = await apiRequest("/tasks", "POST", args);
return {
content: [{
type: "text",
text: `任务创建成功!\n${JSON.stringify(task, null, 2)}`,
}],
};
}
default:
throw new Error(`Unknown tool: ${name}`);
}
});
const transport = new StdioServerTransport();
server.connect(transport);配置:
{
"mcpServers": {
"company-api": {
"command": "node",
"args": ["/path/to/company-api-mcp-server/dist/index.js"],
"env": {
"COMPANY_API_KEY": "your-api-key"
}
}
}
}场景 2:数据库查询 MCP Server #
需求:让 AI 能安全地查询数据库
// database-mcp-server.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { Pool } from "pg";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
// 数据库连接
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
});
// 白名单查询(只允许 SELECT)
const ALLOWED_TABLES = ["users", "products", "orders"];
const MAX_RESULTS = 100;
const server = new Server(
{ name: "database-server", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "query_table",
description: "查询数据库表(只读)",
inputSchema: {
type: "object",
properties: {
table: {
type: "string",
description: "表名",
enum: ALLOWED_TABLES,
},
columns: {
type: "array",
items: { type: "string" },
description: "要查询的列,默认查询全部",
},
where: {
type: "string",
description: "WHERE 条件(可选)",
},
limit: {
type: "number",
description: `返回数量限制,默认 ${MAX_RESULTS}`,
},
},
required: ["table"],
},
},
{
name: "describe_table",
description: "查看表结构",
inputSchema: {
type: "object",
properties: {
table: {
type: "string",
description: "表名",
enum: ALLOWED_TABLES,
},
},
required: ["table"],
},
},
],
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case "query_table": {
const { table, columns, where, limit = MAX_RESULTS } = args as any;
// 安全校验
if (!ALLOWED_TABLES.includes(table)) {
return {
content: [{
type: "text",
text: `错误:不允许查询表 "${table}"。允许的表:${ALLOWED_TABLES.join(", ")}`,
}],
};
}
// 构建 SQL
const cols = columns?.length ? columns.join(", ") : "*";
const safeLimit = Math.min(limit, MAX_RESULTS);
let sql = `SELECT ${cols} FROM ${table} LIMIT ${safeLimit}`;
if (where) {
sql = `SELECT ${cols} FROM ${table} WHERE ${where} LIMIT ${safeLimit}`;
}
try {
const result = await pool.query(sql);
return {
content: [{
type: "text",
text: `查询成功,共 ${result.rows.length} 条记录:\n${JSON.stringify(result.rows, null, 2)}`,
}],
};
} catch (error) {
return {
content: [{
type: "text",
text: `查询失败:${error.message}`,
}],
};
}
}
case "describe_table": {
const { table } = args as any;
const sql = `
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_name = $1
`;
const result = await pool.query(sql, [table]);
return {
content: [{
type: "text",
text: `表 "${table}" 结构:\n${JSON.stringify(result.rows, null, 2)}`,
}],
};
}
default:
throw new Error(`Unknown tool: ${name}`);
}
});
const transport = new StdioServerTransport();
server.connect(transport);场景 3:前端组件库 MCP Server #
需求:让 AI 了解并使用你的组件库
// component-library-mcp-server.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ListResourcesRequestSchema,
ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
// 组件文档
const components = {
Button: {
description: "按钮组件",
props: [
{ name: "variant", type: "'primary' | 'secondary' | 'ghost'", default: "'primary'" },
{ name: "size", type: "'sm' | 'md' | 'lg'", default: "'md'" },
{ name: "disabled", type: "boolean", default: "false" },
],
example: `<Button variant="primary" size="md">点击我</Button>`,
},
Input: {
description: "输入框组件",
props: [
{ name: "type", type: "'text' | 'password' | 'email'", default: "'text'" },
{ name: "placeholder", type: "string", default: "''" },
{ name: "value", type: "string", default: "''" },
{ name: "onChange", type: "(value: string) => void", default: "-" },
],
example: `<Input placeholder="请输入" value={value} onChange={setValue} />`,
},
Modal: {
description: "弹窗组件",
props: [
{ name: "open", type: "boolean", default: "false" },
{ name: "onClose", type: "() => void", default: "-" },
{ name: "title", type: "string", default: "''" },
],
example: `<Modal open={isOpen} onClose={() => setIsOpen(false)} title="提示">内容</Modal>`,
},
};
const server = new Server(
{ name: "component-library-server", version: "1.0.0" },
{ capabilities: { tools: {}, resources: {} } }
);
// 注册资源(组件文档)
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: Object.entries(components).map(([name, info]) => ({
uri: `component://${name.toLowerCase()}`,
name: `${name} 组件`,
description: info.description,
mimeType: "text/markdown",
})),
};
});
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const { uri } = request.params;
const match = uri.match(/^component:\/\/(.+)$/);
if (match) {
const name = match[1].charAt(0).toUpperCase() + match[1].slice(1);
const info = components[name as keyof typeof components];
if (info) {
const doc = `# ${name} 组件
## 描述
${info.description}
## Props
| 属性 | 类型 | 默认值 |
|------|------|--------|
${info.props.map(p => `| ${p.name} | ${p.type} | ${p.default} |`).join("\n")}
## 使用示例
\`\`\`tsx
${info.example}
\`\`\`
`;
return {
contents: [{ uri, mimeType: "text/markdown", text: doc }],
};
}
}
throw new Error(`Unknown resource: ${uri}`);
});
// 注册工具
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "generate_component_code",
description: "生成组件使用代码",
inputSchema: {
type: "object",
properties: {
component: {
type: "string",
description: "组件名称",
enum: Object.keys(components),
},
props: {
type: "object",
description: "组件属性",
},
},
required: ["component"],
},
},
],
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "generate_component_code") {
const { component, props = {} } = args as any;
const info = components[component as keyof typeof components];
if (!info) {
return {
content: [{
type: "text",
text: `未知组件:${component}`,
}],
};
}
// 生成代码
const propsStr = Object.entries(props)
.map(([key, value]) => {
if (typeof value === "string") {
return `${key}="${value}"`;
} else if (typeof value === "boolean") {
return value ? key : "";
} else {
return `${key}={${JSON.stringify(value)}}`;
}
})
.filter(Boolean)
.join(" ");
const code = `<${component}${propsStr ? " " + propsStr : ""}>按钮</${component}>`;
return {
content: [{
type: "text",
text: `生成的代码:\n\`\`\`tsx\n${code}\n\`\`\``,
}],
};
}
throw new Error(`Unknown tool: ${name}`);
});
const transport = new StdioServerTransport();
server.connect(transport);使用效果:
用户:我需要一个登录表单,用你们公司的组件库
AI:我来帮你创建登录表单。让我先查看可用的组件...
AI 读取 Button、Input 组件文档...
AI:好的,这是登录表单的代码:
```tsx
import { Button, Input } from '@company/ui';
function LoginForm() {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
return (
<form>
<Input
type="text"
placeholder="用户名"
value={username}
onChange={setUsername}
/>
<Input
type="password"
placeholder="密码"
value={password}
onChange={setPassword}
/>
<Button variant="primary">登录</Button>
</form>
);
}
---
## 六、常见问题
### Q1: MCP Server 连接失败怎么办?
**检查步骤:**
```bash
# 1. 确认 Node.js 版本(需要 18+)
node --version
# 2. 手动测试 MCP Server
npx @modelcontextprotocol/server-filesystem /tmp
# 3. 查看日志(Claude Desktop)
# macOS: ~/Library/Logs/Claude/
# Windows: %APPDATA%\Claude\logs\
# 4. 检查配置文件路径是否正确
cat ~/Library/Application\ Support/Claude/claude_desktop_config.json常见错误:
| 错误 | 原因 | 解决 |
|---|---|---|
ENOENT |
找不到命令 | 确认 npx/node 在 PATH 中 |
Connection refused |
Server 未启动 | 检查命令是否正确 |
Permission denied |
权限问题 | chmod +x 或检查路径 |
Q2: 如何调试 MCP Server? #
方法一:直接运行
# 直接运行 Server,查看输出
node /path/to/your-server/dist/index.js
# 通过 stdin 发送测试请求
echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | node dist/index.js方法二:使用 MCP Inspector
# 安装并运行 Inspector
npx @modelcontextprotocol/inspector node dist/index.js
# 打开浏览器查看界面
# http://localhost:5173方法三:添加日志
// 在 Server 代码中添加
console.error("Debug message"); // 使用 stderr,不会影响 MCP 通信
server.setRequestHandler(CallToolRequestSchema, async (request) => {
console.error("Received request:", request.params);
// ...
});Q3: 如何限制 MCP Server 的权限? #
限制文件访问范围:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/username/projects/my-project" // 只允许访问这个目录
]
}
}
}限制网络访问:
// 在代码中限制允许访问的域名
const ALLOWED_DOMAINS = ["api.example.com", "cdn.example.com"];
async function fetchWithRestriction(url: string) {
const { hostname } = new URL(url);
if (!ALLOWED_DOMAINS.includes(hostname)) {
throw new Error(`Domain ${hostname} is not allowed`);
}
return fetch(url);
}Q4: 如何在 MCP Server 中处理错误? #
server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
const { name, arguments: args } = request.params;
// 处理逻辑...
} catch (error) {
// 返回友好的错误信息
return {
content: [{
type: "text",
text: `❌ 操作失败:${error.message}`,
}],
isError: true, // 标记为错误响应
};
}
});Q5: 如何让 MCP Server 支持流式响应? #
// MCP SDK 目前不直接支持流式响应
// 但可以通过多次调用实现类似效果
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const items = ["项目1", "项目2", "项目3"];
const results = [];
for (const item of items) {
// 处理每个项目
const result = await processItem(item);
results.push(result);
// 可以在这里发送进度更新(通过 Resource)
}
return {
content: [{
type: "text",
text: results.join("\n"),
}],
};
});Q6: MCP Server 可以调用其他 MCP Server 吗? #
可以!这叫「MCP 链式调用」。
// 在 MCP Server 中调用另一个 MCP Server
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
// 连接到文件系统 MCP
const transport = new StdioClientTransport({
command: "npx",
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
});
const client = new Client({ name: "my-client", version: "1.0.0" }, {});
await client.connect(transport);
// 调用文件系统的工具
const result = await client.request(
{ method: "tools/call", params: { name: "list_directory", arguments: { path: "/tmp" } } },
CallToolResultSchema
);七、资源汇总 #
官方资源 #
| 资源 | 链接 | 说明 |
|---|---|---|
| MCP 官网 | modelcontextprotocol.io | 官方文档 |
| MCP GitHub | github.com/modelcontextprotocol | 源码和示例 |
| MCP SDK | @modelcontextprotocol/sdk | TypeScript SDK |
| MCP Servers | github.com/modelcontextprotocol/servers | 官方 Servers |
| MCP Inspector | @modelcontextprotocol/inspector | 调试工具 |
社区资源 #
| 资源 | 链接 | 说明 |
|---|---|---|
| awesome-mcp | github.com/punkpeye/awesome-mcp | MCP 资源集合 |
| MCP Marketplace | mcp.so | MCP Server 市场 |
| Smithery | smithery.ai | MCP 工具目录 |
常用 MCP Server #
| Server | 功能 | 链接 |
|---|---|---|
| filesystem | 文件系统 | @modelcontextprotocol/server-filesystem |
| github | GitHub 集成 | @modelcontextprotocol/server-github |
| postgres | PostgreSQL | @modelcontextprotocol/server-postgres |
| sqlite | SQLite | @modelcontextprotocol/server-sqlite |
| brave-search | 网页搜索 | @modelcontextprotocol/server-brave-search |
| puppeteer | 浏览器自动化 | @modelcontextprotocol/server-puppeteer |
| slack | Slack 集成 | @modelcontextprotocol/server-slack |
| google-maps | 地图服务 | @modelcontextprotocol/server-google-maps |
| fetch | HTTP 请求 | @modelcontextprotocol/server-fetch |
| memory | 记忆存储 | @modelcontextprotocol/server-memory |
快速命令速查 #
# 运行文件系统 MCP
npx -y @modelcontextprotocol/server-filesystem /path/to/dir
# 运行 GitHub MCP
GITHUB_TOKEN=xxx npx -y @modelcontextprotocol/server-github
# 运行 SQLite MCP
npx -y @modelcontextprotocol/server-sqlite /path/to/db.sqlite
# 运行 Inspector 调试
npx @modelcontextprotocol/inspector node your-server.js总结速记 #
| 概念 | 说明 |
|---|---|
| MCP | 模型上下文协议,让 AI 连接工具和数据 |
| Host | 运行 AI 的应用(Claude、Cursor) |
| Server | 提供工具和数据的服务端 |
| Tool | 可执行的函数 |
| Resource | 可读取的数据源 |
| Prompt | 预定义的提示词模板 |
开发 MCP Server 的核心步骤:
- 安装
@modelcontextprotocol/sdk - 创建 Server 实例
- 注册 Tools / Resources / Prompts
- 实现处理逻辑
- 配置到 Host 应用
最后更新:2026-03-29