Skip to content

test(gateway): a real gateway in front of a real protocol child, over loopback - #160

Open
earakely-scale wants to merge 2 commits into
mainfrom
test/gateway-tool-context-loopback
Open

earakely-scale wants to merge 2 commits into
mainfrom
test/gateway-tool-context-loopback

Conversation

@earakely-scale

@earakely-scale earakely-scale commented Oct 11, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

#153 binds a ToolContext per tool call inside the protocol, and #145 makes the gateway stamp the caller's role and session on each proxied call. Each was tested on its own side with the other faked. This adds the test that puts a real gateway in front of a real protocol child over loopback, in the integration-local tier:

  • two MCP clients with different AgentEnv-Role headers reach the child's tools as two callers, each with the gateway's per-session key rather than the gateway's connection id, stable across calls on one session;
  • a tool that never declared a ToolContext parameter keeps its schema and is served as before, with the caller still readable through ToolContext.current();
  • a refusal returned by the child's on_tool_call reaches the client through the gateway as isError with its payload intact;
  • a gateway /step call carries the role and no session; a client connecting to the child directly gets its header role and its own connection id;
  • the gateway's and the protocol's wire names are the same constants.

Two protocol docstrings are corrected on the way, with no code change: the marker on the installed dispatch is read by the mount's own second-handler check, not by a downstream boot guard, and caller_from_request takes a _meta session whenever one is present, with or without a _meta role entry.

Testing

  • tst/integration/env/gateway/role_forwarding_local_test.py with packages/agentenv-protocol/tests: 429 passed, clean under -W error::DeprecationWarning.

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 4/5

The PR appears safe to merge, with a non-blocking improvement needed to clean up servers after test failures.

Fix All in CursorFindings

  1. P2 Failed tests leave servers running ▶
Fix with agent prompt
### Issue 1
tst/integration/env/gateway/role_forwarding_local_test.py:71-75
Both servers start before `_stack` enters its `try` block. If gateway setup raises, the child server stays open. An error during gateway shutdown also skips child shutdown. These leftover servers and tasks can add cleanup warnings and obscure the original test failure.

Register cleanup immediately after each server starts, using nested `try/finally` blocks or `AsyncExitStack`, so both servers close even when setup or teardown fails.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Adds a loopback integration test with a real gateway and protocol child.

  • The gateway and protocol child now get tested together over loopback.
  • Protocol docs clarify the tool marker and caller session rules.

Diagram

sequenceDiagram
  participant C as MCP clients
  participant G as Gateway
  participant P as Protocol child
  C->>G: Connect with separate roles
  G->>P: Call tool with role and session
  P-->>G: Tool result or refusal
  G-->>C: Return result
  C->>G: POST /step with role
  G->>P: Call tool with role, no session
  C->>P: Direct call with role header
  P-->>C: Role and child connection session
Loading

Reviews (1) · Last reviewed commit: "docs(protocol): say what the dispatch ma..." · Reviewed by Greptile

earakely-scale and others added 2 commits October 10, 2026 23:07
… loopback

Two loopback servers: a protocol environment and a Gateway with it as
its only backing server. Two MCP clients with different AgentEnv-Role
headers reach the child's tools as two callers, each with the gateway's
per-session key rather than its connection id, stable across calls on
one session; a tool that never asked for the caller keeps its schema and
answers as before; a refusal returned by the child's on_tool_call
reaches the client through the gateway as isError with its payload
intact; a /step call carries the role and no session; a client on the
child directly gets its header role and its own connection id.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…a session is read

The marker on the installed dispatch is read by _check_tool_binding to
refuse a second handler on one app; no downstream guard reads it.
caller_from_request takes the _meta session whenever one is present,
with or without a _meta role entry, and falls back to the connection id
only for a direct caller.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@earakely-scale
earakely-scale requested a review from a team as a code owner October 11, 2026 06:07
Comment on lines +71 to +75
env = _Items()
child_server, child_url = await _serve(env.create_app().streamable_http_app())
gw = Gateway(host="127.0.0.1", port=0, server_name="t",
internal_mcp_servers=[InternalMCPServer("items", f"{child_url}/mcp")])
gw_server, gw_url = await _serve(gw._asgi_app())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Failed tests leave servers running

Both servers start before _stack enters its try block. If gateway setup raises, the child server stays open. An error during gateway shutdown also skips child shutdown. These leftover servers and tasks can add cleanup warnings and obscure the original test failure.

Register cleanup immediately after each server starts, using nested try/finally blocks or AsyncExitStack, so both servers close even when setup or teardown fails.

Prompt To Fix With AI
This is a comment left during a code review.
Path: tst/integration/env/gateway/role_forwarding_local_test.py
Line: 71-75

Comment:
**Failed tests leave servers running**

Both servers start before `_stack` enters its `try` block. If gateway setup raises, the child server stays open. An error during gateway shutdown also skips child shutdown. These leftover servers and tasks can add cleanup warnings and obscure the original test failure.

Register cleanup immediately after each server starts, using nested `try/finally` blocks or `AsyncExitStack`, so both servers close even when setup or teardown fails.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

This branch has not been deployed

No deployments
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