--- id: review-001-consumer-adapter-hygiene name: from_wss/from_mcp consumer fixes — plaintext ws://, 401 classification, token hygiene (CON-03, CON-05..CON-13) status: pending depends_on: [] scope: moderate risk: low impact: component level: implementation tags: [adapters, review-001, mcp, from-wss] --- ## Description Review 001 consumer-adapter findings, minus the hang fix (its own task — review-001-ws-robustness carries WS-02/CON-02), grouped as the small CON cleanup list: - **CON-01 (one-liner)**: `from_mcp/mod.rs:86` imports only the first `tools/list` page; `next_cursor` is never followed. rmcp 1.8 provides `list_all_tools()` for exactly this. Servers that paginate silently truncate the import — no error, no log. Fix and add a paginating-server test (COV gap 11). - **CON-03 (security)**: `from_wss.rs:114-128` accepts plaintext `ws://` and attaches the Bearer token unconditionally. A config typo silently ships a long-lived bearer credential over plaintext. Refuse `ws://` when a token is present — or unconditionally unless explicitly allowed — with a clear error. - **CON-04** (`from_mcp/mod.rs:240-248`): the audio variant of `content_block_union_schema` requires non-existent `"audio"` (property is `data`) — valid audio blocks never satisfy the published `output_schema`. Fix and validate a real audio block. - **CON-05/CON-07**: docs claim per-call credential reads; reality is import-time credentials (`from_mcp` transport-pinned token, `from_wss` bundles carry no capabilities at all). Correct docs, remove the dead capability read (`mod.rs:139-143`). - **CON-06** (`mod.rs:103-116`): 401 classified via `format!("{error:?}").contains("401")` — a `:4010/` port in a URL misclassifies as Unauthorized and real auth failures can be missed. Match typed variants; substring only as last resort. - **CON-11**: transport-level `tools/call` failures → undeclared `CallError::internal`; declare the failure mode (and preserve JSON-RPC error fidelity where cheap). - **CON-12**: remote tool names interpolated into op names unsanitized — a `/` in a tool name breaks the two-segment `ns/op` convention. Sanitize/validate at import. - **CON-13** (`from_wss.rs:48`, `from_mcp/mod.rs:37`): held tokens are plain `Option`; use `Secret` to match the crate's posture (no `Debug` derives exists — keep it that way). - **CON-10**: `[[test]] full_surface` is missing `test-support` in `required-features` → `cargo test --features mcp` fails to compile (empirically verified; masked by CI's `--all-features`). - **CON-08/CON-09**: no teardown path on `FromMCP` (each `import()` leaks an open server-side session + GET SSE stream) and `from_wss` import stacks duplicate sessions on reconnect by design (ADR-070 v1). Either add explicit close/teardown handles or write the ADR-070 note + module docs that make the limitation explicit — do not silently expand scope into a reconnect layer. ## Acceptance Criteria - [ ] Paginated `tools/list` fully imported (paginating-server test) - [ ] `ws://` + token refused (or explicit opt-out) with a clear error (test) - [ ] Audio variant of `content_block_union_schema` satisfied by a valid block (test) - [ ] No substring-based 401 classification on typed paths; a URL containing `:401x` no longer misclassifies (test) - [ ] CON-05/07 docs corrected; dead capability read removed - [ ] CON-11/12: transport-failure error declared; remote tool names sanitized (test) - [ ] Tokens held as `Secret` - [ ] `cargo test --features mcp` compiles and passes (CON-10), as does `cargo test --all-features` - [ ] CON-08/09: close handles exist or docs/ADR-070 note state the limitation ## References - docs/reviews/001-initial-implementation-review.md (Part G, CON-03..CON-13) - docs/architecture/decisions/070-from-wss-consumer-adapter.md ## Notes > Agent fills during implementation. Independent of the WS tasks. > The from_wss notify/pending fixes are tracked separately in > review-001-ws-robustness (WS-02/CON-02 share one mechanism). ## Summary > Filled on completion.