Are you the author? Sign in to claim
mcp-vps
A production-oriented MCP + HTTP control plane for routing work to multiple coding-agent CLIs through one normalized contract.
ChatGPT / Codex / Claude / MCP client / private control UI
│
Streamable HTTP MCP :8787
│
Universal Coder Bridge
│
Hermes → OpenCode → Kilo → [optional AGY] → Hermes
plan implement review finish synthesize
│
/opt/data/workspace
The bridge keeps each CLI's native configured model by default. A caller can override a model for one run without rewriting the CLI's persistent configuration.
/mcpstdio modeTelegram is deliberately not part of this build.
| Adapter | Default state | Role |
|---|---|---|
| Hermes | Enabled | Orchestrator, planner, final synthesis |
| OpenCode | Enabled | Implementation and repository editing |
| Kilo Code | Enabled | Review, debugging, security, risk checks |
| AGY | Disabled | Optional integration/automation finisher; enable only after confirming its local command syntax |
| Codex CLI | Disabled | Optional universal coder |
| Claude Code | Disabled | Optional universal coder |
| Gemini CLI | Disabled | Optional universal coder |
All commands are configured in config/agents.json; the bridge does not invoke an arbitrary shell.
| Tool | Purpose |
|---|---|
agent_describe | List adapters, roles, capabilities, commands, and activity |
agent_health | Check executable availability and versions |
agent_execute | Queue one task on one coder |
pipeline_execute | Run the universal multi-agent coding pipeline |
agent_continue | Create a bridge-level follow-up run from a completed run |
agent_get_run | Read status, PID, heartbeat, output tails, and pipeline steps |
agent_list_runs | List recent runs |
agent_cancel | Cancel queued/running work and terminate the active process group |
agent_list_artifacts | List bridge-created files for a run |
agent_read_artifact | Read one bounded UTF-8 artifact |
agent_continue grounds a new task in the previous run and current repository state. It does not promise native session resumption inside every third-party CLI.
GET /health — unauthenticated liveness checkGET /api/agents — adapter configuration and live healthGET /api/runs?limit=25 — recent runsPOST /api/runs — submit an agent or pipeline runGET /api/runs/:id — inspect one runPOST /api/runs/:id/continue — submit a follow-up runDELETE /api/runs/:id — cancel one runGET /api/runs/:id/events — Server-Sent Events streamPOST|GET|DELETE /mcp — MCP Streamable HTTP transportPort: 8787
HTTP bind: 127.0.0.1
Workspace root: /opt/data/workspace
Artifact root: /opt/data/artifacts
Log file: /opt/data/logs/bridge.log
Global run slots: 2
Model behavior: native unless explicitly overridden
Use Node.js 20 or newer.
sudo mkdir -p /opt/universal-coder-bridge
sudo chown "$USER":"$USER" /opt/universal-coder-bridge
cd /opt/universal-coder-bridge
# Copy or extract this project here.
npm install --no-audit --no-fund
npm run check
npm run verify:runtime
cp .env.example .env
cp config/agents.example.json config/agents.json
Generate a service token:
openssl rand -hex 32
Place it in .env as BRIDGE_AUTH_TOKEN. Keep the bridge on 127.0.0.1 when Caddy is the public HTTPS entry point.
Each enabled coder must be installed and authenticated for the same Linux user that runs the bridge:
hermes --version
opencode --version
kilo --version
Enable only the adapters whose command syntax you have verified locally.
Start directly:
npm run build
npm start
curl http://127.0.0.1:8787/health
Create a dedicated unprivileged user and runtime directories:
sudo useradd --system --create-home --shell /usr/sbin/nologin sorenbridge
sudo mkdir -p /opt/data/{workspace,artifacts,logs}
sudo chown -R sorenbridge:sorenbridge /opt/data
sudo chown -R sorenbridge:sorenbridge /opt/universal-coder-bridge
Install the environment and unit:
sudo cp .env.example /etc/universal-coder-bridge.env
sudo chmod 600 /etc/universal-coder-bridge.env
sudo cp deploy/systemd/universal-coder-bridge.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now universal-coder-bridge
sudo systemctl status universal-coder-bridge
journalctl -u universal-coder-bridge -f
The service unit sets HOME=/home/sorenbridge because agent CLIs commonly keep authentication and writable caches under the service user's home. Install and authenticate each CLI as sorenbridge; do not run the bridge as root.
Copy deploy/caddy/Caddyfile.example, replace bridge.example.com, and keep streaming enabled.
The public hostname must also appear in ALLOWED_HOSTS:
ALLOWED_HOSTS=localhost,127.0.0.1,[::1],bridge.example.com
{
"mcpServers": {
"universal-coders": {
"url": "https://bridge.example.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_BRIDGE_TOKEN"
}
}
}
}
A static bearer token is appropriate for a private, service-to-service bridge. Put a standards-compliant OAuth or identity-aware gateway in front before exposing it as a public multi-user service.
curl -X POST http://127.0.0.1:8787/api/runs \
-H "Authorization: Bearer $BRIDGE_AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"agentId": "opencode",
"task": "Inspect the project, run tests, and fix the failing test.",
"workspace": "my-project",
"model": {"mode": "native"}
}'
One-run model override:
{
"agentId": "opencode",
"task": "Implement the feature and verify it.",
"workspace": "my-project",
"model": {"mode": "override", "value": "provider/model"}
}
curl -X POST http://127.0.0.1:8787/api/runs \
-H "Authorization: Bearer $BRIDGE_AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"kind": "pipeline",
"task": "Add authenticated project sharing and verify it end to end.",
"workspace": "my-project",
"plannerId": "hermes",
"implementerId": "opencode",
"reviewerId": "kilo",
"finalizerId": "hermes",
"maxRevisions": 1
}'
To include a verified finisher adapter, add "finisherId": "agy" after enabling AGY.
curl -X POST http://127.0.0.1:8787/api/runs/RUN_ID/continue \
-H "Authorization: Bearer $BRIDGE_AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{"instruction":"Run the full regression suite and fix anything related."}'
Add an object to config/agents.json:
{
"id": "new-coder",
"displayName": "New Coder",
"description": "What it is responsible for.",
"role": "implementer",
"enabled": true,
"command": "new-coder",
"args": ["run", "{{prompt}}"],
"inputMode": "argument",
"modelArgs": ["--model", "{{model}}"],
"modelArgsIndex": 1,
"env": {},
"capabilities": ["implement", "test"],
"timeoutSeconds": 1200,
"maxConcurrency": 1,
"versionArgs": ["--version"]
}
Templates supported in args: {{prompt}}, {{workspace}}, and {{runId}}. {{model}} is supported in modelArgs.
modelArgsIndex is a zero-based insertion position in the base args array. Set it so model flags never split a flag from the value it consumes. Examples:
Hermes: [chat, --model, MODEL, -q, PROMPT] index 1
OpenCode: [run, --model, MODEL, PROMPT] index 1
Kilo: [run, --auto, --model, MODEL, PROMPT] index 2
Claude: [--model, MODEL, -p, PROMPT, ...] index 0
For CLIs that read the task from stdin, use "inputMode": "stdin"; the configured argument list remains shell-free.
root_shell tool.WORKSPACE_ROOT, including after symlink resolution.BRIDGE_AUTH_TOKEN is rejected at startup.ALLOWED_HOSTS.run.json, stdout.log, and stderr.log are persisted under the artifact root.The coding CLIs can still edit files and execute commands according to their own permissions. Keep .env, SSH keys, API keys, deployment credentials, and unrelated repositories outside WORKSPACE_ROOT. For hostile or untrusted workloads, add a stronger per-run container, VM, or sandbox boundary.
cp .env.example .env
docker compose up --build -d
Compose overrides the container bind address to 0.0.0.0, while publishing the host port only on 127.0.0.1:8787.
The base image contains the bridge, not the coding CLIs. Extend the image with only the adapters you need, or use systemd so the bridge can reach host-installed CLIs and their user-scoped credentials.
BRIDGE_TRANSPORT=stdio npm start
npm install --no-audit --no-fund
npm run typecheck
npm test
npm run verify:runtime
npm run build
See VERIFICATION.md for the checks completed when this package was generated and the remaining environment-dependent verification steps.
40+ tools for querying dashboards, alerts, datasources, and logs in Grafana
Run Claude Code as an MCP server so any agent can delegate coding tasks to it
Browser automation using accessibility snapshots instead of screenshots
Google's universal MCP server supporting PostgreSQL, MySQL, MongoDB, Redis, and 10+ databases