Add a stub MCP upstream test harness for end-to-end /mcp output-path tests
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 157
- Forks
- 32
- Avg merge
- 1h 25m
- Merged PRs (30d)
- 145
Description
Context
The /mcp handler (crates/aisix-proxy/src/mcp.rs) governs a tools/call with the same pipeline as an LLM request: per-tool ACL, rate-limit + budget, input + output guardrails, and a usage event. The input path is testable end-to-end through the router because an input guardrail blocks before any upstream is contacted (input_guardrail_blocks_tool_call_with_forbidden_args drives the real router and asserts the JSON-RPC error envelope + echoed id).
The output path cannot be driven end-to-end today: scanning the tool result happens after the gateway dispatches to a real MCP upstream, and the proxy test harness has no in-process MCP upstream that returns a scannable result. So output-side behavior is currently covered at two levels below the full handler:
output_guardrail_block(the scan/decision helper) — block / allow / no-result / decoded-text-vs-envelope cases.jsonrpc_guardrail_block(the wire-envelope builder both hooks funnel through) — status,code -32600, content-type, echoed id, noresult.
Gap
Two seams are only covered by structural equivalence to the input path, not directly:
- The clean-result pass-through: a clean tool result is buffered and re-wrapped via
Response::from_parts(resp_parts, Body::from(resp_bytes)). A regression that dropped/garbled headers or the body on this path would not be caught. - The output-block wiring end-to-end: handler dispatches → buffers →
output_guardrail_block→jsonrpc_guardrail_block(rpc_id, "tool result", …).
Proposal
Add a minimal in-process MCP upstream stub to the proxy test harness (an mcp_servers entry backed by an EphemeralBridge-style handler that echoes its arguments as a text content block). Then add router-level tests:
- a
tools/callwhose result text carries a forbidden token → HTTP 200 JSON-RPC error,code -32600, echoed request id; - a clean
tools/call→ the upstream result passes through unchanged (status,content-type, body bytes intact).
Why separate
Wiring a real rmcp upstream into the proxy harness is a non-trivial test-infra addition, out of scope for the output-guardrail change itself (#671). Surfaced by independent audit of #673; tracked here so the gap is explicit rather than silent.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with crates/aisix-proxy/src/mcp.rs and the existing input_guardrail_blocks_tool_call_with_forbidden_args, output_guardrail_block, and jsonrpc_guardrail_block tests. Read the proxy test harness around mcp_servers and the EphemeralBridge-style handler, then add router-level coverage for a forbidden result and a clean result. Done means the error preserves HTTP 200, code -32600, and the request id, while the clean response preserves status, content type, and body bytes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- testing
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100