Skip to content

verify: the MCP access-profile denial shape #303

Open

Description

@amirkhan-ak-sf

What needs verifying

"Least-Privileged MCP Access Profiles" (Nov 2026) gives "each consumer a scoped subset
of tools instead of all-or-nothing MCP access".

Three things need confirming:

  1. Whether tool discovery returns only the caller's in-profile tools, or the full
    server tool list with enforcement deferred to call time.
  2. What the gateway returns when an out-of-profile tool is called — status, body,
    and any distinguishing header.
  3. Whether 1 and 2 are identical for both server origins: a Mule-hosted MCP
    server (MCP Bridge, a Mule app) and a framework-built one (e.g. FastMCP over
    streamable HTTP) behind the same gateway. The SDK's consumer path is meant to
    be origin-agnostic (tools: donkey.tools.discover() returns governed MCP tools as native framework tools #221, tools: a typed refusal for a tool outside the consumer's MCP access profile #312); this confirms it rather than assumes it.

Why it blocks work

BG §2.7 already states that discovery filters to "only the tools it is allowed to
call", but donkey.tools.discover is _verify.blocked today (#221) and the
enforcement semantics behind that sentence are unconfirmed.

Without the denial shape, an out-of-profile tool call classifies through the generic
4xx branch in classify() and the agent cannot distinguish "this tool is not
provisioned for you"
— a configuration problem for a human to fix — from "this
call broke a content policy"
— a runtime refusal the agent might handle by
rephrasing. Those need different reactions, and BG §1.2's whole premise is that the
refusal type drives the reaction.

The discovery question matters independently: if discovery is not profile-scoped,
the SDK must filter client-side after resolution, which changes where
tools/filter.py sits in the flow.

Done when

  • Confirmed whether discovery is profile-scoped server-side.
  • The out-of-profile denial shape captured as a fixture.
  • Confirmed whether the denial names the tool or the profile.
  • Questions 1 and 2 answered for both a Mule-hosted and a framework-built
    server, with a fixture for each, or the difference recorded.
  • docs/verified-apis.md row added.

Cross-surface impact

  • tools: session.py and filter.py — where filtering happens depends on the answer.
  • core: errors.py — a new typed refusal if the denial is distinguishable.
  • registry: the discovery query, if profile scoping is a query parameter.
  • llm / integrations: not affected.
  • TypeScript parity (planned): flag.
  • Provisioning CLI: not affected.
  • Nextra docs site: the tool-access section.
  • docs/verified-apis.md: new row.

Related

Activity

  1. added this to the Verification milestone on Sep 9, 2026
  2. added
    blocked-on-verificationCannot be closed by writing code (build plan §0.3)
    area:toolstools/ — MCP session, ToolSet, filtering (Pillar 2)
    size/s~half day, one file
    priority/p2Meaningful improvement, ship soon
    on Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:toolstools/ — MCP session, ToolSet, filtering (Pillar 2)blocked-on-verificationCannot be closed by writing code (build plan §0.3)priority/p2Meaningful improvement, ship soonsize/s~half day, one file

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions