@sghanavati/relay-mcp
v0.1.8
Published
MCP server for Claude Code delegation across Codex, OpenRouter, and LM Studio
Maintainers
Readme
relay-mcp
MCP server that lets Claude Code delegate work to Codex, OpenRouter, and LM Studio through one MCP tool.
Prerequisites: For
provider: "codex", install Codex CLI >= 0.39.0 (npm install -g @openai/codex) and authenticate (codex login). Forprovider: "openrouter"setOPENROUTER_API_KEY. Forprovider: "lmstudio"run LM Studio and setLMSTUDIO_ENDPOINTif needed.
Quick Start
Add this to your Claude Code .mcp.json, then restart Claude Code:
{
"mcpServers": {
"relay-mcp": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@sghanavati/relay-mcp"]
}
}
}Installation
@sghanavati/relay-mcp is a zero-install MCP server when launched with npx.
- No global install of
relay-mcpis required. npx -y @sghanavati/relay-mcpdownloads and runs the published package directly.- You need provider-specific runtime setup (Codex CLI for
codex, API key foropenrouter, local endpoint forlmstudio).
Claude Code Registration
npx (recommended)
Use this in your .mcp.json:
{
"mcpServers": {
"relay-mcp": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@sghanavati/relay-mcp"]
}
}
}local dev variant (from repository root)
Use this when iterating on local source before publishing:
{
"mcpServers": {
"relay-mcp": {
"type": "stdio",
"command": "node",
"args": ["dist/index.js"]
}
}
}Timeout strategy (DOCS-03)
relay-mcp accepts timeout_ms per delegate call. Use this strategy:
- Keep server registration static in
.mcp.json. - Set timeouts per task based on expected scope.
- Start with
300000(5 minutes) for medium tasks. - Default timeout is
600000(10 minutes) when omitted.
Example delegate call with explicit timeout:
delegate({
task: "Refactor auth middleware and update tests",
workdir: "/path/to/repo",
timeout_ms: 300000
});Claude Desktop Registration
On macOS, edit:
~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"relay-mcp": {
"command": "npx",
"args": ["-y", "@sghanavati/relay-mcp"],
"env": {
"RELAY_CODEX_PATH": "/usr/local/bin/codex"
}
}
}
}Find your Codex binary path with:
which codexClaude Desktop does not inherit your shell PATH reliably, so RELAY_CODEX_PATH should be set explicitly.
Usage
In Claude Code, ask for a delegated action, for example:
Use the delegate tool to add a README to /path/to/my-projectClaude Code will issue a tool call like:
delegate({
task: "Add a README.md with setup instructions",
workdir: "/path/to/my-project"
});Delegate Tool Parameters
task(required, string): The instruction passed to the delegated worker.workdir(required, string): Absolute or relative working directory for the delegated run.context(optional, string): Additional context to prepend to the worker prompt.provider(optional, string): Provider to use (codex,openrouter, orlmstudio). Defaults tocodex.model(optional forcodex, required foropenrouter/lmstudio): Model identifier for the selected provider.timeout_ms(optional, number): Per-call timeout in milliseconds. Defaults to600000.mcps(optional, array of strings): MCP server URLs to attach to the Codex worker. Each entry must be anhttp://orhttps://URL. Only applies whenprovider: "codex". Arbitrary endpoints are user-controlled — connect only to servers you trust.Example: '{ "mcps": ["https://mcp.figma.com/mcp"] }'
Typical response payload:
{
"status": "success",
"output": "...",
"files_changed": ["README.md"],
"meta": {
"duration_ms": 45000,
"truncated": false,
"warnings": [],
"model": null,
"token_estimate": 1200,
"exit_code": 0,
"provider": "codex",
"log_file": "~/.relay-mcp/run-<hash>.log"
}
}delegate_parallel
Fan out multiple tasks in parallel with a single MCP call. Returns results in request order with per-task status, output, and metadata.
Parameters:
| Field | Type | Default | Description |
|---|---|---|---|
| tasks | array | required | Array of task objects (see below) |
| continue_on_error | boolean | true | Keep dispatching remaining tasks after a failure |
| max_failures | integer | none | Stop dispatching after N non-success results (error + timeout count) |
| max_concurrency | integer | 5 | Max simultaneous in-flight tasks |
Per-task fields (tasks[]):
| Field | Type | Description |
|---|---|---|
| task | string | Task prompt |
| workdir | string | Absolute working directory |
| provider | string | Provider (default: codex) |
| model | string | Model override |
| timeout_ms | integer | Per-task timeout |
| mcps | string[] | MCP server URLs (codex only) |
| task_label | string | Optional label echoed in result for traceability |
| codex_approval_policy | string | Codex approval policy override (codex only; ignored with warning for other providers) |
Response:
{
"status": "success",
"items": [
{
"task_id": 0,
"task_label": "build-auth",
"task_excerpt": "Implement JWT middleware...",
"run_id": "uuid",
"status": "success",
"output": "...",
"files_changed": ["src/middleware/auth.ts"],
"meta": { ... }
}
],
"summary": {
"success_count": 3,
"error_count": 0,
"timeout_count": 0,
"total_duration_ms": 4200
}
}status is "success" only if all items succeed. items are always returned in request order.
Example — parallel component builds:
{
"tasks": [
{ "task": "Build LoginForm component", "workdir": "/project", "task_label": "login-form" },
{ "task": "Build UserProfile component", "workdir": "/project", "task_label": "user-profile" },
{ "task": "Build NavBar component", "workdir": "/project", "task_label": "navbar" }
],
"max_concurrency": 3,
"continue_on_error": true
}Use Cases
1. Context-Preserving Orchestration
Keep Claude's planning session lean by delegating implementation work to Codex. Claude holds the architecture; Codex executes the sub-tasks without polluting the orchestrator's context window.
delegate({
task: "Implement the auth middleware per the spec in PLAN.md",
workdir: "/path/to/repo"
});2. Batch Code Generation
Generate multiple independent artifacts — components, migrations, API routes — each in a fresh Codex context. The orchestrator's growing session history never bleeds into the worker's input.
delegate({
task: "Generate CRUD routes for users, posts, and comments in src/routes/",
workdir: "/path/to/repo"
});3. Test Generation from Spec
After a feature is built, delegate test writing as a standalone, self-contained task.
delegate({
task: "Write Jest unit tests for src/auth/middleware.ts covering success, expired token, and missing token cases",
workdir: "/path/to/repo"
});4. Scoped Refactoring
Delegate well-defined refactors without polluting the main session with diff noise.
delegate({
task: "Migrate all fetch() calls in src/api/ to use the axios client",
workdir: "/path/to/repo"
});5. Documentation Generation
Auto-generate JSDoc, API docs, or README sections for a module after implementation.
delegate({
task: "Add JSDoc comments to all exported functions in src/utils/",
workdir: "/path/to/repo"
});6. Plan-Driven Execution (Orchestrator Pattern)
Use Claude as the planning engine and relay-mcp as the execution bridge.
Each task in a written plan maps to a delegate call; Claude reviews files_changed
before moving to the next task.
Plan phase → Claude writes task specs
Execute → delegate each task to Codex
Review → Claude reads files_changed, verifies output
Repeat → next taskWhen not to use it
- Tasks that require back-and-forth decisions mid-execution (Codex runs
--full-auto) - Work that needs full conversation context (Codex sees only what you pass in
task/context) - Very short one-liners where the delegation roundtrip (Codex startup + execution) exceeds the time to do it inline
Orchestration with tmux + dmux
dmux (npm install -g dmux) arranges a tmux layout where Claude Code
orchestrates from one pane while Codex sessions run in adjacent panes.
tmux window
├── pane 0 Claude Code — GSD orchestrator, relay-mcp registered
├── pane 1 tail -f <relay-log> live output from task 1
├── pane 2 tail -f <relay-log> live output from task 2
└── ...The loop:
- CC writes a plan (GSD), then fires
delegatecalls — one per task - relay-mcp executes each call with the selected provider and returns
files_changed+ output - Each task writes to a provider run log file (
meta.log_file); adjacent panes cantail -flogs live - CC reads
files_changedand output, verifies results, then moves to the next task - You supervise only CC while providers run unattended
Configuration
| Variable | Default | Description |
| --- | --- | --- |
| RELAY_CODEX_PATH | codex from PATH | Full path to Codex binary for PATH-limited environments (especially Claude Desktop). |
| RELAY_LOG_LEVEL | info | Startup log verbosity control. error suppresses the ready banner; other values show it. |
| RELAY_ALLOWED_ROOTS | unset | Optional allowlist for delegate workdir. Path-delimited list (: on macOS/Linux, ; on Windows). If set, workdirs outside these roots are rejected. |
| RELAY_SKIP_GIT_CHECK | 0 | Set to 1 to add --skip-git-repo-check to Codex runs. Default keeps repo check enabled. |
| OPENROUTER_API_KEY | unset | Required for provider: "openrouter". |
| LMSTUDIO_ENDPOINT | http://localhost:1234 | Base URL for LM Studio OpenAI-compatible server. |
| LMSTUDIO_API_KEY | unset | Optional bearer token for LM Studio endpoint. |
RELAY_EVENTS_LOG_PATH— Override the default telemetry log path (~/.relay-mcp/events.jsonl). Useful for custom log routing, tmux/dmux setups, or testing. Example:RELAY_EVENTS_LOG_PATH=/var/log/relay-events.jsonl
Provider model requirement
provider: "codex":modelis optional.provider: "openrouter"orprovider: "lmstudio":modelis required.provider: "openrouter"andprovider: "lmstudio"are generation-only and always returnfiles_changed: [].
Provider examples
delegate({
provider: "openrouter",
model: "google/gemini-2.5-pro",
task: "Review this implementation and return a concise risk list",
workdir: "/path/to/repo"
});delegate({
provider: "lmstudio",
model: "qwen2.5-coder-32b-instruct",
task: "Draft unit tests for src/auth.ts",
workdir: "/path/to/repo"
});Troubleshooting
1) PATH issues (Codex not found)
Symptom:
Error: Codex binary not found ...
Fix:
which codexThen add that path to RELAY_CODEX_PATH in your MCP server config env block.
2) Auth failures
Symptom:
Error: Codex not authenticated
Fix:
codex loginThen restart Claude Code or Claude Desktop.
3) Network/DNS failures
Symptom:
status: "error" with error.code: "CODEX_ERROR" during delegation.
Fix:
- Retry the same delegate call.
- Confirm network/DNS connectivity and any proxy requirements.
- Re-run
codex loginif your session may have expired.
4) Missing model for OpenRouter or LM Studio
Symptom:
status: "error" with error.code: "INVALID_ARGS" and message that model is required.
Fix:
- Add
modelwheneverproviderisopenrouterorlmstudio. - Example:
model: "google/gemini-2.5-pro"for OpenRouter.
5) npx from this package's own repo root
Symptom:
sh: relay-mcp: command not found when running npx -y @sghanavati/relay-mcp from inside the relay-mcp source checkout.
Fix:
- For local development in this repo, run
node dist/index.jsinstead. - For published-package verification, run from any other directory (or use
npm --prefix /tmp exec --yes --package=@sghanavati/relay-mcp -- relay-mcp --version).
Security
workdirvalues are canonicalized withpath.resolve()before subprocess execution.- Optional
RELAY_ALLOWED_ROOTSenforces an explicit allowlist for delegateworkdir. - Codex runs with
--full-autoand can read/write files in the delegated directory. --skip-git-repo-checkis disabled by default and only enabled whenRELAY_SKIP_GIT_CHECK=1.- Run/event logs are written under
~/.relay-mcp(directory mode700, file mode600best-effort). relay-mcpdoes not store credentials, API keys, or session tokens; authentication remains in Codex CLI.
Threat model: relay-mcp is designed for trusted local developer use. Guardrails (workdir allowlist, log permissions, git check gating) defend against accidental prompt-driven mistakes and path escapes — not adversarial attacks. MCP endpoints passed via mcps are fully trusted; connect only to servers you control.
License
MIT. See LICENSE.
