Deploy Junctio | (Just Updated) MCP Gateway, One Endpoint for All MCP Servers, Admin Token Set

Junctio MCP gateway: one endpoint for many MCP servers, REST API, API keys

Deploy Junctio | (Just Updated) MCP Gateway, One Endpoint for All MCP Servers, Admin Token Set

Just deployed

/data

Deploy and Host Junctio on Railway

Built for an LLM agent to deploy and use. There is no setup form and nothing to fill in: the admin token is generated at deploy time, and the contract below lists every address, variable name and one script that creates an MCP endpoint, attaches a server to it and calls a tool through it.

Junctio is a self-hosted MCP gateway. You register your MCP servers once (stdio, HTTP or SSE), group them into namespaces, and publish each namespace as one authenticated endpoint at /mcp/ plus the endpoint slug. Every client, such as Claude Code, Codex, Cursor or a custom agent, connects to that one URL instead of configuring each server by hand. It prefixes tool names per server, supports API keys and OAuth, and has a REST API and web UI.

About Hosting Junctio

This template runs one service, the official ghcr.io/k2so-dev/junctio 0.2.6 image pinned by digest. State is a SQLite database in /data on an attached volume, so servers, namespaces, endpoints and API keys survive redeploys. The volume is root-owned on Railway, so the start command fixes ownership and then drops to the image's own user before launching the gateway.

JUNCTIO_ADMIN_TOKEN is the headless admin credential for /api/v1/*, and it is also what is required to choose the web UI admin password on a fresh install, so a stranger who finds the URL first cannot claim the instance. JUNCTIO_SECRET encrypts stored upstream credentials; keep it stable. Both are generated per deploy and stay the same across redeploys.

Stdio servers run inside this container. Use the bunx runtime for npm packages: the npx runtime fails on this image because its bundled npm cannot load its own cache module (Class extends value undefined). Stdio servers need outbound network access from the service and the first start of a server pays its download time. JUNCTIO_TRUST_PROXY is left off on purpose: on Railway the right-most x-forwarded-for entry is the edge hop, which changes per request, so trusting it would make the login rate limit useless.

Agent contract

  • Public URL: JUNCTIO_BASE_URL (https:// plus the service's RAILWAY_PUBLIC_DOMAIN). Web UI at /, REST API at /api/v1/, endpoints at /mcp/ plus the endpoint slug.
  • Private URL: http://junctio.railway.internal:8080, exposed as JUNCTIO_PRIVATE_URL.
  • Credentials: JUNCTIO_ADMIN_TOKEN (admin) and JUNCTIO_SECRET (encryption key, not for clients). Client API keys start with jn_ and are minted through the REST API.
  • Auth: admin calls send Authorization: Bearer followed by the admin token. MCP clients send Authorization: Bearer followed by an API key, or X-API-Key. Anonymous API calls get 401.
  • Health: GET /health returns 200 without credentials.
  • Protocol: Streamable HTTP, stateless. A new endpoint accepts MCP revision 2026-07-28 and sends it in the request _meta, plus Mcp-Method and, for named calls, Mcp-Name headers.
# run with JUNCTIO_BASE_URL and JUNCTIO_ADMIN_TOKEN set (needs curl and jq)
AUTH="Authorization: Bearer $JUNCTIO_ADMIN_TOKEN"
JSON="Content-Type: application/json"
S=$(date +%s)
curl -s -o /dev/null -w "health: %{http_code}\n" "$JUNCTIO_BASE_URL/health"
curl -s -o /dev/null -w "anonymous api: %{http_code}\n" "$JUNCTIO_BASE_URL/api/v1/namespaces"
SRV=$(curl -s -H "$AUTH" -H "$JSON" -d "{\"name\":\"everything$S\",\"transport\":\"stdio\",\"runtime\":\"bunx\",\"args\":[\"@modelcontextprotocol/server-everything\"]}" "$JUNCTIO_BASE_URL/api/v1/servers" | jq -r .id)
NS=$(curl -s -H "$AUTH" -H "$JSON" -d "{\"name\":\"agents$S\"}" "$JUNCTIO_BASE_URL/api/v1/namespaces" | jq -r .id)
curl -s -o /dev/null -w "attach server: %{http_code}\n" -H "$AUTH" -H "$JSON" -d "{\"serverId\":\"$SRV\"}" "$JUNCTIO_BASE_URL/api/v1/namespaces/$NS/servers"
curl -s -o /dev/null -w "create endpoint: %{http_code}\n" -H "$AUTH" -H "$JSON" -d "{\"slug\":\"demo$S\",\"namespaceId\":\"$NS\",\"authMode\":\"api_key\"}" "$JUNCTIO_BASE_URL/api/v1/endpoints"
EP=$(curl -s -H "$AUTH" "$JUNCTIO_BASE_URL/api/v1/endpoints" | jq -r ".[] | select(.slug==\"demo$S\") | .id")
KEY=$(curl -s -H "$AUTH" -H "$JSON" -d "{\"name\":\"agent\",\"endpointId\":\"$EP\"}" "$JUNCTIO_BASE_URL/api/v1/api-keys" | jq -r .token)
META='"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientInfo":{"name":"curl","version":"1.0.0"},"io.modelcontextprotocol/clientCapabilities":{}}'
mcp() { curl -s -H "Authorization: Bearer $KEY" -H "$JSON" -H "Accept: application/json, text/event-stream" -H "MCP-Protocol-Version: 2026-07-28" -H "Mcp-Method: $1" ${3:+-H} ${3:+"Mcp-Name: $3"} -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"$1\",\"params\":{$2$META}}" "$JUNCTIO_BASE_URL/mcp/demo$S"; }
for i in 1 2 3 4 5 6 7 8 9 10 11 12; do TOOL=$(mcp tools/list "" | jq -r '.result.tools[0].name // empty'); if [ -n "$TOOL" ]; then break; fi; sleep 5; done
echo "first tool: $TOOL"
mcp tools/call "\"name\":\"${TOOL%%__*}__echo\",\"arguments\":{\"message\":\"hello junctio\"}," "${TOOL%%__*}__echo" | jq -r '.result.content[0].text'

A fresh deploy prints health: 200, anonymous api: 401, attach server: 200, create endpoint: 201, the first tool name (the first run waits while bunx downloads the example server) and Echo: hello junctio.

Why Deploy Junctio on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying Junctio on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.

  • Agent-ready - generated admin token, contract block and one working script; no setup form.
  • One URL for every MCP server - clients connect once instead of configuring each server.
  • State survives redeploys - servers, endpoints and keys live in SQLite on a volume.
  • Locked from the first request - admin setup needs the token, endpoints need an API key or OAuth.
  • Public HTTPS endpoint - claude.ai and Claude Desktop connectors can reach it with the built-in OAuth server.

Common Use Cases

  • One MCP endpoint for a team of coding agents - Claude Code, Codex and Cursor share the same tool set and the same keys.
  • Remote access to local-only MCP servers - run stdio servers on the gateway and reach them over HTTPS.
  • Per-client access control - one API key per endpoint, a rate limit per minute, and a request log of every call.

Dependencies for Junctio Hosting

  • One Railway volume mounted at /data, created by the template.

Deployment Dependencies


Template Content

More templates in this category

View Template
Chat Chat
Chat Chat, your own unified chat and search to AI platform.

okisdev
117
View Template
Weaviate
Vector database with hybrid search and an API key-protected API

zer0person
1
View Template
Möbius v0.1 Personal AI OS
Self-hosted AI agent that builds and runs apps for you, with memory.

bento
1