Skip to content

feat(mcp): /mcp and an MCP context segment — S5 (visibility) - #57

Merged
ndemianc merged 1 commit into
developfrom
feat/mcp-s5-visibility
Jul 28, 2026
Merged

feat(mcp): /mcp and an MCP context segment — S5 (visibility)#57
ndemianc merged 1 commit into
developfrom
feat/mcp-s5-visibility

Conversation

@ndemianc

Copy link
Copy Markdown
Contributor

Stacked on #55review that first; this diff is only the two visibility surfaces.

Until now MCP was invisible unless it happened to work. There was no way to ask what is configured, why a server is not being used, or what these servers cost in context on every turn.

1. /mcp — configured servers, not running ones

That distinction is the whole design. The questions worth asking are "why is my server not being used?" and "what is this repo asking to run?" — and a list built from live handles answers neither, because the interesting server is the one that is absent.

Each row carries state, provenance, and the literal command it would run:

state means
running connected, tool count and allow-listed count shown
needs approval a repo-defined server waiting on the G1 consent card
not started configured, not connected

needs approval is separated from not started on purpose: a repo server waiting on consent is working exactly as designed, and reporting only "not running" would send someone debugging a non-problem.

When a server is live, tool names and their allow-list state come from the same buildAgentTools + classifyMcpTool the agent uses — so the list cannot claim a tool is allow-listed while runTool refuses it. A destructive tool sitting in the allow-list is counted as not allowed, matching what actually happens at call time.

summarizeMcp() is pure and unit-tested. The command re-reads config on each invocation, because /mcp is most useful immediately after an edit that appeared to do nothing.

2. An MCP tools segment in the context popover

Every tool schema rides every turn, so a chatty server is a standing tax on the window rather than a one-off — and it was folded invisibly into Tools.

The segment is carved out of that slice, never added alongside it. tools already counts every schema, MCP included, so adding would double-count and the bar would stop summing to used — which does not read as a bug, it reads as the model used more context than it did. A dedicated test asserts the segments always total the window across the MCP, no-MCP, over-estimate and junk-input cases.

Hidden entirely when no server contributed a schema, which is nearly every run.

Found while testing

ctxSegments took x || 0 for its numeric inputs. That rescues NaN and null but passes a string straight through to Math.max, which yields NaN and silently un-sums the whole bar. Unreachable today — the caller type-checks — but this function's entire contract is that the segments add up, so it now coerces properly.

Verification

24 suites, 0 failures. 66 mcpConfig cases, 5 new ctxSegments, 11 webviewCss.

The webview is covered by static assertions, matching how chat.html is tested here (there is no DOM harness): the command is wired end to end, all three row states exist, and the command line is rendered escaped and wrapping rather than truncated.

Remaining

S6 — Streamable HTTP transport and the 2026-07-28 revision, resources/prompts, and a "Manage MCP servers…" QuickPick. Reach, not security: every gate in §4 is enforced as of #55.

Until now MCP was entirely invisible unless it happened to work: no way to ask
what is configured, why a server is not being used, or what these servers cost in
context every turn. Two surfaces close that.

1. `/mcp` — lists CONFIGURED servers, not running ones.

   Deliberate: the questions worth asking are "why is my server not being used?"
   and "what is this repo asking to run?", and a list built from live handles
   answers neither — the interesting server is the one that is absent.

   Each row carries state, provenance, and the literal command it would run.
   State distinguishes `needs approval` from `not started`, because a repo server
   waiting on the G1 consent card is working exactly as designed and saying only
   "not running" would send the user debugging a non-problem.

   When a server IS live, tool names and their allow-list state come from the same
   buildAgentTools + classifyMcpTool the agent uses — so the list cannot claim a
   tool is allow-listed while runTool refuses it. A destructive tool sitting in the
   allow-list is counted as NOT allowed, matching what actually happens.

   summarizeMcp() is pure and unit-tested; the command re-reads config each time,
   because /mcp is most useful right after an edit that appeared to do nothing.

2. An `MCP tools` segment in the context-usage popover.

   Every tool schema rides EVERY turn, so a chatty server is a standing tax on the
   window rather than a one-off — and it was folded invisibly into `Tools`.

   Carved OUT of that slice, never added alongside: `tools` already counts every
   schema, MCP included, so adding would double-count and the bar would stop
   summing to `used` — which does not look like a bug, it looks like the model used
   more context than it did. A dedicated test asserts the segments always total the
   window across the MCP, no-MCP, over-estimate and junk-input cases.

   Hidden when no server contributed a schema, which is nearly every run.

Found while testing: ctxSegments took `x || 0` for its numeric inputs, which
rescues NaN and null but passes a STRING through to Math.max, yielding NaN and
silently un-summing the whole bar. Unreachable today (the caller type-checks), but
this function's entire contract is that the segments add up, so it now coerces.

66 mcpConfig cases, 5 ctxSegments, 11 webviewCss; 24 suites, 0 failures.
@ndemianc
ndemianc changed the base branch from feat/mcp-s4b-launch-gate to develop July 28, 2026 02:11
@ndemianc
ndemianc requested a review from Copilot July 28, 2026 02:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds visibility surfaces for MCP in the LevelCode AI extension so users can (1) inspect configured MCP servers and their trust/running state, and (2) see the standing context-window cost of MCP tool schemas per turn.

Changes:

  • Introduces a /mcp slash command in the chat webview, backed by an extension-side “overview” that re-reads merged MCP config and correlates it with live handles, tool allow-policy, and G1 launch trust.
  • Splits “Tools” context usage into “Tools” + “MCP tools” (carved out of the existing tools slice) and hardens ctxSegments() input coercion to avoid NaN propagation.
  • Adds unit/static tests covering /mcp wiring/rendering, summarizeMcp() behavior, and the context-segment invariants.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
extensions/levelcode-ai/media/chat.html Adds /mcp command handling + MCP list rendering; adds MCP tools context segment and numeric coercion hardening in ctxSegments().
extensions/levelcode-ai/extension.js Implements mcpOverview() and wires listMcpmcpList message flow end-to-end.
extensions/levelcode-ai/mcpConfig.js Adds pure summarizeMcp() to produce configured-first MCP status rows, including per-tool allow-state via shared agent classification logic.
extensions/levelcode-ai/agent.js Computes and reports mcpTools token estimate alongside tools for context breakdown.
extensions/levelcode-ai/test/mcpConfig.test.js Adds S5 coverage for configured-vs-running listing, trust-state semantics, allow-state reporting, and junk-input tolerance.
extensions/levelcode-ai/test/webviewCss.test.js Adds static assertions that /mcp is intercepted, wired, and renders all row states with escaped, wrapping command lines.
extensions/levelcode-ai/test/ctxSegments.test.js New extracted-from-chat.html unit tests asserting segment-sum invariants and MCP carve-out behavior.
docs/MCP.md Updates S5 documentation to reflect completed /mcp and context-usage segment behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ndemianc
ndemianc merged commit 1ae25d6 into develop Jul 28, 2026
1 check passed
@ndemianc
ndemianc deleted the feat/mcp-s5-visibility branch July 28, 2026 02:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants