Skip to content

codelitt/codemode-x

Repository files navigation

codemode-x

MCP plugin for Claude Code. Compresses your APIs, databases, Lambda functions, and docs into 2 MCP tools (~1,000 tokens) instead of N tools (100K+ tokens).

Claude writes TypeScript against a typed SDK. Code runs in a sandbox.

Built by Carbon and Codelitt.

How it works

cmx_search("users orders")                                     →  typed SDK signatures for matching tools
cmx_execute("await sdk.api.getUsers()")                         →  real API call, sandboxed
cmx_execute("await sdk.data.rawQuery({ sql: 'SELECT ...' })")  →  database query, read-only

Two tools:

  1. cmx_search(query) — FTS5 full-text search across all your APIs, database tables, and docs. Returns typed SDK signatures for matches only.
  2. cmx_execute(code) — runs TypeScript in a VM sandbox using sdk.<domain>.<method>(). AST-validated. Credentials injected at runtime, never in context.

This is not RAG. The search index holds function signatures, not data. sdk.api.getUsers() makes a real HTTP request to your running server. sdk.data.rawQuery({ sql: '...' }) hits your actual database. The compression is about discovery — Claude finds the right endpoint in ~500 tokens instead of loading every tool definition into context.

Why not just use a bigger context window?

Every MCP tool you register costs tokens on every request, even if Claude only uses one. 25 endpoints = ~100K tokens of tool schemas before Claude writes a single line of code. codemode-x makes that ~1K tokens.

Same reason databases have indexes even when you have plenty of RAM.

Maturity

Developers at Codelitt dogfood codemode-x at Carbon for real estate operations. Express, OpenAPI, and Database adapters run against production APIs and data daily. Markdown, Lambda (manifest mode), Python, and MCP Bridge have test coverage but less mileage. Lambda AWS discovery is beta.

Quick start

cd your-project
npm install codemode-x

# Interactive setup — detects Express/OpenAPI files, generates config
npx codemode-x init

# Or create a config manually
cat > codemode-x.config.js << 'EOF'
export default {
  sdkName: 'myapp',
  domains: [
    {
      name: 'api',
      adapter: 'express',
      source: './server.js',
      baseUrl: 'http://localhost:3000',
      auth: { scope: 'readwrite' },
      // Or use header-based auth with an env var:
      // auth: { type: 'header', key: 'X-API-Key', envVar: 'MY_API_KEY' },
    },
  ],
};
EOF

# Test your config
npx codemode-x test

# Start as MCP server
npx codemode-x start

Install

Option 1: Claude Code marketplace

/install codemode-x

Installs as a Claude Code plugin with automatic updates. Then run npx codemode-x init in your project to generate a config.

If codemode-x isn't in your marketplace yet:

/plugin marketplace add codelitt/codemode-x
/plugin install codemode-x@codemode-x

Option 2: npm

npm install -g codemode-x
cd your-project
npx codemode-x init    # generates codemode-x.config.js + .mcp.json

Restart Claude Code. cmx_search and cmx_execute appear automatically.

Option 3: Manual .mcp.json

Create .mcp.json in your project root:

{
  "mcpServers": {
    "codemode-x": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "codemode-x", "start"],
      "cwd": "/path/to/your/project"
    }
  }
}

Add .mcp.json to .gitignore if it contains secrets.

Adapters

Each adapter introspects a source (API code, spec file, database, etc.) and generates typed SDK methods.

Adapter Source What it does Status
express Express.js app file Parses route handlers via AST Production
openapi OpenAPI 3.x spec (JSON) Extracts operations + schemas Production
database SQLite database file Introspects schema, generates query tools Production
markdown Markdown files/globs Indexes docs as searchable content Stable
lambda AWS Lambda functions Manifest file or AWS discovery Manifest: Stable, AWS discovery: Beta
python Python modules Introspects functions via subprocess Stable
mcp-bridge Existing MCP servers Bridges MCP tools into codemode-x Stable

Production = dogfooded in real workloads. Stable = implemented with test coverage, not yet production. Beta = functional but limited testing.


Express

Parses Express.js source via AST. Extracts app.get(), app.post(), etc. and generates typed SDK methods.

export default {
  sdkName: 'myapp',
  domains: [
    {
      name: 'api',
      adapter: 'express',
      source: './server.js',
      baseUrl: 'http://localhost:3000',
      auth: { scope: 'readwrite' },
    },
  ],
};

Claude sees sdk.api.getProperties(), sdk.api.createUser({ name, email }). Calls go via HTTP to your running server.

OpenAPI

Parses OpenAPI 3.x / Swagger JSON specs. Extracts operations with parameters, request bodies, and response schemas.

export default {
  sdkName: 'myapp',
  domains: [
    {
      name: 'api',
      adapter: 'openapi',
      source: './openapi.json',
      baseUrl: 'https://api.example.com',
    },
  ],
};

Path params, query params, and request body properties become typed method parameters. Response schemas become TypeScript types.

Markdown

Splits markdown files by heading into searchable sections.

export default {
  sdkName: 'myapp',
  domains: [
    {
      name: 'docs',
      adapter: 'markdown',
      source: './docs/**/*.md',
    },
  ],
};

Single files or globs. Claude finds relevant doc sections alongside API methods when searching.

Lambda functions

Two modes:

Manifest mode — you define a JSON file with function names and schemas:

export default {
  sdkName: 'platform',
  domains: [
    { name: 'payments', adapter: 'lambda', source: './manifests/payments.json' },
    { name: 'users', adapter: 'lambda', source: './manifests/users.json' },
  ],
};

AWS discovery mode — scans your account, reads schemas from function tags:

export default {
  sdkName: 'platform',
  domains: [
    {
      name: 'api',
      adapter: 'lambda',
      source: 'us-east-1',
      options: {
        prefix: 'myapp-',              // only functions starting with this
        tags: { team: 'payments' },     // only functions with these tags
      },
    },
  ],
};

Invocation via Lambda.invoke(), not HTTP. Credentials from your environment.

Manifest mode is fully tested. AWS discovery mode is beta — works but hasn't been used in production.

Full guide: docs/lambda-adapter.md

Database

Introspects a SQLite database schema and generates query tools. Read-only by default.

export default {
  sdkName: 'myapp',
  domains: [
    {
      name: 'data',
      adapter: 'database',
      source: './app.db',
      options: {
        tables: ['users', 'orders'],    // optional: only these tables
        // exclude: ['migrations'],      // or: exclude these tables
      },
    },
  ],
};

Per-table query{TableName} tools with columns as optional filters:

await sdk.data.queryUsers()                     // SELECT * FROM users
await sdk.data.queryUsers({ name: 'Alice' })    // WHERE name = 'Alice'
await sdk.data.queryUsers({ age: 30 })          // WHERE age = 30

Plus a rawQuery tool for arbitrary read-only SQL:

await sdk.data.rawQuery({
  sql: 'SELECT u.name, COUNT(o.id) as order_count FROM users u JOIN orders o ON u.id = o.user_id GROUP BY u.name'
})

SQL validation:

  • Allowed: SELECT, PRAGMA, EXPLAIN
  • Blocked: INSERT, UPDATE, DELETE, DROP, ALTER, CREATE
  • Multi-statement queries rejected

Column types map automatically: INTEGERnumber, TEXT/VARCHARstring, REALnumber, BOOLEANboolean.

Full guide: docs/database-adapter.md

Python

Introspects Python modules via subprocess. Extracts function signatures, type hints, and docstrings. Each public function becomes an SDK method.

export default {
  sdkName: 'myapp',
  domains: [
    {
      name: 'analytics',
      adapter: 'python',
      source: './lib/analytics.py',
      options: {
        python: 'python3',              // optional: path to interpreter
        functions: ['run_report'],       // optional: only include these
        // exclude: ['helper_fn'],       // or: exclude these
      },
    },
  ],
};

Given:

def get_user_stats(user_id: str, days: int = 30) -> Dict[str, float]:
    """Get usage statistics for a user over a time period."""
    ...

Claude sees: sdk.analytics.getUserStats({ user_id: string, days?: number }) → Record<string, number>

Type hints map: strstring, int/floatnumber, boolboolean, List[X]X[], Optional[X]X | null.

Functions run via subprocess. Python gets its own process with params as JSON. No shared memory, no import conflicts.

Full guide: docs/python-adapter.md

MCP Bridge

Wraps an existing MCP server's tools as codemode-x SDK methods.

export default {
  sdkName: 'myapp',
  domains: [
    {
      name: 'github',
      adapter: 'mcp-bridge',
      source: 'node /path/to/github-mcp-server.js',
      options: {
        tools: ['search_repos', 'get_file'],  // optional: only include these
        // exclude: ['delete_repo'],            // or: exclude these
      },
    },
  ],
};

Source can be a command string or config object:

// Command string
source: 'python -m my_mcp_server'

// Config object (for env vars, custom args)
source: {
  command: 'node',
  args: ['./mcp-server/index.js', '--port', '3000'],
  env: { API_KEY: 'xxx' },
}

Connects via stdio, discovers tools via listTools(), maps JSON Schema parameters to typed SDK methods. At runtime, cmx_execute proxies calls through the MCP client.

Any MCP server — GitHub, Slack, Postgres, whatever — gets collapsed into the 2-tool interface with search across all of them.

Full guide: docs/mcp-bridge-adapter.md

Memory database

Pair with memory-x for queryable, persistent memory backed by SQLite. memory-x turns markdown files into structured tables — dynamically infers schema from your content.

Setup

npm install -g memory-x

memoryx init
memoryx import ./CLAUDE.md
memoryx import ./docs/
memoryx status

Using with codemode-x

Add the memory database as a domain:

export default {
  sdkName: 'myapp',
  domains: [
    {
      name: 'memory',
      adapter: 'database',
      source: './memory.db',
      options: { writable: true },  // Claude can write live context
    },
    {
      name: 'api',
      adapter: 'express',
      source: './server.js',
      baseUrl: 'http://localhost:3000',
    },
  ],
};

Claude can query context alongside APIs:

await sdk.memory.queryPeople({ who: 'Alice' })
await sdk.memory.queryTerms({ term: 'SLA' })
await sdk.memory.rawQuery({ sql: "SELECT * FROM people WHERE role LIKE '%Lead%'" })
await sdk.api.getUsers()

Full guide: docs/memory-database.md

Multi-domain configs

Combine adapters in one config. cmx_search searches across all of them:

export default {
  sdkName: 'myapp',
  domains: [
    { name: 'api',      adapter: 'express',  source: './server.js', baseUrl: 'http://localhost:3000', auth: { scope: 'readwrite' } },
    { name: 'payments', adapter: 'lambda',   source: './manifests/payments.json' },
    { name: 'data',     adapter: 'database', source: './app.db' },
    { name: 'memory',   adapter: 'database', source: './memory.db' },
    { name: 'docs',     adapter: 'markdown', source: './docs/**/*.md' },
  ],
};

Search for "users" returns API endpoints, database tables, and doc sections — all typed, all callable through sdk.*.

How we use it at Carbon

We run this at Carbon for real estate operations. Express and OpenAPI adapters hit our rent comps API and property management system in production. Database and markdown adapters handle portfolio context and ops docs.

export default {
  sdkName: 'carbon',
  domains: [
    { name: 'rentComps', adapter: 'express', source: './server.js', baseUrl: 'http://localhost:3001' },
    { name: 'portfolio', adapter: 'database', source: './properties.db' },
    { name: 'memory', adapter: 'database', source: './memory.db' },
    { name: 'docs', adapter: 'markdown', source: './docs/**/*.md' },
  ],
};

"rent comps for Maple Ridge" returns the API endpoint, the property record, and the relevant docs. Still 2 MCP tools.

Architecture

User query → cmx_search → FTS5/BM25 index → typed SDK signatures (~500 tokens)
                                ↓
User code  → cmx_execute → AST validation → VM sandbox → sdk.domain.method()
                                                              ↓
                                              HTTP / Lambda.invoke() / SQLite / Python subprocess / MCP proxy

Security

  • AST validation blocks require, import, fetch, process, eval, Function
  • VM sandbox via vm.createContext — no Node globals exposed
  • Credentials injected at execution time only, never in LLM context
  • Header auth: auth: { type: 'header', key: 'X-API-Key', envVar: 'MY_API_KEY' } injects from env vars at request time
  • Read-only by default — writes require explicit auth: { scope: 'readwrite' }
  • Database read-only by default — writable opt-in via options: { writable: true }
  • SQL validation rejects write statements and multi-statement queries in read-only mode

CLI

npx codemode-x init     # interactive setup
npx codemode-x test     # discover tools, show what Claude sees
npx codemode-x start    # start MCP server (stdio)

Development

npm install
npm run build
npm test

npm run test:watch       # watch mode
npm run test:live        # e2e against running server

Docs

License

MIT

About

Universal Code Mode Plugin for Claude Code — compress any API into 2 MCP tools

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages