api7 / api7/aisix

Add a stub MCP upstream test harness for end-to-end /mcp output-path tests

Open
#674 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
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, no result.

Gap

Two seams are only covered by structural equivalence to the input path, not directly:

  1. 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.
  2. The output-block wiring end-to-end: handler dispatches → buffers → output_guardrail_blockjsonrpc_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/call whose 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.