AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
MCP verified Apache-2.0 Self-run

Contextforge Gateway Rs

mcp-contextforge-gateway-rs-contextforge-gateway-rs · by contextforge-gateway-rs

ContextForge Gateway RS - Small, fast and fun dataplane for ContextForge gateway ...like Ford Focus RS

No reviews yet
0 installs
22 views
0.0% view→install

Install

$ agentstack add mcp-contextforge-gateway-rs-contextforge-gateway-rs

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/mcp-contextforge-gateway-rs-contextforge-gateway-rs)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude DesktopCursorWindsurf

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Contextforge Gateway Rs? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

ContextForge Dataplane

Architecture, configuration, and operations documentation lives in [The ContextForge Gateway Book](docs/book/src/SUMMARY.md) under docs/book. Build it locally with mdbook serve docs/book; see [docs/book/README.md](docs/book/README.md) for details.

Running

  1. Start Redis and gateways
docker compose -f docker/docker-compose-local.yaml up -d

Check Redis and backend status:

docker compose -f docker/docker-compose-local.yaml ps redis gateway-one gateway-two
  1. Run gateway
    cargo run --bin contextforge-gateway-rs -- --address 0.0.0.0:8001 --redis-port 6379 --redis-address 127.0.0.1 --token-verification-public-key assets/jwt.key.pub  --token-verification-private-key assets/jwt.key --number-of-cpus 16 --redis-mode=plain-text --upstream-connection-mode=plain-text-or-tls

This should spin up Redis instance and two mcp-gateways: a simple counter and a conformance test server from mcp-rust-sdk

  1. Get a test JWT token
curl --request GET \
  --url http://127.0.0.1:8001/contextforge-rs/admin/tokens/admin@example.com \
  --header 'accept: application/json' \  
  --header 'content-type: application/json'
  1. Use the token to add a test user to Redis
curl --request POST \
  --url http://127.0.0.1:8001/contextforge-rs/admin/userconfigs/admin@example.com \
  --header 'authorization: Bearer {{token}}' \
  --header 'content-type: application/json' \
  --data '{
  "virtual_hosts": {
    "c0ffee00f001f00lf00ldeadbeefdead": {
      "backends": {
        "gateway-one": {
          "name": "gateway-one",
          "url": "http://127.0.0.1:5555/mcp",
          "transport": "STREAMABLEHTTP",
          "passthrough_headers": [],
          "allowed_tool_names": [],
          "allowed_resource_names": [],
          "allowed_prompt_names": []
        },
        "gateway-two": {
          "name": "gateway-two",
          "url": "http://127.0.0.1:5556/mcp",
          "transport": "STREAMABLEHTTP",
          "passthrough_headers": [],
          "allowed_tool_names": [],
          "allowed_resource_names": [],
          "allowed_prompt_names": []
        }
      }
    }
  }
}'
  1. Spin up MCP Inspector to test the calls

Runtime CPEX Plugins

Runtime CPEX plugins are disabled by default. Enable hook execution when starting the gateway:

cargo run --release --bin contextforge-gateway-rs -- \
  --address 0.0.0.0:8001 \
  --redis-port 6379 \
  --redis-address 127.0.0.1 \
  --token-verification-public-key assets/jwt.key.pub \
  --token-verification-private-key assets/jwt.key \
  --number-of-cpus 16 \
  --redis-mode=plain-text \
  --upstream-connection-mode=plain-text-or-tls \
  --runtime-plugins-enabled true

Plugin configuration is stored in Redis at key ContextForgeGatewayRuntimePluginConfig. The value can be JSON or MessagePack with version: 1 and cpex containing the CPEX config. When runtime plugins are enabled with Redis config, this key must exist before startup. The gateway reloads that key while running, builds a new initialized CPEX runtime, and swaps the runtime registry to the new immutable PluginManager. The existing PluginManager is not mutated after initialization.

This integration currently passes only tool payloads. CPEX configs that enable route-based plugin selection, plugin directories, global policies/defaults, non-tool hooks, or plugin conditions are rejected in this PR. Redis write access to this key is a control-plane trust boundary because it controls which registered hooks run.

Payload Marker Demo

This demo uses the test-plugins feature, which includes the demo plugin crates from cpex-plugins-rs. The plugin must be included in the gateway build before the gateway starts. Redis runtime registration activates already-registered factories; it does not load new Rust code into a running process.

Build the gateway with the demo plugin factories:

cargo check -p contextforge-gateway-rs --features test-plugins

The test-plugins feature registers those demo plugin factories through the gateway's generic CMF factory adapter.

Start Redis and the sample MCP backends:

GATEWAY_CPU_LIMIT=1 \
GATEWAY_CPU_RESERVATION=0.5 \
GATEWAY_MEM_LIMIT=1G \
GATEWAY_MEM_RESERVATION=512M \
docker compose -f docker/docker-compose-local.yaml up -d

Check Redis and backend status:

docker compose -f docker/docker-compose-local.yaml ps redis gateway-one gateway-two

Register the payload marker config in Redis before starting the enabled gateway:

docker compose -f docker/docker-compose-local.yaml exec -T redis redis-cli SET ContextForgeGatewayRuntimePluginConfig '{
  "version": 1,
  "cpex": {
    "plugins": [
      {
        "name": "payload-marker",
        "kind": "contextforge/payload-marker",
        "hooks": ["cmf.tool_post_invoke"]
      }
    ]
  }
}'

Run only one gateway process on port 8001 at a time. Stop the current gateway with Ctrl-C before switching between disabled and enabled plugin runs.

Start the gateway with runtime plugins disabled for a baseline run:

cargo run --release --features test-plugins --bin contextforge-gateway-rs -- \
  --address 0.0.0.0:8001 \
  --redis-port 6379 \
  --redis-address 127.0.0.1 \
  --token-verification-public-key assets/jwt.key.pub \
  --token-verification-private-key assets/jwt.key \
  --number-of-cpus 16 \
  --redis-mode=plain-text \
  --upstream-connection-mode=plain-text-or-tls \
  --runtime-plugins-enabled false

Start the gateway with runtime plugins enabled for the marker run:

cargo run --release --features test-plugins --bin contextforge-gateway-rs -- \
  --address 0.0.0.0:8001 \
  --redis-port 6379 \
  --redis-address 127.0.0.1 \
  --token-verification-public-key assets/jwt.key.pub \
  --token-verification-private-key assets/jwt.key \
  --number-of-cpus 16 \
  --redis-mode=plain-text \
  --upstream-connection-mode=plain-text-or-tls \
  --runtime-plugins-enabled true

Get a token:

TOKEN=$(curl --silent --show-error --request GET \
  --url http://127.0.0.1:8001/contextforge-rs/admin/tokens/admin@example.com \
  --header 'accept: application/json' \
  --header 'content-type: application/json')

Create the gateway user config:

curl --silent --show-error --request POST \
  --url http://127.0.0.1:8001/contextforge-rs/admin/userconfigs/admin@example.com \
  --header "authorization: Bearer ${TOKEN}" \
  --header 'content-type: application/json' \
  --data '{
    "virtual_hosts": {
      "c0ffee00f001f00lf00ldeadbeefdead": {
        "backends": {
          "gateway-one": {
            "name": "gateway-one",
            "url": "http://127.0.0.1:5555/mcp",
            "transport": "STREAMABLEHTTP",
            "passthrough_headers": [],
            "allowed_tool_names": [],
            "allowed_resource_names": [],
            "allowed_prompt_names": []
          }
        }
      }
    }
  }'

Open an MCP session:

INIT_HEADERS=$(mktemp)
curl --silent --show-error \
  --dump-header "${INIT_HEADERS}" \
  --url http://127.0.0.1:8001/contextforge-rs/servers/c0ffee00f001f00lf00ldeadbeefdead/mcp \
  --header "authorization: Bearer ${TOKEN}" \
  --header 'content-type: application/json' \
  --header 'accept: application/json, text/event-stream' \
  --data '{
    "jsonrpc": "2.0",
    "id": 0,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-11-25",
      "capabilities": {},
      "clientInfo": { "name": "curl", "version": "0.1.0" }
    }
  }'
SESSION_ID=$(awk 'tolower($1) == "mcp-session-id:" { gsub("\r", "", $2); print $2 }' "${INIT_HEADERS}")
curl --silent --show-error \
  --url http://127.0.0.1:8001/contextforge-rs/servers/c0ffee00f001f00lf00ldeadbeefdead/mcp \
  --header "authorization: Bearer ${TOKEN}" \
  --header "mcp-session-id: ${SESSION_ID}" \
  --header 'mcp-protocol-version: 2025-11-25' \
  --header 'content-type: application/json' \
  --header 'accept: application/json, text/event-stream' \
  --data '{"jsonrpc":"2.0","method":"notifications/initialized"}'

Send a tool request:

curl --silent --show-error \
  --url http://127.0.0.1:8001/contextforge-rs/servers/c0ffee00f001f00lf00ldeadbeefdead/mcp \
  --header "authorization: Bearer ${TOKEN}" \
  --header "mcp-session-id: ${SESSION_ID}" \
  --header 'mcp-protocol-version: 2025-11-25' \
  --header 'content-type: application/json' \
  --header 'accept: application/json, text/event-stream' \
  --data '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "gateway-one-say_hello",
      "arguments": {}
    }
  }'

With --runtime-plugins-enabled false, the response content should include only the backend tool result:

hello

With --runtime-plugins-enabled true, the response content should include the backend tool result plus an additional text part:

[cpex:payload-marker]

Tracing & Metrics

The gateway exports OTLP traces and metrics (issue #4721), and a local verification stack (Langfuse + OTel Collector + Prometheus) ships as compose overlays under docker/. The full walkthrough — flags, stack setup, starter PromQL queries, and a debugging checklist — lives in the book: [Telemetry And Diagnostics](docs/book/src/telemetry-and-diagnostics.md).

Performance Tests

As above and then run:

cargo run --release --bin contextforge-load-test -- --host 'http://127.0.0.1:8001' -r 40 -u 120 --run-time 120s --report-file report.html

[Performance reports](./reports)

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.