Install
$ agentstack add mcp-contextforge-gateway-rs-contextforge-gateway-rs ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo 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.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
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 →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
- 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
- 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
- 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'
- 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": []
}
}
}
}
}'
- 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.
- Author: contextforge-gateway-rs
- Source: contextforge-gateway-rs/contextforge-gateway-rs
- License: Apache-2.0
- Homepage: https://ibm.github.io/mcp-context-forge/latest/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.