You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adds --mcp-stdio, a headless MCP server for clients that launch and own the process, and centralizes shell output so stdio, --quiet, and machine mode follow one policy.
Why
HTTP MCP (--mcp [port]) needs a listening localhost port that any local user can reach, and its lifetime is separate from the client. With stdio, the client owns the process and its pipes: no port, per-client state, and shutdown when the client closes stdin.
easy local setup/no open http
clear life cycle with seperate by client states
Open Question: If it is really needed.
Stdio contract
stdin: MCP JSON-RPC requests only. Commands can never read it.
stdout: MCP messages only. Managed console output is redirected to stderr before startup, and Spectre is configured for stderr without ANSI.
stderr: startup errors, logs, warnings, and required instructions (such as device-code sign-in).
Closing stdin stops the server, including with open subscriptions or pending confirmations.
Supported: startup --connect/--database/--container, protocol 2025-11-25 and earlier (initialize) and 2026-07-28 (server/discover), destructive-command confirmations, and location subscriptions. Rejected at startup: --mcp, --lsp, -c, -k, --clear-history, and --mcp-stdio passed through a response file.
Removed from the tool list, help, and direct invocation, including aliases: jq, theme, and commands restricted from MCP that cannot be confirmed (exit, edit, watch, welcome, sproc, udf, trigger). Destructive commands (delete, rm, rmdb, rmcon) stay available through MCP confirmation. HTTP mode keeps its existing tool list.
Stdio mode does not load or record shell history.
Sign-in never opens a browser. A headless server has no user at the terminal, and the browser launcher (for example xdg-open) inherits the process stdout. --tenant/--hint connections use device code sign-in, and endpoint-only connections use DefaultAzureCredential without its interactive browser step. Cancelling the tool call ends a pending sign-in.
Centralized output
User-facing output now goes through ShellOutput with an explicit category: Information, Progress, Warning, Error, RequiredInstruction, or Result.
--quiet suppresses information, progress, banners, and command echoes. Results, warnings, errors, and required instructions stay visible, including code previews shown before a confirmation prompt.
Machine-mode stdout carries only the interpreter's final result. Tables that commands draw for interactive users no longer appear there.
theme, help, and edit now throw errors instead of printing and returning them. In machine mode their failures previously exited with code 1 and no message; they now produce one {"status":"error",...} object on stderr. Interactive and script errors are reported once.
New analyzer rule CZ0003 fails the build on direct Console/AnsiConsole output outside ShellOutput. Line-editor drawing keeps scoped suppressions.
Commits
Add headless MCP stdio mode
Disable shell history in MCP stdio mode
Centralize shell output through a category-based policy
Update Copilot instructions for MCP stdio and output policy
Keep MCP stdio sign-in non-interactive
Known limitations
Device-code instructions appear only on stderr, so someone must read them from the client's server log. Surfacing them through MCP could be a follow-up.
Stdio isolates the protocol stream but is not a sandbox. The client still acts with the process owner's file and Cosmos permissions.
Reserve stdin and stdout for MCP, support confirmations and subscriptions, and stop on input EOF. Omit unsupported commands from stdio tools and help while preserving HTTP behavior.
Route all user-facing output through ShellOutput so --quiet, machine mode, and MCP stdio are decided in one place. Quiet suppresses information and progress but keeps results, warnings, errors, and required instructions. Machine-mode stdout carries only the interpreter result, and theme, help, and edit failures are reported once through the central error reporter. Add analyzer rule CZ0003 to reject direct console output.
Never open a browser in stdio mode: tenant or hint connections use device code sign-in with instructions on stderr, and endpoint-only connections use DefaultAzureCredential without its interactive browser step.
The overall line coverage in commit 0abc080 in the dev/mkrueger/mcp_std... branch is 67%. The line coverage in commit 3a9dc25 in the main branch is 66%.
Show a line coverage summary of the most impacted files.
Cancel startup on stdin EOF, enforce a shared 60-second connection and navigation deadline, and preserve buffered protocol input. Add lifecycle and cancellation regression tests and update documentation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The default Pipe applies bounded writer backpressure, but nothing consumes Input until startup connection/navigation finishes. If a client queues more than the pipe threshold and then closes stdin, CopyToAsync can block flushing into the pipe before it observes EOF, so StartupToken is not cancelled until the 60-second deadline. Use a startup buffering strategy that keeps draining stdin through EOF (while bounding/spooling safely), and cover an input larger than the pipe threshold.
Reject response-file stdio before LSP early return
CosmosDBShell/Program.cs:79
This validation still runs after the early LSP return above. If a response file contains --mcp-stdio and the direct command line also contains --lsp or --stdio, the process starts LSP at lines 63–67 and never reaches this rejection. Parse and reject response-file stdio requests before any protocol-mode early return so the documented direct-command-line and incompatibility rules cannot be bypassed.
In machine mode this guard suppresses every validation warning, even when non-strict directory validation succeeds. That bypasses the new category policy and contradicts the documented --quiet contract that warnings remain visible on stderr; single-file validation already preserves warnings on successful machine-mode runs. Buffer the warnings while scanning and emit them after the loop only when invalidCount == 0 (while retaining the single structured error when validation fails).
Fixed the directory-validation warning handling. Successful machine-mode and quiet scans now emit warnings on stderr after the scan; failed scans still emit only the structured error. Main is merged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
--mcp-stdio, a headless MCP server for clients that launch and own the process, and centralizes shell output so stdio,--quiet, and machine mode follow one policy.Why
HTTP MCP (
--mcp [port]) needs a listening localhost port that any local user can reach, and its lifetime is separate from the client. With stdio, the client owns the process and its pipes: no port, per-client state, and shutdown when the client closes stdin.Open Question: If it is really needed.
Stdio contract
Supported: startup
--connect/--database/--container, protocol2025-11-25and earlier (initialize) and2026-07-28(server/discover), destructive-command confirmations, and location subscriptions. Rejected at startup:--mcp,--lsp,-c,-k,--clear-history, and--mcp-stdiopassed through a response file.Removed from the tool list,
help, and direct invocation, including aliases:jq,theme, and commands restricted from MCP that cannot be confirmed (exit,edit,watch,welcome,sproc,udf,trigger). Destructive commands (delete,rm,rmdb,rmcon) stay available through MCP confirmation. HTTP mode keeps its existing tool list.Stdio mode does not load or record shell history.
Sign-in never opens a browser. A headless server has no user at the terminal, and the browser launcher (for example
xdg-open) inherits the process stdout.--tenant/--hintconnections use device code sign-in, and endpoint-only connections useDefaultAzureCredentialwithout its interactive browser step. Cancelling the tool call ends a pending sign-in.Centralized output
User-facing output now goes through
ShellOutputwith an explicit category: Information, Progress, Warning, Error, RequiredInstruction, or Result.--quietsuppresses information, progress, banners, and command echoes. Results, warnings, errors, and required instructions stay visible, including code previews shown before a confirmation prompt.theme,help, andeditnow throw errors instead of printing and returning them. In machine mode their failures previously exited with code 1 and no message; they now produce one{"status":"error",...}object on stderr. Interactive and script errors are reported once.Console/AnsiConsoleoutput outsideShellOutput. Line-editor drawing keeps scoped suppressions.Commits
Known limitations