客户端工具执行服务器

一个动态注册和执行客户端工具的代理服务器,支持在客户端环境中执行工具调用,适用于浏览器DOM操作、本地文件访问等场景。

  • by mcpc-tech
  • TypeScript
  • 本地部署
  • 6 星标
  • 更新于
在 GitHub 查看 mcpc-tech/cmcp

使用说明

客户端工具执行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,桌面客户端 可以访问文件

架构流程 🔄

  1. 服务器开始时是一个空的代理,没有任何预定义的工具
  2. 客户端连接客户端建立与服务器的SSE连接
  3. 工具注册客户端通过(仅提供模式)发送工具定义 client/register_tools
  4. 服务器注册表服务器更新其工具注册表,加入客户端的工具 模式;架构;方案
  5. MCP呼叫外部系统通过服务器发现并调用工具
  6. 代理调用服务器代理通过通知调用相应的客户端
  7. 客户端执行🔥 工具在客户端运行 可完全访问 客户端环境
  8. 回应结果通过服务器返回给调用者
  9. 客户端断开连接服务器自动移除客户端的工具

关键点服务器从不执行工具——它只负责路由调用到 实际执行发生在客户端!

高级:木偶传输 🎭

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

其工作原理如下:

  1. 🌐 Chrome 连接并注册 DOM 工具
  2. 💻 Cursor 连接至 bindPuppet 指向Chrome的传输(或传输层)
  3. 🤖 通过 Cursor 调用 AI 工具 → bindPuppet 转发到Chrome → Chrome 执行
  4. ✨ 结果通过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 - 快速操作