Skip to content

feat(mcp): name per-server concerns and default posture in mcp list - #241

Merged
Zongwei9888 merged 1 commit into
HKUDS:mainfrom
raymondginger2018-sudo:feat/mcp-list-risk-summary
Sep 27, 2026
Merged

Zongwei9888 merged 1 commit into
HKUDS:mainfrom
raymondginger2018-sudo:feat/mcp-list-risk-summary

Conversation

@raymondginger2018-sudo

Copy link
Copy Markdown
Contributor

Implements the operator-facing risk summary asked for in #220, in the shape that PR's closing note specified:

a ~20-line addition to the mcp list view over McpServerInfo, with a test, is the shape we would merge.

What this does

mcp list showed configuration/auth/runtime state and left the operator to cross-reference --json for anything that should give them pause. It gains a CONCERNS column plus one footer line, derived only from fields McpServerInfo already exposes -- no protocol change, no new module, no new config, no new dependency.

A row lists only what is explicitly configured or actually broken:

label meaning
disabled the server is off
missing-env a required env key is absent
sends-credential the server is handed a credential

The other two readings hold for every server that never made the choice -- an absent enabledTools resolves to every tool (core/config.py substitutes ["*"]), and auto/approve add no MCP approval gate (core/harness/permissions.py) -- so they are stated once in a footer line instead of repeated on every row:

Default posture among N enabled servers: A expose all tools, B add no MCP approval gate.

Measured on a six-server config, the per-row form lit up 4 of 5 enabled rows with the same two defaults, which is how an operator learns to ignore the column.

Only key names are read, never credential values. The NAME column is now width-aware, so a long server name cannot skew the table. Rows whose configuration did not parse stay out of the footer: the posture fields on those rows are defaults filled in by the invalid-row builder in mcp_service.py, not choices anyone made.

Tests

tests/test_mcp_cli.py asserts the rendered stdout -- the table cells and the footer counts -- so re-adding a default-triggered label to every row fails loudly, and so does counting an unparsed row.

Scope

cli/mcp_cli.py +73/-2 and tests/test_mcp_cli.py +72/-0. Every reading is a pure function of fields that already exist on the wire, so McpServerInfo keeps its 33 fields and the desktop fixtures are untouched. Rebased on current main (behind_by: 0, no conflicts).

`mcp list` showed configuration/auth/runtime state and left the operator to
cross-reference `--json` for anything that should give them pause.

CONCERNS states only what is explicitly configured or actually broken:
`disabled`, `missing-env`, `sends-credential`. The two permissive readings that
hold for every server which never made the choice -- an absent `enabledTools`
resolves to every tool (core/config.py substitutes `["*"]`), and
`auto`/`approve` add no MCP approval gate (core/harness/permissions.py) -- are
stated once in a footer line instead of repeated on every row. Measured on a
six-server config, the per-row form lit up 4 of 5 enabled rows with the same two
defaults, which is how an operator learns to ignore the column.

Only key names are read, never credential values. The NAME column is now
width-aware, so a long server name cannot skew the table.

Rows whose configuration did not parse stay out of the footer: the posture
fields on those rows are defaults filled in by the invalid-row builder in
mcp_service.py, not choices anyone made, so counting them would report a posture
that was never configured.

Rendered in cli/mcp_cli.py only: every reading is a pure function of fields that
already exist on the wire, so McpServerInfo keeps its 33 fields and the desktop
fixtures are untouched.

Tests assert the rendered stdout -- the table cells and the footer counts -- so
re-adding a default-triggered label to every row fails loudly, and so does
counting an unparsed row.
@Zongwei9888
Zongwei9888 merged commit 2fafe40 into HKUDS:main Sep 27, 2026
12 checks passed
Zongwei9888 added a commit that referenced this pull request Sep 27, 2026
…e in mcp list

mcp list gains a CONCERNS column (disabled, missing-env, sends-credential) and
a one-line count of enabled servers that expose every tool or add no MCP
approval gate, derived only from fields McpServerInfo already exposes.
Repair: document the column in the headless guide.
Contributed by raymondginger2018-sudo.
@Zongwei9888

Copy link
Copy Markdown
Collaborator

Merged into main as d347294. Thank you @raymondginger2018-sudo — this is the shape we asked for on #220, and the decision to state the two default-driven readings once in a footer instead of lighting up every row is a good call. I verified the footer against core/harness/permissions.py: auto and approve both return the global decision unchanged, so "add no MCP approval gate" is accurate.

One small addition on our side: a paragraph in docs/HEADLESS_AND_AUTOMATION.md next to the mcp list example explaining the new column and footer.

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