Control tool access
Every MCP server in Catalyst has an access policy — an allow-list that decides which caller agents may use which tools. The policy is created automatically with each MCP server and starts deny-all: no caller can discover or call any tool until you grant access. You change it at runtime with the diagrid mcpserver access commands — no redeploy, no code change.
A MCP server access policy checks two things:
- Tool grants decide which caller agent can use which tool.
- A user identity requirement decides whether a call must also say which person it acts for.
Catalyst enforces the policy at its MCP proxy endpoint, on the hop between the caller and the server:
- Discovery is filtered.
tools/listreturns only the tools the calling agent is granted, so an unauthorized tool is invisible rather than merely un-callable. - Calls are gated. An unauthorized
tools/callis rejected with403 Forbiddenbefore the request reaches the upstream server. With a full deny-all policy the MCP session itself is refused.
Prerequisites
- An
MCPServerconnection in your project. - The Diagrid CLI, authenticated with
diagrid login.
See the current policy
A new MCP server denies everything. Inspect its policy at any time:
# Full detail for one server
diagrid mcpserver access get mcp-server
# Every server's policy in the project
diagrid mcpserver access list
For a brand-new server, get reports a deny-all policy with no rules.
Grant access to specific tools
Grant an agent access to one or more named tools. A rule is an allow-list entry: it names a caller (an agent, or * for any) and the tools it may use (names, or * for all).
diagrid mcpserver access grant mcp-server \
--caller analyst-agent \
--allow-tools add,echo \
--wait
analyst-agent can now discover and call add and echo. Any other tool stays hidden in tools/list and returns 403 if called. Every other caller is still denied.
A policy change is rolled out to the data plane before it takes effect, which takes a few seconds. Apply one change at a time and pass --wait, or preview a verdict instantly with access test.
Open a server to all callers
To allow every caller every tool — useful for a trusted internal server — use wildcards:
diagrid mcpserver access grant mcp-server --caller "*" --allow-tools "*" --wait
Revoke access
Remove specific tool grants, or a caller's entire rule:
# Remove only the echo grant; analyst-agent keeps add
diagrid mcpserver access revoke mcp-server --caller analyst-agent --allow-tools echo
# Remove the caller's whole rule
diagrid mcpserver access revoke mcp-server --caller analyst-agent --all
Preview a verdict
access test checks a sample call locally against the same tool grants the data plane enforces. It does not call the upstream server and does not wait for a rollout, so it's the fastest way to confirm a rule before your agent runs:
diagrid mcpserver access test mcp-server \
--caller analyst-agent \
--tool get_weather_alert
# → ALLOWED: ... or DENIED: ...
access test only checks tool grants. If the server also requires a user identity, Catalyst rejects any call without one before it looks at the grants. So a call can get ALLOWED here and still be rejected. To see whether the server requires a user identity, run:
diagrid mcpserver access user-identity get mcp-server
Require a user identity
Tool grants control which agent can call a tool, but not which person the agent acts for. By default, Catalyst doesn't pass a user identity to the server at all. This command turns that on and makes it required:
diagrid mcpserver access user-identity require mcp-server --wait
Now every call to mcp-server must include a verified user. Catalyst rejects a call without one with 401 oauth.missing_token, before it checks any tool grants.
To see both checks in one place, use diagrid mcpserver access get, which shows a User identity: line next to the grants, or diagrid mcpserver access list, which shows whether each server in the project requires a user.
To require specific scopes, roll this out without breaking existing callers, or look up the error codes a rejected call returns, see Require a user identity.
How the policy is structured
Under the hood, each MCP server has exactly one MCPServerAccessPolicy resource (cra.diagrid.io/v1beta1), named the same as the server and lifecycle-locked to it — Catalyst creates and deletes it with the server, and you edit its rules and its identity requirement through the CLI. You don't author this resource by hand; the structure below is what the access commands manage for you.
apiVersion: cra.diagrid.io/v1beta1
kind: MCPServerAccessPolicy
metadata:
name: mcp-server # matches the MCPServer name (1:1)
spec:
mcpServerRef: mcp-server
rules: # empty ⇒ deny everything
- callers:
- appID: analyst-agent # exact App ID, or "*" for any caller
grants:
- capability: tools # the unit of authorization today
names: ["add", "echo"] # tool names, or "*" for all
auth: # if omitted, no user identity is required
spiffeJWT:
requireUser: true
requiredScopes: ["crm.read"]
A call is allowed only if some rule matches both the caller and the tool; otherwise it is denied. The grant and revoke commands change spec.rules, and the user-identity commands change spec.auth.
What's next
- Require a user identity — make each call say which user it acts for, and roll it out without breaking callers.
- Connect an MCP client — point your agent at the server and see the policy take effect.
- Authentication — how callers authenticate to Catalyst and Catalyst to the upstream server.
- Security and trust posture — the identity, authorization, and audit model behind these controls.