Skip to content
API Reference
Get Started
Use Cases

Allow one tool, deny the next

Permit an agent one tool on an MCP server and refuse the adjacent one, so access is a property of policy rather than of the agent behaving as expected.

An MCP server usually exposes many tools, and access to it is usually all or nothing. If an agent needs one of those tools, it gets the write ones too, and nothing but the agent’s own restraint stands between them.

Access to an MCP server tends to be a single decision. The agent can reach the server, and the server exposes whatever it exposes.

That collapses a set of very different operations into one grant. A server that reads issues and also closes them offers both to anyone who can reach it. The agent that needed the first now holds the second, and the difference between a summary and a deletion is a matter of which tool the model decides to call.

Restraint is where the control usually lives, and it is the wrong place for it. A prompt that says only read, a system message, a carefully scoped instruction: all of those are requests rather than rules, and none of them survives a model that misreads the situation or a prompt that was crafted to redirect it.

Splitting the server into two servers is the workaround, and it multiplies the thing you have to run. Every new distinction becomes another deployment, another registration, and another URL for someone to configure, which is why teams stop drawing distinctions.

flowchart LR
    A[Your Agent] -->|"one grant to the server"| B[MCP Server]
    B --> C[read_issue]
    B --> D[close_issue]
    B --> E[delete_project]
  • One MCP server exposes tools you would answer differently if asked about individually
  • The distinction you need is per tool rather than per server
  • A reviewer wants the boundary enforced somewhere they can inspect, rather than described in a prompt
  • You would rather refuse a call than rely on an agent not making it

Suppose an internal MCP server wraps your ticketing system. An assistant should be able to read tickets and add comments. It should not be able to close or delete them. Same server, same agent, and the difference should hold whether or not the model behaves as intended.

Where the tool is fine but the caller is the question, the pattern you want is per-user access. See Act as the user who asked and Same agent, different user.

Where the agent runs tools locally rather than through a server, there is no gateway in the path and the enforcement point is the agent’s own tool-call loop. See Govern a coding agent.

Where the distinction you need is inside a single tool, such as permitting a query but constraining which rows it returns, the Resource enforces that itself.

Register the MCP server behind a Unified Access Gateway and the gateway becomes the point where each call is decided.

Rather than one grant to the server, policy names the individual tool. The action Cedar evaluates is the method plus the tool name, so permit on one tool and silence on the next produces exactly the boundary you wanted, and default deny means silence is a refusal.

The decision happens before the call reaches the upstream. A refused tool call does not arrive at your ticketing system and get rejected there; it stops at the gateway, and the refusal is a policy record rather than an application error.

flowchart LR
    A[Your Agent] -->|"tools/call"| B[Unified Access Gateway]
    B -->|"evaluate action + tool name"| C{Policy}
    C -->|permit| D[MCP Server]
    C -->|no match, default deny| E[Refused and recorded]
  1. Your MCP server is registered as an upstream of a Unified Access Gateway, so agents reach it through one gateway URL.
  2. You write fine-grained policies naming individual tools, where the Cedar action carries the MCP method and the tool name together.
  3. On each call the gateway evaluates policy against the invoking identity, the upstream, and that specific tool.
  4. A permitted call is forwarded. One that matches no permit is refused under default deny, without reaching the upstream.
  5. The Activity feed and the Audit Log record the policy decision, so an allow and a refusal are equally legible.

The boundary is a rule rather than a hope. Whether the agent calls the adjacent tool stops being a question about the model and becomes a question about policy, which is a thing you can read, review, and change without redeploying an agent.

One server can serve several different levels of access. The distinction you were going to draw by running two deployments is drawn in policy instead, against the same upstream and the same URL.

Refusals are evidence. A denied tool call is a policy record naming the identity, the upstream, and the decision, so “prove this agent could not do that” is answerable from the log rather than from the prompt.

You write policy per tool, which means knowing the tool names. The names come from the server, so a server that renames a tool changes what your policy matches. Treat tool names as an interface and review policy when an upstream version changes.

Tools are the surface the gateway covers. Requests for other MCP surfaces, such as prompts or resources, are answered with a method-not-found error rather than forwarded, so a server whose value is in those surfaces is not the case to start with. The prompts and resources section covers the intended shape.

The decision is recorded; the execution is not. What lands in the audit trail is the authorization decision carrying the tool it was made against. The downstream effect of a permitted call belongs to the upstream system’s own logs, so an end-to-end story usually joins the two.

Off-the-shelf and custom upstreams differ in what policy can express. A server built with the SDKs can carry distinctions of your own design. One you did not write exposes whatever tools it exposes, and policy works with those names rather than with finer scopes inside them.

Enforcement, and at the gateway rather than in the agent. A refused call does not reach the upstream. That matters for a reviewer, because the boundary does not depend on the agent’s cooperation or on the upstream implementing anything.

What happens if the gateway cannot tell which tool is being called?

Section titled “What happens if the gateway cannot tell which tool is being called?”

It refuses. The gateway pins the operation it authorized against the full request before forwarding, and a request whose contents do not match what was authorized is rejected rather than passed through. The failure direction is shut, which is the answer a security reviewer is looking for when they ask about parser edge cases.

Can we scope inside a tool, for example read-only against a provider’s API?

Section titled “Can we scope inside a tool, for example read-only against a provider’s API?”

Not through this mechanism. Policy decides which tool may be called, and constraining what a single tool may do inside the upstream is the upstream’s own concern. Where a provider offers finer scopes of its own, those are configured on the Provider rather than expressed as a tool policy.

How is this different from what our MCP client already does?

Section titled “How is this different from what our MCP client already does?”

A client’s allow list lives with the client and is only as good as the client’s configuration on each machine. This decision is made centrally, applies to every agent reaching the gateway, and produces a record. Where you need both, the two compose: the client narrows what the agent is offered, and policy decides what it may actually call.

  • A deployment server where read and plan are permitted and apply is not
  • A finance MCP server where lookups are broadly available and anything that moves money is not
  • A customer-data server where an assistant may search but not export
  • A shared internal server used by several agents, each permitted a different subset of its tools

The shape is the same each time. One server exposing operations of genuinely different consequence, and a boundary you want enforced somewhere other than the model’s judgment.