feat(tui): ask for workspace trust on startup with the v2 engine - #2453
Conversation
|
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0fe3f7d020
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const gatedMcpServers = Object.keys(withProject) | ||
| .filter((name) => !(name in userOnly)) |
There was a problem hiding this comment.
Disclose same-name project MCP overrides
When a project-level .mcp.json defines a server with the same name as a user-global MCP server, loadMcpServers(includeProject: true) uses the project definition because the loader merges user < project, but this filter suppresses that name simply because it exists in userOnly. In that case the trust prompt can show no gated server even though choosing trust replaces a trusted/global server with a repo-provided command and connects it, so the consent prompt misses exactly the project code being enabled. Compare the effective configs or track project-origin names instead of filtering only by key presence.
AGENTS.md reference: AGENTS.md:L22-L22
Useful? React with 👍 / 👎.
| const notice = | ||
| this.opts.gatedMcpServers.length > 0 | ||
| ? `Kimi Code loads project-level MCP servers (.mcp.json, .kimi-code/mcp.json) only in trusted folders. They run as local processes on your machine. This folder defines: ${this.opts.gatedMcpServers.join(', ')}.` |
There was a problem hiding this comment.
Sanitize MCP names before rendering trust prompt
For an untrusted repo, the server names come directly from project-controlled .mcp.json files and are interpolated into the terminal output before the user has granted trust. wrapTextWithAnsi/theme coloring preserves embedded ESC/OSC bytes, and this codebase already notes that pi-tui renders strings straight to the terminal, so a malicious server name can emit terminal control sequences from the trust dialog itself. Strip control sequences (or otherwise render names as inert text) before joining them into this notice.
AGENTS.md reference: AGENTS.md:L22-L22
Useful? React with 👍 / 👎.
… secondary model, workspace trust - A6 (MoonshotAI#2210): TurnResult.hit_step_cap + render_step_capped_continuation; goal pursuit continues with a step-capped prompt when a turn hits the per-turn step limit (2 tests) - A12 (MoonshotAI#2232): secondary-model config surface — [secondary_model] section + KIMI_SECONDARY_MODEL/EFFORT behind the experimental gate; Task/AgentSwarm subagents bind the resolved model (4 tests) - A15 (MoonshotAI#2379): TaskOutput non-blocking — native interceptor ignores block/timeout; prompt text no longer advertises block=false - C6 (MoonshotAI#2453): workspace trust — McpConnectionState.workspace_trusted drives the .mcp.json stdio approval gate; session/create workspace_trusted RPC + rust-loop wiring (2 tests) - gen:wire regenerated (workspace_trusted landed in wire.gen.ts) - 2011 lib + 51 integration tests green, 0 warnings
Related Issue
Related: #373 — this PR delivers the mechanism on the experimental v2 engine (
KIMI_CODE_EXPERIMENTAL_FLAG); the default v1 engine has no trust concept, so the issue may be worth keeping open until trust reaches the default surface.Problem
agent-core-v2 already enforces workspace trust: project-level MCP servers (
.mcp.json,.kimi-code/mcp.json) only load in trusted workspaces, with the marker persisted under the kimi home (file presence = trusted). But the engine deliberately ships no interactive prompt, and the TUI — which bootstraps the v2 engine in-process — had no trust surface at all. On the v2 engine, a TUI session in an unfamiliar folder therefore ran silently with project MCP servers disabled, with no way to grant trust from the CLI (the only existing surface is kap-server's REST routes, consumed by kimi web / kimi-inspect).What changed
node-sdk — new trust surface on the SDK facade:
getWorkspaceTrustInfo(workDir)returns{ trusted, gatedMcpServers }: the trust state plus the names of project-level MCP servers that trusting would enable, diffed through the engine's ownworkspaceMcpConfigloader. Best-effort: an unreadable/invalid project file degrades to an empty list instead of failing the caller.trustWorkspace(workDir)grants trust. The flip firesIWorkspaceTrust.onDidChange, which makes the engine'sworkspaceMcpConfigreload with project files included — project MCP servers connect live, no restart needed.engineAccessorescape hatch (IWorkspaceLifecycleService.handlerFor({ root })→IWorkspaceTrust), the same pathcreateSessionalready takes.TUI — on startup with the v2 engine, before any session is created:
kimi -pnever reaches the TUI), in the migration branch, or when the workspace is already trusted. The trust check itself is best-effort and never blocks startup.Also fixed along the way: the prompt path initially started the pi-tui event loop twice, double-pushing the terminal's Kitty keyboard-protocol flags (one stack entry survived exit and the user's shell then received CSI-u sequences as
9;1:3u…garbage); the loop now starts exactly once, and the decline path skips the editor restore so no orphaned input box lingers above the exit message.Tests: v2-client trust tests in node-sdk (untrusted + gated-server enumeration across both project files, invalid
.mcp.jsondegradation, marker persisted in the kimi home);TrustPromptComponentrender/keyboard tests. Verified end-to-end under a PTY: the prompt renders with the server list → choosing trust persists the marker and the project MCP server connects in the same session → relaunch shows no prompt → Esc exits cleanly before any session is created.Checklist
gen-changesetsskill — no changeset: the behavior only takes effect on the experimental v2 engine (skill rule 6; recent v2-migration PRs such as feat(node-sdk): migrate the SDK method surface to agent-core-v2 #2262 / feat(agent-core-v2): introduce the Workspace domain and the agent-profile registry extension point #2366 shipped without one).gen-docsskill — no doc update: the prompt is only reachable on the experimental engine; user docs cover shipped surfaces.