About
Client-Tool-Execution MCP Server
README
Create Client-Tool-Execution MCP Server
Core Features 🎯
- Dynamic Tool Registration: Clients connect and register their tools automatically
- Client-Side Tool Execution: Tools execute on the client side, not the server - perfect for browser DOM manipulation, local file access, or environment-specific operations
- Transparent Proxy: Server acts as a proxy, routing tool calls to the appropriate client for execution
- Puppet Transport: Delegate MCP methods to another transport - for example, let Cursor's AI call tools that execute in Chrome's browser environment
This enables you to:
- 🔄 Register custom tools dynamically when clients connect
- ⚡ Execute tools directly on the client - not on the server
- 🌐 Build tools that interact with client-specific environments (browser DOM, local files, etc.)
- 🔗 Create flexible, client-driven AI tool ecosystems where execution happens where the data lives
Getting Started 🚀
Installation
# Using Node (better compatibility)
npm i @mcpc-tech/cmcp
# Using Deno
deno add jsr:@mcpc/cmcp
Complete Example
Here's a minimal working example:
Server Usage 📡
The server acts as a proxy and registry - it has no predefined tools and simply routes execution to clients:
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
Client Usage 🖥️
Clients register tools with implementations that execute locally on the client:
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
Example Tool Call 🔧
// 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!
Want more ready-made client tools? Find many example tool definitions at the AI Tools Registry: https://ai-tools-registry.vercel.app/
Why Client-Side Execution? 🤔
Traditional MCP: Tools execute on the server
- ❌ Server needs access to all resources (files, DOM, APIs)
- ❌ Security concerns with server-side execution
- ❌ Limited to server environment capabilities
Client-Tool-Execution MCP: Tools execute on the client
- ✅ Client has natural access to its own environment (DOM, local files, etc.)
- ✅ Better security - no need to expose sensitive resources to server
- ✅ Scalable - each client handles its own execution load
- ✅ Environment-specific - browser clients can manipulate DOM, desktop clients can access files
Architecture Flow 🔄
- Server: Starts as an empty proxy with no predefined tools
- Client Connect: Client establishes SSE connection to server
- Tool Registration: Client sends tool definitions (schema only) via
client/register_tools - Server Registry: Server updates its tool registry with client's tool schemas
- MCP Call: External system discovers and calls tools via server
- Proxy Call: Server proxies call to appropriate client via notification
- Client Execution: 🔥 Tool runs on CLIENT side with full access to client environment
- Response: Result flows back through server to caller
- Client Disconnect: Server automatically removes client's tools
Key Point: The server never executes tools - it only routes calls to clients where the actual execution happens!
Advanced: Puppet Transport 🎭
bindPuppet connects two client transports so one client can use another
client's tools.
Core Idea: Bind Cursor's transport to Chrome's transport → Cursor's requests forward to Chrome.
Example: Cursor → 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
How it works:
- 🌐 Chrome connects and registers DOM tools
- 💻 Cursor connects with
bindPuppetpointing to Chrome's transport - 🤖 AI calls tool via Cursor →
bindPuppetforwards to Chrome → Chrome executes - ✨ Result returns through Chrome → Cursor → AI
In practice (using handleConnecting):
// Chrome: GET /sse?sessionId=chrome
// Cursor: GET /sse?sessionId=cursor&puppetId=chrome
// !!!NOW Cursor controls Chrome like a puppet
Use Cases
- 🖥️ Cursor + Chrome: AI in your editor controls browser automation
- 🤖 AI Agent + Multiple Browsers: One AI coordinating tools across multiple browser tabs
- 📱 Desktop App + Mobile Client: Desktop AI accessing mobile-specific capabilities
- 🔗 Multi-Environment Workflows: Chain tools across different runtime environments
Available Methods
Methods you can delegate (from PUPPET_METHODS):
tools/list,tools/call- Tool operationsresources/list,resources/read- Resource operationsprompts/list- Prompt operations
Install Cmcp in Claude Desktop, Claude Code & Cursor
unyly install cmcpInstalls into Claude Desktop, Claude Code, Cursor & VS Code — handles npx, uvx and build-from-source repos for you.
First time? Get the CLI: curl -fsSL https://unyly.org/install | sh
Or configure manually
Run in your terminal:
claude mcp add cmcp -- npx -y @mcpc-tech/cmcpFAQ
Is Cmcp MCP free?
Yes, Cmcp MCP is free — one-click install via Unyly at no cost.
Does Cmcp need an API key?
No, Cmcp runs without API keys or environment variables.
Is Cmcp hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Cmcp in Claude Desktop, Claude Code or Cursor?
Open Cmcp on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
Fetch
Web content fetching and conversion for efficient LLM usage.
AWS KB Retrieval
Retrieval from AWS Knowledge Base using Bedrock Agent Runtime.
by modelcontextprotocolSpring AI MCP Server
Provides auto-configuration for setting up an MCP server in Spring Boot applications.
llm-analysis-assistant
A very streamlined mcp client that supports calling and monitoring stdio/sse/streamableHttp, and can also view request responses through the /logs page. It also
by xuzexin-hzCompare Cmcp with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All ai MCPs
