Repository navigation
feat(providers): support dynamic token grants for MCP endpoints #3658
Copy link
Copy link
Closed
Labels
state:acceptedA maintainer decided OpenShell should pursue this issueA maintainer decided OpenShell should pursue this issue
Description
Summary
Support dynamic provider token grants on endpoints configured with protocol: mcp, so OpenShell can enforce MCP tool-level policy and inject a short-lived credential on the same request.
Problem
OpenShell currently requires a choice between MCP-aware policy enforcement and dynamic credential injection:
- With
protocol: mcp, the Supervisor can parse MCP JSON-RPC and restrict individual tools such asjira_search, but the MCP relay does not execute the provider's dynamictoken_grantbefore forwarding the request. - With
protocol: rest, the REST relay executes the dynamic grant and injects the bearer token, but policy is limited to the HTTP method and endpoint path. OpenShell cannot distinguish one MCP tool from another inside that request.
The REST compatibility path allows the integration to function, but it weakens enforcement from an individual MCP-tool allowlist to an exact-path POST allow rule.
Requested behavior
- Execute configured dynamic token grants for admitted
protocol: mcprequests. - Parse and enforce MCP
tools/listandtools/callpolicy before obtaining or injecting the downstream credential. - Inject the resolved credential using the provider's configured authentication style and header placement.
- Fail closed when policy admission, credential resolution, or credential injection fails.
- Keep credential values and reusable credential handles outside the sandbox and agent-visible state.
- Preserve MCP-specific audit events without recording credential values.
Example configuration
endpoints:
- host: mcp.example.com
port: 443
protocol: mcp
path: /jira/mcp
enforcement: enforce
mcp:
strict_tool_names: true
rules:
- allow:
method: tools/list
- allow:
method: tools/call
params:
name:
glob: jira_search
credentials:
- name: access_token
auth_style: bearer
header_name: Authorization
token_grant:
url: https://credential-broker.example.com/api/token/grant
audience: jira
scopes:
- mcp.read
subject_token:
credential: subject_tokenAcceptance criteria
- An allowed MCP tool call executes its configured dynamic token grant and receives the injected credential.
- A disallowed MCP tool is rejected before credential resolution and upstream execution.
tools/listandtools/callremain subject to MCP-specific policy.- Grant failure, timeout, or an unresolved credential prevents the upstream request.
- The actual credential and any reusable credential handle are never exposed to the sandbox or agent.
- Credential injection remains restricted to the matched scheme, host, port, and path with TLS inspection active.
- Logs and policy events identify the MCP method/tool and grant outcome without exposing token values.
- Tests cover allowed and denied tools, grant success and failure, cache expiry/refresh, redaction, and cross-sandbox isolation.
Example use case
An agent calls a Jira-compatible MCP endpoint. OpenShell admits only jira_search, obtains a user-delegated short-lived bearer token through the configured token grant, injects it into Authorization, and forwards the request. The agent never receives the bearer token.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
state:acceptedA maintainer decided OpenShell should pursue this issueA maintainer decided OpenShell should pursue this issue
Activity
Pranjulcr7 commentedon Sep 29, 2026
Hi, I looked at where this sits in the code. In
l7/relay.rs,relay_with_inspectionsends MCP endpoints torelay_jsonrpc, which runs the MCP policy check and then forwards the request without callingtoken_grant_injection::inject_if_needed.relay_restdoes call it after admission, so the fix is probably to add the same step on the JSON-RPC path once a request is allowed.relay_with_route_selectionlooks like it has the same gap, which I think is what #3657 is about, so one change might cover both.Two things I wasn't sure about: for a batched JSON-RPC request, should every call be admitted before any grant runs? And should
tools/listget a token too, or onlytools/call?Happy to work on this once it's triaged, if you're open to an outside contributor.
Pranjulcr7 commentedon Sep 29, 2026
I pushed a [reproduction with instructions and test output](https://github.com/Pranjulcr7/OpenShell/blob/50656645074372d17e299715aed5faa7111ada7d/reproductions/3658.md).
The allowed MCP call reaches upstream without invoking the grant resolver or adding Authorization. The same request under REST gets the token. A denied MCP tool returns 403 without resolving credentials or forwarding anything.
Two controls pass; the admitted-MCP test fails on the missing grant. This uses the existing in-memory fixtures, with no production changes. Happy to work on the implementation once the scope is confirmed.
johntmyers commentedon Oct 6, 2026
This looks reasonable to support. MCP policy enforcement and dynamic authentication should work together: admit the MCP operation first, then resolve and inject the credential before forwarding.
Suggested implementation guidance:
Tests should cover actual proxy dispatch for single and multiple endpoints, allowed and denied tools, mixed batches where supported, middleware transformations, grant failures/timeouts, cache refresh, provider updates, and ambiguous or mismatched credential bindings.
Two clarifications to the issue: the current profile field is token_grant.token_endpoint, rather than url; and allowing tools/list controls access to that operation—it does not imply filtering disallowed tools from the response.
johntmyers commentedon Oct 8, 2026
closing for #4152 which covers MCP paths