使用说明
客户端工具执行MCP服务器 🚀
创建客户端-工具-执行MCP服务器
核心功能🎯
- 动态工具注册客户端连接并注册其工具 自动地
- 客户端工具执行工具在客户端执行,而不是在(服务器端)执行 服务器 - 非常适合进行浏览器DOM操作、本地文件访问或 特定环境下的操作
- 透明代理服务器充当代理,将工具调用路由到 适合的客户以进行执行
- 木偶运输将MCP方法委托给另一个传输层——例如, 让Cursor的AI调用在Chrome浏览器环境中执行的工具
这使您能够:
- 当客户端连接时,动态注册自定义工具
- ⚡ 执行工具 直接在客户端 - 不在服务器上
- 🌐 构建能够与客户端特定环境(浏览器DOM, 本地文件等)
- 🔗 创建灵活、以客户为导向的AI工具生态系统,实现执行落地 数据所在的(地方/位置)
开始起步 🚀
安装
# Using Node (better compatibility)
npm i @mcpc-tech/cmcp
# Using Deno
deno add jsr:@mcpc/cmcp
完整示例
以下是一个最简工作示例:
服务器使用情况 📡
服务器充当一个 代理和注册表 - 它没有预定义的工具,并且 简单地将执行路由到客户端:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { createClientExecServer } from "@mcpc/cmcp";
// Server is just a proxy - no tools, no execution logic
const server = createClientExecServer(
new Server({ name: "dynamic-mcp-server", version: "1.0.0" }),
"dynamic-server",
);
// Server routes all tool calls to the appropriate client
// All execution happens on the client side
客户端使用 🖥️
客户注册工具 (带有)具体实施方式/实现 在本地执行的 客户端:
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
import { type ClientToolDefinition, createClientExecClient } from "@mcpc/cmcp";
const client = createClientExecClient(
new Client({ name: "browser-client", version: "1.0.0" }),
"browser-client-001",
);
// Define tools with LOCAL implementations (executed on client)
const tools: ClientToolDefinition[] = [
{
name: "querySelector",
description: "Query DOM elements using CSS selectors",
inputSchema: {
type: "object",
properties: {
selector: { type: "string", description: "CSS selector to query" },
action: {
type: "string",
description: "Action to perform",
enum: ["getText", "click", "getAttribute"],
},
attribute: { type: "string", description: "Attribute name" },
},
required: ["selector", "action"],
},
// 🔥 Implementation runs on CLIENT side - has access to DOM, local files, etc.
implementation: async (args: Record<string, unknown>) => {
const { selector, action, attribute } = args;
const element = document.querySelector(selector as string);
if (!element) {
throw new Error(`Element not found: ${selector}`);
}
switch (action) {
case "getText":
return element.textContent || "";
case "click":
element.click();
return `Clicked element: ${selector}`;
case "getAttribute":
return element.getAttribute(attribute as string);
default:
throw new Error(`Unknown action: ${action}`);
}
},
},
];
// Register tools (stored locally until connection)
client.registerTools(tools);
// Connect and register tools to server
await client.connect(
new SSEClientTransport(new URL("http://localhost:9000/sse")),
);
console.log("Client connected and tools registered!");
// Client stays connected to handle tool execution requests
示例工具调用🔧
// External MCP client connecting to the server
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
const mcpClient = new Client({
name: "external-client",
version: "1.0.0",
});
await mcpClient.connect(
new SSEClientTransport(new URL("http://localhost:9000/sse")),
);
// Call tools registered by connected clients
const result = await mcpClient.callTool({
name: "querySelector",
arguments: {
selector: "#my-button",
action: "click",
},
});
console.log(result); // "Clicked element: #my-button"
// ✨ The actual DOM manipulation happened on the CLIENT side!
想要更多现成的客户端工具吗?在……可以找到许多示例工具定义 AI工具注册表:https://ai-tools-registry.vercel.app/
为何选择客户端执行? 🤔
**传统MCP(多通道处理器/多通道系统,具体含义根据上下文确定)**工具在服务器上执行
- ❌ 服务器需要访问所有资源(文件、DOM、API)
- ❌ 服务器端执行的安全隐患
- ❌ 受限于服务器环境能力
**客户端工具执行MCP(或:客户端工具执行机制/流程/配置等,具体翻译取决于MCP在上下文中的具体含义)**工具在客户端执行
- ✅ 客户端自然地访问其自身环境(DOM、本地文件等)
- ✅ 更好的安全性 - 无需将敏感资源暴露给服务器
- ✅ 可扩展性 - 每个客户端负责处理自己的执行负载
- ✅ 环境特定 - 浏览器客户端可以操作DOM,桌面客户端 可以访问文件
架构流程 🔄
- 服务器开始时是一个空的代理,没有任何预定义的工具
- 客户端连接客户端建立与服务器的SSE连接
- 工具注册客户端通过(仅提供模式)发送工具定义
client/register_tools - 服务器注册表服务器更新其工具注册表,加入客户端的工具 模式;架构;方案
- MCP呼叫外部系统通过服务器发现并调用工具
- 代理调用服务器代理通过通知调用相应的客户端
- 客户端执行🔥 工具在客户端运行 可完全访问 客户端环境
- 回应结果通过服务器返回给调用者
- 客户端断开连接服务器自动移除客户端的工具
关键点服务器从不执行工具——它只负责路由调用到 实际执行发生在客户端!
高级:木偶传输 🎭
bindPuppet 连接两个客户端传输,以便一个客户端可以使用另一个客户端的传输
客户的工具。
核心理念将 Cursor 的传输绑定到 Chrome 的传输 → Cursor 的请求 转发到Chrome。
示例:光标 → Chrome
import { bindPuppet, SSEServerTransport } from "@mcpc/cmcp";
// Chrome's transport (connected to Chrome client with DOM tools)
const chromeTransport = new SSEServerTransport("/messages", "chrome");
// Cursor's transport, bound to Chrome's
const cursorTransport = new SSEServerTransport("/messages", "cursor");
const boundTransport = bindPuppet(
cursorTransport, // Main transport
chromeTransport, // Puppet - receives forwarded calls
["tools/list", "tools/call"],
);
// Result: When Cursor calls a tool → forwards to Chrome → Chrome executes
其工作原理如下:
- 🌐 Chrome 连接并注册 DOM 工具
- 💻 Cursor 连接至
bindPuppet指向Chrome的传输(或传输层) - 🤖 通过 Cursor 调用 AI 工具 →
bindPuppet转发到Chrome → Chrome 执行 - ✨ 结果通过Chrome → Cursor → AI返回
在实践中 (使用 handleConnecting):
// Chrome: GET /sse?sessionId=chrome
// Cursor: GET /sse?sessionId=cursor&puppetId=chrome
// !!!NOW Cursor controls Chrome like a puppet
用例
- **🖥️ Cursor + Chrome(可译为:“Cursor浏览器扩展+Chrome浏览器”或根据具体语境简化为“Cursor与Chrome”)**您编辑器中的AI控制浏览器自动化
- 🤖 AI代理 + 多个浏览器一个协调多个(系统/工具)的人工智能工具 浏览器标签页
- 📱 桌面应用程序 + 移动客户端桌面AI访问移动专属功能 能力
- 🔗 多环境工作流跨不同运行时的链工具 环境
可用方法
你可以委托的方法(来自 PUPPET_METHODS):
tools/list,tools/call- 工具操作resources/list,resources/read- 资源操作prompts/list- 快速操作
