1. Conduid
  2. Developer Tools
  3. Codemode
MCP server · Developer Tools

Codemode

Go library for building MCP servers where the agent writes code instead of chaining tool calls

65Good

Scored 8 days ago · breakdown

About Codemode

Codemode is an MCP server published by cnap-tech in the Developer Tools category: go library for building MCP servers where the agent writes code instead of chaining tool calls.

The repository has 4 stars and 0 forks, with the last commit 2 months ago. Recent commit activity is the strongest signal that reported issues will get attention.

Install

From source
git clone https://github.com/cnap-tech/codemode

This server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.

Ask AI

✦

Ask AI about Codemode

Powered by Claude · Grounded in docs

I know everything about Codemode. Ask me about installation, configuration, usage, or troubleshooting.

Security checks

  • ✓README presentThe repository ships documentation.
  • ✓License declaredUsable under a stated license.
  • !Scoped permissionsDoesn't declare a permission scope. Assume it can do anything its process can.

3 checks have not been run yet.

Releases

v0.4.2CodeMode v0.4.2 · 24 Jul 2026Restores trusted publishing metadata and ships the OpenAPI search reliability hardening. LLRT native packages now validate on PRs but publish only through an explicit main-branch dispatch.
v0.4.1v0.4.1 — safe OpenAPI search graphs · 24 Jul 2026CodeMode 0.4.1 keeps OpenAPI schemas fully pre-resolved for AI search while safely bounding alias-expanded sandbox transports. It adds concurrent spec preparation reuse, accurate violation reporting, native Date compatibility, and coverage…
v0.4.0v0.4.0 — LLRT capability boundary hardening · 17 Jun 2026Packages @robinbraemer/codemode@0.4.0 @robinbraemer/llrt@0.2.0 @robinbraemer/llrt-* native packages@0.2.0 Highlights Adds explicit data-only and capability executor contracts. Adds LLRT callJsonWithHost manifest execution with no raw…
v0.3.2v0.3.2 · 16 Jun 2026Publishes the hardened LLRT follow-up after v0.3.1 / v0.1.1. abort LLRT host-call contexts when execution completes or times out forward AbortSignal through CodeMode request bridge and cancel response readers on abort/error add…
v0.3.1v0.3.1 · 16 Jun 2026Summary Harden LLRT native execution by disabling default module/file/package loading for sandboxed call_json execution. Hide response headers from sandbox code unless explicitly exposed and harden protected request header filtering.…

README

codemode

Two MCP tools that replace hundreds. Give an AI agent your OpenAPI spec and a request handler — it discovers and calls your entire API by writing JavaScript in a sandboxed runtime.

Instead of defining individual MCP tools for every API endpoint (list-pods, create-product, get-logs, ...), CodeMode exposes just two tools:

  • search — the agent writes JS to filter your OpenAPI spec and discover endpoints
  • execute — the agent writes JS to call your API via an injected client

This is the same pattern Cloudflare uses to expose 2,500+ API endpoints through just two MCP tools, reducing context window usage by 99.9%.

Try It

Requires mise for tooling (Node.js, pnpm, Task):

git clone https://github.com/cnap-tech/codemode.git
cd codemode
mise install   # installs Node 24, pnpm 10, Task
task install   # installs dependencies
task example   # runs the Petstore demo

Fetches the real Petstore OpenAPI spec from the web, then runs search + execute against a local Hono mock — no API keys needed.

Install

pnpm add @robinbraemer/codemode

# Install the sandbox runtime:
pnpm add isolated-vm       # V8 isolates

Quick Start

import { CodeMode } from '@robinbraemer/codemode';
import { Hono } from 'hono';

const app = new Hono();
app.get('/v1/clusters', (c) => c.json([{ id: '1', name: 'prod' }]));
app.post('/v1/clusters', async (c) => {
  const body = await c.req.json();
  return c.json({ id: '2', ...body }, 201);
});

const codemode = new CodeMode({
  spec: myOpenAPISpec,              // OpenAPI 3.x spec, or async getter
  request: app.request.bind(app),   // in-process, no network hop
});

// The agent searches the spec to discover endpoints...
const search = await codemode.callTool('search', {
  code: `async () => {
    const results = [];
    for (const [path, methods] of Object.entries(spec.paths)) {
      for (const [method, op] of Object.entries(methods)) {
        if (op.tags?.some(t => t.toLowerCase() === 'clusters')) {
          results.push({ method: method.toUpperCase(), path, summary: op.summary });
        }
      }
    }
    return results;
  }`
});

// ...then executes API calls
const result = await codemode.callTool('execute', {
  code: `async () => {
    const res = await api.request({ method: "GET", path: "/v1/clusters" });
    return res.body;
  }`
});

MCP Server Integration

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CodeMode } from '@robinbraemer/codemode';
import { registerTools } from '@robinbraemer/codemode/mcp';

const codemode = new CodeMode({
  spec: () => fetchOpenAPISpec(),
  request: app.request.bind(app),
});

const server = new McpServer({ name: 'my-api', version: '1.0.0' });
registerTools(codemode, server);

const transport = new StdioServerTransport();
await server.connect(transport);

How It Works

AI Agent
  │ writes JavaScript code
  ▼
CodeMode MCP Server
  │
  ├─ search(code) → runs JS with preprocessed OpenAPI spec
  │   → all $refs resolved inline, only essential fields kept
  │   → agent discovers endpoints, schemas, parameters
  │
  └─ execute(code) → runs JS with injected request client
      → api.request() calls your handler in-process
      → no network hop, auth handled automatically

All code runs in an isolated V8 sandbox. The sandbox has zero I/O by default — no require, no process, no fetch, no filesystem. The only way to interact with the outside world is through the injected globals (spec for search, {namespace}.request() for execute).

Each tool call gets a fresh sandbox with no state carried over between calls.

API

new CodeMode(options)

Option Type Default Description
spec OpenAPISpec | () => OpenAPISpec | Promise<OpenAPISpec> required OpenAPI 3.x spec or async getter
request (input, init?) => Response required Fetch-compatible handler (app.request.bind(app) for Hono)
namespace string "api" Client name in sandbox (api.request(...)). Must be a valid JS identifier, not a reserved name.
baseUrl string "http://localhost" Base URL for relative paths
sandbox SandboxOptions see below Sandbox resource limits
executor Executor IsolatedVMExecutor Custom sandbox executor
maxResponseTokens number 25000 Token limit for response truncation (0 to disable)
maxRequests number 50 Max requests per execute() call
maxResponseBytes number 10485760 Max response body size in bytes (10MB)
allowedHeaders string[] undefined Header whitelist. When unset, a blocklist strips Authorization, Cookie, Host, X-Forwarded-*, Proxy-*.
maxRefDepth number 50 Max $ref resolution depth

SandboxOptions

Option Type Default Description
memoryMB number 64 V8 isolate memory limit
timeoutMs number 30000 CPU timeout in ms (caps pure compute)
wallTimeMs number 60000 Wall-clock timeout in ms (caps total elapsed time including async I/O)

Methods

codemode.tools(): ToolDefinition[]

Returns MCP-compatible tool definitions for search and execute.

codemode.callTool(name, { code }): Promise<ToolCallResult>

Route a tool call. Returns { content: [{ type: "text", text }], isError? }.

codemode.search(code): Promise<ToolCallResult>

Run search code directly (shorthand for callTool('search', { code })).

codemode.execute(code): Promise<ToolCallResult>

Run execute code directly (shorthand for callTool('execute', { code })).

codemode.setToolNames(search, execute): this

Override default tool names. Useful when running multiple CodeMode instances.

codemode.dispose(): void

Clean up sandbox resources.

Sandbox API

Inside search

The spec global is the preprocessed OpenAPI spec with all $ref pointers resolved inline:

// Find endpoints by tag
async () => {
  const results = [];
  for (const [path, methods] of Object.entries(spec.paths)) {
    for (const [method, op] of Object.entries(methods)) {
      if (op.tags?.some(t => t.toLowerCase() === 'clusters')) {
        results.push({ method: method.toUpperCase(), path, summary: op.summary });
      }
    }
  }
  return results;
}

// Get endpoint with requestBody schema (refs are already resolved)
async () => {
  const op = spec.paths['/v1/products']?.post;
  return { summary: op?.summary, requestBody: op?.requestBody };
}

// Spec metadata
async () => ({
  title: spec.info.title,
  version: spec.info.version,
  endpoints: Object.keys(spec.paths).length,
})

Inside execute

The {namespace}.request() function makes API calls through the host handler:

// GET with query params
async () => {
  const res = await api.request({
    method: "GET",
    path: "/v1/clusters",
    query: { limit: 10 },
  });
  return res.body;
}

// POST with body
async () => {
  const res = await api.request({
    method: "POST",
    path: "/v1/products",
    body: { name: "Redis", chart: "bitnami/redis" },
  });
  return { status: res.status, body: res.body };
}

// Chain calls
async () => {
  const list = await api.request({ method: "GET", path: "/v1/clusters" });
  const details = await Promise.all(
    list.body.map(c =>
      api.request({ method: "GET", path: `/v1/clusters/${c.id}` })
    )
  );
  return details.map(d => d.body);
}

Request options:

Field Type Description
method string HTTP method ("GET", "POST", etc.)
path string API path ("/v1/clusters")
query Record<string, string | number | boolean> Query parameters (optional)
body unknown Request body, auto-serialized as JSON (optional)
headers Record<string, string> Additional headers (optional)

Response: { status: number, headers: Record<string, string>, body: unknown }

Spec Preprocessing

CodeMode automatically preprocesses your OpenAPI spec before passing it to the search sandbox:

  • $ref resolution — all $ref pointers are resolved inline (circular refs become { $circular: ref })
  • Field extraction — only essential fields kept per operation: summary, description, tags, operationId, parameters, requestBody, responses
  • Metadata preserved — info, servers, and components.schemas are kept alongside processed paths

You can also use the preprocessing utilities directly:

import { resolveRefs, processSpec, extractTags } from '@robinbraemer/codemode';

const processed = processSpec(rawSpec);
const tags = extractTags(rawSpec);

Executors

CodeMode uses isolated-vm (V8 isolates) for sandboxed execution. You can pass a custom instance:

import { CodeMode, IsolatedVMExecutor } from '@robinbraemer/codemode';

const codemode = new CodeMode({
  spec,
  request: handler,
  executor: new IsolatedVMExecutor({
    memoryMB: 128,
    timeoutMs: 60_000,   // CPU time limit
    wallTimeMs: 120_000, // total elapsed time limit
  }),
});
Executor Package Performance Portability
IsolatedVMExecutor isolated-vm Native V8 speed Node.js

Custom Executor

Implement the Executor interface to use your own sandbox:

import { CodeMode, type Executor, type ExecuteResult } from '@robinbraemer/codemode';

class MyExecutor implements Executor {
  async execute(code: string, globals: Record<string, unknown>): Promise<ExecuteResult> {
    // `code` is an async arrow function as a string: "async () => { ... }"
    // `globals` contains named values to inject:
    //   - plain data (objects, arrays, primitives) → read-only values
    //   - functions → callable host functions
    //   - objects with function values → namespace with callable methods
    return { result: ..., logs: [] };
  }

  dispose() { /* clean up */ }
}

const codemode = new CodeMode({
  spec,
  request: handler,
  executor: new MyExecutor(),
});

Token Efficiency

Approach Context Tokens
Individual MCP tools (15-50+ tools) ~15,000-50,000+
Full OpenAPI spec in context ~1,000,000+
CodeMode (2 tools) ~1,000

License

MIT

README copy captured when this server was indexed; it may lag the repository. The original is authoritative.

Questions

About Codemode

How do I install Codemode?

No package has been published for this server, so install it from source: clone the repository and follow its README.

Is Codemode safe to use with an AI agent?

Its trust score is 65 out of 100 (good). It passes 2 of the 3 static security checks run so far; the failures are listed above. It has no ConduID identity yet, so agent calls to it are not receipted.

Is Codemode still maintained?

Yes — the latest release is v0.4.2 (24 Jul 2026), and the last commit was 2 months ago. The repository has 4 stars.