feat(client): ADCPClient.from_mcp_client() factory for in-process MCP transport#293
Open
feat(client): ADCPClient.from_mcp_client() factory for in-process MCP transport#293
Conversation
- Use explicit None check for agent_id (empty string now preserved) - Replace assert isinstance with explicit RuntimeError for -O safety https://claude.ai/code/session_014Lazxs8FCWcVzzKi8MpLPi
…rom_mcp_client - Type client as ClientSession via TYPE_CHECKING import - Reorder params (capabilities_ttl, validate_features, strict_idempotency) to match ADCPClient.__init__ for consistency - Add inline comment clarifying adcp_client lifecycle in docstring example https://claude.ai/code/session_014Lazxs8FCWcVzzKi8MpLPi
Acting on dx-expert review of this PR: - ``ADCPClient.from_mcp_client`` docstring: add a Warning block above Args. Surfaces three traps a docstring-skimmer would otherwise miss: (1) ``close()`` and ``async with`` exit are no-ops on injected sessions, (2) webhook + ``on_activity`` are intentionally not wired because there is no HTTP transport for a callback, (3) an uninitialized session surfaces as an opaque MCP error rather than a friendly one. - Move ``from uuid import uuid4`` to module-level imports — the ``uuid4 as _uuid4`` rebind inside the method was unconventional with no benefit. - ``docs/testing-guide.md``: new "In-Process MCP Fixtures" section showing the canonical ``contextlib.AsyncExitStack`` + ``create_client_server_memory_streams`` + ``ClientSession`` + ``ADCPClient.from_mcp_client`` pattern. Without this, the factory is invisible outside the docstring and someone reading the testing guide reaches for a loopback HTTP server (and re-files the parity issue, which is how this PR started). 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.
Closes #291
Summary
Adds
ADCPClient.from_mcp_client(client, *, agent_id=None, ...)— a classmethod that wraps a pre-connectedmcp.ClientSessionand returns a fully configuredADCPClient. Parity with JSAgentClient.fromMCPClient()(v5.19.0). The primary use case is compliance test fleets that need the full client path exercised against an in-process MCP server viamcp.shared.memory.create_client_server_memory_streams, without standing up a loopback HTTP server.Mechanics:
MCPAdapter._get_session()already short-circuits whenself._session is not None. The factory injects the caller-owned session there and sets a_session_is_injectedflag soclose()skips_cleanup_failed_connection— the caller owns the lifecycle. All existing client surface (validation, idempotency,validate_features, capability cache) works unchanged through the factory path. Request signing is intentionally absent from the factory params: the hook is wired into the HTTP transport layer that is bypassed here.What was tested
pytest tests/test_protocols.py::TestFromMcpClientFactory— 8 new tests: session injected, unique default agent_id, explicit agent_id, tool calls route through injected session,close()no-op,async withexit no-op, validation wired, unique idempotency tokenspytest tests/ -x -q --ignore=tests/integration --ignore=tests/conformance/signing/test_ip_pinned_transport.py— 2185 passed, 21 skipped, 0 failuresruff check src/adcp/protocols/mcp.py src/adcp/client.py— cleanmypy src/adcp/protocols/mcp.py src/adcp/client.py— cleanNits surfaced (not fixed — reviewer discretion)
test_tool_call_routes_through_injected_sessioncallsadapter._call_mcp_tooldirectly rather than the publicget_productsmethod; either level is valid, but the public surface is more refactor-stablestrict_idempotency=Truewiresidempotency_capability_checkon the adapter; a test asserting the hook is set would complete coverage of that flagawait session.initialize()get an opaque MCP error string inTaskResult.error)testing-guide.md(if present) does not referencefrom_mcp_client— follow-on documentation taskBucket gap
No
clientlabel exists in this repo. Bucket for this issue is client (ADCPClient surface). Flagged in run summary.Pre-PR review
agent_id,if not isinstanceguard replacingassert,ClientSessiontype annotation viaTYPE_CHECKING)__init__, inline lifecycle comment in docstring example); server-wiring placeholder comment noted as adequate for first iterationSession: https://claude.ai/code/session_014Lazxs8FCWcVzzKi8MpLPi
Generated by Claude Code