A CLI for turning MCP (Model Context Protocol) servers into TypeScript functions.
Instead of loading thousands of tool definitions into an LLM context window, mcp-codemode generates a small SDK tree that IDE agents can discover by reading code on demand.
- Node.js >= 20.0.0
- npm or pnpm
Get up and running in 3 steps:
# 1. Initialize the project configuration
npx @merl-ai/mcp-codemode init
# 2. Add an MCP server (interactive prompt)
npx @merl-ai/mcp-codemode add
# 3. Generate TypeScript wrappers
npx @merl-ai/mcp-codemode syncThat's it! Your generated tools are now available in the codemode/ directory.
Choose one of the following installation methods:
No installation needed. Use npx to run commands directly:
npx @merl-ai/mcp-codemode init
npx @merl-ai/mcp-codemode add
npx @merl-ai/mcp-codemode syncInstall globally for system-wide access:
npm install -g @merl-ai/mcp-codemodeThen use the mcp-codemode command directly:
mcp-codemode init
mcp-codemode add
mcp-codemode syncInstall as a project dependency:
npm install @merl-ai/mcp-codemode @merl-ai/mcp-codemode-runtimeThen use via npm scripts or npx:
npx mcp-codemode syncThe Quick Start above covers the essentials. This section provides detailed explanations for each step and additional options:
Create a new codemode.config.json file in your project root:
npx @merl-ai/mcp-codemode initThis creates a basic configuration file. Verify it was created:
cat codemode.config.jsonAdd a server with an interactive prompt:
npx @merl-ai/mcp-codemode addThe prompt will ask for:
- Server name (e.g.,
supabase,cloudflare-observability) - Transport type (
stdioorhttp) - Connection details (command, args, or URL)
Add a server directly via command line:
npx @merl-ai/mcp-codemode add \
--yes \
--name supabase \
--transport stdio \
--command npx \
--args "-y,mcp-remote,https://mcp.supabase.com/mcp?project_ref=YOUR_PROJECT_REF"Edit codemode.config.json directly:
# Open the config file in your editor
code codemode.config.json
# or
vim codemode.config.jsonAdd a server entry:
{
"servers": [
{
"name": "supabase",
"transport": {
"type": "stdio",
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.supabase.com/mcp?project_ref=YOUR_PROJECT_REF"]
}
}
]
}Generate wrappers for all configured servers:
npx @merl-ai/mcp-codemode syncGenerate wrappers for a specific server:
npx @merl-ai/mcp-codemode sync --server supabaseCheck if sync is needed (without generating):
npx @merl-ai/mcp-codemode sync --checkImport and use the generated wrappers:
// Import all tools from a server
import * as supabase from "./codemode/servers/supabase/index.js";
// Call a tool
const url = await supabase.getProjectUrl({});
const tables = await supabase.listTables({ schemas: ["public"] });Or import specific tools:
import { getProjectUrl, listTables } from "./codemode/servers/supabase/index.js";
const url = await getProjectUrl({});
const tables = await listTables({ schemas: ["public"] });Each tool file can be executed directly with JSON input:
# Tool with no input (empty object)
echo '{}' | npx tsx ./codemode/servers/supabase/tools/get_project_url.ts
# Tool with input parameters
echo '{"schemas": ["public"]}' | npx tsx ./codemode/servers/supabase/tools/list_tables.tsNote: Ensure tsx is available. Install globally if needed:
npm install -g tsxOr use npx tsx (no installation required).
The codemode/scripts/ folder is for creating custom workflows that combine MCP tools with your own logic. This is especially useful for:
- Orchestrating multiple tools — Chain tool calls together
- Adding business logic — Conditional execution, error handling, retries
- Creating reusable workflows — Multi-step operations that accomplish higher-level goals
- Collaborating with AI — LLMs and humans can iterate on scripts together
Example script:
// codemode/scripts/my-workflow.ts
import { listTables, executeSql } from "../servers/supabase/index.js";
async function main() {
const tables = await listTables({ schemas: ["public"] });
for (const table of tables.tables) {
const result = await executeSql({
sql: `SELECT COUNT(*) FROM ${table.name}`,
});
console.log(`${table.name}: ${result.rows[0].count} rows`);
}
}
main().catch(console.error);Run scripts with:
npx tsx codemode/scripts/my-workflow.tsScripts are testable, versionable, and can be committed to source control. See codemode/scripts/README.md for more examples.
your-project/
├── codemode.config.json # Configuration file
├── codemode/ # Generated output (commit this!)
│ ├── README.md # LLM-friendly usage guide
│ ├── catalog.json # Tool index for discovery
│ ├── servers/ # Generated server wrappers
│ │ └── <server-name>/
│ │ ├── index.ts # Barrel exports
│ │ └── tools/ # Individual tool wrappers
│ │ └── *.ts
│ ├── scripts/ # Custom scripts folder
│ │ ├── README.md # Scripts documentation
│ │ └── example.ts # Starter template
│ ├── .snapshots/ # Schema snapshots
│ │ └── <server-name>/
│ │ ├── latest.json # Latest tool schemas
│ │ └── latest.meta.json
│ └── .reports/ # Change reports
│ └── <server-name>/
│ └── *.md
└── .github/workflows/ # Optional automation
├── mcp-codemode-sync.yml # Auto-sync workflow
├── ci.yml # CI workflow
└── release.yml # Release workflow
codemode/— Generated TypeScript wrappers (commit to version control)codemode/servers/<serverSlug>/— Server-specific wrapperscodemode/scripts/— Custom scripts that combine tools with your logiccodemode/catalog.json— Searchable index of all toolscodemode/.snapshots/— Schema snapshots for deterministic buildscodemode/.reports/— Human-readable diff reports when schemas change
MCP Codemode uses cosmiconfig and supports multiple file formats:
codemode.config.json(recommended)mcp-codemode.config.js/.cjs/.mjsmcp-codemode.config.ts.mcp-codemoderc/.mcp-codemoderc.json/.mcp-codemoderc.yamlpackage.json("mcp-codemode"field)
The config file is automatically discovered by searching up the directory tree.
View your current configuration:
cat codemode.config.jsonExample configuration:
{
"servers": [
{
"name": "supabase",
"transport": {
"type": "stdio",
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.supabase.com/mcp?project_ref=YOUR_REF"],
"env": {
"SUPABASE_ACCESS_TOKEN": "${SUPABASE_ACCESS_TOKEN}"
}
}
},
{
"name": "cloudflare-observability",
"transport": {
"type": "http",
"url": "https://observability.mcp.cloudflare.com/mcp"
}
}
],
"generation": {
"outDir": "codemode",
"language": "ts"
},
"security": {
"allowStdioExec": true,
"envAllowlist": ["PATH", "HOME"]
}
}Array of MCP server configurations:
name(string, required): Unique identifier for the servertransport(object, required): Connection configurationtype: "stdio": Run a command/processcommand(string): Command to execute (e.g.,"npx")args(string[]): Command argumentsenv(object): Environment variables (optional)auth(object, optional): Authentication configurationtype: "bearer": Bearer token authenticationtokenEnv(string): Name of environment variable containing the token
type: "none": No authentication (default if omitted)
type: "http": Connect via HTTPurl(string): Server URLauth(object, optional): Authentication configurationtype: "bearer": Bearer token authenticationtokenEnv(string): Name of environment variable containing the token
type: "none": No authentication (default if omitted)
Code generation settings (required):
outDir(string, required): Output directory for generated files (e.g.,"./toolbox")language(string, required): Target language (currently only"ts")
Security settings (required):
allowStdioExec(boolean, required): Allow executing stdio commands. Set totrueto enable stdio transports.envAllowlist(string[], required): Environment variables to pass through to stdio transports. Only allowlisted variables are copied (explicittransport.enventries are always included).
CLI behavior settings (optional):
interactive(boolean, optional): Enable interactive prompts. Defaults totrueif omitted.
MCP client metadata (optional):
name(string, optional): Client name sent to MCP servers during handshake. Defaults to"mcp-codemode-runtime"if omitted.version(string, optional): Client version sent to MCP servers during handshake. Defaults to"0.1.0"if omitted.
Output compaction settings (optional): Automatically reduces large tool outputs to prevent context bloat.
enabled(boolean, required): Enable/disable output compactionstrategy(enum, required): Compaction strategy to use:"truncate": Keep first N characters, discard the rest"summarize": Extract beginning and end, omit middle"persist-to-file": Save full output to disk, return file reference
thresholds(object, required): When to trigger compactionbytes(number, optional): Byte size threshold (e.g.,50000for 50KB)tokens(number, optional): Estimated token threshold (e.g.,12000for ~12k tokens)- At least one threshold must be specified; compaction triggers if either is exceeded
truncateLength(number, optional): Max characters to keep when using"truncate"strategy (default:5000)summaryMaxLength(number, optional): Total characters to keep when using"summarize"strategy (default:3000)persistDir(string, optional): Directory for saved outputs when using"persist-to-file"strategy (default:"codemode/.cache/compacted")
Example with truncate strategy:
{
"compaction": {
"enabled": true,
"strategy": "truncate",
"thresholds": {
"bytes": 50000
},
"truncateLength": 5000
}
}Example with summarize strategy:
{
"compaction": {
"enabled": true,
"strategy": "summarize",
"thresholds": {
"tokens": 12000
},
"summaryMaxLength": 3000
}
}Example with persist-to-file strategy:
{
"compaction": {
"enabled": true,
"strategy": "persist-to-file",
"thresholds": {
"bytes": 100000
},
"persistDir": "codemode/.cache/compacted"
}
}MCP Codemode supports bearer token authentication for both HTTP and stdio transports. Tokens are resolved from environment variables at runtime.
Before config validation, MCP Codemode automatically loads environment variables from:
.env(lower priority).env.local(higher priority, overrides.env)
This ensures that tokenEnv values resolve properly during config validation.
{
"servers": [
{
"name": "supabase",
"transport": {
"type": "http",
"url": "https://mcp.supabase.com/mcp",
"auth": {
"type": "bearer",
"tokenEnv": "SUPABASE_MCP_TOKEN"
}
}
},
{
"name": "custom-server",
"transport": {
"type": "stdio",
"command": "npx",
"args": ["mcp-server"],
"auth": {
"type": "bearer",
"tokenEnv": "CUSTOM_SERVER_TOKEN"
}
}
}
]
}Create a .env.local file (or .env) with your tokens:
SUPABASE_MCP_TOKEN=your_token_here
CUSTOM_SERVER_TOKEN=your_other_token_hereNote: Add .env.local to .gitignore to keep tokens out of version control.
When running in CI environments (detected via CI, GITHUB_ACTIONS, or ACT environment variables), or when using the --skip-missing-auth flag:
- Missing tokens: Servers with missing auth tokens are skipped with a warning, rather than causing the sync to fail
- Invalid tokens: If a token is present but authentication fails (401/403), that server is marked as failed but the sync continues with other servers
- Exit code: The process exits with code 0 if at least one server succeeds, even if some servers fail due to auth issues
This allows CI pipelines to run successfully even when some servers don't have auth tokens configured.
If authentication fails for a specific server (e.g., invalid token, expired credentials), only that server is marked as failed. The sync process continues with remaining servers and completes successfully if at least one server succeeds. This prevents a single auth failure from stopping the entire sync operation.
npx @merl-ai/mcp-codemode --helpCheck which servers are configured:
cat codemode.config.json | grep -A 5 '"name"'npx @merl-ai/mcp-codemode syncnpx @merl-ai/mcp-codemode sync --server supabasenpx @merl-ai/mcp-codemode sync --checkConnect to a server and snapshot its tools/resources without regenerating code:
# Introspect all servers
npx @merl-ai/mcp-codemode introspect
# Introspect a specific server
npx @merl-ai/mcp-codemode introspect --server supabaseThis creates snapshots in codemode/.snapshots/ but does not generate TypeScript wrappers. Useful for debugging server connections or inspecting schema changes.
Edit codemode.config.json and remove the server entry, then sync:
# Edit the file
vim codemode.config.json
# Regenerate (removes orphaned files)
npx @merl-ai/mcp-codemode syncThis repository uses GitHub Actions for continuous integration and automated maintenance. Three workflows are configured:
- CI (
ci.yml) - Runs on every PR and push tomain(builds, tests, lints) - MCP Codemode Sync (
mcp-codemode-sync.yml) - Automatically regenerates MCP wrappers when upstream schemas change - Release (
release.yml) - Publishes packages to npm using Changesets
All workflows support local testing with act:
pnpm act:ci # Test CI workflow
pnpm act:sync # Test sync workflow
pnpm act:release # Test release workflow
pnpm act:clean # Clean up Docker containersFor detailed workflow documentation, including authentication setup, secrets configuration, and advanced testing, see .github/workflows/README.md.
If you see an error about allowStdioExec, enable it in your config:
# Edit the config
vim codemode.config.json
# Add or update the security section:
# "security": {
# "allowStdioExec": true
# }Ensure tsx is available for CLI execution:
# Check if tsx is installed
which tsx
# Install if missing
npm install -g tsx
# Or use npx
npx tsx ./codemode/servers/supabase/tools/get_project_url.tsRegenerate all wrappers:
npx @merl-ai/mcp-codemode syncCheck what changed:
git diff codemode/Verify your server configuration:
# Check the config
cat codemode.config.json
# Test the connection manually (for stdio)
npx mcp-remote https://mcp.supabase.com/mcp?project_ref=YOUR_REFFor contributors working on MCP Codemode itself:
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Run tests
pnpm test
# Type check
pnpm typecheck
# Lint code
pnpm lint
# Format code
pnpm format
# Run the CLI locally
pnpm mcp-codemode syncSee CONTRIBUTING.md for development setup and guidelines.
MIT