5 min read

McpVanguard on Railway#

This is the minimum public setup for running the current McpVanguard SSE gateway on Railway so an external evaluator can validate the deployment, auth path, and remote MCP connection flow without local support.

What This Solves#

  • Brings up a remote McpVanguard gateway with the start command the repo ships today.
  • Exposes a stable public health check.
  • Makes the auth header and SSE endpoint explicit.
  • Calls out the current semantic and behavioral caveats before evaluation starts.

Uses#

  • Railway
  • SSE
  • MCP

Current Railway Fit#

ConcernCurrent behavior
Web portvanguard sse reads Railway's PORT automatically and defaults to 8080
Public routesGET /health is public; GET /sse and POST /messages are the main remote MCP routes
AuthWhen VANGUARD_API_KEY is set, /sse and /messages accept either X-Api-Key or Authorization: Bearer ...
Start commandRailway config starts vanguard sse --server "$MCP_SERVER_COMMAND" --semantic --behavioral
Semantic healthThe Railway start command enables semantic checks, so /health can degrade if no cloud provider is configured and Ollama is unreachable
Behavioral stateSingle-instance deploys work with in-memory state; multi-instance deployments need Redis for shared state
Health is deeper than liveness

Railway can use GET /health as the public readiness path, but this endpoint checks more than process liveness. With the current start command, semantic and behavioral layers are enabled, so missing semantic provider configuration can push the endpoint to 503 even if the web process itself is up.

The repository already includes Railway and Nixpacks config. The effective start command is:

Bash
vanguard sse --server "$MCP_SERVER_COMMAND" --semantic --behavioral

That command works on Railway because the SSE server binds to 0.0.0.0 and reads PORT directly from the environment.

Required Variables#

VariableRequiredWhy
MCP_SERVER_COMMANDYesThe MCP server process Vanguard wraps and protects
VANGUARD_API_KEYYesProtects the public /sse and /messages routes
VANGUARD_MODERecommendedSet enforce for blocking or audit for shadow-mode evaluation

Example MCP_SERVER_COMMAND:

Bash
npx @modelcontextprotocol/server-filesystem /app/data

Optional Variables#

VariableWhen to set itEffect
VANGUARD_OPENAI_API_KEYYou want semantic scoring without self-hosting OllamaEnables the built-in OpenAI semantic provider
VANGUARD_SEMANTIC_CUSTOM_URLYou have an OpenAI-compatible providerPoints semantic scoring at a custom backend
VANGUARD_SEMANTIC_CUSTOM_KEYYour custom provider requires authAuthenticates the custom semantic backend
VANGUARD_SEMANTIC_CUSTOM_MODELYour custom provider needs an explicit modelSelects the model used for semantic scoring
VANGUARD_OLLAMA_URLYou have reachable Ollama infrastructureLets semantic health pass through Ollama instead of a cloud provider
VANGUARD_REDIS_URLYou plan to run more than one replicaShares behavioral session state across instances
VANGUARD_VEX_URLYou want VEX-backed audit receiptsSends audit events to a VEX deployment
VANGUARD_VEX_KEYYour VEX deployment requires authAuthenticates the VEX audit write path
VANGUARD_LOG_LEVELYou need more deployment detailRaises log verbosity
VANGUARD_AUDIT_FORMATYou want machine-readable audit logsSwitches logs to JSON output

First Smoke Test#

Once Railway assigns a public domain, check the public health endpoint first:

Bash
curl -sS https://your-project.up.railway.app/health

Expected response shape:

JSON
{
  "status": "ok",
  "version": "1.8.1",
  "layers": {
    "l1_rules": "ok",
    "l2_semantic": "ok",
    "l3_behavioral": "ok"
  },
  "timestamp": 1711022400.0
}

The exact version, layer values, and timestamp can differ. The stable contract is that status, version, layers, and timestamp are present.

Step 2: Connect a Remote MCP Client#

Download the example client config:

Exact config shape:

JSON
{
  "mcpServers": {
    "vanguard-remote": {
      "url": "https://your-project.up.railway.app/sse",
      "headers": {
        "X-Api-Key": "replace-with-your-vanguard-api-key"
      }
    }
  }
}

Artifact produced:

  • A remote MCP client entry that routes tool calls through the Railway-hosted McpVanguard gateway

How to inspect it:

  • Confirm the client points at /sse, not the root domain
  • Confirm the header name is X-Api-Key if you are using key-based auth
  • If your client prefers bearer auth, send the same key as Authorization: Bearer <key>

Step 3: Verify the Protected Message Path#

Once a client is attached, McpVanguard will receive MCP traffic on:

TEXT
GET /sse
POST /messages

Expected behavior:

  • Authorized requests are proxied to the wrapped MCP server
  • Blocked calls return a JSON-RPC error before the underlying MCP server sees them
  • GET /health remains public for deployment checks

Evaluation Flow After Deploy#

  1. Run the public /health check.
  2. Attach a remote MCP client using the /sse URL and X-Api-Key header.
  3. Confirm the wrapped server responds through Vanguard.
  4. If you need cryptographic audit receipts, pair the deployment with Deploy on Railway for the VEX service.

Current Limitations#

  • The Railway config enables --semantic by default. If no cloud semantic provider is configured and no reachable Ollama instance exists, /health can return 503.
  • Multi-instance deployments should use VANGUARD_REDIS_URL; otherwise behavioral state is isolated per instance.
  • The public evaluation path is SSE-first. Stdio examples still exist, but they are not the Railway integration surface.
  • MCP_SERVER_COMMAND must be fully runnable inside the Railway container; if it depends on local desktop paths or host-only binaries, the deploy will start but the wrapped MCP server will not behave correctly.

Railway References#

Found something unclear or incorrect?Report issueor useEdit this page
Edit this page on GitHub