Skip to main content
Glama

code2mcp - Code Mode MCP Server

Execute TypeScript code to call MCP tools instead of using direct tool calls. Based on Cloudflare's revolutionary Code Mode pattern.

What is Code Mode?

Instead of exposing MCP tools directly to the LLM (which wastes tokens and struggles with complex tools), Code Mode:

  1. Converts MCP tools into TypeScript APIs with full type definitions

  2. Has the LLM write code that calls those APIs

  3. Executes code in a secure sandbox with access only to specified MCP servers

  4. Returns only the final results to the LLM, not intermediate data

Benefits

  • 98% token reduction for complex multi-tool workflows

  • Better tool understanding: LLMs are trained on millions of TypeScript examples

  • Handle complex tools: Full APIs vs simplified tool schemas

  • Secure execution: Sandboxed code, no network/filesystem access

  • API keys hidden: Keys stored in orchestrator, never exposed to LLM

Installation

# Clone or create project
npm install

# Build (TypeScript compilation only)
npm run build

# Build with API generation (recommended for first-time setup)
npm run build:full

Note: build:full generates TypeScript API files from your MCP servers, which helps Claude understand parameter names and types. See IMPROVEMENTS.md for details.

Configuration

1. Pre-Configured MCP Servers ✅

Already configured and ready to use! Five MCP servers are pre-configured:

  1. Context7 - Data storage and context management

  2. Playwright - Browser automation and web scraping

  3. Bright Data - Proxy network and geo-distributed scraping

  4. Chrome DevTools - Chrome DevTools Protocol integration

  5. Firecrawl - Advanced web crawling and content extraction

See CONFIGURED_SERVERS.md for details on each server.

To add more servers, edit src/index.ts and modify the MCP_SERVERS array:

const MCP_SERVERS: MCPServerConfig[] = [
  // ... existing 5 servers ...
  {
    name: 'your-server',
    transport: 'stdio',
    command: 'npx',
    args: ['your-mcp-package'],
    env: {},
  },
];

2. Set Environment Variables

cp .env.example .env
# Edit .env with your API keys

3. Register with Claude Code

Add to ~/.claude.json:

{
  "mcpServers": {
    "code2mcp": {
      "command": "node",
      "args": ["/absolute/path/to/code2mcp/build/index.js"],
      "env": {
        "LOG_LEVEL": "info",
        "WEATHER_API_KEY": "your_key_here"
      }
    }
  }
}

Usage

Example 1: Simple Tool Call

User: "What's the weather?"

Claude writes:

const weather = await __mcp_call('weather__get_current', { 
  city: 'San Francisco' 
});
console.log(`Temperature: ${weather.temperature}°F`);

Output:

=== Execution Logs ===
Temperature: 65°F

=== Result ===
(undefined)

Execution time: 234ms

Example 2: Multi-Step Workflow (Token Savings!)

User: "Get my Google Doc and update Salesforce"

Claude writes:

// Fetch document (potentially 50,000 tokens)
const doc = await __mcp_call('google_drive__get_document', {
  documentId: 'abc123'
});

// Update Salesforce (large document stays in sandbox!)
await __mcp_call('salesforce__update_record', {
  objectType: 'Lead',
  recordId: 'xyz789',
  data: {
    Notes: doc.content  // 50K tokens never enter Claude's context!
  }
});

console.log('Updated Salesforce with document content');

Key Benefit: The 50,000-token document never enters Claude's context. Only the logs are returned!

Example 3: Complex Orchestration

// Get all files modified in last week
const files = await __mcp_call('google_drive__list_files', {
  modifiedAfter: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString()
});

console.log(`Found ${files.length} files`);

// Process each file
for (const file of files) {
  const doc = await __mcp_call('google_drive__get_document', {
    documentId: file.id
  });
  
  // Analyze sentiment (simple keyword matching)
  const sentiment = analyzeSentiment(doc.content);
  
  console.log(`${file.title}: ${sentiment}`);
}

function analyzeSentiment(text) {
  const positive = (text.match(/great|excellent|success/gi) || []).length;
  const negative = (text.match(/issue|problem|failure/gi) || []).length;
  return positive - negative;
}

This kind of complex orchestration would be impossible with standard MCP tool calling!

Architecture

┌─────────────────────────────────────┐
│   Claude Code (MCP Client)          │
│   Sees: ONE tool (execute_code)     │
└──────────────┬──────────────────────┘
               │ Writes TypeScript code
               ▼
    ┌──────────────────────────────────┐
    │   code2mcp Server                │
    │   - Compiles TypeScript          │
    │   - Executes in Node.js VM       │
    │   - Injects __mcp_call binding   │
    └──────────────┬───────────────────┘
                   │ Routes tool calls
                   ▼
    ┌──────────────────────────────────┐
    │   MCP Orchestrator               │
    │   - Manages MCP server conns     │
    │   - Stores API keys              │
    │   - Routes to correct server     │
    └──────────────┬───────────────────┘
                   │
         ┌─────────┴─────────┬──────────┐
         ▼                   ▼          ▼
    ┌─────────┐      ┌──────────┐  ┌─────────┐
    │ Google  │      │Salesforce│  │ Weather │
    │ Drive   │      │          │  │   MCP   │
    │ MCP     │      │   MCP    │  │         │
    └─────────┘      └──────────┘  └─────────┘

Development

# Development mode with hot reload
npm run dev

# Build
npm run build

# Test with MCP Inspector
npm run inspector

# Generate TypeScript APIs manually
npm run generate-apis

Security

The sandbox provides basic isolation:

  • ✅ No network access (fetch, XMLHttpRequest, WebSocket blocked)

  • ✅ No filesystem access (fs, path blocked)

  • ✅ No process access (child_process, process blocked)

  • ✅ Only __mcp_call() binding available

  • ✅ API keys stored in orchestrator, never in sandbox

  • ✅ Timeout enforcement (default 30s)

Note: This uses Node.js built-in vm module, which provides basic isolation but is not as secure as isolated-vm or Deno. For production use, consider:

  1. Using Deno with strict permissions

  2. Using isolated-vm with older Node.js version (v20)

  3. Running in a containerized environment

  4. Deploying to Cloudflare Workers (best isolation)

Token Usage Comparison

Standard MCP (Direct Tool Calling)

Tool definitions: 10K tokens (50 tools × 200 tokens)
Intermediate results: 40K tokens (large documents)
Conversation: 50K tokens
────────────────────────────────────────────────
Total: ~100K tokens

Code Mode

Code written by LLM: 2K tokens
Execution logs: 1K tokens
Conversation: 50K tokens
────────────────────────────────────────────────
Total: ~53K tokens

Token Reduction: 47% for simple workflows, 98% for complex workflows!

Documentation

See /DOCS folder for complete architecture documentation:

  • DOCS/Architecture/SYSTEM_MAP.md - Complete architecture overview

  • DOCS/Architecture/CODE_STRUCTURE.md - File organization

  • DOCS/Etc/CODE_MODE_IMPLEMENTATION_PLAN.md - Detailed implementation plan

References

License

ISC

Contributing

Contributions welcome! This is a reference implementation of the Code Mode pattern.

Roadmap

  • Configuration file support (vs hardcoded in src/index.ts)

  • Deno sandbox implementation for better security

  • TypeScript API browser/explorer

  • Support for HTTP/WebSocket MCP transports

  • Streaming execution logs

  • Code templates library

  • Performance optimizations

  • Comprehensive test suite


Built with ❤️ implementing Cloudflare's Code Mode pattern

Available Tools

1 tool
execute_codeA

Execute TypeScript code with access to MCP tool APIs.

Available APIs:

context7:

  • __mcp_call('context7__resolve-library-id', {libraryName: value}) [context7] Resolves a package/product name to a Context7-compatible library ID and returns a list of matching libraries.

You MUST call this function before 'get-library-docs' to obtain a valid Context7-compatible library ID UNLESS the user explicitly provides a library ID in the format '/org/project' or '/org/project/version' in their query.

Selection Process:

  1. Analyze the query to understand what library/package the user is looking for

  2. Return the most relevant match based on:

  • Name similarity to the query (exact matches prioritized)

  • Description relevance to the query's intent

  • Documentation coverage (prioritize libraries with higher Code Snippet counts)

  • Source reputation (consider libraries with High or Medium reputation more authoritative)

  • Benchmark Score: Quality indicator (100 is the highest score)

Response Format:

  • Return the selected library ID in a clearly marked section

  • Provide a brief explanation for why this library was chosen

  • If multiple good matches exist, acknowledge this but proceed with the most relevant one

  • If no good matches exist, clearly state this and suggest query refinements

For ambiguous queries, request clarification before proceeding with a best-guess match. Parameters: libraryName: string

  • __mcp_call('context7__get-library-docs', {context7CompatibleLibraryID: value, topic?: value, page?: value}) [context7] Fetches up-to-date documentation for a library. You must call 'resolve-library-id' first to obtain the exact Context7-compatible library ID required to use this tool, UNLESS the user explicitly provides a library ID in the format '/org/project' or '/org/project/version' in their query. Parameters: context7CompatibleLibraryID: string, topic?: string, page?: integer

playwright:

  • __mcp_call('playwright__browser_close', {}) [playwright] Close the page

  • __mcp_call('playwright__browser_resize', {width: value, height: value}) [playwright] Resize the browser window Parameters: width: number, height: number

  • __mcp_call('playwright__browser_console_messages', {onlyErrors?: value}) [playwright] Returns all console messages Parameters: onlyErrors?: boolean

  • __mcp_call('playwright__browser_handle_dialog', {accept: value, promptText?: value}) [playwright] Handle a dialog Parameters: accept: boolean, promptText?: string

  • __mcp_call('playwright__browser_evaluate', {function: value, element?: value, ref?: value}) [playwright] Evaluate JavaScript expression on page or element Parameters: function: string, element?: string, ref?: string

  • __mcp_call('playwright__browser_file_upload', {paths?: value}) [playwright] Upload one or multiple files Parameters: paths?: array

  • __mcp_call('playwright__browser_fill_form', {fields: value}) [playwright] Fill multiple form fields Parameters: fields: array

  • __mcp_call('playwright__browser_install', {}) [playwright] Install the browser specified in the config. Call this if you get an error about the browser not being installed.

  • __mcp_call('playwright__browser_press_key', {key: value}) [playwright] Press a key on the keyboard Parameters: key: string

  • __mcp_call('playwright__browser_type', {element: value, ref: value, text: value, submit?: value, slowly?: value}) [playwright] Type text into editable element Parameters: element: string, ref: string, text: string, submit?: boolean, slowly?: boolean

  • __mcp_call('playwright__browser_navigate', {url: value}) [playwright] Navigate to a URL Parameters: url: string

  • __mcp_call('playwright__browser_navigate_back', {}) [playwright] Go back to the previous page

  • __mcp_call('playwright__browser_network_requests', {}) [playwright] Returns all network requests since loading the page

  • __mcp_call('playwright__browser_run_code', {code: value}) [playwright] Run Playwright code snippet Parameters: code: string

  • __mcp_call('playwright__browser_take_screenshot', {type?: value, filename?: value, element?: value, ref?: value, fullPage?: value}) [playwright] Take a screenshot of the current page. You can't perform actions based on the screenshot, use browser_snapshot for actions. Parameters: type?: string, filename?: string, element?: string, ref?: string, fullPage?: boolean

  • __mcp_call('playwright__browser_snapshot', {}) [playwright] Capture accessibility snapshot of the current page, this is better than screenshot

  • __mcp_call('playwright__browser_click', {element: value, ref: value, doubleClick?: value, button?: value, modifiers?: value}) [playwright] Perform click on a web page Parameters: element: string, ref: string, doubleClick?: boolean, button?: string, modifiers?: array

  • __mcp_call('playwright__browser_drag', {startElement: value, startRef: value, endElement: value, endRef: value}) [playwright] Perform drag and drop between two elements Parameters: startElement: string, startRef: string, endElement: string, endRef: string

  • __mcp_call('playwright__browser_hover', {element: value, ref: value}) [playwright] Hover over element on page Parameters: element: string, ref: string

  • __mcp_call('playwright__browser_select_option', {element: value, ref: value, values: value}) [playwright] Select an option in a dropdown Parameters: element: string, ref: string, values: array

  • __mcp_call('playwright__browser_tabs', {action: value, index?: value}) [playwright] List, create, close, or select a browser tab. Parameters: action: string, index?: number

  • __mcp_call('playwright__browser_wait_for', {time?: value, text?: value, textGone?: value}) [playwright] Wait for text to appear or disappear or a specified time to pass Parameters: time?: number, text?: string, textGone?: string

chrome-devtools:

  • __mcp_call('chrome-devtools__click', {uid: value, dblClick?: value}) [chrome-devtools] Clicks on the provided element Parameters: uid: string, dblClick?: boolean

  • __mcp_call('chrome-devtools__close_page', {pageIdx: value}) [chrome-devtools] Closes the page by its index. The last open page cannot be closed. Parameters: pageIdx: number

  • __mcp_call('chrome-devtools__drag', {from_uid: value, to_uid: value}) [chrome-devtools] Drag an element onto another element Parameters: from_uid: string, to_uid: string

  • __mcp_call('chrome-devtools__emulate', {networkConditions?: value, cpuThrottlingRate?: value}) [chrome-devtools] Emulates various features on the selected page. Parameters: networkConditions?: string, cpuThrottlingRate?: number

  • __mcp_call('chrome-devtools__evaluate_script', {function: value, args?: value}) [chrome-devtools] Evaluate a JavaScript function inside the currently selected page. Returns the response as JSON so returned values have to JSON-serializable. Parameters: function: string, args?: array

  • __mcp_call('chrome-devtools__fill', {uid: value, value: value}) [chrome-devtools] Type text into a input, text area or select an option from a element. Parameters: uid: string, value: string

  • __mcp_call('chrome-devtools__fill_form', {elements: value}) [chrome-devtools] Fill out multiple form elements at once Parameters: elements: array

  • __mcp_call('chrome-devtools__get_console_message', {msgid: value}) [chrome-devtools] Gets a console message by its ID. You can get all messages by calling list_console_messages. Parameters: msgid: number

  • __mcp_call('chrome-devtools__get_network_request', {reqid?: value}) [chrome-devtools] Gets a network request by an optional reqid, if omitted returns the currently selected request in the DevTools Network panel. Parameters: reqid?: number

  • __mcp_call('chrome-devtools__handle_dialog', {action: value, promptText?: value}) [chrome-devtools] If a browser dialog was opened, use this command to handle it Parameters: action: string, promptText?: string

  • __mcp_call('chrome-devtools__hover', {uid: value}) [chrome-devtools] Hover over the provided element Parameters: uid: string

  • __mcp_call('chrome-devtools__list_console_messages', {pageSize?: value, pageIdx?: value, types?: value, includePreservedMessages?: value}) [chrome-devtools] List all console messages for the currently selected page since the last navigation. Parameters: pageSize?: integer, pageIdx?: integer, types?: array, includePreservedMessages?: boolean

  • __mcp_call('chrome-devtools__list_network_requests', {pageSize?: value, pageIdx?: value, resourceTypes?: value, includePreservedRequests?: value}) [chrome-devtools] List all requests for the currently selected page since the last navigation. Parameters: pageSize?: integer, pageIdx?: integer, resourceTypes?: array, includePreservedRequests?: boolean

  • __mcp_call('chrome-devtools__list_pages', {}) [chrome-devtools] Get a list of pages open in the browser.

  • __mcp_call('chrome-devtools__navigate_page', {type?: value, url?: value, ignoreCache?: value, timeout?: value}) [chrome-devtools] Navigates the currently selected page to a URL. Parameters: type?: string, url?: string, ignoreCache?: boolean, timeout?: integer

  • __mcp_call('chrome-devtools__new_page', {url: value, timeout?: value}) [chrome-devtools] Creates a new page Parameters: url: string, timeout?: integer

  • __mcp_call('chrome-devtools__performance_analyze_insight', {insightSetId: value, insightName: value}) [chrome-devtools] Provides more detailed information on a specific Performance Insight of an insight set that was highlighted in the results of a trace recording. Parameters: insightSetId: string, insightName: string

  • __mcp_call('chrome-devtools__performance_start_trace', {reload: value, autoStop: value}) [chrome-devtools] Starts a performance trace recording on the selected page. This can be used to look for performance problems and insights to improve the performance of the page. It will also report Core Web Vital (CWV) scores for the page. Parameters: reload: boolean, autoStop: boolean

  • __mcp_call('chrome-devtools__performance_stop_trace', {}) [chrome-devtools] Stops the active performance trace recording on the selected page.

  • __mcp_call('chrome-devtools__press_key', {key: value}) [chrome-devtools] Press a key or key combination. Use this when other input methods like fill() cannot be used (e.g., keyboard shortcuts, navigation keys, or special key combinations). Parameters: key: string

  • __mcp_call('chrome-devtools__resize_page', {width: value, height: value}) [chrome-devtools] Resizes the selected page's window so that the page has specified dimension Parameters: width: number, height: number

  • __mcp_call('chrome-devtools__select_page', {pageIdx: value}) [chrome-devtools] Select a page as a context for future tool calls. Parameters: pageIdx: number

  • __mcp_call('chrome-devtools__take_screenshot', {format?: value, quality?: value, uid?: value, fullPage?: value, filePath?: value}) [chrome-devtools] Take a screenshot of the page or element. Parameters: format?: string, quality?: number, uid?: string, fullPage?: boolean, filePath?: string

  • __mcp_call('chrome-devtools__take_snapshot', {verbose?: value, filePath?: value}) [chrome-devtools] Take a text snapshot of the currently selected page based on the a11y tree. The snapshot lists page elements along with a unique identifier (uid). Always use the latest snapshot. Prefer taking a snapshot over taking a screenshot. The snapshot indicates the element selected in the DevTools Elements panel (if any). Parameters: verbose?: boolean, filePath?: string

  • __mcp_call('chrome-devtools__upload_file', {uid: value, filePath: value}) [chrome-devtools] Upload a file through a provided element. Parameters: uid: string, filePath: string

  • __mcp_call('chrome-devtools__wait_for', {text: value, timeout?: value}) [chrome-devtools] Wait for the specified text to appear on the selected page. Parameters: text: string, timeout?: integer

The code will run in a secure sandbox with:

  • No network access

  • No filesystem access

  • Access only to MCP tool APIs

  • console.log() output will be returned to you

Example Usage:

// Example: Call a single tool
const result = await __mcp_call('server__tool_name', {
  param: 'value'
});
console.log('Result:', result);

Multi-step workflow example:

// Fetch data from one service
const data = await __mcp_call('service1__get_data', {
  id: '123'
});

// Process and send to another service
await __mcp_call('service2__update', {
  value: data.content
});

console.log('Workflow complete');

Note: Intermediate data stays in the sandbox (doesn't enter your context), saving massive amounts of tokens for complex workflows.

ParametersJSON Schema
NameRequiredDescriptionDefault
codeYesTypeScript code to execute in the sandbox
timeoutNoTimeout in milliseconds (default: 30000)

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It excellently describes the sandbox environment constraints (no network/filesystem access, only MCP APIs), how console.log output is returned, and that intermediate data stays in the sandbox. It also details the available MCP APIs (context7, playwright, chrome-devtools) with their specific functions and parameters, providing rich behavioral context beyond basic execution.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely long (over 1500 words) and not front-loaded. While it contains valuable information, much of it (like detailed API listings with parameters) could be better presented elsewhere. The core purpose is buried among extensive API documentation. It lacks efficient structure and contains significant redundancy in parameter listings that don't directly serve the tool's description purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex tool with no annotations and no output schema, the description provides exceptional completeness. It covers execution environment constraints, available APIs with detailed functions, examples of usage patterns, data flow considerations, and security boundaries. Given the tool's complexity and lack of structured metadata, this description gives the agent everything needed to understand how to use the tool effectively.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% description coverage, clearly documenting both parameters. The description doesn't add any additional semantic information about the 'code' or 'timeout' parameters beyond what the schema provides. It focuses on behavioral aspects and API details instead. With high schema coverage, the baseline score of 3 is appropriate as the description doesn't enhance parameter understanding but doesn't need to compensate for gaps.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Execute TypeScript code with access to MCP tool APIs.' It specifies the language (TypeScript), the execution environment (sandbox), and the key capability (access to MCP tool APIs). This is specific, distinguishes it from any hypothetical siblings, and goes beyond just restating the name.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool: for executing TypeScript code in a sandbox with MCP API access. It includes examples of single calls and multi-step workflows. However, it doesn't explicitly state when NOT to use it or mention alternatives, as there are no sibling tools provided. The guidance is comprehensive within its scope but lacks comparative exclusion criteria.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 1 tool updatev1.0.0
    • First observedexecute_code

TDQS

A4/5.0
Disambiguation5/5

The single tool 'execute_code' has a clearly distinct purpose: executing TypeScript code with access to MCP tool APIs. Since there is only one tool, there is no ambiguity or overlap with other tools. The tool's description is specific and focused on code execution within a sandbox environment.

Naming Consistency5/5

With only one tool named 'execute_code', naming consistency is inherently perfect. The tool follows a clear verb_noun pattern (execute_code), and there are no other tools to compare or create inconsistencies with.

Tool Count2/5

The server has only one tool, which feels too thin for its apparent scope. The tool description mentions access to multiple MCP tool APIs (context7, playwright, chrome-devtools), suggesting a broader purpose of code execution with various integrations, but the tool surface is limited to a single generic execution tool. This could lead to agent confusion or inefficiency in handling specific tasks.

Completeness2/5

The server is severely incomplete for its implied domain. While 'execute_code' provides a generic execution capability, there are no dedicated tools for common operations like listing available APIs, managing the sandbox environment, or handling errors. The tool relies on embedded API calls within code, which may cause gaps in agent workflows and reduce usability for specific tasks.

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/blas0/code2mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server