feat(instances): add crew= scope to the session read MCP tools - #6874
feat(instances): add crew= scope to the session read MCP tools#6874cixuuz wants to merge 1 commit into
Conversation
Design Review (Fable 5) — 🟡 CONCERNSDesign-level review of Design-Verdict: CONCERNS Sound surface at the right seam, but the read-path incognito guarantee rests on peer cooperation and silently vanishes against an older peer. Watch
Suggestions
[DESIGN-REVIEWED] 0052642 |
First Principles Review (Fable 5) — 🟡 CONCERNSPremise-level review of All premises verified. The federated route and generic proxy are genuinely owner-dashboard-only (0 MCP-reachable alternatives), the registry allows arbitrary display names (so First-Principles-Verdict: CONCERNS Read-side incognito enforcement ships via an undeclared Not justified as shipped
What this change shipsIntent: let an agent read a connected remote crew's session history through the three existing session-read MCP tools — an ADDITION.
Watch
Subtractions
[FIRST-PRINCIPLES-REVIEWED] 0052642 |
GPT 5.6 Review — 🔴 changes requested (blocking)GPT 5.6 found at least one blocking issue that must be resolved before merging This comment is updated in place on each push. BLOCKING -- src/kiro_crew/dashboard/handlers_instances.py:968 -- Crew reads admit channel-origin agents as owners BLOCKING -- src/kiro_crew/dashboard/handlers/sessions.py:1277 -- Metadata I/O blocks the gateway event loop FINDING -- docs/system-specs/modules/instances.md:1558 -- The claimed missing incognito check contradicts the implemented FINDING -- src/kiro_crew/dashboard/handlers_instances.py:1154 -- [BLOCK-MERGE] 0052642 Adjudication (Opus 4.8) — is blocking on each finding proportionate?Based on my review: F2 — F1 (fenced) — [ADJUDICATION] 0052642 total=1 uphold=1 downgrade=0 [ADJUDICATION-FENCED] 0052642 fenced=1 flagged=0 False positive or not applicable? A repository writer can comment: |
Opus 4.8 Review — ✅ no blocking findingsReviewed Review detailsNo findings block the merge. FINDING — src/kiro_crew/dashboard/handlers_instances.py:393 and :450 — [OPUS-REVIEWED] 0052642 Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
3e19c28 to
6137380
Compare
|
GPT 5.6 review — all three BLOCKING findings fixed on
|
6137380 to
5091ee7
Compare
|
GPT 5.6 review — both findings fixed on
Span note (prepare-pr same-span tracking): |
bolichen97
left a comment
There was a problem hiding this comment.
Description / code mismatch
The Description's checklist states existing tests pass, but the new transport wrapper in mcp_tools/sessions.py deterministically fails a pre-existing exhaustiveness gate on every shard that collects it.
1. Diff breaks the internal-secret call-site coverage gate, while the checklist claims existing tests pass
The Description says — > - [x] Existing tests pass and new tests added for new functionality
The code does — the new _crew_query wrapper (def at src/kiro_crew/mcp_tools/sessions.py:194) funnels all three crew tools through a single transport call whose path is a runtime-composed f-string, mcp_core._get(f"{path}?{qs}" if qs else path), at src/kiro_crew/mcp_tools/sessions.py:201. test_every_transport_call_resolves_to_a_path in test/test_mcp_call_site_auth_coverage.py:513 walks every mcp_core._get / transport call site and requires each to resolve to a literal /api head; this one does not resolve, and the site is not in the reviewed _KNOWN_UNRESOLVED exemption set, so the gate fails.
Risk — the failure is platform-independent and deterministic: any shard that collects test_mcp_call_site_auth_coverage.py goes red, which is consistent with the four red Backend Test shards on the head SHA (3.10 shard 2, 3.12 shard 2, Windows shards 1 and 2) plus the Coverage Gate — though the check-run payloads carry no summary text, so that attribution is circumstantial and the reproduced local failure is the blocking fact. The gate exists because registering a dashboard route and granting it internal access are two separate manual edits; its entire value is exhaustiveness. One stray unresolved call site means the suite can no longer vouch for any MCP call path, not just this one. Merging as-is either lands a red gate or invites silencing it by editing the ratchet the test explicitly says not to edit.
Required change — make the transport call resolvable to a literal /api head: build the query string at each call site and pass a concrete path, or drop the wrapper and call mcp_core._get("/api/crew-sessions/search?...") per tool, so test_every_transport_call_resolves_to_a_path passes. If the wrapper is kept, take the reviewed _KNOWN_UNRESOLVED exemption deliberately and state that choice. Either way, the Description's "Existing tests pass" box must reflect the real state.
Open PR relationship auditThis is a consolidated, point-in-time code-level audit note. It compares complete merge-base diffs and current/merged code; it does not treat a shared topic as duplication or partial coverage as completion. Relationship findings
No PR, Issue, label, branch, or review state was changed by the relationship-note portion of this audit. |
|
🤖 Kiro Crew [operator: NicholasRBowers#a942f9ca]: This PR has been inactive for 7+ days. I reviewed the blockers but they require your input:
When you've addressed these, the pipeline will re-assess on its next cycle. |
Adds three dedicated internal-secret endpoints (/api/crew-sessions/search|list|read) and wires an optional crew= arg on search_chat_history, list_sessions and get_chat_session to read a remote crew's sessions over the tunnel. Search reuses search_sessions_remote; list/read ride the generic proxy_request carrier, buffered and re-redacted. Local (no-crew) path is unchanged. Adds spec section 16 and TestCrewScopedSessionReads.
5091ee7 to
0052642
Compare
|
Rebased onto main Conflicts resolved (3):
Gates run locally on changed files: black, isort, flake8, and pytest Please review the resolution. A maintainer push makes the maintainer the last pusher, so a second approver is needed under the repo's last-push rule. Reply if anything looks wrong. |
Problem / Motivation
The kirocrew-core session-read MCP tools (
search_chat_history,list_sessions,get_chat_session) can only read the local crew'sConversationLog. Anagent that wants to consult a connected remote crew's sessions (e.g. "what did
chick decide about X?") has no way to do so — the federated read that already
exists (
GET /api/instances/search-sessions, §15) is an owner-dashboardsurface, unreachable over the MCP process's
X-Internal-Secrethandshake, andit is search-only (no list, no full transcript).
Why it matters
Cross-crew consultation is the agent-to-agent half of the remote-crew work
(the human-facing view is separate, #6180). Without it, an agent driving one
crew is blind to a sibling crew's history even though the SSH tunnel and the
proxy carrier (#6211) already exist — the capability is one MCP surface away.
What changed (motivation → approach → change)
Goal: give the three read tools an optional
crew=<id|name>scope thatreads a connected remote crew's sessions, mirroring the local tools' contract,
with the local (no-
crew) path byte-for-byte unchanged.Approach: the MCP process reaches the gateway over
X-Internal-Secret, soit cannot use the owner-dashboard federated route. Rather than add a second
identity type to that bulk-disclosure endpoint, add three dedicated
STRICT-internal endpoints (
/api/crew-sessions/{search,list,read}) registeredin
_register_mcp_routes(so both the dashboard and the headless--slack-onlygateway serve them, like
/api/sessions/summarize). Reuse transport rather thaninventing it:
searchrides the existingsearch_sessions_remote;list/readride the generic
proxy_requestcarrier (#6211) — no new peer-request method.Change:
mcp_tools/sessions.py: optionalcrewarg on all three tools; when set theyGETthe new endpoints; local branch unchanged.handlers_instances.py: three internal-secret handlers that resolve the crew(exact id first, then name), buffer the peer reply under an 8 MB cap
before decode within a total-time budget, redact every peer field before
clamping, exclude incognito/temporary rows (search/list) and filter the
transcript to
RECALL_ROLES(read) — carrying the local tools' guarantees —and audit each call with the originating MCP caller's session key.
validation.py:crewfield on the three schemas (accepts registry displaynames; control chars barred).
server.py/routes/connections.py: register under_register_mcp_routes;/api/crew-sessionson_STRICT_INTERNAL_API_PATHS.docs/system-specs/modules/instances.md§16.Tests
test/test_instances.py::TestCrewScopedSessionReads(13 direct-handler tests):internal-secret gate (403 without it), unknown-crew 404, peer-row reshaping,
name resolution, exact-id-beats-colliding-name, remote-failure mapping, list
reshaping, tail-capped read, traversal-key rejection, proxy-error mapping,
incognito/temporary exclusion on search + list, RECALL_ROLES filtering
on read, and the relaxed
crewname pattern.Manual verification
N/A — unit coverage sufficient. The endpoints are exercised end-to-end with a
faked tunnel manager (
search_sessions_remote+ an asyncproxy_requestcontext manager); the real transport carrier is already covered by existing
test_instances.pyproxy tests.Related Issues
no linked issue: new agent-facing capability, independent of #6180 (frontend
chat view) and #6845 (api/stream event feed). A follow-up is noted in code + spec
for read-side incognito enforcement (needs a peer per-session metadata endpoint
that does not exist yet); the discovery paths (search/list) already exclude
incognito.
Why no screenshot: backend + MCP tool schema + tests + spec only; no
frontend path is touched and nothing renders differently in the browser.
Checklist