Skip to main content
Glama

codemode-mcp-gateway

Connect your MCP servers once. Discover and compose their tools with JavaScript.

codemode-mcp-gateway exposes one MCP tool, execute, instead of adding every upstream tool schema to your agent's tool catalog. Agents discover tools on demand, inspect their schemas, and write JavaScript to combine calls and return relevant results.

Use it with MCP clients such as Claude Code and Codex. The gateway handles tool connections and execution—not models or agent loops.

Status: Working MVP, not a production-hardened sandbox. Build from source with Bun 1.4.3.

Quick start

1. Install

Requires Bun 1.4.3. Run from the repository root:

bun install --frozen-lockfile --ignore-scripts
bun run install:gw
"$HOME/.local/bin/gw" --version

Add ~/.local/bin to your PATH to use gw directly.

The standalone executable includes its runtime. Local upstream servers may still require their own runtimes and dependencies. Builds target the current platform; standalone verification currently covers macOS arm64.

2. Configure your MCP servers

Prepare the configuration and HTTP authentication token:

gw setup --transport http

Edit ~/.config/codemode-mcp-gateway/config.json. For example, to connect Notion:

{
  "mcp": {
    "servers": {
      "notion": {
        "type": "remote",
        "url": "https://mcp.notion.com/mcp",
        "oauth": {}
      }
    }
  }
}

Validate the configuration and authorize access:

gw config check
gw auth login notion

Login is explicit and interactive. The running gateway uses saved credentials and refreshes them noninteractively.

For a local MCP server, use a command instead:

{
  "mcp": {
    "servers": {
      "my-server": {
        "type": "local",
        "command": ["bun", "/absolute/path/to/mcp-server.ts"]
      }
    }
  }
}

The local server must already exist and support MCP over stdio. Its working directory defaults to the configuration directory. Local and remote servers can coexist under mcp.servers.

Setup creates only missing gateway files. It does not configure clients, authorize upstreams, or start a process.

3. Start the gateway

gw serve

Keep this terminal running. The default endpoint is:

http://127.0.0.1:4791/mcp

In another terminal, check upstream readiness and browse tools:

gw status
gw tools list
gw tools list notion

Upstreams connect independently. Connected servers remain usable if another server is unavailable.

4. Connect your agent

Retrieve your gateway token privately:

gw token show

Replace <your-private-token> below. Never commit real tokens or copy them into logs. Gateway HTTP authentication is separate from upstream OAuth.

Claude Code

Merge this entry into the user-level mcpServers object in ~/.claude.json, preserving existing settings:

{
  "mcpServers": {
    "codemode-mcp-gateway": {
      "type": "http",
      "url": "http://127.0.0.1:4791/mcp",
      "headers": {
        "Authorization": "Bearer <your-private-token>"
      }
    }
  }
}

Codex

Add this entry to ~/.codex/config.toml, or $CODEX_HOME/config.toml:

[mcp_servers.codemode-mcp-gateway]
url = "http://127.0.0.1:4791/mcp"
http_headers = { Authorization = "Bearer <your-private-token>" }
startup_timeout_sec = 60
tool_timeout_sec = 60

Restart or reconnect your client after editing its configuration.

Both clients can share the running gateway. They do not launch it, and closing either client does not stop it.

Related MCP server: Code Mode MCP Server

Discover, inspect, call

Agents submit JavaScript to execute({ code }). Code runs as an async function body, so top-level await and return work.

These examples use the math upstream from the gateway examples. Each snippet is a separate execute invocation—not a terminal command.

Discover tools

return await tools.searchTools({
  query: "add numbers",
  server: "math",
});

Search returns ranked name and description previews, pagination information, and upstream availability. Full schemas are fetched separately.

Inspect a schema

Use the exact qualified name returned by discovery:

return await tools.describeTool({ name: "math.add" });

Call the tool

After inspecting its schema:

const response = await tools["math.add"]({ a: 2, b: 3 });

if (response.isError) {
  return response.content;
}

return response.structuredContent.sum;

The result is 5.

Complete upstream MCP responses are available inside the script. Check isError explicitly: an upstream tool error is returned data, not automatically a thrown JavaScript exception.

Compose calls

Use ordinary JavaScript to combine independent requests and select the result you need:

const responses = await Promise.all([
  tools["math.add"]({ a: 2, b: 3 }),
  tools["math.add"]({ a: 10, b: 20 }),
]);

return responses.map((response) => {
  if (response.isError) {
    return { error: response.content };
  }

  return { sum: response.structuredContent.sum };
});

CLI examples

# Validate configuration without connecting
gw config check

# Test fresh upstream connections, then close them
gw probe
gw probe notion

# Inspect the running HTTP gateway
gw status
gw status --json

# Browse its current tool catalog
gw tools list
gw tools list notion
gw tools list notion --offset 50
gw tools list --all
gw tools list notion --json

# Authorize an OAuth upstream
gw auth login notion

# Get focused help
gw help
gw help auth login

status and tools list query the running HTTP gateway. probe opens separate, temporary upstream connections.

Use --config /path/to/config.json to select another configuration. Restart the gateway after changing upstream definitions.

See the gateway guide for full configuration and command details.

Client-owned stdio

If you prefer your client to launch its own gateway, configure a stdio command instead of an HTTP endpoint:

{
  "command": "/absolute/path/to/gw",
  "args": ["serve", "--transport", "stdio"]
}

Each launch owns separate upstream connections and execution limits. No gateway HTTP token or listening port is needed. Saved upstream credentials are still required where applicable.

For a nondefault configuration, append "--config", "/absolute/path/to/config.json" to args.

How it works

MCP client
    │
    │ execute({ code })
    ▼
Gateway
    ├── Fresh worker + QuickJS VM
    │       │
    │       └── Tool calls over a JSON bridge
    │                   │
    └── Host adapters ──┴── Upstream MCP servers
    │
    ▼
Returned value or error text

Each execution runs in a fresh QuickJS VM with resource limits. Scripts have no direct access to host filesystem, network, or process APIs. External actions go through configured host tools.

The host owns upstream connections and credentials. Each execution receives a snapshot of available tool bindings; an HTTP gateway shares its executor and upstream connections across client sessions.

Results and large output

Agent-facing responses contain text: strings are returned directly, and other values are serialized as JSON.

Above 40,000 UTF-8 bytes, the gateway returns a preview and a private local path to the full output. Clients can read that file with their own file or shell tools when they share the gateway's filesystem. Files are temporary and tied to the MCP session.

See the execution reference for output and lifecycle details.

Execution boundaries

  • Tools retain the permissions of their upstream connections.

  • Cancellation cannot undo upstream side effects.

  • Failed scripts are not automatically replayed.

  • Guest memory and execution limits do not cap all host work or upstream payload allocations.

  • HTTP serving is authenticated and loopback-only.

  • Upstream OAuth credentials are stored locally as plaintext files with owner-only permissions.

Default gateway limits include four concurrent executions, 100 tool calls per execution, ten active calls per execution, and a 256 MiB guest memory limit.

See limits and boundaries and local deployment for the complete contracts.

Packages

Package

Purpose

@codemode-mcp-gateway/codemode

Execute JavaScript with host tools, without an MCP dependency

@codemode-mcp-gateway/mcp

Adapt MCP clients and expose executors as MCP servers

codemode-mcp-gateway

Upstream connections, discovery, configuration, OAuth, and the gw CLI

All three currently support Bun only. Package names are provisional and unpublished.

Development

bun install --frozen-lockfile --ignore-scripts
bun run check
bun run example

bun run check runs builds, typechecking, lint, formatting checks, tests, and packaged-consumer verification.

See testing conventions, the script guide, and project conventions.

Documentation

License

MIT. Third-party components retain their respective licenses and notices.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides secure execution of arbitrary JavaScript code within a sandboxed QuickJS WASM environment, allowing language models or other MCP clients to safely run JavaScript code snippets without compromising the host system.
    5
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables LLMs to interact with MCP servers by writing TypeScript/JavaScript code instead of direct tool calls. Provides a code execution sandbox that accesses MCP servers through HTTP proxy endpoints.
    23 npm
    126
    Apache 2.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    A meta MCP server that orchestrates other MCP servers by lazily connecting to them and exposing their tools as JavaScript libraries. It allows users to execute JavaScript code that programmatically interacts with multiple MCP servers within a unified environment.
    7 npm
    1
    MIT