Skip to content

fix(mcp): evaluate security when listing tools and resources - #8483

Open
Amoifr wants to merge 1 commit into
api-platform:4.3from
Amoifr:fix-8455-mcp-list-security
Open

fix(mcp): evaluate security when listing tools and resources#8483
Amoifr wants to merge 1 commit into
api-platform:4.3from
Amoifr:fix-8455-mcp-list-security

Conversation

@Amoifr

@Amoifr Amoifr commented Aug 28, 2026

Copy link
Copy Markdown
Q A
Branch? 4.3
Tickets Fix #8455
License MIT
Doc PR /

ListHandler returned every registered element, so an anonymous caller could read the name, the description and the full input schema of a tool it was not allowed to invoke. Invocation itself was already denied since #8435; only discovery leaked.

Elements whose operation-level security denies the current caller are now dropped from tools/list and resources/list.

The two design questions from the issue

Only security is evaluated. securityPostDenormalize and securityPostValidation need arguments and an object that do not exist at list time, so they cannot take part. The filter is therefore best-effort on security alone, which is what the class docblock now says.

Expressions that need call-time variables leave the element listed. An expression reading object, previous_object or a uri variable cannot be evaluated before the tool runs: the expression language rejects the unknown name, and the element stays visible. tools/call still enforces it, so nothing is granted that was not granted before. This mirrors what AccessCheckerProvider already does when it skips the pre_read stage for expressions using the object, so I did not add a configuration flag: hiding those elements would hide tools the caller is perfectly allowed to call, and no flag is needed to describe a behaviour that is already the codebase's convention. Happy to turn it into an option if you would rather have it explicit.

Notes

  • Filtering happens after paging, so a page can hold fewer elements than the page size. The cursor still walks the whole registry, so no element is skipped, and the MCP spec puts no constraint on page size.
  • The new constructor arguments are nullable and come last, so ListHandler keeps working unfiltered when security is not installed (ignoreOnInvalid() on the checker).
  • SyntaxError is only referenced in a catch, and api-platform/mcp does not gain a dependency on symfony/expression-language, the same way Handler already uses RequestStack without requiring symfony/http-foundation.

Tests

  • Unit: a denied tool is dropped, a granted one is kept, an expression needing call-time variables keeps the tool listed, and the same for resources/list.
  • Functional, on the existing McpSecuredTools fixture: an anonymous caller no longer sees secured_tool but still sees secured_post_denormalize_tool, secured_post_validation_tool and secured_uri_variable_tool; an admin sees all of them. Both fail on 4.3 without the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant