feat: add FastMcpBootstrapper#105
Merged
Merged
Conversation
Design captured for replacing InstrumentNotReadyWarning with a pre- instantiation `is_configured` classmethod check + structured skipped_instruments introspection + single INFO summary log. The current post-PR-#86 behavior fires a warning every time an instrument's is_ready() returns False — typically a user-config opt-out, not an anomaly. Every service that uses a subset of available instruments emits multiple warnings on bootstrap; tests can't suppress without breaking the warning assertions. The redesign moves the config check before check_dependencies, makes it a classmethod (preserves PR #88's no-instantiation-on-missing-dep constraint), and removes the warning entirely. dep-missing still warns (genuine deployment surprise). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The original design aimed to wrap FastMCP.lifespan with combine_lifespans to wire teardown automatically. Implementation surfaced that FastMCP.lifespan is a read-only bound method on AggregateProvider and the runtime hook is the private _lifespan attribute (set at constructor time only). The spec's documented fallback — "teardown is manual" — is now the adopted approach. Updates: - Spec: §"Teardown wiring risk" → §"Teardown is manual"; tests list drops ASGI-lifespan and user-lifespan-preserve tests, adds test_fastmcp_teardown_resets_is_bootstrapped. - Plan: Task 4 module skeleton no longer mutates lifespan; Task 5 reduced to single teardown-reset assertion; integrations page documents how users wire teardown themselves. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…eadyError Final-review followup: assert on the project's typed exception rather than bare RuntimeError so a future change to the base class hierarchy doesn't silently weaken the test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests.
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Earlier work concluded teardown had to be manual because FastMCP.lifespan is a read-only bound method. Re-investigation surfaced FastMCP.add_provider, which DOES accept post-construction providers and invokes each provider's lifespan async context manager during ASGI startup/shutdown. A small _TeardownProvider(Provider) wraps bootstrapper.teardown() and is registered automatically from FastMcpBootstrapper.__init__. Users no longer need to call teardown() manually — it runs when the ASGI application that serves application.http_app() shuts down. Restores test_fastmcp_teardown_runs_via_asgi_lifespan with a hand-rolled ASGI lifespan driver. Drops the "manual teardown" section from the integrations doc. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Matches the fastapi-all / litestar-all / faststream-all naming pattern. fastmcp-all = [lite-bootstrap[fastmcp,fastmcp-metrics,sentry,logging,pyroscope]], so users can install the whole stack with a single extra rather than composing five extras by hand. Updates docs/introduction/installation.md to list `fastmcp-all` in the "all" row and drops the now-obsolete "no rollup" note above the table. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A recent faststream release tightened AsgiFastStream's typed signature to BrokerUsecase (no None). The wo_broker test path passed broker=None positionally, which started failing CI with both a ty error and a runtime AttributeError on _update_fd_config. build_faststream_config now omits the broker argument entirely when no broker is provided. test_faststream_bootstrap_health_check_wo_broker keeps its semantics (verifying the brokerless health-check path). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ngInstrument LoggingInstrument.check_dependencies (the parent) already returns is_structlog_installed, and BaseBootstrapper._register_or_skip filters the instrument out before instantiation when it returns False. Reaching FastMcpLoggingInstrument.bootstrap() therefore implies structlog is installed; the inner guard is unreachable defensive code. Surfaced by codecov flagging it as uncovered on PR #105. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… _TeardownProvider Three of the spec/plan sections still described the short-lived "manual teardown" fallback that was reverted in commit b786781. Specifically: - spec §"Teardown is manual" → §"Teardown via Provider.lifespan" - spec Tests list: restore test_fastmcp_teardown_runs_via_asgi_lifespan - plan locked-decisions: replace "Teardown: manual" with the add_provider wiring; mention fastmcp-all rollup - plan Task 5: explain the direct + lifespan test pair Also adds a one-line comment to _TeardownProvider explaining that FastMCP exposes no on_shutdown-style API and Provider.lifespan is the only public post-construction hook. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
FastMcpBootstrapperandFastMcpConfigthat wire the lite-bootstrap instrument stack (Sentry, Pyroscope, structlog logging with an MCP protocol-level access-log middleware, JSON health endpoint, Prometheus metrics endpoint) onto a user-suppliedFastMCPinstance.import_checker,instruments_typesClassVar registry, and single-file bootstrapper module mirroringfaststream_bootstrapper.py.fastmcp(depends onfastmcp),fastmcp-metrics(addsprometheus-client>=0.20), andfastmcp-allrollup (parity withfastapi-all/litestar-all/faststream-all).Provider.lifespanhook. The bootstrapper registers an internal_TeardownProviderfrom its__init__, and the provider'slifespanasync-cm runsbootstrapper.teardown()on ASGI shutdown.FastMCP.lifespanitself is a read-only bound method (the real hook is_lifespan, captured at constructor time only), soadd_provideris the only public post-construction lifecycle hook — that's what we use. Users don't need to callteardown()themselves.Spec:
docs/superpowers/specs/2026-06-01-fastmcp-bootstrapper-design.mdPlan:
docs/superpowers/plans/2026-06-01-fastmcp-bootstrapper.mdTest plan
just test— full suite passes (19 new fastmcp tests + 129 existing)just lint— clean (ruff, eof-fixer, ty)lite_bootstrap/bootstrappers/fastmcp_bootstrapper.pyis 100% via 19 dedicated tests (health route, prometheus route, MCP middleware logging, teardown via direct call and via ASGI lifespan, missing-dependency regression for sentry/structlog/prometheus_client, not-ready when fastmcp is absent)lite-bootstrap[fastmcp-all]in a scratch project, boot aFastMCPapp, hit/health/and/metrics, shut down via ASGI lifespan and confirm teardown runsprometheus-client/ withoutstructlog; confirmUserWarning+ clean boot🤖 Generated with Claude Code