diff --git a/content/docs/(get-started)/example-clients.mdx b/content/docs/(get-started)/example-clients.mdx index b42a5c5..db6b1c7 100644 --- a/content/docs/(get-started)/example-clients.mdx +++ b/content/docs/(get-started)/example-clients.mdx @@ -1,5 +1,203 @@ --- title: MCP客户端示例 -description: MCP客户端示例 --- +支持 MCP 集成的应用程序列表 + +本页概述了支持模型上下文协议(Model Context Protocol,MCP)的应用程序。每个客户端可能支持不同的 MCP 功能,从而实现与 MCP 服务器的不同集成级别。 +## 客户端详情 ## +### Claude 桌面应用(Claude Desktop App) ### +Claude 桌面应用程序提供对 MCP 的全面支持,从而能够与本地工具和数据源进行深度集成。 +主要功能: +- 完全支持资源(Resources),允许附加本地文件和数据 +- 支持提示词模板(prompt templates) +- 工具集成(Tool integration),用于执行命令和脚本 +- 本地服务器连接(Local server connections),以增强隐私和安全性 + +注意:Claude.ai Web 应用程序当前不支持 MCP,MCP 功能仅在桌面应用程序中可用。 + +### Claude Code ### +Claude Code是一个来自Anthropic的交互式代理编码工具,可以帮助您通过自然语言命令更快地编码。它支持MCP的提示和工具集成,也可以作为MCP服务器与其他客户端集成。 + +主要功能: +- 对MCP服务器工具和提示的支持 +- 通过MCP服务器提供自己的工具,用于与其他MCP客户端集成 +### 5ire ### +[5ire](https://github.com/nanbingxyz/5ire) 是一款开源的跨平台桌面 AI 助手,它通过 MCP 服务器支持工具(Tools)。 +主要功能: +- 可以快速启用和禁用内置的 MCP 服务器。 +- 用户可以通过修改配置文件来添加更多服务器。 +- 它是开源且用户友好的,适合初学者。 +- 未来将不断改进对 MCP 的支持。 +### BeeAI Framework ### +[BeeAI 框架(BeeAI Framework)](https://i-am-bee.github.io/beeai-framework) 是一个开源框架,用于大规模构建、部署和服务强大的代理工作流。该框架包括 MCP 工具(MCP Tool),这是一个原生功能,可简化将 MCP 服务器集成到代理工作流中的过程。 +主要功能: +- 将 MCP 工具无缝集成到代理工作流中。 +- 从连接的 MCP 客户端快速实例化框架原生工具。 +- 计划未来支持代理 MCP 功能。 + +了解更多: +[在代理工作流中使用 MCP 工具的示例](https://i-am-bee.github.io/beeai-framework/#/typescript/tools?id=using-the-mcptool-class) +### Cline ### +Cline 是 VS Code 中的一个自主编码代理,它可以编辑文件、运行命令、使用浏览器等等——每一步都需要你的许可。 + +主要功能: +- 通过自然语言创建和添加工具(例如,“添加一个搜索网络的工具”) +- 通过 ~/Documents/Cline/MCP 目录与他人共享 Cline 创建的自定义 MCP 服务器 +- 显示配置的 MCP 服务器及其工具、资源以及任何错误日志 +### Continue ### +[Continue](https://github.com/continuedev/continue) 是一个开源的 AI 代码助手,内置支持所有 MCP 功能。 + +主要功能 +- 键入“@”以提及 MCP 资源(Resources) +- 提示词模板(Prompt templates)显示为斜杠命令 +- 直接在聊天中使用内置工具和 MCP 工具 +- 支持 VS Code 和 JetBrains IDE,以及任何 LLM +### Cursor ### +[Cursor](https://docs.cursor.com/advanced/model-context-protocol) 是一款 AI 代码编辑器。 + +主要功能: +- 在 Cursor Composer 中支持 MCP 工具(Tools) +- 支持 STDIO 和 SSE +### Emacs Mcp ### +[Emacs Mcp](https://github.com/lizqwerscott/mcp.el)是一个 Emacs 客户端,旨在与 MCP 服务器连接,实现无缝连接和交互。 它为 AI 插件(如 gptel 和 llm)提供 MCP 工具调用支持,遵循 Emacs 的标准工具调用格式。 这种集成增强了 Emacs 生态系统中 AI 工具的功能。 +主要功能: +- 为 Emacs 提供 MCP 工具支持。 +### fast-agent ### +[fast-agent](https://github.com/evalstate/fast-agent)是一个Python代理框架,对创建代理和工作流提供简单的声明性支持,对Anthropic和OpenAI模型提供完整的多模态支持。 + +主要功能: +- PDF和图像支持,基于MCP原生类型 +- 用于开发和诊断代理应用程序的交互式前端,包括直通和回放模拟器 +- 内置支持“构建有效代理”工作流。 +- 将agent部署为MCP服务器 +### Genkit ### +[Genkit](https://github.com/firebase/genkit)是一个跨语言SDK,用于构建GenAI功能并将其集成到应用程序中。genkitx-mcp插件允许作为客户端使用MCP服务器,或者从Genkit工具和提示词创建MCP服务器。 + +主要功能: +- 客户端对工具和提示词的支持(部分支持的资源) +- 支持Genkit的Dev UI在线演示平台的丰富发现 +- 与Genkit现有工具和提示符的无缝互操作性 +- 工作跨越顶级供应商的各种各样的GenAI模型 +### GenAIScript ### +使用 [GenAIScript](https://microsoft.github.io/genaiscript/)(在 JavaScript 中)以编程方式为 LLM 组装 prompts。在 JavaScript 中编排 LLM、tools 和 resources。 +主要功能: +- JavaScript 工具箱用于处理提示 +- 便于使用和提高生产力的抽象层 +- 无缝集成 Visual Studio Code +### Goose ### +[Goose](https://github.com/block/goose) 是一个开源 AI 代理,通过自动化编码任务来增强你的软件开发能力。 +主要功能: +- 通过工具(Tools)向 Goose 公开 MCP 功能。 +- 可以直接通过 [extensions directory](https://block.github.io/goose/v1/extensions/)、CLI 或 UI 安装 MCP。 +- Goose 允许你通过[构建自己的 MCP 服务器](https://block.github.io/goose/docs/tutorials/custom-extensions) 来扩展其功能。 +- 包含内置工具,用于开发、Web 抓取、自动化、内存以及与 JetBrains 和 Google Drive 集成。 +### LibreChat ### +[LibreChat](https://github.com/danny-avila/LibreChat) 是一个开源、可定制的 AI 聊天 UI,支持多个 AI 提供商,现在包括 MCP 集成。 +主要功能: +- 通过 MCP 服务器扩展当前的工具生态系统,包括[Code Interpreter](https://www.librechat.ai/docs/features/code_interpreter) 和图像生成工具 +- 使用来自顶级提供商的各种 LLM,将工具添加到可定制的代理(Agents) +- 开源且可自托管,具有安全的多用户支持 +- 未来的路线图包括扩展的 MCP 功能支持 +### mcp-agent ### +[mcp-agent](https://github.com/lastmile-ai/mcp-agent) 是一个简单的、可组合的框架,用于使用模型上下文协议(Model Context Protocol)构建代理。 +主要功能: +- 自动连接管理 MCP 服务器。 +- 将来自多个服务器的工具(Tools)公开给 LLM。 +- 实现了[构建有效代理](https://www.anthropic.com/research/building-effective-agents) 中定义的每个模式。 +- 支持工作流暂停/恢复信号,例如等待人工反馈。 +### Microsoft Copilot Studio ### +[Microsoft Copilot Studio](https://learn.microsoft.com/en-us/microsoft-copilot-studio/agent-extend-action-mcp)是一个强大的SaaS平台,旨在构建自定义AI驱动的应用程序和智能代理,使开发人员能够创建、部署和管理复杂的AI解决方案。 +主要功能: +- 支持MCP工具 +- 用MCP服务器扩展Copilot Studio代理 +- 利用Microsoft统一的、受治理的和安全的API管理解决方案 +### oterm ### +[oterm](https://github.com/ggozad/oterm)是Ollama的终端客户端,允许用户创建聊天/代理。 +主要功能: +- 通过Ollama连接工具,支持多个可完全定制的聊天会话。 +- 支持MCP工具。 +### Roo Code ### +[Roo Code](https://roocode.com/) 通过 MCP 实现 AI 编码辅助。 +主要功能: +- 支持 MCP 工具(Tools)和资源(Resources) +- 与开发工作流程集成 +- 可扩展的 AI 功能 +### Sourcegraph Cody ### +[Cody](https://openctx.org/docs/providers/modelcontextprotocol) 是 Sourcegraph 的 AI 编码助手,它通过 OpenCTX 实现 MCP。 +主要功能: +- 支持 MCP 资源(Resources) +- 与 Sourcegraph 的代码智能集成 +- 使用 OpenCTX 作为抽象层 +- 计划未来支持其他 MCP 功能 +### SpinAI ### +[SpinAI](https://spinai.dev/) 是一个开源 TypeScript 框架,用于构建可观察的 AI 代理。 该框架提供原生 MCP 兼容性,允许代理与 MCP 服务器和工具无缝集成。 +主要功能: +- AI 代理的内置 MCP 兼容性 +- 开源 TypeScript 框架 +- 可观察的代理架构 +- 对 MCP 工具集成的原生支持 +### Superinterface ### +[Superinterface](https://superinterface.ai/) 是 AI 基础设施和开发人员平台,用于构建应用内 AI 助手,支持 MCP 、交互式组件、客户端函数调用等。 +主要功能: +- 在通过 React 组件或脚本标记嵌入的助手中,使用来自 MCP 服务器的工具(Tools) +- SSE 传输支持 +- 使用来自任何 AI 提供商(OpenAI、Anthropic、Ollama 等)的任何 AI 模型 +### TheiaAI/TheiaIDE ### +[Theia AI](https://eclipsesource.com/blogs/2024/10/07/introducing-theia-ai/) 是一个用于构建 AI 增强工具和 IDE 的框架。AI 驱动的 Theia IDE 是一个基于 Theia AI 构建的开放且灵活的开发环境。 +主要功能: +- 工具集成:Theia AI 使 AI 代理(包括 Theia IDE 中的代理)能够利用 MCP 服务器进行无缝工具交互。 +- 可定制的提示词(Prompts):Theia IDE 允许用户定义和调整提示词,动态集成 MCP 服务器以实现定制的工作流程。 +- 自定义代理(agents):Theia IDE 支持利用 MCP 功能创建自定义代理,使用户能够动态设计专用工作流程。 +Theia AI 和 Theia IDE 的 MCP 集成为用户提供了灵活性,使它们成为探索和调整 MCP 的强大平台。 +了解更多: +- [Theia IDE 和 Theia AI MCP 公告](https://eclipsesource.com/blogs/2024/12/19/theia-ide-and-theia-ai-support-mcp/) +- [下载 AI 驱动的 Theia IDE](https://theia-ide.org/) +### Windsurf Editor ### +[Windsurf Editor](https://codeium.com/windsurf) 是一款代理 IDE,将 AI 辅助与开发人员工作流程相结合。 它具有创新的 AI Flow 系统,可在保持开发人员控制同时,实现协作和独立的 AI 交互。 +主要功能: +- 用于人机协作的革命性 AI Flow 范例 +- 智能代码生成和理解 +- 具有多模型支持的丰富开发工具 +### Witsy ### +[Witsy](https://github.com/nbonamy/witsy)是一个人工智能桌面助手,支持Anthropic模型和作为LLM工具的MCP服务器。 +主要功能: +- 支持多个MCP服务器 +- 用于执行命令和脚本的工具集成 +- 本地服务器连接,增强隐私和安全性 +- 从Smithery.ai易于安装 +- 开源,可用于macOS, Windows和Linux +### Zed ### +[Zed](https://zed.dev/docs/assistant/model-context-protocol) 是一款高性能代码编辑器,具有内置 MCP 支持,专注于提示词模板(prompt templates)和工具集成。 +主要功能: +- 提示词模板(Prompt templates)在编辑器中显示为斜杠命令 +- 工具集成,用于增强编码工作流程 +- 与编辑器功能和工作区上下文紧密集成 +- 不支持 MCP 资源 +### OpenSumi ### +[OpenSumi](https://github.com/opensumi/core) 是一个可以帮助您快速构建 AI Native IDE 产品的框架。 +主要功能: +- 在 OpenSumi 中支持 MCP 工具(Tools) +- 支持内置 IDE MCP 服务器和自定义 MCP 服务器 +### Daydreams ### +[Daydreams](https://github.com/daydreamsai/daydreams) 是一个用于在链上执行任何操作的生成式代理框架 +主要功能: +- 在配置中支持 MCP 服务器(Servers) +- 公开 MCP 客户端 +### Apify MCP Tester ### +[Apify MCP Tester](https://github.com/apify/tester-mcp-client)是一个使用服务器发送事件(server - sent Events, SSE)连接到任何MCP服务器的开源客户端。它是一个独立的Apify Actor,设计用于在SSE上测试MCP服务器,支持授权标头。它使用纯JavaScript(老派风格),并托管在Apify上,允许您无需任何设置即可运行它。 +主要功能: +- 通过SSE连接到任意MCP服务器。 +- 与[Apify MCP服务器](https://apify.com/apify/actors-mcp-server)一起工作,与一个或多个[Apify actor](https://apify.com/store)进行交互。 +- 动态地利用基于上下文和用户查询的工具(如果服务器支持)。 +## 向您的应用程序添加 MCP 支持 ## +如果您已将 MCP 支持添加到您的应用程序,我们鼓励您提交拉取请求以将其添加到此列表中。 MCP 集成可以为您的用户提供强大的上下文 AI 功能,并使您的应用程序成为不断增长的 MCP 生态系统的一部分。 +添加 MCP 支持的好处: +- 使用户能够带来自己的上下文和工具(Tools) +- 加入不断增长的、可互操作的 AI 应用程序生态系统 +- 为用户提供灵活的集成选项 +- 支持本地优先的 AI 工作流程 + +要开始在您的应用程序中实现 MCP,请查看我们的 [Python](https://github.com/modelcontextprotocol/python-sdk) 或 [TypeScript SDK 文档](https://github.com/modelcontextprotocol/typescript-sdk) +## 更新和更正 ## +此列表由社区维护。 如果您发现任何不准确之处或想要更新有关您的应用程序中 MCP 支持的信息,请提交拉取请求或在我们的[文档存储库](https://github.com/modelcontextprotocol/docs/issues)中新开一个问题。 diff --git a/content/docs/(get-started)/quick-start/client-developers.mdx b/content/docs/(get-started)/quick-start/client-developers.mdx index a32b110..ffbbd4b 100644 --- a/content/docs/(get-started)/quick-start/client-developers.mdx +++ b/content/docs/(get-started)/quick-start/client-developers.mdx @@ -10,17 +10,17 @@ description: 快速开始 - 客户端开发者 import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; - + 本教程完整的代码在[这里](https://github.com/modelcontextprotocol/quickstart-resources/tree/main/mcp-client-python) -## 系统需求 ## +## 系统需求 [!toc] 开始之前,确认你的系统满足如下需求: - 操作系统Mac或Windows - 安装了最新版本的Python - 安装了最新版本的uv -## 设置环境 ## +## 设置环境 [!toc] 首先,用uv新建一个Python项目: ```js # Create project directory @@ -45,7 +45,7 @@ rm hello.py # Create our main file touch client.py ``` -## 安装你的API key ## +## 安装你的API key [!toc] 你需要从[Anthropic Console](https://console.anthropic.com/settings/keys)获取一个Anthropic API key 创建一个.env文件来存储它: @@ -61,11 +61,11 @@ ANTHROPIC_API_KEY= ```js echo ".env" >> .gitignore ``` - + 请确保您的ANTHROPIC_API_KEY安全! -## 创建客户端 ## -### 客户端基础机构 ### +## 创建客户端 [!toc] +### 客户端基础结构 [!toc] 首先,我们设置import和创建基础的客户端类: ```js import asyncio @@ -88,7 +88,7 @@ class MCPClient: self.anthropic = Anthropic() # methods will go here ``` -### 服务器连接管理 ### +### 服务器连接管理 [!toc] 接下来,我们实现连接MCP服务器的方法: ```js @@ -121,7 +121,7 @@ async def connect_to_server(self, server_script_path: str): tools = response.tools print("\nConnected to server with tools:", [tool.name for tool in tools]) ``` -### 查询处理的逻辑 ### +### 查询处理的逻辑 [!toc] 现在,现在让我们添加处理查询和工具调用的核心功能: ```js async def process_query(self, query: str) -> str: @@ -192,7 +192,7 @@ async def process_query(self, query: str) -> str: return "\n".join(final_text) ``` -### 和Chat进行交互 ### +### 互动聊天 [!toc] 现在我们添加一些chat来回交互和清理的功能: ```js async def chat_loop(self): @@ -217,7 +217,7 @@ async def cleanup(self): """Clean up resources""" await self.exit_stack.aclose() ``` -### main函数入口要点 ### +### main函数入口 [!toc] 最后,我们添加main入口执行逻辑 ```js async def main(): @@ -236,8 +236,8 @@ if __name__ == "__main__": import sys asyncio.run(main()) ``` -完整的client.py文件在这里 -## 关键组件说明 ## +完整的client.py文件在[这里](https://gist.github.com/zckly/f3f28ea731e096e53b39b47bf0a2d4b1) +## 关键组件说明 [!toc] 1. 客户端初始化 - MCPClient类初始化会话管理和API客户端 - 使用AsyncExitStack进行适当的资源管理 @@ -261,7 +261,7 @@ if __name__ == "__main__": - 妥善清理资源 - 连接问题的错误处理 - 安全关机程序 -## 通常的定制化要点 ## +## 通常的定制化要点 [!toc] 1. 工具处理 - 修改process_query()来处理特定的工具类型 - 为工具调用添加自定义错误处理 @@ -274,19 +274,19 @@ if __name__ == "__main__": - 添加GUI或web界面 - 实现丰富的控制台输出 - 添加命令历史记录或自动完成 -## 运行客户端 ## +## 运行客户端 [!toc] 运行客户端,可选择任意服务器: ```js uv run client.py path/to/server.py # python server uv run client.py path/to/build/index.js # node server ``` - + 如果你还在从服务器快速入门继续天气教程,你的命令可能看起来像这样:python client.py .../weather/src/weather/server.py 客户端将会: 1. 连接到指定的服务器 2. 列出可用的工具 -3. 开始一个交互对话的会话,你可以实现以下操作: +3. 开始一个互动聊天的会话,你可以实现以下操作: - 输入查询 - 查看工具的执行情况 - 从Claude得到响应 @@ -294,7 +294,7 @@ uv run client.py path/to/build/index.js # node server 下面是一个在服务器快速入门教程中连接到天气服务器的示例: ![ImaImageZoomge](/client-claude-cli-python.png) -## 工作机制 ## +## 工作机制 [!toc] 当你提交查询时: 1. 客户端从服务器获取可用工具的列表 2. 您的查询将与工具描述一起发送给Claude @@ -303,7 +303,7 @@ uv run client.py path/to/build/index.js # node server 5. 结果被送回给Claude 6. Claude用自然语言响应 7. 将返回的响应显示给用户 -## 最佳实践 ## +## 最佳实践 [!toc] 1. 错误处理 - 始终将工具调用封装在try-catch块中 - 提供有意义的错误消息 @@ -316,8 +316,8 @@ uv run client.py path/to/build/index.js # node server - 将API key安全地存储在.env文件中 - 验证服务器响应 - 谨慎处理工具的使用权限 -## 故障排除 ## -### 服务器路径问题 ### +## 故障排除 [!toc] +### 服务器路径问题 [!toc] - 再次检查服务器的路径是否正确 - 如果相对路径不起作用,请使用绝对路径 - 对于Windows用户,请确保在路径中使用正斜杠(/)或转义反斜杠(\) @@ -335,7 +335,7 @@ uv run client.py /Users/username/projects/mcp-server/weather.py uv run client.py C:/projects/mcp-server/weather.py uv run client.py C:\\projects\\mcp-server\\weather.py ``` -### 响应时间 ### +### 响应时间 [!toc] - 第一个响应可能需要30秒才能返回 - 这是正常的,发生在: - 服务器初始化 @@ -343,7 +343,7 @@ uv run client.py C:\\projects\\mcp-server\\weather.py - 工具正在执行 - 随后的反应通常更快 - 在最初的等待期间,不要中断该过程 -### 常见错误信息 ### +### 常见错误信息 [!toc] 当你看到: - FileNotFoundError:检查你的服务器路径 - Connection refused:确认服务器在运行并且路径正确 @@ -351,6 +351,995 @@ uv run client.py C:\\projects\\mcp-server\\weather.py - Timeout error:考虑在客户端配置中增加超时 - Rust is fast - Rust is fast + + 本教程完整的代码在[这里](https://github.com/modelcontextprotocol/quickstart-resources/tree/main/mcp-client-typescript) +## 系统需求 [!toc] +开始之前,确认你的系统满足如下需求: + +- 操作系统Mac或Windows +- 安装了Node.js17或更高版本 +- 安装了最新版本的npm +- Anthropic API key (Claude) + +## 设置环境 [!toc] +首先,新建和安装项目: + + + ```js +# Create project directory +mkdir mcp-client-typescript +cd mcp-client-typescript + +# Initialize npm project +npm init -y + +# Install dependencies +npm install @anthropic-ai/sdk @modelcontextprotocol/sdk dotenv + +# Install dev dependencies +npm install -D @types/node typescript + +# Create source file +touch index.ts + ``` + + + ```js + # Create project directory +md mcp-client-typescript +cd mcp-client-typescript + +# Initialize npm project +npm init -y + +# Install dependencies +npm install @anthropic-ai/sdk @modelcontextprotocol/sdk dotenv + +# Install dev dependencies +npm install -D @types/node typescript + +# Create source file +new-item index.ts +``` + + +修改package.json设置type:"module"和build脚本 + +```js title="package.json" +{ + "type": "module", + "scripts": { + "build": "tsc && chmod 755 build/index.js" + } +} +``` +在项目的根目录创建一个tsconfig.json文件 +```js title="tsconfig.json" +{ + "compilerOptions": { + "target": "ES2022", + "module": "Node16", + "moduleResolution": "Node16", + "outDir": "./build", + "rootDir": "./", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["index.ts"], + "exclude": ["node_modules"] +} +``` +## 安装你的API Key [!toc] +你需要从[Anthropic Console](https://console.anthropic.com/settings/keys)获取一个Anthropic API key +创建一个.env文件来存储它: +```js +echo "ANTHROPIC_API_KEY=" > .env +``` +将.env文件添加到你的.gitignore: +```js +echo ".env" >> .gitignore +``` + + 请确保您的ANTHROPIC_API_KEY安全! + +## 创建客户端 [!toc] +### 客户端基础结构 [!toc] +首先,我们index.ts中设置import和创建基础的客户端类: +```js +import { Anthropic } from "@anthropic-ai/sdk"; +import { + MessageParam, + Tool, +} from "@anthropic-ai/sdk/resources/messages/messages.mjs"; +import { Client } from "@modelcontextprotocol/sdk/client/index.js"; +import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; +import readline from "readline/promises"; +import dotenv from "dotenv"; + +dotenv.config(); + +const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY; +if (!ANTHROPIC_API_KEY) { + throw new Error("ANTHROPIC_API_KEY is not set"); +} + +class MCPClient { + private mcp: Client; + private anthropic: Anthropic; + private transport: StdioClientTransport | null = null; + private tools: Tool[] = []; + + constructor() { + this.anthropic = new Anthropic({ + apiKey: ANTHROPIC_API_KEY, + }); + this.mcp = new Client({ name: "mcp-client-cli", version: "1.0.0" }); + } + // methods will go here +} +``` +### 服务器连接管理 [!toc] +接下来,我们实现连接MCP服务器的方法: + +```js +async connectToServer(serverScriptPath: string) { + try { + const isJs = serverScriptPath.endsWith(".js"); + const isPy = serverScriptPath.endsWith(".py"); + if (!isJs && !isPy) { + throw new Error("Server script must be a .js or .py file"); + } + const command = isPy + ? process.platform === "win32" + ? "python" + : "python3" + : process.execPath; + + this.transport = new StdioClientTransport({ + command, + args: [serverScriptPath], + }); + this.mcp.connect(this.transport); + + const toolsResult = await this.mcp.listTools(); + this.tools = toolsResult.tools.map((tool) => { + return { + name: tool.name, + description: tool.description, + input_schema: tool.inputSchema, + }; + }); + console.log( + "Connected to server with tools:", + this.tools.map(({ name }) => name) + ); + } catch (e) { + console.log("Failed to connect to MCP server: ", e); + throw e; + } +} +``` +### 查询处理的逻辑[!toc] +现在,现在让我们添加处理查询和工具调用的核心功能: +```js +async processQuery(query: string) { + const messages: MessageParam[] = [ + { + role: "user", + content: query, + }, + ]; + + const response = await this.anthropic.messages.create({ + model: "claude-3-5-sonnet-20241022", + max_tokens: 1000, + messages, + tools: this.tools, + }); + + const finalText = []; + const toolResults = []; + + for (const content of response.content) { + if (content.type === "text") { + finalText.push(content.text); + } else if (content.type === "tool_use") { + const toolName = content.name; + const toolArgs = content.input as { [x: string]: unknown } | undefined; + + const result = await this.mcp.callTool({ + name: toolName, + arguments: toolArgs, + }); + toolResults.push(result); + finalText.push( + `[Calling tool ${toolName} with args ${JSON.stringify(toolArgs)}]` + ); + + messages.push({ + role: "user", + content: result.content as string, + }); + + const response = await this.anthropic.messages.create({ + model: "claude-3-5-sonnet-20241022", + max_tokens: 1000, + messages, + }); + + finalText.push( + response.content[0].type === "text" ? response.content[0].text : "" + ); + } + } + + return finalText.join("\n"); +} +``` +### 互动聊天 [!toc] +现在我们添加一些聊天互动和清理的功能: +```js +async chatLoop() { + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + + try { + console.log("\nMCP Client Started!"); + console.log("Type your queries or 'quit' to exit."); + + while (true) { + const message = await rl.question("\nQuery: "); + if (message.toLowerCase() === "quit") { + break; + } + const response = await this.processQuery(message); + console.log("\n" + response); + } + } finally { + rl.close(); + } +} + +async cleanup() { + await this.mcp.close(); +} +``` +### main函数入口 [!toc] +最后,我们添加main入口执行逻辑 +```js +async function main() { + if (process.argv.length < 3) { + console.log("Usage: node index.ts "); + return; + } + const mcpClient = new MCPClient(); + try { + await mcpClient.connectToServer(process.argv[2]); + await mcpClient.chatLoop(); + } finally { + await mcpClient.cleanup(); + process.exit(0); + } +} + +main(); +``` +## 运行客户端 [!toc] +运行客户端,可选择任意服务器: +```js +# Build TypeScript +npm run build + +# Run the client +node build/index.js path/to/server.py # python server +node build/index.js path/to/build/index.js # node server +``` + + 如果你还在从服务器快速入门继续天气教程,你的命令可能看起来像这样:node build/index.js .../quickstart-resources/weather-server-typescript/build/index.js + +客户端将会: +1. 连接到指定的服务器 +2. 列出可用的工具 +3. 开始一个互动聊天的会话,你可以实现以下操作: +- 输入查询 +- 查看工具的执行情况 +- 从Claude得到响应 + +## 工作机制 [!toc] +当你提交查询时: +1. 客户端从服务器获取可用工具的列表 +2. 您的查询将与工具描述一起发送给Claude +3. Claude决定使用哪些工具(如果有的话) +4. 客户端通过服务器执行工具调用请求 +5. 结果被送回给Claude +6. Claude用自然语言响应 +7. 将返回的响应显示给用户 +## 最佳实践 [!toc] +1. 错误处理 +- 为了更好的检测错误,使用 TypeScript 的类型系统 +- 将工具调用封装在try-catch块中 +- 提供有意义的错误消息 +- 优雅地处理连接问题 +2. 安全性 +- 将API key安全地存储在.env文件中 +- 验证服务器响应 +- 谨慎处理工具的使用权限 +## 故障排除 [!toc] +### 服务器路径问题 [!toc] +- 再次检查服务器的路径是否正确 +- 如果相对路径不起作用,请使用绝对路径 +- 对于Windows用户,请确保在路径中使用正斜杠(/)或转义反斜杠(\) +- 验证服务器文件具有正确的扩展名(Python为.py或Node.js为.js) + +正确的路径示例: +```js +# Relative path +node build/index.js ./server/build/index.js + +# Absolute path +node build/index.js /Users/username/projects/mcp-server/build/index.js + +# Windows path (either format works) +node build/index.js C:/projects/mcp-server/build/index.js +node build/index.js C:\\projects\\mcp-server\\build\\index.js +``` +### 响应时间 [!toc] +- 第一个响应可能需要30秒才能返回 +- 这是正常的,发生在: + - 服务器初始化 + - Claude处理查询 + - 工具正在执行 +- 随后的反应通常更快 +- 在最初的等待期间,不要中断该过程 +### 常见错误信息 [!toc] +当你看到: +- Error: Cannot find module:检查项目的构建文件夹,并确保 TypeScript 编译成功 +- Connection refused:确认服务器在运行并且路径正确 +- Tool execution failed:验证工具所需的环境变量是否已设置 +- ANTHROPIC_API_KEY is not set: 检查 .env 文件和环境变量 +- TypeError:确认调用的工具,参数使用了正确的类型 + + + + + 这是一个基于Spring AI MCP自动配置和boot starter的快速入门演示。要了解如何手动创建同步和异步MCP客户端,请参阅[Java SDK Client](https://modelcontextprotocol.io/sdk/java/mcp-client)文档 + +这个例子演示了如何构建一个交互式聊天机器人,它结合了Spring AI的模型上下文协议(MCP)和[Brave Search MCP服务器](https://github.com/modelcontextprotocol/servers/tree/main/src/brave-search)。 +该应用程序创建了一个对话界面,由Anthropic的Claude AI模型提供支持,该模型可以通过Brave Search执行互联网搜索, +从而实现用自然语言与实时网络数据交互。您可以在[这里](https://github.com/spring-projects/spring-ai-examples/tree/main/model-context-protocol/web-search/brave-chatbot)找到本教程的完整代码。 +## 系统需求 [!toc] +开始之前,确认你的系统满足如下需求: + +- 安装了Java17或更高版本 +- 安装了Maven3.6版本或以上 +- npx 包管理工具 +- Anthropic API key (Claude) +- Brave Search API key +## 设置环境 [!toc] +1. 安装 npx (Node Package eXecute): 首先确认安装 npm 并运行: +```js +npm install -g npx +``` +2. 克隆项目仓库 +```js +git clone https://github.com/spring-projects/spring-ai-examples.git +cd model-context-protocol/brave-chatbot +``` +3. 设置API的key值 +```js +export ANTHROPIC_API_KEY='your-anthropic-api-key-here' +export BRAVE_API_KEY='your-brave-api-key-here' +``` +4. 构建应用 +```js +./mvnw clean install +``` +5. 用Maven运行应用 +```js +./mvnw spring-boot:run +``` + + 请确保您的ANTHROPIC_API_KEY和BRAVE_API_KEY的安全! + +## 工作机制 [!toc] +该应用程序通过几个组件将Spring AI与Brave Search MCP服务器集成在一起: +### MCP客户端配置 [!toc] +1. pom.xml中需要的依赖: +```js + + org.springframework.ai + spring-ai-starter-mcp-client + + + org.springframework.ai + spring-ai-starter-model-anthropic + +``` +2. 应用程序需要添加的属性 +```js +spring: + ai: + mcp: + client: + enabled: true + name: brave-search-client + version: 1.0.0 + type: SYNC + request-timeout: 20s + stdio: + root-change-notification: true + servers-configuration: classpath:/mcp-servers-config.json + anthropic: + api-key: ${ANTHROPIC_API_KEY} +``` +这会使spring-ai-starter-mcp-client根据所提供的服务器配置创建一个或多个mcp客户端。 +3. MCP服务器配置(mcp-servers-config.json): +```js +{ + "mcpServers": { + "brave-search": { + "command": "npx", + "args": [ + "-y", + "@modelcontextprotocol/server-brave-search" + ], + "env": { + "BRAVE_API_KEY": "" + } + } + } +} +``` +### 实现对话 [!toc] +聊天机器人是使用Spring AI的ChatClient与MCP工具的集成来实现的 +```js +var chatClient = chatClientBuilder + .defaultSystem("You are useful assistant, expert in AI and Java.") + .defaultTools((Object[]) mcpToolAdapter.toolCallbacks()) + .defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory())) + .build(); +``` +关键特性: +- 自然语言理解使用Claude AI模型 +- 通过MCP集成Brave Search,实现实时网络搜索 +- 使用InMemoryChatMemory保持对话内存 +- 像交互式命令行工具一样运行 +### 构建和运行 实现对话 [!toc] +```js +./mvnw clean install +java -jar ./target/ai-mcp-brave-chatbot-0.0.1-SNAPSHOT.jar +``` +或者 +```js +./mvnw spring-boot:run +``` +应用程序将启动一个互动聊天会话,您可以在其中提出问题。当聊天机器人需要从互联网上查找信息来回答你的问题时,它会使用Brave Search。 + +聊天机器人可以: + +- 使用其内置知识回答问题 +- 需要搜索网页时使用Brave Search +- 通过对话中前面的信息记住上下文 +- 综合多个来源的信息,提供全面的答案 +### 高级配置 [!toc] +MCP客户端支持额外的配置选项: +- 通过McpSyncClientCustomizer或McpAsyncClientCustomizer定制客户端 +- 多个客户端采用多种传输类型:STDIO和SSE(服务器发送的事件) +- 与Spring AI工具执行框架集成 +- 自动客户端初始化和生命周期管理 +对于基于WebFlux的应用,你可以使用WebFlux starter: +```js + + org.springframework.ai + spring-ai-mcp-client-webflux-spring-boot-starter + +``` +它提供了类似的功能,但使用基于webflux的SSE传输实现,推荐用于生产环境部署。 + + + 本教程完整的代码在[这里](https://github.com/modelcontextprotocol/kotlin-sdk/tree/main/samples/kotlin-mcp-client) +## 系统需求 [!toc] +开始之前,确认你的系统满足如下需求: +- 安装了Java17或更高版本 +- Anthropic API key (Claude) +## 设置环境 [!toc] +首先,让我们安装java和gradle(如果你还没有安装的话)。您可以从[Oracle JDK官方网站](https://www.oracle.com/java/technologies/downloads/)下载java。验证您的java安装: +```js +java --version +``` +首先,新建和安装项目: + + + ```js +# Create a new directory for our project +mkdir kotlin-mcp-client +cd kotlin-mcp-client + +# Initialize a new kotlin project +gradle init + ``` + + + ```js +# Create a new directory for our project +md kotlin-mcp-client +cd kotlin-mcp-client +# Initialize a new kotlin project +gradle init +``` + + +运行gradle init之后,你会看到创建项目的选项。选择Application作为项目类型,Kotlin作为编程语言,Java 17作为Java版本。 + +或者,您可以使用IntelliJ IDEA项目向导创建Kotlin应用程序。 + +创建项目后,添加以下依赖项: + + + ```js +val mcpVersion = "0.4.0" +val slf4jVersion = "2.0.9" +val anthropicVersion = "0.8.0" + +dependencies { + implementation("io.modelcontextprotocol:kotlin-sdk:$mcpVersion") + implementation("org.slf4j:slf4j-nop:$slf4jVersion") + implementation("com.anthropic:anthropic-java:$anthropicVersion") +} + ``` + + + ```js +def mcpVersion = '0.3.0' +def slf4jVersion = '2.0.9' +def anthropicVersion = '0.8.0' +dependencies { + implementation "io.modelcontextprotocol:kotlin-sdk:$mcpVersion" + implementation "org.slf4j:slf4j-nop:$slf4jVersion" + implementation "com.anthropic:anthropic-java:$anthropicVersion" +} +``` + +此外,添加以下插件到您的构建脚本: + + + ```js +plugins { + id("com.github.johnrengelman.shadow") version "8.1.1" +} + ``` + + + ```js +plugins { + id 'com.github.johnrengelman.shadow' version '8.1.1' +} +``` + + +## 安装你的API key [!toc] + +你需要从[Anthropic Console](https://console.anthropic.com/settings/keys)获取一个Anthropic API key +设置API的key值: +```js +export ANTHROPIC_API_KEY='your-anthropic-api-key-here' +``` + + 请确保您的ANTHROPIC_API_KEY安全! + +## 创建客户端 [!toc] +### 客户端基础结构 [!toc] +首先,我们创建基础的客户端类: +```js +class MCPClient : AutoCloseable { + private val anthropic = AnthropicOkHttpClient.fromEnv() + private val mcp: Client = Client(clientInfo = Implementation(name = "mcp-client-cli", version = "1.0.0")) + private lateinit var tools: List + + // methods will go here + + override fun close() { + runBlocking { + mcp.close() + anthropic.close() + } + } +``` +### 服务器连接管理 [!toc] +接下来,我们实现连接一个MCP服务器的方法: + +```js +suspend fun connectToServer(serverScriptPath: String) { + try { + val command = buildList { + when (serverScriptPath.substringAfterLast(".")) { + "js" -> add("node") + "py" -> add(if (System.getProperty("os.name").lowercase().contains("win")) "python" else "python3") + "jar" -> addAll(listOf("java", "-jar")) + else -> throw IllegalArgumentException("Server script must be a .js, .py or .jar file") + } + add(serverScriptPath) + } + + val process = ProcessBuilder(command).start() + val transport = StdioClientTransport( + input = process.inputStream.asSource().buffered(), + output = process.outputStream.asSink().buffered() + ) + + mcp.connect(transport) + + val toolsResult = mcp.listTools() + tools = toolsResult?.tools?.map { tool -> + ToolUnion.ofTool( + Tool.builder() + .name(tool.name) + .description(tool.description ?: "") + .inputSchema( + Tool.InputSchema.builder() + .type(JsonValue.from(tool.inputSchema.type)) + .properties(tool.inputSchema.properties.toJsonValue()) + .putAdditionalProperty("required", JsonValue.from(tool.inputSchema.required)) + .build() + ) + .build() + ) + } ?: emptyList() + println("Connected to server with tools: ${tools.joinToString(", ") { it.tool().get().name() }}") + } catch (e: Exception) { + println("Failed to connect to MCP server: $e") + throw e + } +} +``` +同时创建一个辅助函数为Anthropic将JsonObject转换为JsonValue: +```js +private fun JsonObject.toJsonValue(): JsonValue { + val mapper = ObjectMapper() + val node = mapper.readTree(this.toString()) + return JsonValue.fromJsonNode(node) +} +``` +### 查询处理的逻辑 [!toc] +现在,现在让我们添加处理查询和工具调用的核心功能: +```js +private val messageParamsBuilder: MessageCreateParams.Builder = MessageCreateParams.builder() + .model(Model.CLAUDE_3_5_SONNET_20241022) + .maxTokens(1024) + +suspend fun processQuery(query: String): String { + val messages = mutableListOf( + MessageParam.builder() + .role(MessageParam.Role.USER) + .content(query) + .build() + ) + + val response = anthropic.messages().create( + messageParamsBuilder + .messages(messages) + .tools(tools) + .build() + ) + + val finalText = mutableListOf() + response.content().forEach { content -> + when { + content.isText() -> finalText.add(content.text().getOrNull()?.text() ?: "") + + content.isToolUse() -> { + val toolName = content.toolUse().get().name() + val toolArgs = + content.toolUse().get()._input().convert(object : TypeReference>() {}) + + val result = mcp.callTool( + name = toolName, + arguments = toolArgs ?: emptyMap() + ) + finalText.add("[Calling tool $toolName with args $toolArgs]") + + messages.add( + MessageParam.builder() + .role(MessageParam.Role.USER) + .content( + """ + "type": "tool_result", + "tool_name": $toolName, + "result": ${result?.content?.joinToString("\n") { (it as TextContent).text ?: "" }} + """.trimIndent() + ) + .build() + ) + + val aiResponse = anthropic.messages().create( + messageParamsBuilder + .messages(messages) + .build() + ) + + finalText.add(aiResponse.content().first().text().getOrNull()?.text() ?: "") + } + } + } + + return finalText.joinToString("\n", prefix = "", postfix = "") +} +``` +### 互动聊天 [!toc] +现在我们添加一些聊天互动: +```js +suspend fun chatLoop() { + println("\nMCP Client Started!") + println("Type your queries or 'quit' to exit.") + + while (true) { + print("\nQuery: ") + val message = readLine() ?: break + if (message.lowercase() == "quit") break + val response = processQuery(message) + println("\n$response") + } +} +``` +### main函数入口 [!toc] +最后,我们添加main执行函数: +```js +fun main(args: Array) = runBlocking { + if (args.isEmpty()) throw IllegalArgumentException("Usage: java -jar /build/libs/kotlin-mcp-client-0.1.0-all.jar ") + val serverPath = args.first() + val client = MCPClient() + client.use { + client.connectToServer(serverPath) + client.chatLoop() + } +} +``` +## 运行客户端 [!toc] +运行客户端,可选择任意服务器: +```js +./gradlew build + +# Run the client +java -jar build/libs/.jar path/to/server.jar # jvm server +java -jar build/libs/.jar path/to/server.py # python server +java -jar build/libs/.jar path/to/build/index.js # node server +``` + + 如果你还在从服务器快速入门继续天气教程,你的命令可能看起来像这样:java -jar build/libs/kotlin-mcp-client-0.1.0-all.jar .../samples/weather-stdio-server/build/libs/weather-stdio-server-0.1.0-all.jar + +客户端将会: +1. 连接到指定的服务器 +2. 列出可用的工具 +3. 开始一个互动聊天的会话,你可以实现以下操作: +- 输入查询 +- 查看工具的执行情况 +- 从Claude得到响应 +## 工作机制 [!toc] +当你提交查询时: +1. 客户端从服务器获取可用工具的列表 +2. 您的查询将与工具描述一起发送给Claude +3. Claude决定使用哪些工具(如果有的话) +4. 客户端通过服务器执行工具调用请求 +5. 结果被送回给Claude +6. Claude用自然语言响应 +7. 将返回的响应显示给用户 +## 最佳实践 [!toc] +1. 错误处理 +- 利用Kotlin的类型系统显式地对错误建模 +- 当可能出现异常时,将外部工具和API调用封装在try-catch块中 +- 提供清晰和有意义的错误消息 +- 优雅地处理网络超时和连接问题 +2. 安全性 +- 将API密钥和Secret安全地存储local.properties或环境变量、secret manager中。 +- 验证所有外部响应,以避免意外或不安全的数据使用 +- 使用工具时,谨慎对待权限和信任边界 +## 故障排除 [!toc] +### 服务器路径问题 [!toc] +- 再次检查服务器脚本的路径是否正确 +- 如果相对路径不起作用,请使用绝对路径 +- 对于Windows用户,请确保在路径中使用正斜杠(/)或转义反斜杠(\) +- 确保安装了所需的运行时环境(java为java, npm为Node.js,或uv为Python) +- 验证服务器文件具有正确的扩展名(Java为.jar,Python为.py或Node.js为.js) + +正确的路径示例: +```js +# Relative path +java -jar build/libs/client.jar ./server/build/libs/server.jar + +# Absolute path +java -jar build/libs/client.jar /Users/username/projects/mcp-server/build/libs/server.jar + +# Windows path (either format works) +java -jar build/libs/client.jar C:/projects/mcp-server/build/libs/server.jar +java -jar build/libs/client.jar C:\\projects\\mcp-server\\build\\libs\\server.jar +``` +### 响应时间 [!toc] +- 第一个响应可能需要30秒才能返回 +- 这是正常的,发生在: + - 服务器初始化 + - Claude处理查询 + - 工具正在执行 +- 随后的反应通常更快 +- 在最初的等待期间,不要中断该过程 +### 常见错误信息 [!toc] +当你看到: +- Connection refused:确认服务器在运行并且路径正确 +- Tool execution failed:验证工具所需的环境变量是否已设置 +- ANTHROPIC_API_KEY is not set: 检查你的环境变量 + + + 本教程完整的代码在[这里](https://github.io/modelcontextprotocol/csharp-sdk/tree/main/samples/QuickstartClient) +## 系统需求 [!toc] +开始之前,确认你的系统满足如下需求: +- .NET 8.0或更高版本 +- Anthropic API key (Claude) +- 操作系统Windows, Linux, 或MacOS +## 设置环境 [!toc] +首先,创建一个.NET项目 +```js +dotnet new console -n QuickstartClient +cd QuickstartClient +``` +然后,为项目添加需要的依赖 +```js +dotnet add package ModelContextProtocol --prerelease +dotnet add package Anthropic.SDK +dotnet add package Microsoft.Extensions.Hosting +``` +## 安装你的API key [!toc] + +你需要从[Anthropic Console](https://console.anthropic.com/settings/keys)获取一个Anthropic API key +```js +dotnet user-secrets init +dotnet user-secrets set "ANTHROPIC_API_KEY" "" +``` +## 创建客户端 [!toc] +### 客户端基础结构 [!toc] +首先,我们创建基础的客户端类: +```js +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; + +var builder = Host.CreateEmptyApplicationBuilder(settings: null); + +builder.Configuration + .AddUserSecrets(); +``` +这将创建一个.NET控制台应用程序的开端,该应用程序可以从用户Secret中读取API Key。 + +接下来,我们将设置MCP客户端: +```js +var (command, arguments) = args switch +{ + [var script] when script.EndsWith(".py") => ("python", script), + [var script] when script.EndsWith(".js") => ("node", script), + [var script] when Directory.Exists(script) || (File.Exists(script) && script.EndsWith(".csproj")) => ("dotnet", $"run --project {script} --no-build"), + _ => throw new NotSupportedException("An unsupported server script was provided. Supported scripts are .py, .js, or .csproj") +}; + +await using var mcpClient = await McpClientFactory.CreateAsync(new() +{ + Id = "demo-server", + Name = "Demo Server", + TransportType = TransportTypes.StdIo, + TransportOptions = new() + { + ["command"] = command, + ["arguments"] = arguments, + } +}); + +var tools = await mcpClient.ListToolsAsync(); +foreach (var tool in tools) +{ + Console.WriteLine($"Connected to server with tools: {tool.Name}"); +} +``` + + 请确保为命名空间添加以下using语句: + ```js +using ModelContextProtocol.Client; +using ModelContextProtocol.Protocol.Transport; + ``` + +这将配置一个MCP客户端,该客户端将连接到一个作为命令行参数提供的服务器。然后列出来自连接服务器的可用工具。 +### 查询处理的逻辑 [!toc] +现在,现在让我们添加处理查询和工具调用的核心功能: +```js +using IChatClient anthropicClient = new AnthropicClient(new APIAuthentication(builder.Configuration["ANTHROPIC_API_KEY"])) + .Messages + .AsBuilder() + .UseFunctionInvocation() + .Build(); + +var options = new ChatOptions +{ + MaxOutputTokens = 1000, + ModelId = "claude-3-5-sonnet-20241022", + Tools = [.. tools] +}; + +while (true) +{ + Console.WriteLine("MCP Client Started!"); + Console.WriteLine("Type your queries or 'quit' to exit."); + + string? query = Console.ReadLine(); + + if (string.IsNullOrWhiteSpace(query)) + { + continue; + } + if (string.Equals(query, "quit", StringComparison.OrdinalIgnoreCase)) + { + break; + } + + var response = anthropicClient.GetStreamingResponseAsync(query, options); + + await foreach (var message in response) + { + Console.Write(message.Text); + } + Console.WriteLine(); +} +``` +## 关键组件说明 [!toc] +1. 客户端初始化 +- 客户端使用 McpClientFactory.CreateAsync() 进行初始化,它将设置传输类型和运行服务器的命令。 +2. 服务器连接 +- 支持 Python、Node.js 和 .NET 服务器。 +- 服务器使用参数中指定的命令启动。 +- 配置使用 stdio 与服务器通信。 +- 初始化会话和可用工具。 +3. 查询处理 +- 使用 [Microsoft.Extensions.AI](https://learn.microsoft.com/dotnet/ai/ai-extensions) 作为聊天客户端。 +- 将 IChatClient 配置为使用自动工具(函数)调用。 +- 客户端读取用户输入并将其发送至服务器。 +- 服务器处理查询并返回响应。 +- 回复将显示给用户。 +## 运行客户端 [!toc] +运行客户端,可选择任意服务器: +```js +dotnet run -- path/to/server.csproj # dotnet server +dotnet run -- path/to/server.py # python server +dotnet run -- path/to/server.js # node server +``` + + 如果你还在从服务器快速入门继续天气教程,你的命令可能看起来像这样:dotnet run -- path/to/QuickstartWeatherServer + +客户端将会: +1. 连接到指定的服务器 +2. 列出可用的工具 +3. 开始一个互动聊天的会话,你可以实现以下操作: +- 输入查询 +- 查看工具的执行情况 +- 从Claude得到响应 +4. 完成后退出会话 + +下面是一个在服务器快速入门教程中连接到天气服务器的示例: +![ImaImageZoomge](/quickstart-dotnet-client.png) + + +## 下一步 + + + 查看我们的官方MCP服务器库和实现 + + + 查看支持MCP集成的客户端列表 + + + 学习如何用像Claude一样的LLMs加快您的MCP开发 + + + 了解MCP如何连接客户端、服务器和LLMs + + + + diff --git a/content/docs/concepts/prompts.mdx b/content/docs/concepts/prompts.mdx new file mode 100644 index 0000000..09ed2a4 --- /dev/null +++ b/content/docs/concepts/prompts.mdx @@ -0,0 +1,392 @@ +--- +title: 提示词 +--- +import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; + +创建可重用的提示词模板和工作流 + +提示词使服务器能够定义可重用的提示模板和工作流,客户机可以轻松地将其呈现给用户和LLM。它们提供了一种强大的方式来标准化和共享常见的LLM交互。 + +提示词被设计为由用户控制,这意味着它们由服务器暴露给客户端,目的是让用户能够显式地根据自己的需要选择要使用的提示词。 + +## 概述 ## +MCP中的提示符是预定义的模板,可以: +- 接受动态参数 +- 包含来自资源的上下文 +- 串联起多次交互 +- 指导特定的工作流程 +- 像UI元素一样的交互界面(如斜杠命令) +## 提示词结构 ## +每个提示符定义为: +```js +{ + name: string; // Unique identifier for the prompt + description?: string; // Human-readable description + arguments?: [ // Optional list of arguments + { + name: string; // Argument identifier + description?: string; // Argument description + required?: boolean; // Whether argument is required + } + ] +} +``` +## 发现提示词 ## +客户端可以通过 prompts/list 端点发现提示词: +```js +// Request +{ + method: "prompts/list" +} + +// Response +{ + prompts: [ + { + name: "analyze-code", + description: "Analyze code for potential improvements", + arguments: [ + { + name: "language", + description: "Programming language", + required: true + } + ] + } + ] +} +``` +## 使用提示词 ## +要使用提示词,客户端发起 prompts/get 请求: +```js +// Request +{ + method: "prompts/get", + params: { + name: "analyze-code", + arguments: { + language: "python" + } + } +} + +// Response +{ + description: "Analyze Python code for potential improvements", + messages: [ + { + role: "user", + content: { + type: "text", + text: "Please analyze the following Python code for potential improvements:\n\n```python\ndef calculate_sum(numbers):\n total = 0\n for num in numbers:\n total = total + num\n return total\n\nresult = calculate_sum([1, 2, 3, 4, 5])\nprint(result)\n```" + } + } + ] +} +``` +## 动态提示词 ## +提示词可以是动态的,并且包含以下: +### 嵌入式资源上下文 ### +```js +{ + "name": "analyze-project", + "description": "Analyze project logs and code", + "arguments": [ + { + "name": "timeframe", + "description": "Time period to analyze logs", + "required": true + }, + { + "name": "fileUri", + "description": "URI of code file to review", + "required": true + } + ] +} +``` +处理 prompts/get 请求时: +```js +{ + "messages": [ + { + "role": "user", + "content": { + "type": "text", + "text": "Analyze these system logs and the code file for any issues:" + } + }, + { + "role": "user", + "content": { + "type": "resource", + "resource": { + "uri": "logs://recent?timeframe=1h", + "text": "[2024-03-14 15:32:11] ERROR: Connection timeout in network.py:127\n[2024-03-14 15:32:15] WARN: Retrying connection (attempt 2/3)\n[2024-03-14 15:32:20] ERROR: Max retries exceeded", + "mimeType": "text/plain" + } + } + }, + { + "role": "user", + "content": { + "type": "resource", + "resource": { + "uri": "file:///path/to/code.py", + "text": "def connect_to_service(timeout=30):\n retries = 3\n for attempt in range(retries):\n try:\n return establish_connection(timeout)\n except TimeoutError:\n if attempt == retries - 1:\n raise\n time.sleep(5)\n\ndef establish_connection(timeout):\n # Connection implementation\n pass", + "mimeType": "text/x-python" + } + } + } + ] +} +``` +### 多步骤工作流 ### +```js +const debugWorkflow = { + name: "debug-error", + async getMessages(error: string) { + return [ + { + role: "user", + content: { + type: "text", + text: `Here's an error I'm seeing: ${error}` + } + }, + { + role: "assistant", + content: { + type: "text", + text: "I'll help analyze this error. What have you tried so far?" + } + }, + { + role: "user", + content: { + type: "text", + text: "I've tried restarting the service, but the error persists." + } + } + ]; + } +}; +``` +## 示例实现 ## +下面是在MCP服务器中实现提示词的一个完整示例: + + + ```js +import { Server } from "@modelcontextprotocol/sdk/server"; +import { + ListPromptsRequestSchema, + GetPromptRequestSchema +} from "@modelcontextprotocol/sdk/types"; + +const PROMPTS = { + "git-commit": { + name: "git-commit", + description: "Generate a Git commit message", + arguments: [ + { + name: "changes", + description: "Git diff or description of changes", + required: true + } + ] + }, + "explain-code": { + name: "explain-code", + description: "Explain how code works", + arguments: [ + { + name: "code", + description: "Code to explain", + required: true + }, + { + name: "language", + description: "Programming language", + required: false + } + ] + } +}; + +const server = new Server({ + name: "example-prompts-server", + version: "1.0.0" +}, { + capabilities: { + prompts: {} + } +}); + +// List available prompts +server.setRequestHandler(ListPromptsRequestSchema, async () => { + return { + prompts: Object.values(PROMPTS) + }; +}); + +// Get specific prompt +server.setRequestHandler(GetPromptRequestSchema, async (request) => { + const prompt = PROMPTS[request.params.name]; + if (!prompt) { + throw new Error(`Prompt not found: ${request.params.name}`); + } + + if (request.params.name === "git-commit") { + return { + messages: [ + { + role: "user", + content: { + type: "text", + text: `Generate a concise but descriptive commit message for these changes:\n\n${request.params.arguments?.changes}` + } + } + ] + }; + } + + if (request.params.name === "explain-code") { + const language = request.params.arguments?.language || "Unknown"; + return { + messages: [ + { + role: "user", + content: { + type: "text", + text: `Explain how this ${language} code works:\n\n${request.params.arguments?.code}` + } + } + ] + }; + } + + throw new Error("Prompt implementation not found"); +}); + ``` + + + ```js + from mcp.server import Server +import mcp.types as types + +# Define available prompts +PROMPTS = { + "git-commit": types.Prompt( + name="git-commit", + description="Generate a Git commit message", + arguments=[ + types.PromptArgument( + name="changes", + description="Git diff or description of changes", + required=True + ) + ], + ), + "explain-code": types.Prompt( + name="explain-code", + description="Explain how code works", + arguments=[ + types.PromptArgument( + name="code", + description="Code to explain", + required=True + ), + types.PromptArgument( + name="language", + description="Programming language", + required=False + ) + ], + ) +} + +# Initialize server +app = Server("example-prompts-server") + +@app.list_prompts() +async def list_prompts() -> list[types.Prompt]: + return list(PROMPTS.values()) + +@app.get_prompt() +async def get_prompt( + name: str, arguments: dict[str, str] | None = None +) -> types.GetPromptResult: + if name not in PROMPTS: + raise ValueError(f"Prompt not found: {name}") + + if name == "git-commit": + changes = arguments.get("changes") if arguments else "" + return types.GetPromptResult( + messages=[ + types.PromptMessage( + role="user", + content=types.TextContent( + type="text", + text=f"Generate a concise but descriptive commit message " + f"for these changes:\n\n{changes}" + ) + ) + ] + ) + + if name == "explain-code": + code = arguments.get("code") if arguments else "" + language = arguments.get("language", "Unknown") if arguments else "Unknown" + return types.GetPromptResult( + messages=[ + types.PromptMessage( + role="user", + content=types.TextContent( + type="text", + text=f"Explain how this {language} code works:\n\n{code}" + ) + ) + ] + ) + + raise ValueError("Prompt implementation not found") + ``` + + +## 最佳实践 ## +在执行提示词时: +1. 使用清晰、描述性的提示词名称 +2. 为提示词和参数提供详细的描述 +3. 验证所有必需的参数 +4. 优雅地处理缺失的参数 +5. 考虑对提示模板进行版本控制 +6. 在适当的时候缓存动态内容 +7. 实现错误处理 +8. 用文档记录需要的参数格式 +9. 考虑提示组合性 +10. 使用各种输入测试提示词 +## 用户界面集成 ## +提示词可以在客户端UI中以如下方式展示: +- 斜线指令 +- 快捷操作 +- 上下文菜单项 +- 命令面板项 +- 指导工作流 +- 互动的形式 +## 更新和更改 ## +服务器可以将提示词的更改通知客户端: +1. 服务器功能:prompts.listChanged +2. 通知:notifications/prompts/list_changed +3. 客户端重新获取提示词列表 +## 安全注意事项 ## +在执行提示词时: +- 验证所有参数 +- 清理验证用户输入 +- 考虑限速 +- 实现访问控制 +- 审计提示词的使用 +- 妥善处理敏感资料 +- 验证生成的内容 +- 实现超时 +- 考虑提示词注入攻击风险 +- 用文档记录安全要求 \ No newline at end of file diff --git a/content/docs/concepts/resources.mdx b/content/docs/concepts/resources.mdx new file mode 100644 index 0000000..eb8b73d --- /dev/null +++ b/content/docs/concepts/resources.mdx @@ -0,0 +1,214 @@ +--- +title: 资源 +--- +import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; + +将服务器中的数据和内容暴露给 LLM + +资源是模型上下文协议(MCP)的核心要素,它允许服务器暴露数据和内容,客户端可以读取这些数据和内容,并将其用作与LLM 交互的上下文。 + + 资源旨在由应用程序控制,这意味着客户端应用程序可以决定如何以及何时使用这些资源。不同的 MCP 客户端处理资源的方式可能不同。例如: + - Claude Desktop 目前要求用户在使用资源前明确选择资源 + - 其他客户端可能会根据启发式方法自动选择资源 + - 有些实现甚至允许AI模型本身决定使用哪些资源 + + 服务器作者在实施资源支持时,应准备好处理任何这些交互模式。为了将数据自动暴露给模型,服务器作者应使用由模型控制的原语,如 “工具”(Tools)。 + +## 概述 +资源代表 MCP 服务器希望提供给客户端的任何类型的数据。这可能包括 +- 文件内容 +- 数据库记录 +- API 响应 +- 实时系统数据 +- 屏幕截图和图像 +- 日志文件 +- 更多 + +每个资源都由唯一的 URI 标识,可包含文本或二进制数据。 +## 资源的URI +使用遵循以下格式的uri来标识资源: +```js +[protocol]://[host]/[path] +``` +例如: +- file:///home/user/documents/report.pdf +- postgres://database/customers/schema +- screen://localhost/display1 + +协议和路径结构由MCP服务器的实现定义。服务器可以定义自己的自定义URI模式。 +## 资源类型 +资源可以包含两种类型的内容: +### 文本资源 +文本资源包含UTF-8编码的文本数据。这些适用于: +- 源代码 +- 配置文件 +- 日志文件 +- JSON / XML数据 +- 纯文本 +### 二进制资源 +二进制资源包含以base64编码的原始二进制数据。这些适用于: +- 图片 +- pdf文档 +- 音频文件 +- 视频文件 +- 其他非文本格式 +## 资源发现 +客户端可以通过两种主要方法发现可用资源: +### 直接资源 +服务器通过resources/list endpoint公开一个具体的资源列表。每种资源包括: +```js +{ + uri: string; // Unique identifier for the resource + name: string; // Human-readable name + description?: string; // Optional description + mimeType?: string; // Optional MIME type +} +``` +### 资源模板 +对于动态资源,服务器可以公开URI模板,客户端可以使用它来构造有效的资源URI: +```js +{ + uriTemplate: string; // URI template following RFC 6570 + name: string; // Human-readable name for this type + description?: string; // Optional description + mimeType?: string; // Optional MIME type for all matching resources +} +``` +## 读取资源 +为了读取资源,客户端使用资源URI发出resources/read请求。 + +服务器响应一个资源内容列表: +```js +{ + contents: [ + { + uri: string; // The URI of the resource + mimeType?: string; // Optional MIME type + + // One of: + text?: string; // For text resources + blob?: string; // For binary resources (base64 encoded) + } + ] +} +``` + +服务器可以在响应一个resources/read请求时返回多个资源。例如,这可以用于在读取目录时返回目录内的文件列表。 + +## 资源更新 +MCP通过两种机制支持资源的实时更新: +### 列表的变化 +当可用资源列表发生变化时,服务器可以通过notifications/resources/list_changed通知通知客户端。 +### 内容更改 +客户端可以订阅特定资源的更新: +1. 客户端对资源URI发送resources/subscribe +2. 当资源发生变化时,服务器发送notifications/resources/updated +3. 客户端可以通过resources/read获取最新的内容 +4. 客户端可以通过resources/unsubscribe取消订阅 +## 示例实现 ## +下面是在MCP服务器中实现资源支持的一个简单示例: + + + + + ```js +const server = new Server({ + name: "example-server", + version: "1.0.0" +}, { + capabilities: { + resources: {} + } +}); + +// List available resources +server.setRequestHandler(ListResourcesRequestSchema, async () => { + return { + resources: [ + { + uri: "file:///logs/app.log", + name: "Application Logs", + mimeType: "text/plain" + } + ] + }; +}); + +// Read resource contents +server.setRequestHandler(ReadResourceRequestSchema, async (request) => { + const uri = request.params.uri; + + if (uri === "file:///logs/app.log") { + const logContents = await readLogFile(); + return { + contents: [ + { + uri, + mimeType: "text/plain", + text: logContents + } + ] + }; + } + + throw new Error("Resource not found"); +}); + ``` + + + ```js +app = Server("example-server") + +@app.list_resources() +async def list_resources() -> list[types.Resource]: + return [ + types.Resource( + uri="file:///logs/app.log", + name="Application Logs", + mimeType="text/plain" + ) + ] + +@app.read_resource() +async def read_resource(uri: AnyUrl) -> str: + if str(uri) == "file:///logs/app.log": + log_contents = await read_log_file() + return log_contents + + raise ValueError("Resource not found") + +# Start server +async with stdio_server() as streams: + await app.run( + streams[0], + streams[1], + app.create_initialization_options() + ) +``` + + +## 最佳实践 ## +在实施资源支持时: +1. 使用清晰、描述性的资源名称和URI +2. 包括有用的描述来指导LLM的理解 +3. 已知的情况下,设置适当的MIME类型 +4. 为动态内容实现资源模板 +5. 对经常变化的资源使用订阅 +6. 用清晰的错误信息优雅地处理错误 +7. 考虑对大型资源列表进行分页 +8. 在适当的时候缓存资源内容 +9. 在处理之前验证URI +10. 记录您的自定义URI方案 +## 安全注意事项 ## +在对外暴露资源时: +- 验证所有资源URI +- 实施适当的访问控制 +- 清理文件路径以防止目录遍历 +- 谨慎处理二进制数据 +- 考虑对资源读取进行速率限制 +- 审计资源访问 +- 对传输中的敏感数据进行加密 +- 验证MIME类型 +- 为长时间运行的读取设置超时 +- 适当地处理资源清理 + diff --git a/content/docs/concepts/roots.mdx b/content/docs/concepts/roots.mdx new file mode 100644 index 0000000..d79b3e7 --- /dev/null +++ b/content/docs/concepts/roots.mdx @@ -0,0 +1,59 @@ +--- +title: 根 +--- +理解 MCP 中的根(Roots) + +根是 MCP 中的一个概念,它定义了服务器可以运行的边界。 它们为客户端提供了一种告知服务器相关资源及其位置的方式。 +## 什么是根? +根是一个 URI,客户端建议服务器应该关注它。 当客户端连接到服务器时,它会声明服务器应该使用的根。 虽然主要用于文件系统路径,但根可以是任何有效的 URI,包括 HTTP URL。 + +例如,根可以是: +```js +file:///home/user/projects/myapp +https://api.example.com/v1 +``` +## 为什么使用根? +根有几个重要的用途: +1. 指导性 (Guidance):它们告知服务器关于相关的资源和位置 +2. 清晰性 (Clarity):根可以明确哪些资源是工作区的一部分 +3. 组织性 (Organization):多个根可以让你同时处理不同的资源 +## 根的工作原理 ## +当客户端支持根时,它: +1. 在连接期间声明 roots 功能 (capability) +2. 向服务器提供建议的根列表 +3. 在根发生更改时通知服务器(如果支持) + +虽然根是信息性的,并非强制性的,但服务器应该: +1. 尊重提供的根 +2. 使用根 URI 来定位和访问资源 +3. 优先在根边界内进行操作 +## 常见用例 ## +根通常用于定义: +- 项目目录 +- 仓库位置 +- API 终端 (API endpoints) +- 配置位置 +- 资源边界 +## 最佳实践 ## +使用根时: +1. 只建议必要的资源 +2. 使用清晰、描述性的根名称 +3. 监控根的可访问性 +4. 优雅地处理根更改 +## 示例 ## +以下是典型的 MCP 客户端如何公开根: +```js +{ + "roots": [ + { + "uri": "file:///home/user/projects/frontend", + "name": "Frontend Repository" + }, + { + "uri": "https://api.example.com/v1", + "name": "API Endpoint" + } + ] +} +``` +此配置建议服务器关注本地存储库和 API 终端,同时保持它们的逻辑分离。 diff --git a/content/docs/concepts/sampling.mdx b/content/docs/concepts/sampling.mdx new file mode 100644 index 0000000..cc7c526 --- /dev/null +++ b/content/docs/concepts/sampling.mdx @@ -0,0 +1,195 @@ +--- +title: 采样 +--- +让您的服务器向 LLM 请求补全 + +采样 (Sampling) 是一项强大的 MCP 功能,它允许服务器通过客户端请求 LLM 补全(completions),从而实现复杂的代理行为,同时保持安全性和隐私。 + +此 MCP 功能在 Claude 桌面客户端 (Claude Desktop client)中尚不支持。 + +## 采样的工作原理 ## +采样流程包括以下步骤: +1. 服务器向客户端发送 sampling/createMessage 请求 +2. 客户端审核请求并可以修改它 +3. 客户端从 LLM 采样 +4. 客户端审核补全结果 +5. 客户端将结果返回给服务器 +这种人机协作的设计,确保用户保持对 LLM 所见和所生成内容的控制。 +## 消息格式 ## +采样请求使用标准化的消息格式: +```js +{ + messages: [ + { + role: "user" | "assistant", + content: { + type: "text" | "image", + + // For text: + text?: string, + + // For images: + data?: string, // base64 encoded + mimeType?: string + } + } + ], + modelPreferences?: { + hints?: [{ + name?: string // Suggested model name/family + }], + costPriority?: number, // 0-1, importance of minimizing cost + speedPriority?: number, // 0-1, importance of low latency + intelligencePriority?: number // 0-1, importance of capabilities + }, + systemPrompt?: string, + includeContext?: "none" | "thisServer" | "allServers", + temperature?: number, + maxTokens: number, + stopSequences?: string[], + metadata?: Record +} +``` +## 请求参数 ## +### 消息 ### +messages 数组包含要发送到 LLM 的对话历史记录。每条消息都有: +- role: 消息的角色,值可以是 "user"(用户)或 "assistant"(助手) +- content: 消息的内容,可以是: + - 带有 text 字段的文本内容 + - 带有 data(base64 编码)和 mimeType 字段的图像内容 +### 模型偏好 ### +modelPreferences 对象允许服务器指定其模型选择偏好: + +- hints: 客户端可用于选择合适模型的模型名称建议数组: + - name: 可以匹配完整或部分模型名称的字符串(例如,“claude-3”,“sonnet”) + - 客户端可以将提示(hints)映射到来自不同提供商的等效模型 + - 多个提示(hints)按偏好顺序评估 +- 优先级值(0-1 归一化): + - costPriority: 最小化成本的重要性 + - speedPriority: 低延迟响应的重要性 + - intelligencePriority: 高级模型能力的重要性 + +客户端根据这些偏好及其可用模型进行最终模型选择。 +### 系统提示 ### +可选的 systemPrompt 字段允许服务器请求特定的系统提示(system prompt)。 客户端可以修改或忽略此提示。 +### 上下文包含 ### +includeContext 参数指定要包含的 MCP 上下文: + +- "none":无其他上下文 +- "thisServer":包含来自请求服务器的上下文 +- "allServers":包含来自所有连接的 MCP 服务器的上下文 + +客户端控制实际包含哪些上下文。 +### 采样参数 ### +使用以下方法微调 LLM 采样: + +- temperature: 控制随机性(0.0 到 1.0) +- maxTokens: 要生成的最大令牌(token)数 +- stopSequences: 停止生成的序列数组 +- metadata: 其他特定于提供程序的参数 +## 响应格式 ## +客户端返回一个补全的结果 +```js +{ + model: string, // Name of the model used + stopReason?: "endTurn" | "stopSequence" | "maxTokens" | string, + role: "user" | "assistant", + content: { + type: "text" | "image", + text?: string, + data?: string, + mimeType?: string + } +} +``` +## 示例请求 ## +以下是客户端请求采样的示例: +```js +{ + "method": "sampling/createMessage", + "params": { + "messages": [ + { + "role": "user", + "content": { + "type": "text", + "text": "What files are in the current directory?" + } + } + ], + "systemPrompt": "You are a helpful file system assistant.", + "includeContext": "thisServer", + "maxTokens": 100 + } +} +``` +## 最佳实践 ## +实现采样时: +1. 始终提供清晰、结构良好的提示词 +2. 适当地处理文本和图像内容 +3. 设置合理的令牌(token)限制 +4. 通过 includeContext 包含相关上下文 +5. 在使用响应之前对其进行验证 +6. 优雅地处理错误 +7. 考虑对采样请求进行速率限制(rate limiting) +8. 记录可能出现的采样行为 +9. 使用各种模型参数进行测试 +10. 监控采样成本 +## 人工参与控制 ## +采样的设计考虑了人为的监督: +### 对提示词 ### +- 客户端应向用户显示建议的提示词 +- 用户应该能够修改或拒绝提示词 +- 系统提示词可以被过滤或修改 +- 上下文包含由客户端控制 +### 对补全 ### +- 客户端应向用户显示补全结果 +- 用户应该能够修改或拒绝补全结果 +- 客户端可以过滤或修改补全结果 +- 用户控制使用哪个模型 +## 安全注意事项 ## +实施采样时: +- 验证所有消息内容 +- 清理敏感信息 +- 实施适当的速率限制 +- 监控采样使用情况 +- 加密传输中的数据 +- 处理用户数据隐私 +- 审核采样请求 +- 控制成本风险 +- 实施超时 +- 优雅地处理模型错误 +## 常见模式 ## +### 智能代理工作流 ### +采样支持诸如以下代理模式: +- 阅读和分析资源 +- 根据上下文做出决策 +- 生成结构化数据 +- 处理多步骤任务 +- 提供交互式帮助 +### 上下文管理 ### +上下文的最佳实践: +- 仅请求最少必要的上下文 +- 清晰地构建上下文 +- 处理上下文大小限制 +- 根据需要更新上下文 +- 清理过时的上下文 +### 错误处理 ### +强健的错误处理应满足: +- 捕获采样失败 +- 处理超时错误 +- 管理速率限制 +- 验证响应 +- 提供回退行为 +- 适当地记录错误 +## 限制 ## +请注意以下限制: +- 采样取决于客户端功能 +- 用户控制采样行为 +- 上下文大小有限制 +- 可能存在速率限制 +- 应考虑成本 +- 模型可用性各不相同 +- 响应时间各不相同 +- 并非所有内容类型都支持采样 + diff --git a/content/docs/concepts/tools.mdx b/content/docs/concepts/tools.mdx new file mode 100644 index 0000000..2c049b7 --- /dev/null +++ b/content/docs/concepts/tools.mdx @@ -0,0 +1,272 @@ +--- +title: 工具 +--- +import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; + +使LLM通过服务器执行操作 + +工具是模型上下文协议(MCP)中的一个强大的原语,它使服务器能够向客户端暴露可执行功能。通过工具,LLM可以与外部系统进行交互,执行计算,并在现实世界中执行操作。 + + 工具被设计为 model-controlled (模型控制)的,这意味着工具由服务器暴露给客户端,目的是AI模型能够自动调用它们(过程中由人授权批准)。 + +## 概述 ## +MCP中的工具允许服务器暴露可执行函数,这些函数可由客户端调用,并由LLM使用来执行操作。工具的主要方面包括: +- 发现:客户端可以通过 tools/list 端点列出可用的工具 +- 调用:使用 tools/call 端点调用工具,服务器在其中执行请求的操作并返回结果 +- 灵活性:工具的范围从简单的计算到复杂的API交互 + +与资源一样,工具由唯一名称标识,并且可以包含指导其使用的描述。然而,与资源不同的是,工具是动态操作,例如可以修改状态或与外部系统交互。 +## 工具的定义结构 ## +每个工具都用以下结构定义: +```js +{ + name: string; // Unique identifier for the tool + description?: string; // Human-readable description + inputSchema: { // JSON Schema for the tool's parameters + type: "object", + properties: { ... } // Tool-specific parameters + } +} +``` +## 工具实现 ## +以下是在MCP服务器中实现一个基本工具的示例: + + + ```js + const server = new Server({ + name: "example-server", + version: "1.0.0" +}, { + capabilities: { + tools: {} + } +}); + +// Define available tools +server.setRequestHandler(ListToolsRequestSchema, async () => { + return { + tools: [{ + name: "calculate_sum", + description: "Add two numbers together", + inputSchema: { + type: "object", + properties: { + a: { type: "number" }, + b: { type: "number" } + }, + required: ["a", "b"] + } + }] + }; +}); + +// Handle tool execution +server.setRequestHandler(CallToolRequestSchema, async (request) => { + if (request.params.name === "calculate_sum") { + const { a, b } = request.params.arguments; + return { + content: [ + { + type: "text", + text: String(a + b) + } + ] + }; + } + throw new Error("Tool not found"); +}); + ``` + + + ```js + app = Server("example-server") + +@app.list_tools() +async def list_tools() -> list[types.Tool]: + return [ + types.Tool( + name="calculate_sum", + description="Add two numbers together", + inputSchema={ + "type": "object", + "properties": { + "a": {"type": "number"}, + "b": {"type": "number"} + }, + "required": ["a", "b"] + } + ) + ] + +@app.call_tool() +async def call_tool( + name: str, + arguments: dict +) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]: + if name == "calculate_sum": + a = arguments["a"] + b = arguments["b"] + result = a + b + return [types.TextContent(type="text", text=str(result))] + raise ValueError(f"Tool not found: {name}") + ``` + + +## 工具模式示例 ## +以下是一些服务器可以提供的工具类型的示例: +### 系统操作 ### +与本地系统交互的工具: +```js +{ + name: "execute_command", + description: "Run a shell command", + inputSchema: { + type: "object", + properties: { + command: { type: "string" }, + args: { type: "array", items: { type: "string" } } + } + } +} +``` +### API的集成 ### +包装了外部API的工具: +```js +{ + name: "github_create_issue", + description: "Create a GitHub issue", + inputSchema: { + type: "object", + properties: { + title: { type: "string" }, + body: { type: "string" }, + labels: { type: "array", items: { type: "string" } } + } + } +} +``` +### 数据处理 ### +转换或分析数据的工具: +```js +{ + name: "analyze_csv", + description: "Analyze a CSV file", + inputSchema: { + type: "object", + properties: { + filepath: { type: "string" }, + operations: { + type: "array", + items: { + enum: ["sum", "average", "count"] + } + } + } + } +} +``` +## 最佳实践 ## +在实现工具时: +1. 提供清晰、描述性的名称和描述 +2. 对参数使用详细的JSON模式定义 +3. 在工具描述中包括示例,来说明模型应该如何使用它们 +4. 实现适当的错误处理和验证 +5. 对长期操作使用进度报告 +6. 保持工具操作的单一性和原子性 +7. 记录可能的返回值结构 +8. 实现适当的超时 +9. 考虑对资源密集型操作的速率限制 +10. 使用日志工具,用于调试和监控 +## 安全注意事项 ## +暴露工具时: +### 输入验证 ### +- 根据模式验证所有参数 +- 清理验证文件路径和系统命令 +- 验证URL和外部标识符 +- 检查参数大小和范围 +- 防止命令注入 +### 访问控制 ### +- 在需要的地方实现身份验证 +- 使用适当的授权检查 +- 审计工具使用情况 +- 速率限制请求 +- 监控访问权限滥用 +### 错误处理 ### +- 不要将内部错误暴露给客户端 +- 记录与安全相关的错误 +- 适当地处理超时 +- 错误发生后清理资源 +- 验证返回值 +## 工具发现和更新 ## +MCP支持动态工具发现: +1. 客户端可以随时列出可用的工具 +2. 服务器可以使用notifications/tools/list_changed通知客户端工具更改 +3. 可以在运行时添加或删除工具 +4. 可以更新工具定义(尽管这应该谨慎地进行) +## 错误处理 ## +工具错误应该在结果对象中报告,而不是作为MCP协议级错误报告。这允许LLM发现并潜在地处理错误。当工具遇到错误时: +1. 将结果中的isError设置为true +2. 在内容数组中包含错误详细信息 + +下面是一个正确处理工具错误的例子: + + + ```js + try { + // Tool operation + const result = performOperation(); + return { + content: [ + { + type: "text", + text: `Operation successful: ${result}` + } + ] + }; +} catch (error) { + return { + isError: true, + content: [ + { + type: "text", + text: `Error: ${error.message}` + } + ] + }; +} + ``` + + + ```js + try: + # Tool operation + result = perform_operation() + return types.CallToolResult( + content=[ + types.TextContent( + type="text", + text=f"Operation successful: {result}" + ) + ] + ) +except Exception as error: + return types.CallToolResult( + isError=True, + content=[ + types.TextContent( + type="text", + text=f"Error: {str(error)}" + ) + ] + ) + ``` + + +这种方法允许LLM看到发生了错误,并可能采取纠正措施或请求人工干预。 +## 测试工具 ## +MCP工具的全面测试策略应包括: +- 功能测试:通过验证有效输入,并适当处理无效输入来验证工具执行的正确性 +- 集成测试:使用真实的和模拟的依赖来测试工具与外部系统的交互 +- 安全性测试:验证身份验证、授权、输入清理和速率限制 +- 性能测试:检查负载下的行为、超时处理和资源清理 +- 错误处理:确保工具通过MCP协议正确报告错误并清理资源 diff --git a/content/docs/concepts/transports.mdx b/content/docs/concepts/transports.mdx new file mode 100644 index 0000000..9fa3718 --- /dev/null +++ b/content/docs/concepts/transports.mdx @@ -0,0 +1,371 @@ +--- +title: 传输 +--- +import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; + +了解 MCP 的通信机制 + +Model Context Protocol (MCP) 中的传输层为 clients 和 servers 之间的通信提供基础。传输层处理消息发送和接收的底层机制。 +## 消息格式 ## +MCP 使用 JSON-RPC 2.0 作为其传输格式。传输层负责将 MCP 协议消息转换为 JSON-RPC 格式进行传输,并将接收到的 JSON-RPC 消息转换回 MCP 协议消息。 + +使用的 JSON-RPC 消息有三种类型: +### 请求 ### +```js +{ + jsonrpc: "2.0", + id: number | string, + method: string, + params?: object +} +``` +### 响应 ### +```js +{ + jsonrpc: "2.0", + id: number | string, + result?: object, + error?: { + code: number, + message: string, + data?: unknown + } +} +``` +### 通知 ### +```js +{ + jsonrpc: "2.0", + method: string, + params?: object +} +``` +## 内置传输层种类 ## +MCP 包含两个标准传输实现: + +### 标准输入输出 (stdio) ### +stdio 传输通过标准输入和输出流进行通信。这对于本地集成和命令行工具特别有用。 + +在以下情况下使用 stdio: +- 构建命令行工具 +- 实现本地集成 +- 需要简单的进程通信 +- 使用 shell 脚本 + + + ```js + const server = new Server({ + name: "example-server", + version: "1.0.0" +}, { + capabilities: {} +}); + +const transport = new StdioServerTransport(); +await server.connect(transport); + ``` + + + ```js + const client = new Client({ + name: "example-client", + version: "1.0.0" +}, { + capabilities: {} +}); + +const transport = new StdioClientTransport({ + command: "./server", + args: ["--option", "value"] +}); +await client.connect(transport); + ``` + + + ```js + app = Server("example-server") + +async with stdio_server() as streams: + await app.run( + streams[0], + streams[1], + app.create_initialization_options() + ) + ``` + + + ```js + params = StdioServerParameters( + command="./server", + args=["--option", "value"] +) + +async with stdio_client(params) as streams: + async with ClientSession(streams[0], streams[1]) as session: + await session.initialize() + ``` + + + +### 服务器发送事件 (SSE) ### +SSE 传输通过 HTTP POST 请求实现服务器到客户端的流式通信。 + +在以下情况下使用 SSE: + +- 仅需要 server-to-client 的流式通信 +- 在受限网络中工作 +- 实现简单更新 + + + ```js + import express from "express"; + +const app = express(); + +const server = new Server({ + name: "example-server", + version: "1.0.0" +}, { + capabilities: {} +}); + +let transport: SSEServerTransport | null = null; + +app.get("/sse", (req, res) => { + transport = new SSEServerTransport("/messages", res); + server.connect(transport); +}); + +app.post("/messages", (req, res) => { + if (transport) { + transport.handlePostMessage(req, res); + } +}); + +app.listen(3000); + ``` + + + ```js + const client = new Client({ + name: "example-client", + version: "1.0.0" +}, { + capabilities: {} +}); + +const transport = new SSEClientTransport( + new URL("http://localhost:3000/sse") +); +await client.connect(transport); + ``` + + + ```js + from mcp.server.sse import SseServerTransport +from starlette.applications import Starlette +from starlette.routing import Route + +app = Server("example-server") +sse = SseServerTransport("/messages") + +async def handle_sse(scope, receive, send): + async with sse.connect_sse(scope, receive, send) as streams: + await app.run(streams[0], streams[1], app.create_initialization_options()) + +async def handle_messages(scope, receive, send): + await sse.handle_post_message(scope, receive, send) + +starlette_app = Starlette( + routes=[ + Route("/sse", endpoint=handle_sse), + Route("/messages", endpoint=handle_messages, methods=["POST"]), + ] +) + ``` + + + ```js + async with sse_client("http://localhost:8000/sse") as streams: + async with ClientSession(streams[0], streams[1]) as session: + await session.initialize() + ``` + + + +## 自定义传输层 ## +MCP 使得为特定需求实现自定义传输层变得简单。任何传输层实现只需符合 Transport 接口: + +你可以为以下情况实现自定义传输: +- 自定义网络协议 +- 专用通信通道 +- 与现有系统集成 +- 性能优化 + + + ```js + interface Transport { + // Start processing messages + start(): Promise; + + // Send a JSON-RPC message + send(message: JSONRPCMessage): Promise; + + // Close the connection + close(): Promise; + + // Callbacks + onclose?: () => void; + onerror?: (error: Error) => void; + onmessage?: (message: JSONRPCMessage) => void; +} + ``` + + + ```js + @contextmanager +async def create_transport( + read_stream: MemoryObjectReceiveStream[JSONRPCMessage | Exception], + write_stream: MemoryObjectSendStream[JSONRPCMessage] +): + """ + Transport interface for MCP. + + Args: + read_stream: Stream to read incoming messages from + write_stream: Stream to write outgoing messages to + """ + async with anyio.create_task_group() as tg: + try: + # Start processing messages + tg.start_soon(lambda: process_messages(read_stream)) + + # Send messages + async with write_stream: + yield write_stream + + except Exception as exc: + # Handle errors + raise exc + finally: + # Clean up + tg.cancel_scope.cancel() + await write_stream.aclose() + await read_stream.aclose() + ``` + + +## 错误处理 ## +传输实现应处理各种错误场景: +1. 连接错误 +2. 消息解析错误 +3. 协议错误 +4. 网络超时 +5. 资源清理 + +错误处理示例: + + + ```js + class ExampleTransport implements Transport { + async start() { + try { + // Connection logic + } catch (error) { + this.onerror?.(new Error(`Failed to connect: ${error}`)); + throw error; + } + } + + async send(message: JSONRPCMessage) { + try { + // Sending logic + } catch (error) { + this.onerror?.(new Error(`Failed to send message: ${error}`)); + throw error; + } + } +} + ``` + + + 注意,虽然 MCP 服务器通常使用 asyncio 实现,但我们更建议用 anyio 来实现底层接口如传输,以获得更广泛的兼容性。 + ```js + @contextmanager +async def example_transport(scope: Scope, receive: Receive, send: Send): + try: + # Create streams for bidirectional communication + read_stream_writer, read_stream = anyio.create_memory_object_stream(0) + write_stream, write_stream_reader = anyio.create_memory_object_stream(0) + + async def message_handler(): + try: + async with read_stream_writer: + # Message handling logic + pass + except Exception as exc: + logger.error(f"Failed to handle message: {exc}") + raise exc + + async with anyio.create_task_group() as tg: + tg.start_soon(message_handler) + try: + # Yield streams for communication + yield read_stream, write_stream + except Exception as exc: + logger.error(f"Transport error: {exc}") + raise exc + finally: + tg.cancel_scope.cancel() + await write_stream.aclose() + await read_stream.aclose() + except Exception as exc: + logger.error(f"Failed to initialize transport: {exc}") + raise exc + ``` + + +## 最佳实践 ## +在实现或使用 MCP 传输时: +1. 正确处理连接生命周期 +2. 实现适当的错误处理 +3. 在连接关闭时清理资源 +4. 使用适当的超时 +5. 在发送前验证消息 +6. 记录传输事件以便调试 +7. 在适当时实现重连逻辑 +8. 处理消息队列中的背压 +9. 监控连接健康状况 +10. 实现适当的安全措施 +## 安全注意事项 ## +在实现传输时: +​ +### 认证和授权 ### +- 实现适当的认证机制 +- 验证客户端凭据 +- 使用安全的令牌处理 +- 实现授权检查 +### 数据安全 ### +- 使用 TLS 进行网络传输 +- 加密敏感数据 +- 验证消息完整性 +- 实现消息大小限制 +- 对输入数据进行清理验证 +### ​网络安全 ### +- 实现速率限制 +- 使用适当的超时 +- 处理拒绝服务场景 +- 监控异常模式 +- 实施适当的防火墙规则 +## 调试传输 ## +一些调试传输层问题的小贴士: +1. 启用调试日志 +2. 监控消息流 +3. 检查连接状态 +4. 验证消息格式 +5. 测试错误场景 +6. 使用网络分析工具 +7. 实现健康检查 +8. 监控资源使用 +9. 测试边界情况 +10. 使用适当的错误跟踪 diff --git a/content/docs/test.mdx b/content/docs/test.mdx deleted file mode 100644 index d1ee3a8..0000000 --- a/content/docs/test.mdx +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: Components -description: Components ---- - -## Code Block - -```js -console.log('Hello World'); -``` - -## Cards - - - - - diff --git a/content/docs/tutorials/debugging.mdx b/content/docs/tutorials/debugging.mdx new file mode 100644 index 0000000..59e8fe3 --- /dev/null +++ b/content/docs/tutorials/debugging.mdx @@ -0,0 +1,204 @@ +--- +title: 调试 +--- +import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; + +调试模型上下文协议(MCP)集成的综合指南 + +有效的调试对于开发 MCP 服务器或将其与应用程序集成至关重要。本指南涵盖了 MCP 生态系统中可用的调试工具和方法。 + + 本指南适用于 macOS,其他平台的指南即将推出。 + +## 调试工具概览 ## +MCP 提供了几种不同级别的调试工具: +1. MCP 检查器(MCP Inspector) +- 交互式调试界面 +- 直接服务器测试 +- 有关详细信息,请参阅检查器指南 +2. Claude 桌面开发者工具(Claude Desktop Developer Tools) +- 集成测试 +- 日志收集 +- Chrome DevTools 集成 +3. 服务器日志记录(Server Logging) +- 自定义日志记录实现 +- 错误跟踪 +- 性能监控 +## 在 Claude 桌面版中调试 ## +### 检查服务器状态 ### +Claude.app 界面提供了基本的服务器状态信息: +1. 单击![ImaImageZoomge](/claude-desktop-mcp-plug-icon.svg)图标查看: +- 已连接的服务器 +- 可用的提示词和资源 +2. 单击![ImaImageZoomge](/claude-desktop-mcp-hammer-icon.svg)图标查看: +- 提供给模型的工具 +### 查看日志 ### +从 Claude 桌面版查看详细的 MCP 日志: +```js +# 实时跟踪日志 +tail -n 20 -F ~/Library/Logs/Claude/mcp*.log +``` +日志捕获: +- 服务器连接事件 +- 配置问题 +- 运行时错误 +- 消息交换 +### 使用 Chrome 开发者工具 ### +在 Claude 桌面版中访问 Chrome 的开发者工具来调查客户端的错误: +1. 创建一个 developer_settings.json 文件,并将 allowDevTools 设置为 true: +```js +echo '{"allowDevTools": true}' > ~/Library/Application\ Support/Claude/developer_settings.json +``` +2. 打开开发者工具DevTools:Command-Option-Shift-i +注意:您将看到两个 DevTools 窗口: +- 主要内容窗口 +- 应用程序标题栏窗口 + +使用控制台(Console)面板检查客户端错误。 + +使用网络(Network)面板检查: +- 消息负载 +- 连接时序 +## 常见问题 ## +### 工作目录 ### +当在Claude 桌面版使用MCP服务器时: +- 通过 claude_desktop_config.json 启动的服务器的工作目录可能未定义(例如 macOS 上的 /),因为 Claude 桌面版可能会从任何位置启动 +- 始终在您的配置和 .env 文件中使用绝对路径,以确保可靠的操作 +- 对于通过命令行直接测试服务器,工作目录将是您运行命令的位置 + +例如,在 claude_desktop_config.json 中,使用: +```js +{ + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/username/data"] +} +``` +而不是像 ./data 这样的相对路径 +### 环境变量 ### +MCP 服务器仅自动继承环境变量的子集,例如 USER、HOME 和 PATH。 + +要覆盖默认变量或提供您自己的变量,您可以在 claude_desktop_config.json 中指定一个 env 键: +```js +{ + "myserver": { + "command": "mcp-server-myapp", + "env": { + "MYAPP_API_KEY": "some_key", + } + } +} +``` +### 服务器初始化 ### +常见的初始化问题: +1. 路径问题 +- 不正确的服务器可执行文件路径 +- 缺少所需的文件 +- 权限问题 +- 尝试使用command的绝对路径 +2. 配置错误 +- 无效的 JSON 语法 +- 缺少必需字段 +- 类型不匹配 +3. 环境问题 +- 缺少环境变量 +- 不正确的变量值 +- 权限限制 +### 连接问题 ### +当服务器无法连接时: +1. 检查 Claude 桌面版日志 +2. 验证服务器进程是否正在运行 +3. 使用调试器(Inspector) 进行独立测试 +4. 验证协议兼容性 +## 实现日志记录 ## +### 服务器端日志记录 ### +当构建使用本地 stdio 传输(Transport,)的服务器时,所有记录到 stderr(标准错误)的消息将自动被主机应用程序(例如 Claude Desktop)捕获。 + +本地MCP服务器不应该将消息记录到stdout(标准输出),因为这会干扰协议操作。 + +对于所有传输,您还可以通过发送日志消息通知向客户端提供日志记录: + + + ```js + server.request_context.session.send_log_message( + level="info", + data="Server started successfully", +) + ``` + + + ```js + server.sendLoggingMessage({ + level: "info", + data: "Server started successfully", +}); + ``` + + +要记录的重要事件: +- 初始化步骤 +- 资源访问 +- 工具执行 +- 错误情况 +- 性能指标 +### 客户端日志记录 ### +在客户端应用程序中: +1. 启用调试日志记录 +2. 监控网络流量 +3. 跟踪消息交换 +4. 记录错误状态 +## 调试工作流程 ## +### 开发周期 ### +1. 初始开发 +- 使用 Inspector 进行基本测试 +- 实现核心功能 +- 添加日志记录点 +2. 集成测试 +- 在 Claude Desktop 中测试 +- 监控日志 +- 检查错误处理 +### 测试更改 ### +为了有效地测试更改: +- 配置更改:重启 Claude Desktop +- 服务器代码更改:使用 Command-R 重新加载 +- 快速迭代:在开发期间使用 调试器(Inspector) +## 最佳实践 ## +### 日志记录策略 ### +1. 结构化日志记录(Structured Logging) +- 使用一致的格式 +- 包括上下文 +- 添加时间戳 +- 跟踪请求 ID +2. 错误处理(Error Handling) +- 记录堆栈跟踪 +- 包括错误上下文 +- 跟踪错误模式 +- 监控恢复 +3. 性能跟踪(Performance Tracking) +- 记录操作时序 +- 监控资源使用情况 +- 跟踪消息大小 +- 测量延迟 +### 安全注意事项 ### +调试时: +1. 敏感数据(Sensitive Data) +- 清理日志 +- 保护凭据 +- 屏蔽个人信息 +2. 访问控制(Access Control) +- 验证权限 +- 检查身份验证 +- 监控访问模式 +## 获取帮助 ## +遇到问题时: +1. 第一步 +- 检查服务器日志 +- 使用 调试器(Inspector) 进行测试 +- 审查配置 +- 验证环境 +2. 支持渠道 +- GitHub 问题(GitHub issues) +- GitHub 讨论(GitHub discussions) +3. 提供信息 +- 日志摘录 +- 配置文件 +- 重现步骤 +- 环境详情 \ No newline at end of file diff --git a/content/docs/tutorials/inspector.mdx b/content/docs/tutorials/inspector.mdx new file mode 100644 index 0000000..fe8d427 --- /dev/null +++ b/content/docs/tutorials/inspector.mdx @@ -0,0 +1,96 @@ +--- +title: 调试器Inspector +--- +import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; + +以下是使用 MCP 调试器(Inspector)测试和调试模型上下文协议(MCP)服务器的深度指南。 +MCP [调试器](https://github.com/modelcontextprotocol/inspector)是一个交互式的开发者工具,用于测试和调试 MCP 服务器。 虽然调试指南将调试器作为整体调试工具包的一部分进行了介绍,但本文档将详细探讨 Inspector 的特性和功能。 +## 入门 ## +### 安装和基本用法 ### +调试器通过 npx 直接运行,无需安装: +```js +npx @modelcontextprotocol/inspector +``` +```js +npx @modelcontextprotocol/inspector +``` +#### 从 NPM 或 PyPi 检查服务器 #### +从 NPM 或 PyPi 启动的服务器包的常见方式 + + + ```js + npx -y @modelcontextprotocol/inspector npx +# For example +npx -y @modelcontextprotocol/inspector npx server-postgres postgres://127.0.0.1/testdb + ``` + + + ```js + npx @modelcontextprotocol/inspector uvx +# For example +npx @modelcontextprotocol/inspector uvx mcp-server-git --repository ~/code/mcp/servers.git + ``` + + +#### 检查本地开发的服务器 #### +要检查本地开发或作为存储库下载的服务器,最常见的方式是: + + + ```js + npx @modelcontextprotocol/inspector node path/to/server/index.js args... + ``` + + + ```js + npx @modelcontextprotocol/inspector \ + uv \ + --directory path/to/server \ + run \ + package-name \ + args... + ``` + + +请仔细阅读任何随附的 README 文件,以获取最准确的说明。 +## 功能概述 ## +![ImaImageZoomge](/mcp-inspector.png) +MCP 调试器界面 +调试器提供了多个与 MCP 服务器交互的功能: +### 服务器连接面板 ### +- 允许选择用于连接到服务器的传输方式(transport) +- 对于本地服务器,支持自定义命令行参数和环境变量 +### 资源选项卡 ### +- 列出所有可用资源(resource) +- 显示资源元数据(MIME 类型、描述) +- 允许资源内容检查 +- 支持订阅测试 +### 提示选项卡 ### +- 显示可用的提示词模板(prompt template) +- 显示提示词参数和描述 +- 启用带有自定义参数的提示测试 +- 预览生成的消息 +### 工具选项卡 ### +- 列出可用的工具(tool) +- 显示工具模式(schema)和描述 +- 启用带有自定义输入的工具测试 +- 显示工具执行结果 +### 通知面板 ### +- 显示从服务器记录的所有日志 +- 显示从服务器收到的通知 +## 最佳实践 ## +### 开发工作流 ### +1. 开始开发 +- 使用您的服务器启动调试器 +- 验证基本连接 +- 检查能力协商(capability negotiation) +2. 迭代测试 +- 更改服务器 +- 重新构建服务器 +- 重新连接调试器 +- 测试受影响的功能 +- 监控消息 +3. 测试边缘情况 +- 无效输入 +- 缺少提示参数 +- 并发操作 +- 验证错误处理和错误响应 \ No newline at end of file diff --git a/content/docs/your-1st-MCP-server/test.mdx b/content/docs/your-1st-MCP-server/test.mdx deleted file mode 100644 index d1ee3a8..0000000 --- a/content/docs/your-1st-MCP-server/test.mdx +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: Components -description: Components ---- - -## Code Block - -```js -console.log('Hello World'); -``` - -## Cards - - - - - diff --git a/public/claude-desktop-mcp-hammer-icon.svg b/public/claude-desktop-mcp-hammer-icon.svg new file mode 100644 index 0000000..d8e4f80 --- /dev/null +++ b/public/claude-desktop-mcp-hammer-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/claude-desktop-mcp-plug-icon.svg b/public/claude-desktop-mcp-plug-icon.svg new file mode 100644 index 0000000..1cf5678 --- /dev/null +++ b/public/claude-desktop-mcp-plug-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/mcp-inspector.png b/public/mcp-inspector.png new file mode 100644 index 0000000..94834e8 Binary files /dev/null and b/public/mcp-inspector.png differ diff --git a/public/quickstart-dotnet-client.png b/public/quickstart-dotnet-client.png new file mode 100644 index 0000000..73b9f9f Binary files /dev/null and b/public/quickstart-dotnet-client.png differ