PATTERN Cited by 1 source
Per-tool authorization decorator¶
Pattern¶
Per-tool authorization decorator is the pattern of enforcing fine-grained, per-operation authorization in-process inside an MCP server via a small decorator (or equivalent declarative annotation) that sits on each tool handler and consults request-context identity claims before executing the body.
Canonical wiki statement (Pinterest, 2026-03-19):
"Inside the server, tools use a lightweight
@authorize_tool(policy='…')decorator to enforce finer-grained rules (for example, only Ads-eng groups can call aget_revenue_metrics, even if the server itself is reachable from other orgs)." (Source: sources/2026-03-19-pinterest-building-an-mcp-ecosystem-at-pinterest)
Shape¶
# Sketch — Pinterest doesn't publish actual code.
@authorize_tool(policy="groups:ads-eng")
def get_revenue_metrics(args):
# Only reached if the request-context user is in ads-eng.
return query_presto(args.sql)
@authorize_tool(policy="any-authenticated")
def list_tables(args):
# Broader allowlist for a less sensitive tool.
return list_tables_from_catalog()
The decorator:
- Reads the request-context identity (populated by upstream JWT validation at Envoy via
X-Forwarded-User/X-Forwarded-Groupsheaders). - Evaluates the policy expression against the identity claims.
- On failure: returns an authorization-error MCP result without running the tool body.
- On success: invokes the decorated function normally.
Why in-process per-tool — mesh-level alone is too coarse¶
The mesh layer (patterns/layered-jwt-plus-mesh-auth) decides "can this user reach this server?" That's too coarse for Pinterest's Presto case — the Presto MCP server is reachable from the AI chat surface (broad population), but the get_revenue_metrics tool should only be callable by ads-eng. Options:
- Split into two servers. One for broad tools, one for ads-eng-only tools. Duplicates infrastructure; creates registry clutter; forces agent planners to know which server has which tool.
- Let the server reject unauthorized calls internally. Same server, per-tool policy. Pinterest's choice.
The decorator pattern makes the per-tool policy visible (right next to the function body), testable (unit-tested in isolation), and uniform (same decorator across tools).
Two altitudes of authorization compose¶
- Coarse (transport / mesh): Envoy validates JWT + enforces server-reachability rules. "Can user reach this server?"
- Session (optional): Business-group gating at session establishment narrows who can open a session.
- Fine (in-process):
@authorize_tool(...)enforces per-tool rules. "Can user call this specific tool?"
All three altitudes run on the same JWT claims; none is sufficient alone for the range of policies a production MCP ecosystem needs.
Adjacent patterns¶
- patterns/jwt-tenant-claim-extraction — sibling pattern at the data-access altitude: never trust a tenant ID from the request body; always read it from the validated JWT claim. Same request-context-identity-as-source-of-truth discipline applied to tenancy.
- patterns/lambda-authorizer — AWS API Gateway's shape: a separate Lambda runs before the target. Pinterest's decorator is the in-process variant (same JVM / process / runtime), trading the Lambda's isolation for zero additional network hop.
- concepts/fine-grained-authorization — the generic concept this pattern is one instance of.
Policy-language choice is a degree of freedom¶
The post does not disclose Pinterest's policy language — policy='…' is opaque. Plausible choices:
- DSL string —
"groups:ads-eng"/"roles:admin and region:us". - Embedded expression — Python-callable or Python-expression string.
- External policy engine — OPA / Cedar / Casbin pulled in at decorator time.
Each has trade-offs; Pinterest names none. The shape of the pattern (decorator on each tool, policy string or equivalent) transfers regardless of the policy-language choice.
Seen in¶
- sources/2026-03-19-pinterest-building-an-mcp-ecosystem-at-pinterest — canonical wiki instance. Used across Pinterest's MCP servers, explicit example with
get_revenue_metricsrestricted to Ads-eng groups.
Related¶
- systems/pinterest-presto-mcp-server — canonical example of the decorator's fine-grained role (broad-reachable server, narrow per-tool access).
- systems/model-context-protocol — the protocol the decorator operates inside.
- systems/envoy — the upstream enforcement layer that populates the identity headers the decorator reads.
- concepts/fine-grained-authorization — the concept this pattern implements.
- concepts/business-group-authorization-gating — the session-altitude sibling.
- patterns/layered-jwt-plus-mesh-auth — the auth layering this decorator is the innermost layer of.
- patterns/hosted-mcp-ecosystem — the umbrella pattern this is a constituent of.
- patterns/jwt-tenant-claim-extraction — sibling pattern on the request-context-identity axis.
- patterns/lambda-authorizer — adjacent pattern at the out-of-process altitude.