Remote MCP providers

mrl rlm can mount read-only tools from a remote MCP Streamable HTTP server. The trusted mrl host owns endpoint policy, OAuth or bearer secrets, MCP session state, cancellation, and response limits. Generated Python receives ordinary Droste capability bindings—not MCP URLs, credentials, session IDs, transport envelopes, or raw tool results.

This integration is for local and customer-controlled VPC execution. Hosted mrl rlm --remote and /rlm/execute reject remote MCP configuration. Run mrl inside the network that is allowed to reach the MCP server; do not copy private endpoints or credentials into a hosted request.

Configure a source

Create a mode-0600 JSON file such as docs-mcp.json:

{
  "name": "docs",
  "config": {
    "endpoint": "https://mcp.example.com/v1",
    "allowed_endpoints": ["https://mcp.example.com/v1"],
    "tenant_id": "project-123",
    "auth": {
      "type": "bearer",
      "token_ref": "docs-access"
    },
    "allowed_tools": ["search", "read_document"],
    "bindings": {
      "search": "search",
      "read_document": "read_document"
    },
    "effects": {
      "search": "read",
      "read_document": "read"
    },
    "budget_classes": {
      "search": "data.search",
      "read_document": "data.read"
    },
    "policy_metadata": {
      "search": {"read_only": true},
      "read_document": {"read_only": true}
    },
    "source_description": "Approved product documentation."
  },
  "secrets": {
    "docs-access": "DOCS_MCP_TOKEN"
  },
  "allowed_networks": []
}

The config object is the released Droste MCP HTTP contract. ModelRelay deliberately passes it through instead of maintaining a second provider schema.

secrets maps each logical reference used by config.auth to an environment-variable name. Secret values are not accepted in the file:

export DOCS_MCP_TOKEN='replace-with-the-token'

mrl rlm \
  "Compare the current retention and deletion policies" \
  --mcp-config ./docs-mcp.json

mrl reads the value into a tenant/source/reference-scoped host broker and removes DOCS_MCP_TOKEN from the Python subprocess environment. The runner configuration contains only docs-access. The MCP transport asks the authenticated loopback broker for that reference when it needs a bearer token.

Local RLM still runs as your OS user; it is not a general sandbox for unrelated files or services available to that account. The MCP boundary specifically prevents generated code from receiving MCP transport configuration, credentials, sessions, or raw protocol payloads. Run VPC deployments under a dedicated least-privilege service account.

Inside generated code, the approved binding names are available under the configured source:

matches = docs.search(query="retention policy")
policy = docs.read_document(id=matches[0]["id"])

Use --mcp-config more than once to mount multiple providers. If no SQL source already supplies the default, select one explicitly:

mrl rlm "Reconcile the policy with open customer requests" \
  --mcp-config ./docs-mcp.json \
  --mcp-config ./tickets-mcp.json \
  --default-source docs

Source names must be unique Python identifiers. Each run acquires independent MCP sessions and closes them with the runner, so state cannot cross a run or tenant boundary.

OAuth client credentials

For MCP servers using OAuth protected-resource discovery, keep client credentials behind logical references as well:

{
  "type": "oauth_client_credentials",
  "client_id_ref": "docs-client-id",
  "client_secret_ref": "docs-client-secret",
  "resource_metadata_url": "https://mcp.example.com/.well-known/oauth-protected-resource/v1",
  "authorization_server": "https://login.example.com",
  "token_endpoints": ["https://login.example.com/oauth/token"],
  "scopes": ["docs.read"]
}

Map both references in the envelope’s secrets object. Droste performs discovery only against the exact configured resource, issuer, and token-endpoint allowlists. Access and refresh tokens remain in the trusted transport session.

Policy and limits

The configuration must explicitly classify every allowed tool:

  • allowed_tools is the exact discovery allowlist. Unexpected or missing tools fail acquisition.
  • bindings defines the generated Python names.
  • effects must classify every tool as read. mrl rejects effectful tools because this surface has no user-confirmation policy; never mislabel a mutating tool to bypass that gate.
  • budget_classes participates in Droste capability budgeting and audit facts.
  • policy_metadata carries ModelRelay/Droste admission facts without trusting MCP annotations.

Optional hard bounds include startup_timeout_ms, request_timeout_ms, close_timeout_ms, max_frame_bytes, max_descriptor_bytes, max_result_bytes, max_tool_pages, max_tools, max_in_flight, reconnect_attempts, and backoff_ms. Defaults are conservative; raise them only for a measured requirement.

allowed_networks is ModelRelay host policy, not Droste provider configuration. Leave it empty for public endpoints. A VPC deployment may list only the canonical private CIDRs that contain the approved MCP endpoint, for example "allowed_networks": ["10.40.8.0/24"]. Resolved addresses outside those exact networks still fail closed.

The transport requires canonical HTTPS endpoints, pins resolved addresses for each connection, denies private and metadata networks by default, rejects redirects, bounds JSON/SSE frames, reconciles cancellation and deadlines, and normalizes results before the capability broker sees them. mrl rlm --json reports data_source_requests for host attribution; normalized capability metrics remain content-free.

Deployment support

Mode Support Secret owner Network boundary
Local mrl rlm Supported Local mrl host broker Current machine
Customer VPC mrl rlm Supported VPC mrl host broker Customer VPC policy
Hosted mrl rlm --remote / /rlm/execute Not supported; fails closed N/A No MCP endpoint is accepted

Hosted support requires a connector-neutral trusted provider sidecar that feeds Droste’s provider bridge. It must not move MCP transport or auth into the untrusted Pyodide interpreter. Until that substrate exists, use local/VPC mode or wrapper_v1 for an existing hosted wrapper.