Model Context Protocol (MCP) allows AI clients to control CosmosDBShell programmatically.
dotnet run --project CosmosDBShell -- --mcp
dotnet run --project CosmosDBShell -- --mcp 5050Bare --mcp starts the HTTP server on the default port 6128.
Requires VS Code 1.103+
- Open Settings (
Ctrl+,) - Search for
chat.mcp.autostart - Select newAndOutdated
MCP servers will start automatically without manual refresh.
- Open Command Palette (
Ctrl+Shift+P/Cmd+Shift+P) - Run
MCP: List Servers - Select
localCosmosDBShellServer→ Start Server - Check Output tab for startup confirmation
The doctor tool reports local environment and current-connection diagnostics without
changing connection, navigation, or settings. Pass database and container for an
explicit target, query: true for a bounded constant-projection query (consumes RUs),
or arm: true to require an ARM check and opt into bounded discovery. It does not
initiate interactive login. See doctor for limits and verdicts.
Pass who: true (or subcommand: "who") to include known credential type, selected
scope, and unassessed write access. This adds no token acquisition or network probes.
The identity entry's credentialType describes configuration, not a verified
principal. The text-only Doctor Who? heading is not part of the structured report.
The structured report also includes a summary with verdict counts, elapsed
durationMs, and nullable total requestCharge. The clock check estimates offset
only from existing successful response Date headers; it never adds a network probe.
Its nullable clockOffsetSeconds and clockUncertaintySeconds describe an estimate,
not trusted time. Missing usable headers produce clock-unavailable (SKIP).
The updates check performs one bounded, unauthenticated public GitHub release lookup,
even without a Cosmos connection. Pass no-update-check: true to prevent this request.
The lookup sends no Cosmos credentials or target names and installs nothing. Newer
eligible releases produce WARN and latestVersion; unavailable checks produce SKIP.
The versioned report is available in result, including when isError is true.
Doctor's report omits secrets, raw exception messages, and document data. The standard
MCP envelope still includes currentLocation; review resource names before sharing
the complete MCP response outside your organization.
The MCP server runs locally with your user permissions. Connected clients can execute shell commands, which means they can:
- Read database/container metadata
- Query and retrieve documents
- Create, update, and delete resources
Server-side programming commands — stored procedures (sproc), user-defined functions (udf), and triggers (trigger) — are restricted from MCP. Run those commands manually in the shell.
Transactional batches invoked through MCP must use the one-shot batch run subcommand. Stateful batch subcommands (begin, add, execute, cancel, status, and show, including their aliases) are restricted to the interactive shell because MCP tool calls share no client-specific batch state.
Destructive commands (delete, rm, rmcon, rmdb) are gated behind an explicit user confirmation. When a client invokes one, the server sends an MCP elicitation prompt describing the exact command line before anything runs:
- Approved — the command executes normally.
- Declined or cancelled — nothing is executed and the tool call returns an error explaining that the user did not approve.
- Client cannot confirm — if the connected client does not support elicitation, the command is refused (fail-closed) and the response suggests running it manually in the shell.
This replaces any opt-in write flag: destructive commands are always allowed to be invoked, but always require confirmation.
Confirmation includes the connected account endpoint and current navigation location alongside the command and its explicit target arguments. If the connection or navigation state changes while confirmation is pending, the approved command is refused without executing; retry it to confirm the new context. Even navigating away and back invalidates the pending confirmation.
Shell and MCP command execution is serialized against the shared interpreter. Confirmation prompts do not hold the execution lock, so the shell remains usable while waiting. Clients still share a connection and navigation context: pass explicit database and container arguments for independent operations rather than relying on an earlier cd call.
The MCP confirmation applies even when a command is invoked with a force / no-prompt argument (for example rmdb OldDB true). That argument only skips the interactive shell prompt; it does not bypass the MCP elicitation gate.
Database and container resource actions are executed through Azure Resource Manager when an ARM context is attached (Entra ID connections). MCP sessions connected with account keys, emulator credentials, or static data-plane tokens fall back to the Cosmos DB data plane for these actions.
For deterministic ARM routing in multi-subscription environments, start the shell with --connect-subscription and --connect-resource-group.
MCP tool invocations are echoed as command lines in the shell window, so anyone watching the terminal can see what a connected client is doing. They are also recorded in the shell history. History entries are complete and replayable, including any supplied connection strings. Protect the history file accordingly. On Linux and macOS, the shell restricts the history file to its owner.
Positional arguments must be supplied without gaps: a call that provides a positional parameter while omitting an earlier one is rejected, because the equivalent shell command line would bind the value to the omitted slot.
Your MCP client may use a remote LLM. Command outputs, query results, and file contents could be transmitted to external services. Treat all shell output as potentially shared.
| Risk | Mitigation |
|---|---|
| DNS rebinding | Origin header validated on all requests; non-loopback origins rejected |
| Unauthorized access | Bind to localhost only, don't expose port publicly |
| Credential leakage | Use Azure AD instead of connection strings/keys |
| Excessive permissions | Apply least-privilege RBAC, narrow scopes |
| Missing management-plane scope | For ARM-routed actions, connect with Entra ID and grant Cosmos DB Operator or equivalent scoped permissions; otherwise the shell falls back to the data plane |
| Accidental destruction | Destructive commands prompt for confirmation before running; review each request and deny anything unexpected |
| Unnecessary exposure | Disable --mcp when not needed |
- Only enable on trusted machines/networks
- Keep port bound to
127.0.0.1 - Use Azure AD/managed identity authentication
- Review and approve (or deny) destructive operations when prompted
- Don't share secrets (keys, PII) in prompts or outputs
- Disable MCP mode when not actively using it
Every tool result carries the same machine-readable JSON payload in two places:
structuredContent— the payload as first-class structured content, for clients that consume MCP structured results.- A text content block — the identical payload serialized as JSON text, so clients that only read text content blocks continue to work.
Both representations are always byte-for-byte equivalent.
| Field | When present | Description |
|---|---|---|
result |
Commands that produce output | The command result as JSON (objects, arrays, or a scalar). Text-only results are represented as a JSON string. Failed transactional batches include their per-operation summary here alongside error. |
outputText |
CSV output commands with non-empty text | The CSV rendering of the result. Omitted when the CSV output is empty or whitespace. |
continuationToken |
Paged query and container-item ls results |
Opaque token for the next page, or null when no more results are available — unless resultIncomplete is true, where a null token accompanies a truncated result that cannot be resumed. Omitted for query --explain and database/container name listings, which are not paged. |
resultIncomplete |
Truncated results that cannot be resumed | true when the result stops at the requested limit and the query cannot produce a continuation token. Omitted otherwise. |
requestCharge |
Charged data-plane command results | The Cosmos DB request charge (in RUs) consumed by the command, as a number. This is omitted for commands that do not issue a billable request. |
error |
Failed commands | The error message. |
currentLocation |
Always | The shell's current navigation path (for example /MyDatabase/MyContainer), or null when disconnected. |
Successful results set result (and optionally outputText); failed results set error, may also include a structured result, and mark the tool result as an error. currentLocation is always included so a client can track navigation state across calls. Commands report requestCharge whenever their Cosmos DB data-plane requests expose one, including paginated reads, metadata and configuration operations, scripts, change feed reads, handled probes, and charged failures. Multi-request commands aggregate the observed charges. Azure Resource Manager control-plane operations do not consume or report Cosmos DB request units.
This field reports observed cost; it does not enforce an RU budget. Budget guardrails are tracked separately in #162.
The info command result also includes session.requestCharge, the cumulative
charge observed from data-plane commands during the current connection,
including the current info request cost. A
successful connect starts a new total; navigation between databases and
containers does not reset it. This session value is telemetry rather than a
budget or billing total. session.chargedOperationCount counts
command operations that reported a positive request charge; it counts command
operations rather than individual query pages or transactional batch items. If
the shell variable $sessionRequestChargeWarningThreshold is set to a positive value, the
session object also includes session.requestChargeWarningThreshold.
MCP calls to query and container-item ls return one Cosmos DB page per call. max must be positive; when it is omitted or non-positive, the server applies a safe default cap of 100 items. To continue, pass a non-null returned continuationToken as the next call's continuation argument while keeping the query and other options unchanged. The token is opaque; do not parse or edit it. When the token is null and the response does not set resultIncomplete, the result set is exhausted: stop paging and do not send another request with continuation.
continuation is exposed only to MCP callers — there is no corresponding shell option, and the token is never echoed into the shell's command output.
Because max bounds a single page, a call can return fewer items than requested and still have more available; while resultIncomplete is absent or false, treat a non-null continuationToken as the only signal that more results exist. For ls, the result.limitReached flag reports that same condition and is kept for parity with shell and script output. ls always produces resumable pages, so its results never set resultIncomplete.
Some queries cannot be paged at all. Vector ORDER BY, ORDER BY RANK relevance ranking, and DISTINCT projections whose plan cannot export a token execute normally but never return a continuation token. For DISTINCT this is decided by the query plan rather than by the SQL text: SELECT DISTINCT c.category FROM c ORDER BY c.category is not resumable even though it has an ORDER BY, while the scalar SELECT DISTINCT VALUE c.category FROM c ORDER BY c.category is. For those queries the server keeps reading until max is reached and returns a null token. If the limit truncated the results, the response also sets resultIncomplete to true; a null token combined with resultIncomplete means the result set was not exhausted and cannot be resumed. Retry with a larger max or a narrower query instead of sending a continuation.
{
"query": "SELECT * FROM c WHERE c.status = 'active'",
"max": 50,
"continuation": "<token from the previous result>"
}