使用Create-MCP快速构建AI服务器:从协议原理到工程实践
1. 项目概述从零到一用 Create-MCP 构建你的 AI 服务器如果你正在探索如何将大型语言模型LLM的能力更深度、更可控地集成到你的应用或工作流中那么 Model Context ProtocolMCP这个概念你一定不陌生。简单来说MCP 就像是为 AI 模型定义的一套“插件”或“工具”调用标准它允许像 Claude、Cursor 这类 AI 助手通过一个统一的协议安全、规范地调用你提供的各种功能——无论是查询数据库、操作文件还是调用外部 API。这极大地扩展了 AI 的边界让它不再只是一个聊天机器人而是一个能真正帮你“做事”的智能体。但问题来了从头开始构建一个符合 MCP 规范的服务器对于很多开发者尤其是前端或应用层开发者来说门槛不低。你需要理解协议规范、处理 WebSocket 或 SSE 连接、定义工具Tools和资源Resources的 schema、管理上下文……这些底层细节足以劝退一大批想快速尝鲜的人。这就是Create-MCP工具诞生的背景。它不是一个复杂的框架而是一个开箱即用的命令行生成器。它的核心目标非常明确让你用一条命令就获得一个结构清晰、配置完备、可以直接运行和扩展的 MCP 服务器项目骨架。无论你是想为你的团队内部工具增加 AI 能力还是想构建一个连接特定数据源的 AI 代理Create-MCP都能帮你跳过繁琐的初始化阶段直接进入核心业务逻辑的开发。下面我就结合自己的使用经验带你深入拆解这个工具看看它如何让 MCP 服务器的开发变得像创建 React 或 Next.js 应用一样简单。2. 核心设计思路与方案选型解析2.1 为什么选择 CLI 生成器模式在决定使用或评价Create-MCP之前我们需要先理解它背后的设计哲学。市面上集成 AI 能力的方式有很多比如直接调用 OpenAI API、使用 LangChain 等框架、或者自己封装 SDK。Create-MCP聚焦于MCP 服务器这一特定形态选择 CLI 生成器模式是基于以下几个核心考量第一降低协议理解成本。MCP 协议本身有明确的规范但将其转化为可运行的代码需要正确的项目结构、依赖管理和通信层实现。Create-MCP通过预设模板将这些“最佳实践”固化下来。开发者无需深入研究协议文档的每一个细节就能获得一个符合规范的基础项目从而将注意力集中在“我的服务器要提供什么工具”这个业务问题上。第二提供一致的开发体验。就像create-react-app统一了 React 应用的起点一样Create-MCP旨在为 MCP 服务器开发提供一个标准化的起点。这有利于团队协作和项目维护因为大家基于相同的目录结构、工具链和代码风格进行开发减少了沟通和上手的成本。第三强调“生产就绪”。项目描述中特别提到了“production-ready”。这意味着生成的骨架项目不仅仅是一个“Hello World”示例它通常会预先集成一些对生产环境友好的配置比如基本的错误处理、日志记录、环境变量管理、以及 TypeScript 的严格类型检查。这避免了开发者从零开始搭建这些基础设施加快了从原型到部署的进程。第四拥抱生态集成。从关键词可以看到Create-MCP关联了cursor-ai、mcp-client、aws、lambda等。这表明它的模板或设计考虑到了与特定 IDE如 Cursor、客户端库、以及云部署环境的集成。通过 CLI 的交互式选项它可能能引导你生成针对 AWS Lambda 函数部署优化的项目结构或者预先配置好与 Cursor AI 的对接方式这种“场景化”的生成能力是其价值的重要体现。2.2 技术栈与核心依赖推测虽然原始资料没有列出具体的package.json但根据其描述TypeScript Support, AI Integration和 MCP 的通用实现方式我们可以合理推断一个由Create-MCP生成的项目会包含哪些核心依赖运行时与协议实现很可能会使用官方或社区维护的 MCP SDK例如modelcontextprotocol/sdk。这个 SDK 封装了协议通信、工具和资源定义等底层逻辑是构建服务器的基石。语言与工具链基于 Node.js 和 TypeScript。这是目前 JavaScript/TypeScript 生态中实现 MCP 服务器最主流和成熟的选择能提供良好的类型安全和开发体验。开发辅助包括ts-node/tsx用于直接运行 TypeScriptnodemon用于开发热重载eslint和prettier用于代码质量和风格统一。模板引擎CLI 工具本身可能会使用像plop、ejs或handlebars这样的模板引擎来根据用户交互动态生成项目文件。AI 集成库如果选择了 AI 相关的模板可能会预装openai、langchain或anthropic-vertex等 SDK方便你快速接入大模型能力。注意工具的具体版本和选择可能会随着时间更新。最准确的方式是在生成项目后立即查看package.json文件。理解这些依赖的作用有助于你在后续自定义开发时知道该修改哪里以及如何寻找相关的文档。3. 从下载到第一个服务器完整实操指南3.1 环境准备与工具安装在开始之前请确保你的系统满足基本要求。虽然原文提到了 Windows、macOS 和 Linux 的安装包但根据现代 CLI 工具的常见分发方式我更推荐使用 Node.js 的包管理器进行安装这通常能获得更好的版本管理和更新体验。步骤一检查 Node.js 环境打开你的终端Windows 上可以是 PowerShell 或 CMD推荐 PowerShellmacOS/Linux 使用 Terminal运行以下命令node --version npm --version确保 Node.js 版本在 18.0.0 或以上npm 版本在 8.0.0 或以上。如果未安装或版本过低请前往 Node.js 官网 下载并安装最新的 LTS长期支持版本。步骤二安装 Create-MCP CLI根据原始资料提供的 GitHub 仓库信息安装方式可能有两种全局安装推荐如果该工具已发布到 npm 仓库你可以直接使用 npm 或 yarn 进行全局安装使其在系统的任何位置都可调用。npm install -g create-mcp # 或 yarn global add create-mcp使用 npx如果你不想全局安装或者想始终使用最新版本可以使用npx直接运行。npx create-mcplatest create my-server下载可执行文件如果项目主要提供的是打包好的可执行文件如.exe,.dmg则需要按照原文步骤从 GitHub Releases 页面下载对应你操作系统的安装包并按照提示安装。安装后通常可以直接在终端中输入create-mcp来使用。实操心得我通常优先尝试npm install -g的方式因为管理起来最方便。如果找不到包则说明开发者可能还未发布到 npm这时就需要查看仓库的 README寻找诸如“Install from source”或“Clone and link”的本地开发安装指引。3.2 创建你的第一个 MCP 服务器项目假设我们已经成功安装了create-mcp命令行工具。现在让我们创建一个名为my-first-mcp-server的项目。步骤一初始化项目在终端中导航到你希望创建项目的目录然后运行创建命令。# 导航到你的开发目录 cd ~/projects # 运行创建命令 create-mcp create my-first-mcp-server运行命令后CLI 通常会进入一个交互式流程。步骤二交互式配置推测流程根据工具“Templates”和“Clear Area for Customization”的特性它很可能会向你提出一系列问题来定制化你的项目。这个过程可能包括选择模板[?] Please select a template: (Use arrow keys)basic- 一个最基础的 MCP 服务器包含最小示例。ai-enhanced- 集成了基础 AI 调用能力的模板。aws-lambda- 针对 AWS Lambda 部署优化的模板。resource-server- 侧重于暴露 Resources资源的模板。tool-heavy- 侧重于定义 Tools工具的模板。选择包管理器[?] Package manager: (npm / yarn / pnpm)。这决定了项目将使用哪个工具来安装依赖和运行脚本。是否初始化 Git 仓库[?] Initialize a git repository? (Y/n)。通常建议选择“是”以便进行版本控制。是否现在安装依赖[?] Install dependencies now? (Y/n)。选择“是”会让 CLI 自动运行npm install节省你的时间。步骤三项目结构预览命令执行完毕后进入项目目录并查看生成的文件结构。cd my-first-mcp-server ls -la一个典型的、结构良好的 MCP 服务器项目可能如下所示my-first-mcp-server/ ├── src/ │ ├── index.ts # 服务器主入口文件 │ ├── tools/ # 工具Tools定义目录 │ │ └── exampleTool.ts │ ├── resources/ # 资源Resources定义目录 │ │ └── exampleResource.ts │ └── types/ # TypeScript 类型定义 │ └── index.ts ├── package.json # 项目依赖和脚本 ├── tsconfig.json # TypeScript 配置 ├── .env.example # 环境变量示例文件 ├── .gitignore └── README.md # 项目专属说明文档这个结构清晰地将协议的不同概念工具、资源进行了模块化分离非常利于维护和扩展。3.3 理解生成的核心代码让我们打开最关键的src/index.ts文件看看Create-MCP为我们搭建了怎样的基础。以下是一个高度简化和注释的示例反映了生成代码的可能结构// src/index.ts import { Server } from modelcontextprotocol/sdk/server/index.js; import { StdioServerTransport } from modelcontextprotocol/sdk/server/stdio.js; // 导入自定义的工具和资源定义 import { fetchWebpageTool } from ./tools/fetchWebpage.js; import { getSystemInfoResource } from ./resources/systemInfo.js; // 1. 创建 MCP 服务器实例 const server new Server( { name: my-first-mcp-server, // 你的服务器名称 version: 1.0.0, }, { capabilities: { // 2. 声明服务器支持的能力工具和/或资源 tools: {}, resources: {}, }, } ); // 3. 注册自定义工具 // 这里将我们在 tools/ 目录下定义的工具挂载到服务器上 server.setRequestHandler(tools/list, async () ({ tools: [fetchWebpageTool], })); server.setRequestHandler(tools/call, async (request) { if (request.params.name fetchWebpageTool.name) { // 调用工具的实际处理逻辑 const result await fetchWebpageTool.handler(request.params.arguments!); return result; } throw new Error(Unknown tool: ${request.params.name}); }); // 4. 注册自定义资源如果模板支持 server.setRequestHandler(resources/list, async () ({ resources: [getSystemInfoResource], })); server.setRequestHandler(resources/read, async (request) { if (request.params.uri getSystemInfoResource.uri) { const content await getSystemInfoResource.handler(); return { contents: [content] }; } throw new Error(Unknown resource: ${request.params.uri}); }); // 5. 启动服务器使用标准输入输出进行通信这是MCP的常见方式 async function main() { const transport new StdioServerTransport(); await server.connect(transport); console.error(MCP server running on stdio...); } main().catch((error) { console.error(Server error:, error); process.exit(1); });这段代码做了几件关键事初始化服务器、声明能力、注册具体的工具/资源处理函数最后启动一个基于 stdio标准输入输出的传输层。这是 MCP 服务器与客户端如 Claude Desktop、Cursor通信的标准模式之一。注意事项生成的package.json中的scripts字段非常重要。你通常会看到类似以下的命令scripts: { start: tsx src/index.ts, // 开发运行 dev: nodemon src/index.ts, // 开发模式监听文件变化 build: tsc, // 编译为JavaScript test: echo \No tests yet\ }在开发时使用npm run dev可以让你在修改代码后自动重启服务器提升效率。4. 核心功能扩展与自定义开发4.1 如何添加一个新的工具Tool工具是 MCP 的核心它允许 AI 主动执行某个操作。假设我们想添加一个“获取当前天气”的工具。步骤一创建工具定义文件在src/tools/目录下新建一个文件weatherTool.ts。// src/tools/weatherTool.ts import { Tool } from modelcontextprotocol/sdk/types.js; // 1. 定义工具的输入参数 Schema使用 JSON Schema const weatherArgsSchema { type: object, properties: { city: { type: string, description: The name of the city to get weather for, e.g., London, }, unit: { type: string, enum: [celsius, fahrenheit], description: The unit for temperature, default: celsius, }, }, required: [city], } as const; // 2. 定义工具本身 export const getWeatherTool: Tool { name: get_weather, // 工具的唯一标识通常用下划线分隔 description: Get the current weather for a specified city., inputSchema: weatherArgsSchema, }; // 3. 定义工具的处理函数Handler export async function getWeatherHandler(args: { city: string; unit?: celsius | fahrenheit; }) { const { city, unit celsius } args; // 这里应该是调用真实天气API的逻辑例如 OpenWeatherMap // 为了示例我们模拟一个返回 console.error([MCP Server] Fetching weather for ${city} in ${unit}...); // 模拟API调用延迟 await new Promise(resolve setTimeout(resolve, 100)); const mockTemperature unit celsius ? 22°C : 72°F; const mockCondition Sunny; // 返回结构化的结果AI客户端可以很好地解析和呈现 return { content: [ { type: text, text: The current weather in ${city} is ${mockCondition} with a temperature of ${mockTemperature}., }, ], }; }步骤二在服务器中注册新工具修改src/index.ts导入并注册这个新工具。// 在文件顶部添加导入 import { getWeatherTool, getWeatherHandler } from ./tools/weatherTool.js; // 在 server.setRequestHandler(tools/list, ...) 中将新工具加入数组 server.setRequestHandler(tools/list, async () ({ tools: [fetchWebpageTool, getWeatherTool], // 添加 getWeatherTool })); // 在 server.setRequestHandler(tools/call, ...) 中添加对新工具调用的处理 server.setRequestHandler(tools/call, async (request) { const { name, arguments: args } request.params; if (name fetchWebpageTool.name) { // ... 原有的 fetchWebpage 处理逻辑 } else if (name getWeatherTool.name) { // 新增判断分支 const result await getWeatherHandler(args!); return result; } throw new Error(Unknown tool: ${name}); });步骤三测试工具保存所有文件确保你的开发服务器正在运行 (npm run dev)。在支持 MCP 的客户端例如配置了该服务器的 Claude Desktop中你现在就可以直接说“请使用 get_weather 工具查询一下伦敦的天气。” AI 会识别到这个工具并按照你定义的参数格式去调用它。实操心得工具设计的要点描述要清晰description和参数description是 AI 理解工具用途的关键写得越准确AI 调用得越精准。Schema 要严格inputSchema定义了合同的格式。使用enum、required等约束可以强制 AI 提供正确格式的输入减少错误。错误处理要友好在handler函数中一定要用try...catch包裹核心逻辑并返回结构化的错误信息而不是让进程崩溃。例如return { content: [{ type: text, text:Error fetching weather: ${error.message}}], isError: true };。4.2 如何添加一个新的资源Resource资源代表了 AI 可以读取的静态或动态内容比如一个配置文件、一个数据库查询视图或者一个系统状态报告。步骤一创建资源定义文件在src/resources/目录下新建projectStatus.ts。// src/resources/projectStatus.ts import { Resource } from modelcontextprotocol/sdk/types.js; // 1. 定义资源 // URI 是资源的唯一标识符可以包含查询参数 export const projectStatusResource: Resource { uri: file:///project/status, name: Project Status Report, description: A dynamic report showing the current status of the development project., mimeType: text/plain, // 也可以是 application/json }; // 2. 定义资源内容处理函数 export async function getProjectStatusContent() { // 这里可以动态生成内容例如读取文件、查询数据库、调用API const currentTime new Date().toISOString(); const mockStatus { backend: Healthy, frontend: Deploying, database: Connected, lastUpdated: currentTime, }; // 将内容格式化为字符串。对于复杂数据可以考虑返回 JSON。 const contentText PROJECT STATUS REPORT Generated at: ${currentTime} Backend API: ${mockStatus.backend} Frontend App: ${mockStatus.frontend} Database: ${mockStatus.database} ; return { contents: [ { uri: projectStatusResource.uri, mimeType: projectStatusResource.mimeType!, text: contentText, }, ], }; }步骤二在服务器中注册新资源修改src/index.ts导入并注册这个新资源。// 导入 import { projectStatusResource, getProjectStatusContent } from ./resources/projectStatus.js; // 更新 resources/list 处理器 server.setRequestHandler(resources/list, async () ({ resources: [getSystemInfoResource, projectStatusResource], // 添加新资源 })); // 更新 resources/read 处理器 server.setRequestHandler(resources/read, async (request) { const { uri } request.params; if (uri getSystemInfoResource.uri) { // ... 原有逻辑 } else if (uri projectStatusResource.uri) { // 新增判断分支 const content await getProjectStatusContent(); return content; } throw new Error(Unknown resource: ${uri}); });现在AI 客户端就可以通过file:///project/status这个 URI 来读取你动态生成的项目状态报告了。这对于为 AI 提供项目上下文信息非常有用。5. 部署与集成让服务器真正可用5.1 本地开发与调试技巧在将服务器投入生产环境之前充分的本地测试至关重要。技巧一使用 MCP 客户端进行测试除了依赖 Claude Desktop 或 Cursor你可以使用一些专门的 MCP 测试客户端进行更底层的调试。官方测试工具MCP 官方提供了一些简单的测试脚本可以用来检查服务器是否响应正确。编写简易测试脚本你可以自己写一个 Node.js 脚本模拟客户端通过 stdio 与你的服务器通信发送标准的tools/list请求并打印响应验证工具注册是否成功。技巧二善用日志在工具和资源的handler函数中使用console.error输出日志MCP 协议中服务器日志通常输出到 stderr。这能帮助你跟踪执行流程和调试问题。async function getWeatherHandler(args) { console.error([WeatherTool] Handler called with args: ${JSON.stringify(args)}); // ... 业务逻辑 }技巧三环境变量管理Create-MCP生成的.env.example文件是很好的实践。使用dotenv或类似库来管理敏感信息如 API 密钥。# .env OPENWEATHER_API_KEYyour_secret_key_here WEATHER_UNITcelsius在代码中通过process.env.OPENWEATHER_API_KEY读取。务必确保.env文件在.gitignore中避免泄露密钥。5.2 部署到云函数以 AWS Lambda 为例如果选择了aws-lambda模板项目结构可能已经为 Lambda 部署做好了优化。如果没有以下是将一个标准 MCP 服务器适配到 AWS Lambda 的基本思路。核心挑战MCP 服务器默认使用 stdio 通信而 Lambda 是事件驱动HTTP 或直接调用的。我们需要一个适配层。解决方案使用modelcontextprotocol/sdk提供的LambdaServerTransport或类似适配器或者将服务器包装成一个 HTTP 端点。步骤概要修改入口文件创建一个新的入口点如lambda.ts使用 AWS Lambda 的 handler 格式。使用适配器将 MCP 服务器的 stdio 传输替换为处理 Lambda 事件流的传输层。打包部署将项目代码编译后的 JavaScript和node_modules一起打包成 ZIP上传到 Lambda或使用容器镜像。一个极其简化的示例框架如下// src/lambda.ts import { Server } from modelcontextprotocol/sdk/server/index.js; import { LambdaServerTransport } from modelcontextprotocol/sdk/server/lambda.js; // 假设有该适配器 // ... 导入你的工具和资源 const server new Server({ name: mcp-lambda }, { capabilities: { tools: {} } }); // ... 注册工具和资源 // AWS Lambda Handler export const handler async (event: any, context: any) { const transport new LambdaServerTransport(event, context); await server.connect(transport); // 适配器内部会处理与Lambda运行时API的通信 };重要提示部署到 Lambda 需要考虑冷启动时间、超时设置、权限IAM Role等问题。如果你的 MCP 服务器需要访问其他 AWS 服务如 S3、DynamoDB务必正确配置 IAM 策略。5.3 与 AI 客户端集成最后也是最重要的一步让你的 MCP 服务器被 AI 客户端识别和使用。以 Claude Desktop 为例找到 Claude Desktop 的配置文件位置。macOS:~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:%APPDATA%\Claude\claude_desktop_config.json编辑该 JSON 文件在mcpServers部分添加你的服务器配置。{ mcpServers: { my-first-server: { command: node, args: [ /absolute/path/to/your/project/my-first-mcp-server/build/index.js // 指向编译后的入口文件 ], env: { OPENWEATHER_API_KEY: your_key_here } } } }重启 Claude Desktop。在聊天界面你应该能看到新的工具可用通常会在输入框上方出现工具图标或者你可以直接通过描述使用工具。以 Cursor AI 为例Cursor 的配置方式可能类似具体需要参考其官方文档。通常也是在设置中指定一个本地命令或脚本路径来启动你的 MCP 服务器。6. 常见问题与故障排查实录在实际使用Create-MCP和开发 MCP 服务器的过程中你几乎一定会遇到下面这些问题。这里记录了我踩过的坑和解决方案。6.1 安装与启动问题问题一运行create-mcp命令提示“命令未找到”。原因通常是因为全局安装路径没有添加到系统的 PATH 环境变量中或者安装失败。排查检查安装是否成功npm list -g | grep create-mcp。查找全局安装路径npm config get prefix然后检查该路径下的bin文件夹是否有create-mcp的可执行文件。解决方案A推荐使用npxnpx create-mcplatest create my-server。解决方案B将 npm 的全局bin目录添加到 PATH。例如在~/.zshrc或~/.bashrc中添加export PATH$PATH:$(npm config get prefix)/bin然后重启终端。问题二项目创建成功但npm install失败或npm start报错。原因Node.js 版本不兼容或者网络问题导致依赖下载失败。排查确认 Node.js 版本符合项目要求查看项目根目录是否有.nvmrc或package.json中的engines字段。清除 npm 缓存并重试npm cache clean --force npm install。检查是否有特定的原生模块node-gyp编译失败可能需要安装 Python 或 Windows Build Tools。解决方案尝试使用yarn或pnpm进行安装有时可以解决 npm 的依赖解析问题。6.2 开发与调试问题问题三工具被成功列出但 AI 调用时服务器报错或无响应。原因这是最常见的问题根源多在工具处理函数内部。排查步骤看服务器日志这是最重要的信息源。确保你在运行服务器时能看到console.error的输出。检查参数解析AI 传递的参数是否与你定义的inputSchema完全匹配特别是类型string, number, boolean和必需字段。在 handler 开头打印args进行验证。检查异步操作你的 handler 是否是async函数内部的 API 调用或文件读取是否使用了await未处理的 Promise 拒绝会导致进程静默退出。检查错误边界确保 handler 内部有try...catch并将错误信息以 MCP 协议规定的格式返回而不是直接throw一个未捕获的异常。示例调试代码export async function myToolHandler(args: any) { console.error([DEBUG] Handler args:, JSON.stringify(args)); try { // 你的业务逻辑 const result await someAsyncOperation(args.input); return { content: [{ type: text, text: Result: ${result} }] }; } catch (error: any) { console.error([ERROR] Tool execution failed:, error); // 返回结构化错误而不是抛出 return { content: [{ type: text, text: Tool failed: ${error.message} }], isError: true, }; } }问题四修改了工具定义或代码但 AI 客户端没有更新。原因MCP 客户端如 Claude Desktop通常会缓存服务器提供的工具列表。解决方案重启服务器确保你的开发服务器npm run dev已经重启并加载了新代码。重启客户端完全退出并重新启动 Claude Desktop 或 Cursor。检查连接确认客户端配置指向的是正确的、正在运行的服务器实例。6.3 部署与集成问题问题五服务器在本地运行正常但部署到 Lambda 后超时或无响应。原因Lambda 有默认 3 秒的超时限制而 MCP 通信可能涉及多次往返或者权限配置不正确。排查增加超时时间在 Lambda 配置中将函数超时时间延长至 30 秒或 1 分钟。检查日志查看 CloudWatch Logs确认函数是否被触发以及是否有错误日志。权限问题如果工具需要访问网络调用外部 API或 AWS 其他服务确保 Lambda 函数的执行角色IAM Role附带了相应的策略如AWSLambdaBasicExecutionRole和AmazonS3ReadOnlyAccess等。适配器兼容性确认你使用的 MCP Lambda 适配器与你的 SDK 版本和 Lambda 运行时兼容。问题六在 Claude Desktop 中看不到新添加的工具。原因配置文件错误、路径问题或服务器未正确声明工具。排查清单配置文件路径确认claude_desktop_config.json路径正确且 JSON 格式有效无尾随逗号。命令路径args中的路径必须是绝对路径。相对路径在桌面应用环境中可能无法解析。环境变量如果服务器需要环境变量如 API KEY是否在配置的env字段中正确设置了服务器输出启动 Claude Desktop 时查看其日志通常可在应用内或系统标准输出中找到看是否有加载你的服务器以及是否有错误信息。协议兼容性确保你的服务器实现的 MCP 协议版本与客户端兼容。