Skip to content

Python: Add models for the MCP server SDKs (mcp, fastmcp) - #22703

Open
Alex-Hofer wants to merge 1 commit into
github:mainfrom
Alex-Hofer:python-mcp-models
Open

Alex-Hofer wants to merge 1 commit into
github:mainfrom
Alex-Hofer:python-mcp-models

Conversation

@Alex-Hofer

Copy link
Copy Markdown

Implements the proposal in #22702. The observation there about py/xxe, py/xml-bomb and
py/nosql-injection taking only RemoteFlowSource is separate and not changed by this PR.

MCP servers expose tools to LLM agents. Every parameter of a tool, resource or prompt handler is
chosen by the client, that is by a model that prompt injection can steer, or by anyone who can
reach the server over HTTP. This PR models that input for the two Python SDKs as sources of the
remote threat model, as Models-as-Data next to the existing Stdlib.model.yml sources.

Covered:

  • mcp 1.x FastMCP and 2.x MCPServer: tool(), resource(), prompt(), add_tool(fn).
  • The low-level Server: the 1.x decorators call_tool(), read_resource(), get_prompt(), and
    the 2.x constructor handlers on_call_tool, on_read_resource, on_get_prompt, where
    params.arguments / params.uri is the source.
  • fastmcp 2.x to 4.x: tool and prompt bare, called or as a plain call, resource(),
    add_tool, add_prompt, Tool.from_function, fastmcp.tools.tool, the transport headers via
    get_http_headers() and get_http_request().headers.
  • Both SDKs: the bearer token of the Authorization header, in verify_token of TokenVerifier
    (and AuthProvider) subclasses and from get_access_token().token.
  • typeModel rows for the re-exported import paths of the classes.

Tests: library-tests/frameworks/mcp and library-tests/frameworks/fastmcp use MaDTest
(mad-source__remote); every row has a handler with an inline expectation, and classes with the
same method name but no SDK base class have none.

Evidence: with these rows (as a model pack) CodeQL 2.27.1 finds 13 of 28 real, publicly disclosed
MCP server vulnerabilities in mcp-vulnbench
instead of 1; on the half of the cases that was held out while writing the rows, 9 of 16 instead
of 0, at 0.27 to 1.09 alarms per KLOC. Known limits of this form (handlers behind project
decorators, Pydantic-typed parameters, headers read through the Context object) are documented
there and in the issue.

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants