pypi fastmcp 4.2.0
v4.2.0: Mad Skills

one hour ago

FastMCP 4.2 makes skills something a server can serve. A Skill is now a plain value — a name, a description, instructions and files, validated once when you build it — and you can load one from a directory or a package, or build it in code. Put skills on a server with SkillCatalogProvider or SkillsDirectoryProvider and they're served as ordinary resources; clients that speak the experimental Skills extension also get skills/list with a hashed manifest per skill. Client support is still uneven, so FastMCP's own client covers the gap: Client.read_skill() verifies every file's size and digest, and to_directory() installs a skill into any agent's skills folder. Skills follow the rest of FastMCP's composition: they namespace under mounts, pass through proxies with skills=True, list across a ClientGroup, and respect AuthMiddleware.

Dependencies got two upgrades. A dependency can live in the annotation (Annotated[dict, Depends(get_config)]), so the parameter keeps its real type, and a dependency can now own the tool argument it reads through CallArgument. The rest is a broad sweep of fixes across OpenAPI, proxies, auth, telemetry and tasks, including completion no longer suggesting values for prompts or templates a caller can't see.

Check these before upgrading:

  • Python 3.11 or newer is required.
  • The 4.1 skills API is deprecated and goes away in 4.3. The old providers in fastmcp.server.providers.skills and helpers in fastmcp.utilities.skills still work and warn with their replacement; the skills docs have a migration table.
  • Skill is now the authoring class. The wire model that used that name is MCPSkill; the old import keeps working until 4.3.

Thanks to our 129 contributors, including 55 first-time contributors.

What's Changed

Breaking Changes ⚠️

Enhancements ✨

Security 🔒

Fixes 🐞

  • Make the version-check InvalidURL regression independent of proxy parsing by @HootRock in #6048
  • Build the Prefab renderer page on read, not on resources/list by @adam-zovos in #6039
  • Install mounted skills under their own name in sync_skills by @zzstoatzz in #6078
  • Stage skill exports before replacing installed files by @zzstoatzz in #6091
  • fix: Prefix backend hash addresses with double underscores by @jlowin and @BlueX888 in #6100
  • Rebind pre-4.2 Prefab backend addresses through 4.2 proxies by @jakekaplan in #6108
  • Isolate and bound triage verification by @zzstoatzz in #6109
  • Improve OpenAPI upstream error details by @zzstoatzz and @mssaleh in #6141
  • Compare JSON const and enum values by JSON equality by @prassu017 and @alpaylan in #6126
  • Bound Skills proxy backend pagination by @prassu017 and @Yash-Tripath1 in #6104
  • fix: forward script arguments in FastMCPStdioTransport by @KashifManzer and @BlueX888 in #6119
  • Return invalid params for prompts/get with a missing required argument by @asasemahmed and @xubenqiang in #6027
  • Fix kept-alive stdio transports ignoring client timeouts by @HootRock in #6156
  • perf(schema): skip unnecessary reference sibling restoration by @andreivince in #6161
  • fix(cli): prefer Claude Code project servers by @mikamikasuki in #5522
  • fix(cli): preserve JSON content block fields by @mikamikasuki in #5530
  • Keep schema definitions when hydrating a wrapped tool result by @asasemahmed in #5927
  • Reject undeclared OpenAPI tool arguments under strict input validation by @prassu017 and @mssaleh in #6140
  • fix(resources): reverse hostless URIs through Namespace unchanged by @serhiizghama and @andreivince in #5230
  • fix(openapi): preserve timeouts so the server maps them to the actionable message by @BlueX888 in #5847
  • Keep posted review receipts on partial delivery and reject differing reviews by @zzstoatzz in #6178
  • Drop client context holds left by finished tasks by @zzstoatzz in #6205
  • Let clients with different timeouts share a kept-alive stdio session by @zzstoatzz in #6223
  • fix(cli): preserve explicit null in generated tool commands by @likecake in #6191
  • Honor empty tag inclusion filters in multi-server configs by @PennEwan in #6200
  • fix(mcp-config): reuse one OAuth client per configured server by @kbkb628 and @whoskn in #6097
  • Fix and quiet the triage alerts from 2026-11-02 by @zzstoatzz in #6235
  • fix(tasks): send task IDs in routing headers by @eli-yip in #5810
  • fix(middleware): treat an empty methods allowlist as "log nothing" by @gdut4140 in #5727
  • Fix namespaced file resource reads while preserving URI normalization by @BlueLi66 in #5716
  • fix(server): pass typed list request messages to list middleware hooks by @BlueX888 in #5732
  • Stop OpenAPI end-to-end tests from hitting the network by @zzstoatzz in #6249
  • fix(auth): Preserve browser consent bindings across concurrent OAuth approvals by @mikamikasuki in #5541
  • fix(openapi): serialize header and path parameters per the simple style by @Harsh23Kashyap in #5091
  • Fall back to method and path when an OpenAPI name slugs to nothing by @asasemahmed in #5699
  • Convert OpenAPI 3.0 boolean exclusive bounds to numeric bounds by @asasemahmed in #5697
  • Rewrite component refs under not, if/then/else and similar keywords by @asasemahmed in #5698
  • fix(openapi): keep media-type $defs beside component schemas by @BlueX888 in #5709
  • Omit readOnly properties from OpenAPI tool input schemas by @AarnavNoble in #5753
  • fix: name root self-references after the generated root class by @BlueX888 in #5671
  • fix(proxy): keep stale list results out of cache by @mikamikasuki in #5521
  • Match Claude Code project keys by path on Windows by @zzstoatzz and @yongpange in #6240
  • Stop preloading the server before launching the Inspector by @zzstoatzz and @mikamikasuki in #6241
  • Cull expired OAuth state from the default OAuthProxy file store by @zzstoatzz, @nosmile99, and @mheidari98 in #6242
  • Reuse the stdio session after a cancelled startup by @zzstoatzz and @mikamikasuki in #6243
  • Match Gemini function responses to tool-use IDs by @zzstoatzz and @mikamikasuki in #6244
  • Replace parent type keywords when an ArgTransform changes the type by @zzstoatzz, @syf2211, @HootRock, and @chrikrah in #6246
  • Expire idle per-client rate limiters by @zzstoatzz and @mikamikasuki in #6247
  • Match resource templates that spell out a literal query by @zzstoatzz and @arieleven in #6248
  • fix(openapi): preserve explicit null in nullable JSON body properties by @mumu-bird in #5633
  • Keep OpenAPI refs that point into a component schema intact by @zzstoatzz and @AarnavNoble in #6245
  • fix(telemetry): record mounted and nested server spans as INTERNAL by @zzstoatzz and @sonmaximum in #6252
  • fix(client): identify as fastmcp in clientInfo by default by @zzstoatzz in #6254
  • fix(openapi): keep both values when a query object property matches another parameter by @zzstoatzz and @alpaylan in #6256
  • fix(middleware): map exception subclasses in ErrorHandlingMiddleware by @zzstoatzz and @zurmag in #6257
  • fix(client): report a lost connection instead of 'Client is not connected' by @zzstoatzz and @alex-feel in #6259
  • fix(client): keep ClientGroup tool routes after the group context exits by @zzstoatzz, @hntrl, and @YingzuoLiu in #6268
  • Accept structured skill metadata and allowed-tools lists by @jakekaplan in #6292
  • Preserve 4.1 skills type checks and resource-only manifest migration by @zzstoatzz in #6305
  • Fix generated CLIs for tools named app, console or Client by @andreivince in #6056
  • Disambiguate colliding parameter flags in generate-cli by @mohitdixit02 and @andreivince in #6311
  • fix: preserve CRLF descriptions in generated CLI parameter help by @chris00234 in #6075
  • fix(agentic): repair baseline collection verification by @zzstoatzz in #6313
  • Reject non-positive event retention limits by @mikamikasuki in #5535
  • fix(search): rebuild the BM25 index when the tool name set changes by @shi-felix in #6282
  • fix(tools): keep hidden parameter factories out of visible defaults by @shi-felix in #6283
  • fix(auth): accept private-use scheme redirect URIs in CIMD documents by @ColePBryan in #6335
  • Report the stop reason from sampling handlers when no tools are offered by @AarnavNoble in #6342
  • fix(auth): preserve empty authority on custom-scheme redirect URIs by @codesphere-u and @alpaylan in #6347
  • Declare items.type on multi-select list shorthand elicitations by @zzstoatzz, @shi-felix, @Vivek1898, and @alpaylan in #6361
  • Mask prompt handler exceptions when mask_error_details=True by @pratyu2h and @maxmorrish in #6277
  • Send {} for required OpenAPI object bodies with no fields by @rome-xi and @wang1299 in #6340
  • fix(client): keep the response cache inert on legacy connections (#6298) by @xunWhale and @alpaylan in #6321
  • Encode manifest paths in download_skill URIs by @zzstoatzz, @67-luck, and @BlueX888 in #6376
  • Fix skill discovery for nested supporting files by @mahekara28 and @alpaylan in #6310
  • fix: keep additionalProperties on object schemas without a type by @bfs2021 and @alpaylan in #6127
  • Fix hydration of mutually recursive schema types by @zzstoatzz, @wozhenbang2004, and @alpaylan in #6394
  • Isolate filesystem component construction failures by @PennEwan in #6210
  • fix(config): apply tool transforms before tag filters on single servers by @AP24110011695 and @arjunprabhulal in #6214
  • fix(tools): isolate mutable defaults in transformed tool calls by @priy-anshugupta in #6184
  • fix(openapi): make resource templates for non-identifier path parameters readable by @AP24110011695 and @alpaylan in #6187
  • fix(json-schema): keep tools/list working when a root $ref resolves to a boolean schema by @AP24110011695 and @alpaylan in #6185
  • Keep constraints on scalar schema references by @shayanxcyber in #6041
  • fix(server): validate cursors when pagination is disabled by @xu91102 and @DMomplaisir in #6045
  • Document that a custom httpx_client_factory owns its timeout by @asasemahmed and @himanshuchawla0807-gif in #5923
  • Stop PingMiddleware erroring when the client has no back-channel by @asasemahmed in #5901
  • Store sessionless client log levels on the connection by @asasemahmed in #5899
  • Send the whole body when a body $ref with siblings cannot be flattened by @asasemahmed in #5893
  • Pass the transport to the fastmcp-remote proxy so it forwards server-initiated requests by @asasemahmed in #5885
  • fix(cli): forward path, stateless and log-level to SDK MCPServer servers by @BlueX888 in #5870
  • fix(client): preserve a caller-provided OAuth httpx client factory when verify is set by @BlueX888 in #5849
  • fix(prompts): resolve postponed annotations when rendering by @67-luck and @BlueX888 in #5803
  • Roll back the tool stamp when a tool registration is rejected by @Winoren in #5798
  • fix(openapi): hydrate data for wrapped non-object responses with validate_output=False by @nosmile99 and @BlueX888 in #5784
  • Carry prompt argument titles through PromptArgument and proxies by @AarnavNoble in #5749
  • Relay the client's sampling result unchanged through proxies by @AarnavNoble in #5747
  • fix(json-schema): keep x-unsupported-pattern when a format is set by @gdut4140 in #5731
  • fix(tasks): let async-generator tools run as background tasks by @gdut4140 in #5730
  • Honor Code Mode search limits after BM25 ranking by @Winoren and @BlueX888 in #5715
  • Keep the client timeout from capping the HTTP read timeout by @asasemahmed in #5690
  • fix(auth): avoid rereading failed authorization forms by @pei711 and @JordanAfolabiLaw in #5570
  • Fix unbounded Apps dev log retention by @mikamikasuki in #5549
  • Bound error-stat cardinality in ErrorHandlingMiddleware by @mikamikasuki in #5537
  • fix(auth): preserve GitHub sessions across transient verification failures by @sui-ni2 and @benjohngf in #4881
  • Expect the extended read timeout in the factory timeout test by @zzstoatzz in #6395
  • Accept intake's contribution route in the triage review check by @zzstoatzz in #6405
  • fix(auth): keep revocation ownership separate from user identity by @zzstoatzz, @BlueX888, and @67-luck in #6404
  • Authenticate and pin the schema download in the OpenAPI performance test by @zzstoatzz in #6177
  • Use renamed argument names in transformed tool validation errors by @kartikmadan11 in #6158
  • Preserve invalid defaults for omitted JSON Schema fields by @totoyang and @alpaylan in #6133
  • Validate positional array prefixes separately from their tails by @PennEwan and @alpaylan in #6146
  • Stop FastMCP callable caches from retaining dropped tools by @PennEwan and @hanhyperfx in #6147
  • Fix resource templates with multiple query expressions by @xiong-wei1 in #6061
  • fix(json-schema): decode RFC 6901 escapes when extracting $defs names by @AP24110011695 and @RS-ITACHI in #6180
  • Drop backend serverInfo from proxied tool and prompt results by @asasemahmed in #5911
  • fix(telemetry): record exceptions once per span by @DMomplaisir in #5861
  • fix(resources): honor Pydantic field aliases in resource templates by @anh-nguyenn and @BlueX888 in #6054
  • fix(auth): authorize hashed app-tool names and synthesized Prefab resources by @BlueX888 in #5841
  • fix(prompts): honor field aliases when rendering prompts by @BlueX888 in #5836
  • fix(server): serialize structured prompt arguments before middleware by @67-luck and @BlueX888 in #5805
  • fix(oauth-proxy): answer a repeated consent approval with the same redirect by @jamesmaidment in #5775
  • fix(client): stop validating version-pinned call_tool results against the highest version's schema by @gdut4140 in #5725
  • Preserve typed additional properties in hydrated tool results by @PrathmeshPawar2110, @yannvr, @BlueX888, and @hulkbig in #5779
  • fix(server): serve Mcp-Param validation from a wire-schema cache by @akushonkamen and @anormang1992 in #5666
  • Fix #5563: OTel: prefer AccessToken.subject over client_id for enduser.id by @nandanadileep and @omikader in #5565
  • fix: decode URI fragments before schema reference hydration by @HuaTNA in #5561
  • Fix #5559: Configuration helpers still discard explicit port=0 by @nandanadileep and @dream-star-end in #5562
  • Preserve or explicitly reject images in sampling tool results by @mikamikasuki in #5554
  • fix(client): Prevent stale ClientGroup refreshes from replacing newer routes by @mikamikasuki in #5543
  • fix(client): close partial group connections on cancellation by @mikamikasuki in #5519
  • fix(cli): resolve config paths beside fastmcp.json by @mikamikasuki in #5511
  • fix(tasks): retain results after tool removal by @mikamikasuki in #5507
  • fix(tools): reject non-finite floats at the JSON serialization boundary by @akushonkamen and @YogaSakti in #5665
  • Make the partial-construction stdio test fast and strict by @zzstoatzz in #6433
  • test: isolate consent checks and preserve OpenAPI download budget by @Larry-Labs in #5664
  • fix(client): validate accepted elicitation content by @mikamikasuki in #5513
  • Advertise the MCP Apps extension only when the server serves an app by @lancy69 and @adrianto-nanovest in #5062
  • fix: session: UserSession on a resource or resource template fails at registration by @xixi-box and @arjunprabhulal in #6198
  • fix(cli): parse JSON for non-string unions and accept null in call args by @Christian-Sidak and @BHAWESHBHASKAR in #6012
  • Forward URL-mode elicitation through the proxy by @Kushal9889 in #5980
  • Let context list calls run outside a request by @asasemahmed in #5903
  • Keep ResourceLink content on prompt messages by @asasemahmed in #5897
  • Accept WorkOS tokens when required_scopes is set by @asasemahmed in #5881
  • fix(openapi): JSON-encode object form fields in urlencoded request bodies by @BlueX888 in #5851
  • Keep task config and execution on transformed tools by @Winoren and @BlueX888 in #5793
  • fix(proxy): relay non-object tool results across MCP versions by @Lpk124 and @maxime-gautre in #5763
  • Fix #5706: Resource template with a level-3 operator such as {&size} is listed but can never be read by @nandanadileep and @chrikrah in #5711
  • fix: preserve referenced schema definitions by @lux-liang in #5588
  • fix(server): fall back to the highest authorized version on direct lookup by @gshklovs and @CoralGarden52 in #5169
  • Resolve deferred defaults by alias and keep unverified GitHub scopes out of the cache by @zzstoatzz in #6417
  • Drop unpinned ping from auth example clients by @zzstoatzz and @stephaneberle9 in #6418
  • Call a re-versioned tool by its transformed version by @zzstoatzz and @MayankTamakuwala in #6419
  • Apply logging/setLevel to mounted servers over HTTP sessions by @zzstoatzz and @alpaylan in #6421
  • Reconnect StdioTransport when reused on a different event loop by @zzstoatzz and @dsfaccini in #6425
  • Forward list-changed notifications through ProxyClient by @zzstoatzz, @chrikrah, and @ldlda in #6426
  • Report JSON-RPC error codes and request ids on telemetry spans by @zzstoatzz in #6427
  • Stop the SSE endpoint sending a second response after its stream by @zzstoatzz and @JonZeolla in #6431
  • Bypass proxy env when fastmcp dev apps lists tools by @zzstoatzz and @AlyLanier in #6422
  • fix(context): allow background task logging without a session by @67-luck and @BlueX888 in #5806
  • fix(skills): follow empty pagination cursors when listing skills by @67-luck in #6473
  • Fix the CLI .js deprecation warning and a dead error-message link by @zzstoatzz in #6453
  • Ignore stray ResourceWarnings in CLI OAuth warning checks by @zzstoatzz in #6474
  • Accept a sync tool timeout that fires before its thread starts by @zzstoatzz in #6475
  • Drop GC ResourceWarnings at the assertion in CLI OAuth warning checks by @zzstoatzz in #6481

Docs 📚

  • Consolidate skills docs into one Skills over MCP page by @zzstoatzz in #6049
  • Rewrite skills docs around Skill and SkillCatalogProvider by @zzstoatzz in #6066
  • Tighten skills docs examples by @zzstoatzz in #6070
  • Shorten the skills docs page by @zzstoatzz in #6079
  • Badge the skills page as 4.2.0 by @zzstoatzz in #6083
  • Consolidate skills examples around verified Skill values by @zzstoatzz in #6093
  • docs: add v4.2.0a1 changelog entries by @zzstoatzz in #6105
  • Add MCP tool annotations to get_file example by @gl1tchdust in #5976
  • Fix dead links in current documentation by @zzstoatzz and @Wilson0511 in #6142
  • docs: rename Horizon to FastMCP Gateway in current docs by @parkedwards in #5653
  • Document strict-mode handling of undeclared OpenAPI arguments by @zzstoatzz in #6169
  • docs: add v4.2.0a2 changelog entries by @zzstoatzz in #6224
  • docs(settings): explain what FASTMCP_DEBUG actually does by @zzstoatzz and @ianw in #6255
  • docs: pass referrers on outbound links, add organization schema and page descriptions by @madureira-gabriel in #6287
  • docs: add v4.2.0a3 changelog entries by @zzstoatzz in #6306
  • docs: preserve docs routing metadata and release guidance by @zzstoatzz in #6320
  • Correct how tools docs describe bytes return values by @DivyaNarahari97 in #6275
  • docs: add v4.2.0a4 changelog entries by @zzstoatzz in #6388
  • docs: correct the server pages against main by @zzstoatzz in #6406
  • docs: correct the client pages against main by @zzstoatzz in #6407
  • docs: correct the apps pages against main by @zzstoatzz in #6409
  • docs: correct getting started, CLI and deployment pages against main by @zzstoatzz in #6410
  • docs: correct the integration pages against main by @zzstoatzz in #6408
  • docs: label the current docs version v4 by @zzstoatzz in #6411
  • docs: explain root_path for SSE behind a prefix-stripping proxy by @zzstoatzz and @KnittelK in #6215
  • docs: keep the search shortcut hint off the button edge by @zzstoatzz in #6413
  • docs: clarify tool errors and middleware transformations by @rasokiwayami and @jeffsawatzky in #5566
  • docs: server-level component changes don't notify clients by @zzstoatzz and @Ngtvu1752 in #6423
  • docs: badge 4.2.0 features and add the 4.1 → 4.2 upgrade guide by @zzstoatzz in #6436
  • Pre-4.2 polish: stale docs, examples and docstrings by @zzstoatzz in #6452
  • docs: add v4.2.0a5 changelog entries by @zzstoatzz in #6469
  • Update docs logo to new FastMCP wordmark by @ninadewane in #6462
  • docs: add v4.2.0 changelog entries by @zzstoatzz in #6482

Examples & Contrib 💡

Dependencies 📦

  • build(deps): bump mcp from 1.28.1 to 1.30.0 in /examples/testing_demo in the uv group across 1 directory by @dependabot[bot] in #5990

Other Changes 🦾

  • chore(deps): Update dependency ruff to v0.17.2 by @prefect-renovate[bot] in #6233
  • chore(deps): Pin dependencies by @prefect-renovate[bot] in #6064
  • Require patched joserfc by @zzstoatzz in #6371
  • Keep colon-terminated prose lines in docstring tool descriptions by @zzstoatzz, @jlx1999s, and @ptrailblazer89 in #6372
  • chore(deps): Update dependency oauthlib to v4.0.1 [SECURITY] by @prefect-renovate[bot] in #6367
  • chore(deps): Update dependency node to v26 by @prefect-renovate[bot] in #6234
  • chore(deps): Update dependency prefect to v3.9.1 by @prefect-renovate[bot] in #6232
  • Keep completion from suggesting values for hidden references by @zzstoatzz and @pvliesdonk in #6450

New Contributors

  • @adam-zovos made their first contribution in #6039
  • @fprieto14 made their first contribution in #6077
  • @keremoktener made their first contribution in #6077
  • @gl1tchdust made their first contribution in #5976
  • @Yash-Tripath1 made their first contribution in #6104
  • @ianw made their first contribution in #6255
  • @hntrl made their first contribution in #6268
  • @YingzuoLiu made their first contribution in #6268
  • @mohitdixit02 made their first contribution in #6311
  • @chris00234 made their first contribution in #6075
  • @67-luck made their first contribution in #6376
  • @mahekara28 made their first contribution in #6310
  • @shayanxcyber made their first contribution in #6041
  • @DMomplaisir made their first contribution in #6045
  • @xu91102 made their first contribution in #6045
  • @KnittelK made their first contribution in #6215
  • @bkranendonk made their first contribution in #6264
  • @kartikmadan11 made their first contribution in #6158
  • @totoyang made their first contribution in #6133
  • @hanhyperfx made their first contribution in #6147
  • @xiong-wei1 made their first contribution in #6061
  • @anh-nguyenn made their first contribution in #6054
  • @jamesmaidment made their first contribution in #5775
  • @yannvr made their first contribution in #5779
  • @akushonkamen made their first contribution in #5666
  • @anormang1992 made their first contribution in #5666
  • @jeffsawatzky made their first contribution in #5566
  • @rasokiwayami made their first contribution in #5566
  • @omikader made their first contribution in #5565
  • @dream-star-end made their first contribution in #5562
  • @YogaSakti made their first contribution in #5665
  • @Pyhroff made their first contribution in #6063
  • @Larry-Labs made their first contribution in #5664
  • @adrianto-nanovest made their first contribution in #5062
  • @lancy69 made their first contribution in #5062
  • @xixi-box made their first contribution in #6198
  • @glopezz made their first contribution in #6107
  • @BHAWESHBHASKAR made their first contribution in #6012
  • @Christian-Sidak made their first contribution in #6012
  • @Kushal9889 made their first contribution in #5980
  • @Abhi2939 made their first contribution in #5969
  • @ezz3r made their first contribution in #5969
  • @Lpk124 made their first contribution in #5763
  • @maxime-gautre made their first contribution in #5763
  • @lux-liang made their first contribution in #5588
  • @gshklovs made their first contribution in #5169
  • @ninadewane made their first contribution in #6462
  • @MayankTamakuwala made their first contribution in #6419
  • @Ngtvu1752 made their first contribution in #6423
  • @dsfaccini made their first contribution in #6425
  • @ldlda made their first contribution in #6426
  • @carterthayer made their first contribution in #6428
  • @AlyLanier made their first contribution in #6422
  • @CaselIT made their first contribution in #6429
  • @swantzter made their first contribution in #6429

Full Changelog: v4.1.4...v4.2.0

Don't miss a new fastmcp release

NewReleases is sending notifications on new releases.