Skip to content

Bump fastmcp from 2.14.5 to 3.2.0#452

Open
dependabot[bot] wants to merge 1 commit intomainfrom
dependabot/uv/fastmcp-3.2.0
Open

Bump fastmcp from 2.14.5 to 3.2.0#452
dependabot[bot] wants to merge 1 commit intomainfrom
dependabot/uv/fastmcp-3.2.0

Conversation

@dependabot
Copy link
Copy Markdown
Contributor

@dependabot dependabot bot commented on behalf of github Mar 31, 2026

Bumps fastmcp from 2.14.5 to 3.2.0.

Release notes

Sourced from fastmcp's releases.

v3.2.0: Show Don't Tool

FastMCP 3.2 is the Apps release. The 3.0 architecture gave you providers and transforms; 3.1 shipped Code Mode for tool discovery. 3.2 puts a face on it: your tools can now return interactive UIs — charts, dashboards, forms, maps — rendered right inside the conversation.

FastMCPApp

FastMCPApp is a new provider class for building interactive applications inside MCP. It separates the tools the LLM sees (@app.ui()) from the backend tools the UI calls (@app.tool()), manages visibility automatically, and gives tool references stable identifiers that survive namespace transforms and server composition — without requiring host cooperation.

from fastmcp import FastMCP, FastMCPApp
from prefab_ui.actions.mcp import CallTool
from prefab_ui.components import Column, Form, Input, Button, ForEach, Text
app = FastMCPApp("Contacts")
@​app.tool()
def save_contact(name: str, email: str) -> list[dict]:
db.append({"name": name, "email": email})
return list(db)
@​app.ui()
def contact_manager() -> PrefabApp:
with PrefabApp(state={"contacts": list(db)}) as view:
with Column(gap=4):
ForEach("contacts", lambda c: Text(c.name))
with Form(on_submit=CallTool("save_contact")):
Input(name="name", required=True)
Input(name="email", required=True)
Button("Save")
return view
mcp = FastMCP("Server", providers=[app])

The UI is built with Prefab, a Python component library that compiles to interactive UIs. You write Python; the user sees charts, tables, forms, and dashboards. FastMCP handles the MCP Apps protocol machinery — renderer resources, CSP configuration, structured content serialization — so you don't have to.

For simpler cases where you just want to visualize data without server interaction, set app=True on any tool and return Prefab components directly:

@mcp.tool(app=True)
def revenue_chart(year: int) -> PrefabApp:
    with PrefabApp() as app:
        BarChart(data=revenue_data, series=[ChartSeries(data_key="revenue")])
    return app

Built-in Providers

Five ready-made providers you add with a single add_provider() call:

  • FileUpload — drag-and-drop file upload with session-scoped storage

... (truncated)

Changelog

Sourced from fastmcp's changelog.


title: "Changelog" icon: "list-check" rss: true tag: NEW

v3.1.1: 'Tis But a Patch

Pins pydantic-monty below 0.0.8 to fix a breaking change in Monty that affects code mode. Monty 0.0.8 removed the external_functions constructor parameter, causing MontySandboxProvider to fail. This patch caps the version so existing installs work correctly.

Fixes 🐞

Full Changelog: v3.1.0...v3.1.1

v3.1.0: Code to Joy

FastMCP 3.1 is the Code Mode release. The 3.0 architecture introduced providers and transforms as the extensibility layer — 3.1 puts that architecture to work, shipping the most requested capability since launch: servers that can find and execute code on behalf of agents, without requiring clients to know what tools exist.

New Features 🎉

Enhancements 🔧

... (truncated)

Commits
  • 665514e Add forward_resource flag to OAuthProxy (#3711)
  • f189d1f Bump pydantic-monty to 0.0.9 (#3707)
  • 6faa2d6 Remove hardcoded prefab-ui version from pinning warnings (#3708)
  • dd8816c chore: Update SDK documentation (#3701)
  • d274959 docs: note that custom routes are unauthenticated (#3706)
  • 4a54be2 Add examples gallery page (#3705)
  • 961dd50 Add interactive map example with geocoding (#3702)
  • f01d0c5 Add quiz example app, fix dev server empty string args (#3700)
  • 85b7efd chore: Update SDK documentation (#3694)
  • 27abe3c Add sales dashboard and live system monitor examples, bump prefab-ui to 0.17 ...
  • Additional commits viewable in compare view

@dependabot dependabot bot added dependencies Pull requests that update a dependency file python:uv Pull requests that update python:uv code labels Mar 31, 2026
authors = [{ name = "Keboola", email = "devel@keboola.com" }]
dependencies = [
"fastmcp == 2.14.5",
"fastmcp==3.2.0",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 This PR bumps fastmcp from 2.14.5 to 3.2.0, but fastmcp 3.x removed the get_tools() method (which returned dict[str, Tool]) in favor of list_tools() (returning Sequence[Tool]). Two call sites are broken: cli.py:216 will raise AttributeError on HTTP server startup, and generate_tool_docs.py:182 will break the required check-tools-docs CI tox environment. Both locations need to replace get_tools() with list_tools() and remove the .values() calls.

Extended reasoning...

What the bug is and how it manifests

FastMCP 3.x is a major version bump with breaking API changes. The get_tools() method, which previously existed on FastMCP instances and returned a dict[str, Tool], has been removed entirely and replaced by list_tools() which returns Sequence[Tool]. This PR only updates pyproject.toml and uv.lock but makes zero changes to application source code.

The specific code paths that trigger it

Location 1 - src/keboola_mcp_server/cli.py:216:

app.state.mcp_tools_input_schema = {
    tool.name: tool.parameters for tool in (await mcp_server.get_tools()).values()
}

This runs during HTTP server lifespan startup (streamable-http, SSE, http-compat transports). The mcp_server.get_tools() call raises AttributeError before any requests can be served.

Location 2 - src/keboola_mcp_server/generate_tool_docs.py:182:

tools = await mcp.get_tools()
...
doc_gen = ToolDocumentationGenerator(list(tools.values()), categories)

Called by the check-tools-docs tox environment, a required CI check. This also raises AttributeError.

Why existing code does not prevent it

There is no compatibility shim, no try/except, and no version guard. The code assumes get_tools() exists and returns a dict. Verifiers confirmed by inspecting the fastmcp 3.2.0 source that get_tools() does not exist anywhere. Additionally, even fixing the method name to list_tools() would not be enough: calling .values() on the returned Sequence[Tool] would still raise AttributeError.

Impact

  1. HTTP server modes are completely broken: Any deployment using --transport streamable-http, sse, or http-compat will fail to start after this bump.
  2. CI pipeline breaks: The check-tools-docs tox environment fails on every run, blocking future PRs.

How to fix it

Replace get_tools() with list_tools() and drop .values() at both call sites:

cli.py:

app.state.mcp_tools_input_schema = {
    tool.name: tool.parameters for tool in await mcp_server.list_tools()
}

generate_tool_docs.py:

tools = await mcp.list_tools()
...
doc_gen = ToolDocumentationGenerator(list(tools), categories)

Step-by-step proof

  1. Merge this PR, installing fastmcp==3.2.0.
  2. Start the server with --transport streamable-http.
  3. During lifespan startup, _lifespan() in cli.py reaches line 216: (await mcp_server.get_tools()).values().
  4. Python calls mcp_server.get_tools() - FastMCP in 3.2.0 has no such attribute.
  5. AttributeError: 'FastMCP' object has no attribute 'get_tools' is raised.
  6. Server startup fails; the HTTP server never becomes ready.
  7. Separately, tox -e check-tools-docs hits await mcp.get_tools() at generate_tool_docs.py:182 and also raises AttributeError, failing CI.

@dependabot dependabot bot changed the title Build(deps): bump fastmcp from 2.14.5 to 3.2.0 Bump fastmcp from 2.14.5 to 3.2.0 Apr 3, 2026
@dependabot dependabot bot force-pushed the dependabot/uv/fastmcp-3.2.0 branch from 2279619 to 7328bbf Compare April 3, 2026 07:45
authors = [{ name = "Keboola", email = "devel@keboola.com" }]
dependencies = [
"fastmcp == 2.14.5",
"fastmcp==3.2.0",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 FastMCP 3.x changed get_tool() to return Tool | None instead of raising NotFoundError, but both ToolsFilteringMiddleware.on_call_tool() in mcp.py:373 and AuthorizationMiddleware.on_call_tool() in authorization.py:126 immediately access attributes on the return value without a None guard. If a client calls a non-existent or session-disabled tool, both locations will raise AttributeError instead of returning a proper MCP error — add a None check at each call site and raise a ToolError with an appropriate message.

Extended reasoning...

What the bug is and how it manifests

In fastmcp 2.x, FastMCP.get_tool() raised NotFoundError when a tool was not found, so callers could assume the return value was always a non-None Tool object. FastMCP 3.x explicitly changed the signature to async def get_tool(self, name: str, ...) -> Tool | None, returning None when the tool is not found, disabled, or hidden by a session-level transform. The application code was never updated to handle this new return value contract.

The specific code paths that trigger it

Location 1 — mcp.py:373 (ToolsFilteringMiddleware.on_call_tool):

tool = await context.fastmcp_context.fastmcp.get_tool(context.message.name)
if token_role == 'readonly':
if not is_read_only_tool(tool): # line 379 — accesses tool.annotations; AttributeError if tool is None

is_read_only_tool(tool) at mcp.py:47 checks tool.annotations, which immediately raises AttributeError when tool is None. Lines 387, 394, 403 also access tool.name without a None guard.

Location 2 — authorization.py:126 (AuthorizationMiddleware.on_call_tool):

tool = await context.fastmcp_context.fastmcp.get_tool(tool_name)
if not self._is_tool_authorized(tool, allowed_tools, disallowed_tools, read_only_mode):

_is_tool_authorized at authorization.py:90 accesses tool.name directly, raising the same AttributeError if tool is None.

Why existing code does not prevent it

The middleware on_call_tool runs as part of the fastmcp middleware chain, which is invoked before fastmcp's own internal tool lookup. In fastmcp 3.x's call_tool flow (server.py:1113-1131), the middleware is called first (the run_middleware=True path), and the core tool-existence check only happens in the inner run_middleware=False path. So the middleware fires and calls get_tool() on its own initiative before any framework guard can reject the unknown tool name.

What the impact would be

Any client that sends a tools/call request for a tool name that does not exist or has been disabled by a session-level transform will receive an unhandled AttributeError crash in the middleware layer rather than a clean MCP error response. Both the filtering middleware (role-based read-only enforcement) and the authorization middleware (allow/disallow-list enforcement) are affected, meaning both security-relevant middleware layers can crash before doing their job.

How to fix it

Add a None guard immediately after each get_tool() call and raise a ToolError for the not-found case:

tool = await context.fastmcp_context.fastmcp.get_tool(context.message.name)
if tool is None:
    raise ToolError(f'Tool not found.')

Step-by-step proof

  1. Merge this PR (fastmcp 3.2.0 installed).
  2. A client sends tools/call with name="nonexistent_tool".
  3. FastMCP invokes the middleware chain first (run_middleware=True path).
  4. ToolsFilteringMiddleware.on_call_tool (mcp.py:368) is entered.
  5. get_tool("nonexistent_tool") is called; fastmcp 3.x returns None (no tool with that name exists).
  6. is_read_only_tool(None) is called (mcp.py:379); inside, tool.annotations raises AttributeError: NoneType object has no attribute annotations.
  7. The exception propagates up uncaught — the client receives an error response, but not a clean MCP ToolError, and both the read-only check and the feature-flag checks are silently skipped.

authors = [{ name = "Keboola", email = "devel@keboola.com" }]
dependencies = [
"fastmcp == 2.14.5",
"fastmcp==3.2.0",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 This PR does not bump the version in pyproject.toml as required by CLAUDE.md, which states 'Every PR must bump pyproject.toml version before merging.' The version remains at 1.51.0; a patch bump to 1.51.1 (or minor bump to 1.52.0) is needed before this can be merged.

Extended reasoning...

What the issue is

CLAUDE.md contains an explicit project convention: 'Every PR must bump pyproject.toml version before merging.' This PR changes two files — pyproject.toml (fastmcp dependency from 2.14.5 to 3.2.0) and uv.lock — but leaves version = "1.51.0" at line 8 of pyproject.toml unchanged.

The specific location

pyproject.toml line 8 contains version = "1.51.0" and must be incremented before the PR is eligible to merge, per the documented project rule.

Why existing code does not prevent it

There is no automated CI check that enforces the version bump requirement. The rule is documented only in CLAUDE.md as a human-enforced convention, so automated pipelines will not catch it, making manual review the only gate.

Impact

The version in pyproject.toml is used to tag releases. Skipping the bump means the resulting release conflates changes from multiple PRs under one version string, undermining changelogs, dependency pinning by downstream consumers, and release traceability.

How to fix

Increment the patch version: version = "1.51.1". Then run uv lock to regenerate uv.lock with the updated project metadata. A minor bump (1.52.0) would also be acceptable given the major fastmcp dependency upgrade.

Step-by-step proof

  1. Read CLAUDE.md which explicitly states: Every PR must bump pyproject.toml version before merging.
  2. Inspect the PR diff for pyproject.toml: only the fastmcp dependency line changed (2.14.5 to 3.2.0). The version field on line 8 is absent from the diff.
  3. Confirm current value: version = "1.51.0" unchanged from the base branch.
  4. Conclusion: the CLAUDE.md requirement is unmet. The PR cannot be merged as-is without violating the project documented versioning convention.

Matovidlo added a commit that referenced this pull request Apr 3, 2026
…sts 2.33.0

Consolidates 4 Dependabot PRs (#452 #447 #443 #440) into one:
- fastmcp 2.14.5 → 3.2.0 (breaking: get_tools() removed → _list_tools())
- cryptography ~= 46.0 (patch 46.0.6)
- pygments 2.19.2 → 2.20.0 (indirect)
- requests 2.32.5 → 2.33.0 (indirect)

fastmcp 3.x migration:
- Replace get_tools() (dict) with _list_tools() (list) in cli.py, generate_tool_docs.py, tests
- Filter FastMCPDeprecationWarning for serializer in test_json_logging
- Regenerate TOOLS.md (fastmcp 3.x adds "additionalProperties": false to all tool schemas)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dependabot dependabot bot changed the title Bump fastmcp from 2.14.5 to 3.2.0 Build(deps): bump fastmcp from 2.14.5 to 3.2.0 Apr 8, 2026
@dependabot dependabot bot force-pushed the dependabot/uv/fastmcp-3.2.0 branch 2 times, most recently from f1f9753 to a3e2503 Compare April 11, 2026 06:59
@dependabot dependabot bot changed the title Build(deps): bump fastmcp from 2.14.5 to 3.2.0 Bump fastmcp from 2.14.5 to 3.2.0 Apr 13, 2026
@dependabot dependabot bot force-pushed the dependabot/uv/fastmcp-3.2.0 branch 3 times, most recently from ad0858d to 8aaa064 Compare April 13, 2026 13:35
Bumps [fastmcp](https://github.com/PrefectHQ/fastmcp) from 2.14.5 to 3.2.0.
- [Release notes](https://github.com/PrefectHQ/fastmcp/releases)
- [Changelog](https://github.com/PrefectHQ/fastmcp/blob/main/docs/changelog.mdx)
- [Commits](PrefectHQ/fastmcp@v2.14.5...v3.2.0)

---
updated-dependencies:
- dependency-name: fastmcp
  dependency-version: 3.2.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot bot force-pushed the dependabot/uv/fastmcp-3.2.0 branch from 8aaa064 to 787da45 Compare April 13, 2026 14:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file python:uv Pull requests that update python:uv code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants