Skip to main content

MCP gateway Source

ActionRail can use a customer’s existing MCP gateway instead of replacing it. The SDK calls one configured verification tool through MCP Streamable HTTP, then evaluates the returned record with the same match engine used by other Sources.

The verification tool is called outside the agent’s exposed tool surface, so it does not recursively pass through ActionRail.

Run the local example

The packaged example starts a temporary MCP server on loopback, exposes one read-only payment lookup tool, and calls it through the real Streamable HTTP transport. It allows an owned payment, blocks a cross-customer payment, and proves the blocked refund function did not execute.

python3 -m venv .venv
source .venv/bin/activate
python -m pip install actionrail
actionrail-mcp-quickstart

Expected output:

✓ Started a local MCP Streamable HTTP server
✓ Discovered a verification tool marked read-only
✓ Owned payment decision: allow
✓ Cross-customer payment decision: block
✓ The blocked refund function did not execute

No external gateway, Console, account, or model API key is required. The implementation is available in actionrail/mcp_quickstart.py.

Source configuration

sources:
stripe-read-gateway:
adapter: mcp
endpoint: https://gateway.internal/mcp
headers:
Authorization: Bearer ${env:MCP_GATEWAY_TOKEN}
tool: stripe.get_charge
arguments:
charge_id: "{value}"
customer_id: "{customer_id}"
select: data.charge
timeout: 10
require_read_only: true
FieldDefaultDescription
endpointComplete Streamable HTTP MCP URL.
headers{}Transport headers with locally resolved secret references.
toolOne fixed verification tool exposed by the gateway.
arguments{"value": "{value}"}JSON object template for tool arguments.
selectemptyDot path into the tool result; numeric segments can index lists.
timeout101–300 seconds in Console-managed configuration.
require_read_onlytrueMust remain true.

An exact placeholder preserves the original JSON type:

arguments:
amount: "{amount}" # number remains a number
customer: "customer:{customer_id}" # interpolation produces text

Unknown placeholders are rejected before the gateway call.

Rule check

The Source already owns the endpoint, tool, arguments, and response selection. The rule references the Source and supplies match conditions:

ground:
checks:
- source: stripe-read-gateway
match:
- column: customer_id
ctx: customer_id
- column: status
value: succeeded

This convention avoids duplicating gateway wiring across agent rules.

Tool discovery and results

On each verification, the adapter initializes an MCP session, discovers the configured tool across paginated listings, checks its annotation, and calls it.

The adapter prefers structuredContent. For compatibility, it can parse JSON text content when structured content is absent. An MCP isError result becomes a Source error and follows the check’s retry and on_error behavior.

Read-only is defense in depth

ActionRail requires the gateway tool to declare annotations.readOnlyHint: true. Local and Console-managed configuration cannot disable this requirement.

An MCP annotation is not authorization

readOnlyHint is metadata supplied by the server. It does not prevent a mislabeled tool from causing an effect. Use a gateway identity that can invoke only audited read tools, and enforce that permission at the gateway or downstream service.

Recommended controls:

  • a dedicated ActionRail gateway credential;
  • an allowlist containing only required verification tools;
  • server-side validation that those tools are side-effect free;
  • tenant scoping derived from trusted gateway identity, not model arguments;
  • gateway audit logs and bounded timeouts;
  • network access only from the agent runtime.

ActionRail adds grounding behind the existing gateway; it is not itself an MCP gateway or a replacement for gateway authentication, routing, rate limiting, or tool authorization.