MCP plugin for Claude Code. Takes your APIs, databases, Lambda functions, and docs and compresses them 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.
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 handle everything:
cmx_search(query)— find available APIs, database tables, and docs via FTS5 full-text search. Returns matching tool signatures and TS types for only the matched tools.cmx_execute(code)— run TypeScript usingsdk.<domain>.<method>(). AST-validated, sandboxed, credentials injected at runtime.
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' },
},
],
};
EOF
# Test your config
npx codemode-x test
# Start as MCP server
npx codemode-x startclaude mcp add codemode-x -- node /path/to/codemode-x/plugin/start.mjscodemode-x uses adapters to understand different data sources. Each adapter introspects a source (API code, spec file, database, etc.) and generates typed SDK methods that Claude can search and call.
| Adapter | Source | What it does | Status |
|---|---|---|---|
express |
Express.js app file | Parses route handlers via AST | Done |
openapi |
OpenAPI 3.x spec (JSON) | Extracts operations + schemas | Done |
markdown |
Markdown files/globs | Indexes docs as searchable content | Done |
lambda |
AWS Lambda functions | Manifest file or AWS discovery | Done |
database |
SQLite database file | Introspects schema, generates query tools | Done |
python |
Python modules | Introspects functions via subprocess | Done |
mcp-bridge |
Existing MCP servers | Bridges MCP tools into codemode-x | Done |
Parses your Express.js source code using AST analysis. Extracts all app.get(), app.post(), etc. routes 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 methods like sdk.api.getProperties(), sdk.api.createUser({ name, email }). Calls are made via HTTP to your running server.
Parses OpenAPI 3.x / Swagger JSON specs. Extracts all operations with their parameters, request bodies, and response schemas.
export default {
sdkName: 'myapp',
domains: [
{
name: 'api',
adapter: 'openapi',
source: './openapi.json',
baseUrl: 'https://api.example.com',
},
],
};Path parameters, query parameters, and request body properties all become typed method parameters. Response schemas are converted to TypeScript types.
Indexes markdown documentation as searchable content. Splits files by headings into sections, each becoming a searchable tool.
export default {
sdkName: 'myapp',
domains: [
{
name: 'docs',
adapter: 'markdown',
source: './docs/**/*.md',
},
],
};Supports single files or glob patterns. When Claude searches, it finds relevant doc sections alongside API methods.
Turns AWS Lambda functions into SDK methods. 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 happens via Lambda.invoke(), not HTTP. Credentials come from your environment. Supports 1000+ functions — Claude still sees just 2 MCP tools and searches across all of them.
Full guide: docs/lambda-adapter.md
Introspects a SQLite database schema and generates query tools automatically. The database is always opened read-only.
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
},
},
],
};For each table, the adapter generates a query{TableName} tool with all columns as optional filter parameters:
// Claude can write:
await sdk.data.queryUsers() // SELECT * FROM users
await sdk.data.queryUsers({ name: 'Alice' }) // WHERE name = 'Alice'
await sdk.data.queryUsers({ age: 30 }) // WHERE age = 30It also generates 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 enforces read-only access:
- Allowed:
SELECT,PRAGMA,EXPLAIN - Blocked:
INSERT,UPDATE,DELETE,DROP,ALTER,CREATE - Multi-statement queries are rejected
Column types are mapped automatically: INTEGER → number, TEXT/VARCHAR → string, REAL → number, BOOLEAN → boolean.
Full guide: docs/database-adapter.md
Introspects Python modules via subprocess to extract 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 a Python function:
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>
Python type hints map automatically: str → string, int/float → number, bool → boolean, List[X] → X[], Optional[X] → X | null.
Functions are called via subprocess — Python runs in its own process with params as JSON. No shared memory, no import conflicts.
Full guide: docs/python-adapter.md
Connects to an existing MCP server and wraps its tools as codemode-x SDK methods. This bridges any MCP-compatible tool server into the 2-tool architecture.
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
},
},
],
};The source can be a command string or a 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' },
}codemode-x connects via stdio transport, discovers all tools via listTools(), and maps their JSON Schema parameters to typed SDK methods. At runtime, cmx_execute proxies calls through the MCP client.
This means you can take any existing MCP server — GitHub, Slack, Postgres, custom internal tools — and collapse them all into Claude's 2-tool interface with full search across all of them.
Full guide: docs/mcp-bridge-adapter.md
Pair codemode-x with memory-x to give Claude queryable, persistent memory backed by SQLite. memory-x turns any markdown files into structured tables — no hardcoded schemas, it dynamically infers structure from your content.
# Install memory-x
npm install -g memory-x
# Create and populate a memory database
memoryx init
memoryx import ./CLAUDE.md
memoryx import ./docs/
# Check what was created
memoryx statusAdd the memory database as a domain in your config:
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',
},
],
};Now Claude can query your context alongside your APIs:
// Who's on the team?
await sdk.memory.queryPeople({ who: 'Alice' })
// What does "SLA" mean?
await sdk.memory.queryTerms({ term: 'SLA' })
// Free-form search
await sdk.memory.rawQuery({ sql: "SELECT * FROM people WHERE role LIKE '%Lead%'" })
// And still call your APIs
await sdk.api.getUsers()Full guide: docs/memory-database.md
The real power is combining multiple adapters in one config. Claude searches across all of them with a single cmx_search call:
export default {
sdkName: 'myapp',
domains: [
// REST API
{
name: 'api',
adapter: 'express',
source: './server.js',
baseUrl: 'http://localhost:3000',
auth: { scope: 'readwrite' },
},
// Serverless functions
{
name: 'payments',
adapter: 'lambda',
source: './manifests/payments.json',
},
// Application database
{
name: 'data',
adapter: 'database',
source: './app.db',
},
// Project context
{
name: 'memory',
adapter: 'database',
source: './memory.db',
},
// Documentation
{
name: 'docs',
adapter: 'markdown',
source: './docs/**/*.md',
},
],
};A search for "users" might return results from the API (endpoints), the database (tables), and the docs (relevant sections) — all typed, all callable through the same sdk.* interface.
We use this internally at Carbon for real estate operations. One config connects a rent comps API, property database, investor context, and operational 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' },
],
};Claude can search across all domains — "rent comps for Maple Ridge" returns the API endpoint, the property record, and the relevant documentation. Still just 2 MCP tools.
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
- AST validation blocks
require,import,fetch,process,eval, andFunction - VM sandbox via
vm.createContextwith no Node globals exposed - Credentials injected at execution time only, never visible in LLM context
- Read-only by default — write operations require explicit
auth: { scope: 'readwrite' } - Database access is read-only by default — writable mode is opt-in via
options: { writable: true } - SQL validation rejects all write statements and multi-statement queries in read-only mode
# Interactive setup — detects Express/OpenAPI files, generates config
npx codemode-x init
# Test config — discovers tools and shows what Claude will see
npx codemode-x test
# Start as MCP server (stdio transport)
npx codemode-x start
# Memory database — use memory-x (https://github.com/codelitt/memory-x)
memoryx init && memoryx import ./CLAUDE.mdnpm install
npm run build
npm test
# Watch mode
npm run test:watch
# Test against a live server (start your API first)
npm run test:live- Lambda Adapter — manifest format, AWS discovery, tagging convention, filtering
- Database Adapter — SQL validation, type mapping, table filtering
- Python Adapter — type mapping, subprocess execution, docstring parsing
- MCP Bridge Adapter — connecting existing MCP servers, JSON Schema mapping
- Memory Database — using memory-x with codemode-x
MIT