feat(testing): extend build_asgi_app with full serve-layer kwargs#626
feat(testing): extend build_asgi_app with full serve-layer kwargs#626
Conversation
Adopter confirmation (filed #618)Read the full diff against our `core/main.py:build_app()` boilerplate. This kills our private-API imports cleanly. Coverage check against everything our `_serve_kwargs` drives:
After merge, our core/main.py:build_app shrinks from ~40 lines (including `from adcp.decisioning.serve import create_adcp_server_from_platform` and `from adcp.server.serve import _apply_asgi_middleware, _build_mcp_and_a2a_app` private imports) to roughly: ```python One concern: wrapping orderThe PR docstring describes wrapping order matching `_run_mcp_http`. Worth verifying against the production path because we have downstream middleware (signing verification, dual-credential audit, transport detection) that depends on inner-vs-outer ordering. Specifically:
If the answer is "yes, identical to production" then this is mergeable for our use case as-is. Ready to adoptOnce this lands, we'll bump the floor and migrate `build_app` in the same PR. Happy to be the canary integration test — give us a heads-up when this merges. |
|
@bokelley — verified against both Short answer: yes, path_normalize is preserved when The One deliberate divergence from production to be aware of: The wrapping order is identical to production for your Generated by Claude Code |
45b97a9 to
7c78108
Compare
build_asgi_app previously returned only the bare mcp.streamable_http_app() without auth, ASGI middleware, path normalization, or request size capping. This caused silent gaps when tests needed transport-layer fidelity matching production (auth middleware, CORS, custom context_factory, etc.). Now applies the same wrapping chain as _run_mcp_http: auth (innermost) → path_normalize → discovery → size_limit → asgi_middleware New params on build_asgi_app and build_test_client: auth, asgi_middleware, context_factory, middleware, streaming_responses, enable_dns_rebinding_protection, allowed_origins, max_request_size, validation (default DEFAULT_VALIDATION matching production), discovery_base_url Also adds AGENTS.md import quick-reference entry for build_asgi_app, build_test_client, make_request_context so coding agents discover these helpers without falling back to network-layer mocks. Closes #618 https://claude.ai/code/session_012Ujdm5DZ7CyECWqSq9KrHN
…wed_origins to build_test_client - Fix SERVERDEFAULT_VALIDATION → SERVER_DEFAULT_VALIDATION (ImportError blocker found in pre-PR review) - Add allowed_origins param to build_test_client and wire it through to build_asgi_app, matching issue spec https://claude.ai/code/session_012Ujdm5DZ7CyECWqSq9KrHN
7c78108 to
3b335d3
Compare
$(cat <<'EOF'
Summary
Closes #618.
adcp.testing.build_asgi_apppreviously returned a bare MCP ASGI app with no middleware. Adopters writing in-process integration tests had to import private helpers (_wrap_mcp_with_auth,_wrap_with_path_normalize, etc.) to replicate the production middleware stack — the exact friction the issue describes.This PR:
build_asgi_appwith the full set ofserve()-compatible kwargs:auth,allowed_hosts,allowed_origins,asgi_middleware,context_factory,middleware,streaming_responses,enable_dns_rebinding_protection,max_request_size,validation,discovery_base_url._run_mcp_httpinadcp.server.serve(auth → path_normalize → discovery → size_limit → asgi_middleware).build_test_clientwith all of the above exceptallowed_hosts(auto-derived frombase_url).AGENTS.mdimport quick-reference with the new helpers.Changed files
src/adcp/testing/decisioning.pybuild_asgi_appto apply the full middleware chain; extendedbuild_test_clientto forward all new paramstests/test_testing_decisioning.pyAGENTS.mdPre-PR review sign-offs
SERVERDEFAULT_VALIDATIONtypo) found and fixed;allowed_originsmissing frombuild_test_clientadded.discovery_base_urldocstring cross-reference added;allowed_originsparam added tobuild_test_client.Test plan
pytest tests/test_testing_decisioning.py -v— 31/31 passruff check src/adcp/testing/decisioning.py tests/test_testing_decisioning.py— cleanmypy src/adcp/testing/decisioning.py— no new errors (pre-existing httpx/asgi-lifespan optional-dep errors only)python -c "from adcp.testing import build_asgi_app, build_test_client, make_request_context"— imports cleanlyhttps://claude.ai/code/session_012Ujdm5DZ7CyECWqSq9KrHN
EOF
)
Generated by Claude Code