07

MCP Tool and Argument Authorization

Treat every model tool call as an untrusted proposal, filter MCP discovery before it reaches the prompt, and authorize the exact arguments again at execution time.

The enterprise problem and today’s slice

Enterprise problem: A customer may approve a useful connector yet still suffer data loss or disclosure when its dozens of tools, sensitive schemas, and unrestricted arguments are exposed to a model as if reachability were authority.

Whole-course context: The prior slice produced a machine-owned connector binding and credential-free runtime; today consumes that binding and decides which MCP tools the run may discover and which exact call may execute.

Today’s slice: Build a governed tool catalogue, intersect discovery across current policy layers, validate audience-bound MCP credentials, and apply argument- and resource-level policy at the gateway before source-provider authorization.

End-of-day evidence: A reviewer receives a successful in-scope call plus discovery and argument denials, each with full decision inputs, observed outcomes, immutable policy digests, and provider traces where execution occurred.

Still unsolved: Optional user delegation, enterprise-managed MCP consent, human approval of a high-risk intent, and nested agent invocation remain deferred.

Customer use cases

If an MCP server’s entire catalogue is shown merely because the server is reachable, sensitive tool names and schemas leak and the model can propose operations the deployment never needed. Model Context Protocol (MCP) is a protocol through which AI clients discover and call remote tools; discovery and execution are separate authorization decisions. A source-provider access-control list (ACL) is that provider’s own rule set for which identity may reach which resource, and it remains authoritative after platform policy allows a call.

Use case IDActorCustomer jobSuccess outcomeDenial or recovery evidence
D07-UC-01Platform security administratorPublish only reviewed MCP tools to a team deployment and hide everything else from discoverytools/list contains exactly the intersection of server-reviewed, connector-, team-, agent-version-, deployment-, and subject-permitted toolsAn unreviewed or disabled destructive tool is absent from discovery and a direct call to it is independently denied
D07-UC-02Marketing operatorLet an agent post a reviewed message only to approved Marketing channelsAn in-scope call executes with an MCP-resource-specific token and the downstream provider confirms its own ACL decisionA call to an executive or external channel is denied before credential retrieval, while the approved channel remains a positive control

The core invariant is simple: model output is data, not permission. Allowing slack.post_message does not imply authority over every channel, tenant, recipient, text length, visibility, or data class accepted by that tool.

Actor-centred user stories

If users cannot inspect the effective catalogue and policy reason, they cannot distinguish deliberate least privilege from a connector malfunction. These stories require product-visible results for both filtered discovery and the final tools/call decision.

Story IDUse case IDsUser storyObservable acceptance conditions
D07-US-01D07-UC-01As a platform security administrator, I want tool discovery filtered by reviewed and current grants, so that agents neither see nor select destructive or irrelevant capabilitiesPreview shows the exact effective tool set and policy digest; account.delete, user.manage, and unreviewed schema revisions are absent; a direct hidden-tool probe records tool_not_declared_by_agent_version or tool_not_reviewed
D07-US-02D07-UC-02As a Marketing operator, I want the gateway to check channel and content arguments before posting, so that an approved capability cannot escape its intended resourcesThe approved Marketing-channel probe succeeds at Slack; the executive-channel probe is denied before broker lookup; both show actor, resource, scope, conditions, expected and observed outcomes, environment, time, and immutable IDs

MCP annotations such as readOnlyHint, destructiveHint, idempotentHint, or openWorldHint improve description, but they are supplied by the server and are not authorization. A server that labels delete_all_customers read-only does not lower the platform’s reviewed risk classification.

End-to-end product flows

If discovery and calls are tested only through a happy path, stale deployment bindings or malicious server metadata can bypass the intended envelope. Every flow ends in a signed evidence envelope whose minimum fields are actor, resource, scope, precondition, expected result, observed result, environment, timestamp, and immutable run, decision, trace, source, or artifact identifiers.

Flow IDUse case IDsPathTriggerNumbered stepsTerminal evidence
D07-FLOW-01D07-UC-01HappyAdministrator opens “Preview effective MCP tools” for a deployment1. Resolve the current organization, team, subject, immutable agent version, and active deployment.<br>2. Load only tools whose schema digest has passed platform review.<br>3. Intersect connector-enabled, team-enabled, agent-version, deployment, and subject tool sets.<br>4. Return only the surviving names, descriptions, and schemas.<br>5. Seal the inputs and result under one discovery decision ID.Envelope records administrator, MCP server and deployment resource, effective tool scopes, active-policy precondition, expected filtered list, observed exact list, preview environment, timestamp, immutable policy artifact, decision ID, and trace ID
D07-FLOW-02D07-UC-01DeniedAdministrator runs “Probe hidden tool” against a server tool with misleading safe annotations1. Request direct invocation of the hidden tool by name.<br>2. Compare reviewed schema digest and platform risk with the current server schema and annotations.<br>3. Deny before argument processing or credential resolution.<br>4. List tools again to prove the hidden tool remains absent.<br>5. Preserve the server metadata as untrusted evidence.Paired envelopes record administrator actor, hidden tool resource, requested scope, unreviewed or disabled precondition, expected and observed tool_not_reviewed, environment, timestamp, immutable schema digest and trace ID, plus filtered-list positive control
D07-FLOW-03D07-UC-02HappyOperator asks the agent to post the approved campaign message1. Runtime sends its audience-bound run token, connector ID, tool name, and exact arguments to the gateway.<br>2. Revalidate current membership, active deployment, immutable agent manifest, connector binding, and team access.<br>3. Evaluate channel, external-sharing, text-length, data-class, and risk constraints.<br>4. Resolve the already-provisioned service credential.<br>5. Obtain an access token whose audience is the MCP server.<br>6. Call tools/call; let Slack enforce its credential ACL.<br>7. Record both platform decision and provider request result.Envelope records service actor, Marketing channel resource, message.post scope, active binding and allowed-channel preconditions, expected allow, observed Slack success, production-like environment, timestamp, immutable run, decision, trace, schema, and provider request IDs
D07-FLOW-04D07-UC-02DeniedOperator asks the agent to post the same text to an executive channel1. Submit the proposed call with channel_id=C_EXECUTIVE.<br>2. Complete identity, membership, deployment, manifest, connector, and tool checks.<br>3. Compare the argument against deployment allowed channels and external-channel policy.<br>4. Return argument_outside_allowed_resource_scope before broker or MCP network access.<br>5. Repeat with C_CAMPAIGN_OPS as an unaffected positive control.Paired envelopes record operator and service actor chain, requested channels, message.post scope, allowed-channel precondition, expected deny and control allow, observed denial and Slack success, environment, timestamp, immutable run, decision, trace, and provider request IDs

The complete call decision

The gateway must verify, in order, that the run token is valid for the gateway; current team membership remains active; stale membership versions are revalidated; the deployment is active and still points to the immutable agent version; the manifest declares the tool; that exact connector is bound to the deployment; the team may use the connector; the reviewed tool is enabled; the exact arguments fit manifest and deployment constraints; an authorized credential binding exists; risk policy allows or pauses the action; and the downstream provider authorizes the resource. Fail closed with a stable reason at the first failed predicate.

For dynamic permissions, the resource set is an intersection rather than a copied ACL. A user-visible Slack search can access only configured team channels ∩ channels visible to the downstream identity ∩ channels permitted by the deployment. The source provider remains final authority; the platform should not attempt to clone every Slack, Google, Microsoft, or Salesforce ACL.

System design derived from the flows

If the runtime is both policy decision-maker and MCP client, prompt injection or arbitrary code can turn a proposal into a credentialed call. The trusted Tool and MCP Gateway owns discovery, per-call authorization, credential resolution, MCP OAuth behavior, invocation, and decision logging; the runtime owns only a run token and proposed intent.

Use case IDEntry pointResponsible servicesAuthoritative storeFailure evidence
D07-UC-01Deployment “Preview effective MCP tools” and hidden-tool probeTool Registry ingests reviewed schemas; Discovery Service computes the intersection; Deployment Service supplies immutable grants; Policy Engine compares schema digests and risk; Evidence Service seals list decisionsGoverned Tool Registry owned by Tool Governance for reviewed schema and risk; Deployment Store for version grants; source MCP server remains authoritative only for its current advertised catalogueTool absent unexpectedly, hidden tool returned, schema-digest mismatch, unsafe server annotation lowering platform risk, or direct hidden call reaching broker
D07-UC-02Runtime tools/call intent and operator test actionRun Token Verifier, Membership Service, Deployment Service, Tool Gateway, Argument Policy Engine, Risk Engine, Credential Broker, MCP OAuth Client, connector adapter, and Evidence Service execute the numbered checksIdentity and Deployment stores for current authority; Policy Store for constraints; Credential Binding Registry for secret reference; source provider for resource ACL and operation resultStable denial reason, broker access before policy allow, wrong-audience token accepted, provider ACL denial, or missing paired positive control

MCP OAuth boundary

The gateway, not the agent runtime, is the trusted MCP OAuth client; OAuth is the standard protocol used here to obtain delegated, resource-specific access tokens. The external MCP server is a protected resource and must publish protected-resource metadata, receive a token requested for its resource indicator, and validate issuer, audience, scope, and expiry. A platform access token whose audience is the provider UI or runtime must never be passed through to an MCP server. Token passthrough crosses a trust boundary without consent and asks a resource to accept a token not issued for it.

The effective risk is the maximum of server-declared risk, platform-reviewed risk, organization override, and runtime argument risk. Missing annotations are treated cautiously. Discovery filtering reduces information leakage, prompt complexity, tool-selection error, latency, and token use, but it is only defense in depth: the gateway authorizes every direct tools/call again.

A concrete argument policy

The decision is default-deny. For slack.post_message, require the agent version’s message.post permission, membership of channel_id in the deployment allowlist, exclusion from the external-channel set, a governed data classification, and a bounded text length. Mark externally visible posting for later human approval even when the base policy allows it. For slack.search_messages, require message.read and prove every requested channel is inside the permitted set; a list containing one unauthorized channel fails as a whole.

package agents.tools
import rego.v1

default decision := {"allowed": false, "reason": "default_deny"}

decision := {"allowed": true, "reason": "approved_marketing_channel"} if {
  input.tool.name == "slack.post_message"
  input.arguments.channel_id in input.deployment.allowed_channel_ids
  not input.arguments.channel_id in input.deployment.external_channel_ids
  count(input.arguments.text) <= 5000
  input.agent.permissions[_] == "message.post"
}

Data model and ownership

If reviewed schema, effective policy, and execution evidence are not versioned together, a later server change can make an old allow decision impossible to explain. Durable control-plane records capture the exact catalogue, constraints, and decision inputs; tokens and provider data remain outside this database.

Generated-application database: Not created in this slice — filtered discovery, policy, schema revisions, call decisions, and evidence belong to the provider control plane; app-domain roles are explicit inputs and never become connector grants by themselves.

Record or entityStore and ownerPrimary keyForeign key or opaque referenceTenant keyMaterial constraintLifecycle and deletionUse case IDs
GovernedToolRevisionGoverned Tool Registry, owned by Tool Governance(connector_type, tool_name, reviewed_schema_digest)Opaque source-server schema versionorganization_id for overrides; platform baseline uses None — shared reviewed catalogue has no customer tenantPlatform risk cannot be lowered by server annotation; review digest is immutable; default disabled unless explicitly approvedCreate on review, supersede on schema change, quarantine on mismatch, retain review history, expire payload after audit retentionD07-UC-01, D07-UC-02
ToolEnablementPolicy Store, owned by Connector Policy Servicetool_enablement_idLocal FKs to ConnectorInstance, Team, AgentVersion, and DeploymentVersionorganization_idEvery layer may narrow but never widen its parent; effective set is their intersectionCreate in draft, freeze with deployment, revoke immediately, retain policy digest with release evidenceD07-UC-01, D07-UC-02
ArgumentPolicyRevisionPolicy Store, owned by Authorization Serviceargument_policy_revision_idLocal FK to GovernedToolRevision; organization override references parent policy revisionorganization_idDefault deny; constraints are immutable per revision; resource and data-class predicates required for side effectsDraft, test with positive and negative fixtures, publish, supersede, retain digest and test resultsD07-UC-02
DiscoveryDecisionAppend-only Decision Store, owned by Discovery Servicediscovery_decision_idOpaque run and deployment references; local references to tool and policy revision digestsorganization_idExact input-set digests and exact output tool names required; hidden schemas prohibited from responseAppend per list decision, retain under audit policy, redact descriptions on connector deletion while retaining digest and outcomeD07-UC-01
ToolCallDecisionAppend-only Decision Store, owned by Authorization Servicetool_decision_idOpaque run, trace, credential-binding, MCP server, provider request, and policy revision referencesorganization_idDecision must precede broker lookup; exact canonical argument digest and stable reason required; token material prohibitedAppend before execution, complete with observed provider outcome, retain under audit or legal hold, cryptographically erase sensitive argument payload on expiryD07-UC-02
ToolEvidenceEnvelopeEvidence Store, owned by Evidence Serviceevidence_idLocal reference to DiscoveryDecision or ToolCallDecision; opaque artifact and source IDsorganization_idActor, resource, scope, precondition, expected, observed, environment, timestamp, and immutable identifier fields are mandatoryAppend and seal, pair denial with positive control, retain per policy, export on audit, then erase payload and keep tombstoneD07-UC-01, D07-UC-02

Review checklist

  • [ ] The model sees only the effective discovery intersection, and hidden tools remain denied on direct call.
  • [ ] Server annotations never lower platform or organization risk classification.
  • [ ] Exact arguments, resources, and data classes are checked before credential lookup.
  • [ ] MCP access tokens are resource- and audience-specific; platform-token passthrough is impossible.
  • [ ] Every denial is paired with a valid positive control and a complete immutable evidence envelope.