[FEATURE] Cross-surface session discovery: VS Code-launched sessions are invisible to the session-management MCP tools
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
I run several Claude Code sessions at once on one machine against one repository — some from the desktop app, at least one from the VS Code extension — using git worktrees to keep them from colliding.
The session-management MCP tools (list_sessions, get_session, send_message, search_session_transcripts) only ever show me the sessions the desktop app started. A session started by the VS Code extension is absent from list_sessions, and get_session rejects it for both id forms:
Session <uuid> not found.
Session local_<uuid> not found.
send_message resolves through the same lookup, so it cannot deliver to it either, and search_session_transcripts does not match its content.
This is easy to misdiagnose as a per-login split, and it is not. My VS Code session shared the default config directory with the desktop sessions and was still invisible. It also isn't a filtering choice: reading the shipped desktop app, the list_sessions handler filters on exactly two predicates — sessionId != self and include_archived || !isArchived. There is no entrypoint/source predicate, and no entrypoint field exists in the session records to filter on. It enumerates an in-memory map of sessions the desktop app itself spawned.
So a VS Code session is never registered, rather than registered-and-filtered. That distinction matters for the fix: no filter needs relaxing — a registration or discovery path needs to exist.
The practical cost is that the session I most need to see is the one I can't. In my case a VS Code session was working directly in the shared primary checkout — the single most collision-prone place in a worktree setup — while three desktop sessions worked in isolated worktrees. No supported tool could tell me that.
There's a second-order problem too: multi-session coordination conventions are advisory. When one participant is structurally invisible, every convention has a guaranteed defector — the session nobody can see is also the one bound by nothing.
Proposed Solution
Make local session discovery cross-surface. Concretely, any one of these would solve it, in descending order of preference:
list_sessionsenumerates local sessions regardless of which surface launched them. The data already exists on disk —<config-root>/sessions/<pid>.jsonis written by the CLI itself, contains every surface, and already carries anentrypointfield (claude-desktop/claude-vscode) that distinguishes them. Nothing needs inventing; the desktop app just doesn't read it.
- A supported read-only roster tool, if full parity is too invasive — enough to answer "which of my sessions are running, where, and on which surface".
- If messaging must stay desktop-only, fail loudly rather than silently. A session that cannot be addressed should appear in the listing marked unaddressable, instead of being missing. Right now the boundary is only discoverable by noticing an absence, which is exactly the kind of thing that gets confidently guessed at wrong.
Alternative Solutions
I wrote my own roster — roughly 200 lines of PowerShell reading <config-root>/sessions/*.json across every config root, joining to git worktrees, and verifying liveness — and wired it into a SessionStart hook so each new session opens knowing who else is live.
It works, but it depends on an undocumented private file, and two things made it harder than it should be:
- PID reuse. The registry records carry a
procStartfield that appears intended to guard against exactly this, but on my machine it serialises as absent and the guard returns true when it cannot determine the value — i.e. it fails open toward "still alive". A naive liveness check therefore reports a recycled PID as a live session. I had to compute process start times myself and compare them against the recorded session start. - No heartbeat. Registry writes are event-driven, so recency is not a liveness signal in either direction. A "dead" verdict here can never be trusted enough to authorise a destructive action.
I also found what looks like a peer-to-peer session-messaging protocol already compiled into the CLI — named-pipe transport, a typed message envelope, peer lookup by session id — that is inert: the registry field carrying a peer's socket address is written by no code path, so peer discovery can only ever return an empty set. It fails silently, returning an empty peer list rather than an error. I mention it because it suggests much of this may already be built and switched off, which would make (1) cheaper than it looks.
Priority
High - Significant impact on productivity
Feature Category
MCP server integration
Use Case Example
- I open four Claude Code sessions on one repo: three from the desktop app in separate git worktrees, one from the VS Code extension.
- A session asks "who else is working in this repo right now, and where?" so it can avoid duplicating work or editing a file someone else is mid-change on.
list_sessionsreturns the three desktop sessions. The VS Code session — which is editing the shared primary checkout onmain— does not appear at all.- That session goes ahead and works in the primary too, because nothing told it otherwise.
With cross-surface discovery, step 3 would list all four with their surface and working directory, and step 4 wouldn't happen.
Environment
- Windows 11
- Desktop app + VS Code extension on the same machine, same default config directory
- CLI 2.1.219 (desktop-spawned) and 2.1.220 (VS Code-spawned)
Related
- #82141 — documentation gap covering the same tool surface (what
list_sessionsscopes to, and the semantics of session-to-session messaging). This request is the behaviour change; that one is satisfied by documenting current behaviour.
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Still relevant. Sessions started by the VS Code extension remain absent from
list_sessions,get_session,send_message, andsearch_session_transcripts, so a machine running desktop and VS Code sessions side by side has no single roster of what is live.The practical cost, for anyone coordinating several sessions against one repository: you cannot tell "this session does not exist" from "this session is not visible to me". Any tooling built on the MCP session list silently under-reports, and under-reporting is the failure mode that looks like a clean answer.
Related in shape to #84868, where
isRunning: falseconflates idle, not-observable, and gone. Both are cases of a session-listing surface returning a confident answer that omits whole categories.Marked stale by the sweep. Commenting to keep it open.
Still open. The detail I would not want lost from this report is the negative result. My VS Code session shared the default config directory with the desktop sessions and was still absent from
list_sessions, so this is not a per-login split, and reading it as one sends you to the wrong layer.The shipped desktop app filters
list_sessionson two predicates only,sessionId != selfandinclude_archived || !isArchived. There is no entrypoint or source predicate, and no entrypoint field exists in the session records to filter on. So a VS Code session is never registered rather than registered and hidden, which is why both id forms are rejected and whysend_messagecannot route to it.#84868 is the companion problem on the reader's side: for a session absent from the map entirely, no value of
isRunningdescribes it.Still open. The smallest useful change here may be documentation rather than code. A line saying that
list_sessionscovers only sessions started by the desktop app would stop tooling from reading "not listed" as "does not exist".The fuller fix is for sessions started from the VS Code extension to register in the same map, so
get_sessionandsend_messagecan reach them. Until one of those happens, any roster built on these tools under-reports, and it does so without an error.