Repository navigation
Conversation
This comment has been minimized.
This comment has been minimized.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
The provider's auto-created httpx2 client is closed at the end of each server lifespan and httpx2 clients cannot be reopened. Track the default client's base URL, recreate the client when it is closed, and rebind the pre-created tools, resources, and templates to the fresh instance. Caller-supplied clients are still never closed or replaced.
5cb5805 to
104fdbb
Compare
There was a problem hiding this comment.
Automated review by the FastMCP triage reviewer bot.
The lifecycle fix passed targeted verification. One non-blocking scope issue remains: the unrelated OAuth test now ignores every warning originating outside the repository, which can hide dependency warnings caused by the operation being tested.
Remove the tests/cli/test_client_commands.py warning-filter change from this PR; handle any OAuth warning issue separately with its own diagnosis.
Checks
Baseline lifecycle tests: 3 expected failures, 2 passes. Head: 114 focused tests passed. An independent probe verified tool/resource/template results and outgoing requests across two lifespans.
|
Closing for now: #5844 stays open. This also edits an unrelated test, and the fix will land after 4.2. |
Closes #5844
Description
FastMCP.from_openapi(spec)without an explicitclient=could only be connected once. A second lifespan (a secondasync with Client(mcp), re-entering the sameClient, or a fixture that reconnects) failed withRuntimeError: Client failed to connect: Cannot reopen a client instance, once it has been closed.The provider auto-creates anhttpx2.AsyncClient, enters it per lifespan, and httpx2 clients are single-use afteraclose().What changed
DEFAULT_TIMEOUT)._create_owned_client()and_rebind_client(); rebinding updatesself._clientand every pre-createdOpenAPITool,OpenAPIResource, andOpenAPIResourceTemplate, which capture the client object directly.lifespan()recreates and rebinds only when the provider owns the client andself._client.is_closed. The first lifespan reuses the original client; a caller-supplied client is never closed, recreated, or replaced.Contribution type
Bug fix verification
Test path:
tests/server/providers/openapi/test_owned_client_lifespan.py(five tests).Red at
adf90b66(test file from the fix applied, implementation reverted):3 failed, 2 passed, deterministicRuntimeError: Cannot reopen a client instance, once it has been closed.; no collection errors. The two passing tests are intentional guards: a supplied client is not closed, and concurrent first-lifespan entries share the original client.Green at the fix commit:
1209 passed, 26 warningsacrosstests/server/providers/ tests/server/test_providers.py.Validation
uv run --isolated pytest tests/server/providers/ tests/server/test_providers.py -q-> 1209 passeduv run --isolated ruff checkandruff format --checkon the changed files -> cleanuv run --isolated ty check-> All checks passedAI assistance
Tool(s) used: Claude Code
How you used it: investigated from a verified reproduction, implemented the client recreation/rebinding and the regression tests.
Checklist
uv run prek run --all-filesand all checks pass (focused checks passed)