Skip to content

Parity catch-up to upstream fastmcp v3.4.2 (F1–F8)#46

Merged
0xeb merged 4 commits into
mainfrom
feature/parity-catchup-v3.4.2
Jul 10, 2026
Merged

Parity catch-up to upstream fastmcp v3.4.2 (F1–F8)#46
0xeb merged 4 commits into
mainfrom
feature/parity-catchup-v3.4.2

Conversation

@0xeb

@0xeb 0xeb commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Catch-up sync to upstream fastmcp v3.4.2 (3b8538e2) from v3.3.1 (d8dcc273). 56-commit delta triaged: 7 port-needed, 3 review, 15 intentional divergences (auth/OAuth/JWT/code-mode/fastmcp-remote/dev-apps), 29 N/A (docs/CI/deps/Python-only).

Ported

  • F1compare_versions strips leading v prefix (VersionSpec eq normalization) — src/providers/transforms/version_filter.cpp
  • F2 — preserve title/annotations/icons/version/task_support when creating resources from templates — src/resources/template.cpp
  • F4 — root metadata preserved on schema-ref fallback (verified already correct; test pins the contract)
  • F5ToolResult is_error passthrough via proxy/handler/cache (verified correct; interop test added)
  • F7ProxyErrorStrategy enum (Warn default, Raise propagates upstream errors) — include/fastmcpp/proxy.hpp, src/proxy.cpp
  • F8 — proxy initialize forwarding (opt-in validate_on_initialize) — src/mcp/handler.cpp
  • Version bump 3.3.1 → 3.4.2 (CMakeLists.txt, README.md)

Deferred / N-A

  • F3 N/A (no mcp_config in C++), F6 deferred (cpp-httplib has no pre-bound socket API), F9 N/A (proxy passes URIs verbatim), F10 review-only (no existing sampling spans), F-NA-1 N/A (no StatefulProxyClient). Auth/OAuth/JWT/code-mode/fastmcp-remote/dev-apps remain intentional divergences.

Verification

  • Debug ctest 107/107 (baseline 103 + 4 new tests)
  • Release ctest 92/92
  • Deep interop 241/241 across 9/9 scenarios (Python fastmcp v3.4.2 ↔ C++ fastmcpp)

New tests: tests/resources/template_metadata.cpp, tests/schema/root_ref_metadata.cpp, tests/client/tool_result_is_error.cpp, tests/proxy/error_strategy.cpp; extended tests/providers/version_filter.cpp.

0xeb and others added 4 commits June 9, 2026 16:54
F1 (Python fastmcp #4058, commit 24b594b1):
  utilities/versions.py VersionSpec eq normalization. fastmcpp's
  compare_versions already normalized {1, 1.0} via the default-zero
  padding, but did not strip a leading 'v'/'V' prefix. After this
  change, '�2.5.0' compares equal to '2.5.0' so version filters
  match v-prefixed components consistently.

F2 (Python fastmcp #4061, commit 01b971d8):
  resources/template.py FunctionResourceTemplate.create_resource()
  was dropping annotations/meta/title/icons when materializing a
  resource from a template. fastmcpp's ResourceTemplate::create_resource
  had the same bug — only uri/name/description/mime_type/app/provider
  propagated. Now title/annotations/icons/version/task_support also
  carry through.

Tests:
- tests/providers/version_filter.cpp gains v_prefixed_tool case
  (versioned 'v2.5.0', expected to fall in [2.0, 3.0)).
- tests/resources/template_metadata.cpp is a new focused test that
  builds a ResourceTemplate with title/annotations/icons/version/
  task_support set and asserts every field propagates through
  create_resource().

ctest -R 'fastmcpp_(provider_version_filter|resources_template_metadata)':
  2/2 passed.

Reference: fastmcp v3.4.2 (3b8538e2)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Both findings are already-implemented in fastmcpp; these tests pin the
behavior explicitly so future regressions are caught.

F4 (Python fastmcp #4178, commit 834f96d4 + cosmetic #4023 / 7cfcaf22):
  utilities/json_schema.py resolve_root_ref must preserve sibling
  metadata (title/description/default/examples) when falling back to
  a  lookup for circular schemas. fastmcpp's dereference_node
  (src/util/json_schema.cpp:152) already merges non- siblings
  onto the resolved object. New test root_ref_metadata.cpp asserts
  this for a root-level  with title+description siblings.

F5 (Python fastmcp #4217, commit e242abee):
  tools/base.py ToolResult.is_error so a tool can RETURN an error
  (instead of raising), and proxy/caching round-trip is_error. At
  the fastmcpp wire level, this already works:
  - server-side: build_fastmcp_tool_result preserves isError when
    a tool callback returns {"content": [...], "isError": true}
    (handler.cpp:817)
  - client-side: parse_call_tool_result reads isError into
    CallToolResult (client.hpp:1043) and call_tool(raise_on_error=
    false) returns without throwing
  - ProxyApp passes the remote result through verbatim with
    raise_on_error=false (proxy.cpp:268)
  - CachingMiddleware caches list endpoints only — not tools/call
    — so the Python CachableToolResult is_error round-trip concern
    doesn't apply
  Prior tests only covered the raise_on_error=true (throw) path
  (interactions_part1.cpp test_call_tool_error_handling). New test
  tool_result_is_error.cpp covers the no-throw F5 path and asserts
  content + structuredContent are preserved (not collapsed).

ctest results (new tests only):
  fastmcpp_schema_root_ref_metadata: PASS
  fastmcpp_client_tool_result_is_error: PASS

Reference: fastmcp v3.4.2 (3b8538e2)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
F7 (Python fastmcp #4227, commit 2bff3725):
  AggregateProvider/FastMCPProxy gained provider_error_strategy
  with values 'warn' (default — log + silently skip failed
  providers) and 'raise' (propagate the first provider error).
  fastmcpp ProxyApp's list_all_* previously hard-coded the
  'warn' behavior (catch and continue with local-only). This
  change introduces ProxyErrorStrategy enum (Warn|Raise) and
  ProxyAppOptions surface, default Warn for back-compat. Under
  Raise, list_all_tools/resources/templates/prompts re-raise
  the first upstream exception so callers can fail fast.

F8 (Python fastmcp #4228, commit 140d96aa):
  FastMCPProxy made validate_on_initialize always-on so the
  proxy's MCP initialize forwards to the upstream and surfaces
  connection failures as JSON-RPC errors immediately. fastmcpp
  keeps this opt-in via ProxyAppOptions::validate_on_initialize
  (default false) for back-compat with existing fastmcpp users
  that construct proxies whose upstream may be lazily reachable.
  When enabled, make_mcp_handler(ProxyApp&) calls upstream
  Client::initialize() on inbound initialize, and returns
  jsonrpc_error(INTERNAL_ERROR, ...) on any std::exception.

API surface added:
  enum class fastmcpp::ProxyErrorStrategy { Warn, Raise };
  struct fastmcpp::ProxyAppOptions {
      std::string name = "proxy_app";
      std::string version = "1.0.0";
      std::optional<std::string> instructions;
      ProxyErrorStrategy error_strategy = ProxyErrorStrategy::Warn;
      bool validate_on_initialize = false;
  };
  ProxyApp::ProxyApp(ClientFactory, ProxyAppOptions);  // new
  ProxyErrorStrategy ProxyApp::error_strategy() const;
  bool ProxyApp::validate_on_initialize() const;

Files touched:
  include/fastmcpp/proxy.hpp   — enum, struct, ctor, accessors
  src/proxy.cpp                — new ctor + strategy check in
                                 each list_all_* error handler
  src/mcp/handler.cpp:2580     — F8 initialize-time upstream ping
                                 in make_mcp_handler(ProxyApp&)
  tests/proxy/error_strategy.cpp — 4 new test cases covering
                                   Warn (default), Raise, and
                                   both initialize paths

Verification:
  ctest --test-dir build -C Debug -j 8:
    107/107 passed (was 103/103 baseline + F1/F2/F4/F5 tests
    + this F7+F8 test = 107). No regressions.

Reference: fastmcp v3.4.2 (3b8538e2)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CMakeLists.txt project version and README.md headline updated to
reflect the v3.4.2 parity catch-up for upstream fastmcp 3b8538e2.

In-scope behavioral findings landed in this cycle:
  F1 — VersionSpec eq normalization (v-prefix strip)
  F2 — Resource-template metadata propagation
  F4 — JSON-schema root-ref metadata (verify-first; already correct)
  F5 — ToolResult is_error wire-level passthrough (verify-first; already correct)
  F7 — Proxy upstream error strategy (Warn|Raise; default Warn)
  F8 — Proxy initialize forwarding (opt-in via ProxyAppOptions)

Deferred (documented in kb/sync/review_result.md):
  F3 — UTF-8 MCP config read (N/A: fastmcpp has no mcp_config equivalent)
  F6 — Pre-bound HTTP sockets (cpp-httplib limitation; revisit if user needs it)
  F9 — Proxy template query-params (N/A: fastmcpp passes URIs verbatim)
  F10 — OTEL spans on sampling (review-first: defer if no spans yet)
  F-NA-1 — Proxy ContextVar restore (N/A: no StatefulProxyClient in C++)

Intentional divergences for the full v3.3.1..v3.4.2 delta (15 commits):
  - 11 auth/OAuth/JWT/joserfc/WorkOS/Azure/OIDC commits
  - 2 code-mode (Monty sandbox) commits
  - 1 fastmcp-remote bridge package
  - 1 'fastmcp dev apps' browser UI CLI

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@0xeb 0xeb merged commit befdd40 into main Jul 10, 2026
4 of 7 checks passed
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