Add schema discovery command and read-only MCP tool (#160) - #184
Conversation
Add a read-only 'schema' command that infers a container's structure from a bounded sample: partition key path(s), indexing policy summary, estimated document count, and inferred field types (dot notation for nested objects, per-field presence and observed JSON types). --sample selects the sample size (clamped to 1-100, default 20); --database/--container override the target. Exposed as a read-only MCP tool. Includes localization keys, docs (README, docs/commands.md), CHANGELOG entry, and unit tests for the sample-clamping and type-inference helpers.
Code Coverage OverviewLanguages: C# C# / code-coverage/dotnetThe overall line coverage in commit 9e76b61 in the Show a line coverage summary of the most impacted files.
Updated |
There was a problem hiding this comment.
Pull request overview
This PR adds a new schema discovery command (and matching read-only MCP tool) to provide a bounded, structured JSON summary of a Cosmos DB container—partition key paths, indexing policy summary, estimated document count, and inferred field types from a small sample—supporting agentic workflows that need fast, low-risk container introspection.
Changes:
- Introduces
SchemaCommandwith bounded sampling (--sampleclamped to 1–100) and JSON schema inference (dot-notation paths + type sets + per-field presence). - Adds unit tests covering sample clamping and schema/type inference helpers.
- Updates user-facing docs/help text (README,
docs/commands.md, localization strings, CHANGELOG).
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Adds schema to the feature list and describes its discovery output at a high level. |
| docs/commands.md | Documents schema usage, options, examples, and sample output JSON. |
| CosmosDBShell/lang/en.ftl | Adds localized descriptions for the schema command and its options. |
| CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/SchemaCommand.cs | Implements the new schema command and MCP annotation; includes sample clamping + field inference logic. |
| CosmosDBShell.Tests/CommandTests/SchemaCommandTests.cs | Adds unit tests for command registration and helper behaviors (clamping + inference). |
| CHANGELOG.md | Records the new schema command/tool as a new feature. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
docs/commands.md:654
- The sample output shows
"indexingMode": "consistent", but the implementation surfacesContainerIndexingPolicyView.IndexingMode, which is populated viaindexingPolicy.IndexingMode.ToString()and will be Pascal-cased (e.g.,"Consistent", same as the existinginfocommand output). This makes the sample output misleading.
"indexingPolicy": {
"indexingMode": "consistent",
"automatic": true,
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.
Suppressed comments (1)
CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/SchemaCommand.cs:96
- The NotFound handler always throws
error-container_not_found, but a 404 can also be triggered by a missing database. That can produce a misleading message ("container not found") when the real issue is "database not found". Consider checking database existence on the NotFound path and only emitting the container-not-found message when the database is confirmed to exist.
catch (CosmosException e) when (e.StatusCode == HttpStatusCode.NotFound)
{
throw new CommandException(
"schema",
MessageService.GetArgsString(
"error-container_not_found",
"container",
containerName,
"database",
databaseName),
e);
}
Summary
Implements the M4 schema / describe discovery tool from the Agentic & Automation Roadmap.
Adds a read-only
schemacommand and matching MCP tool that return a cheap, bounded discovery summary of a Cosmos DB container. This lets agents and users understand container structure without repeatedly sampling data or guessing field names.For the current container, or one selected with
--database/--container, the default result includes:x-ms-resource-usagequota header without scanning the containerstring,number,boolean,object,array,null), and the number of sampled documents containing each field--sample <n>controls the sample size and is clamped to1-100(default20). Sampling is bounded server-side withSELECT TOP nand client-side withMaxItemCount.--fields-only(alias--short) skips the container metadata read and returns onlysampledDocumentsandfields, producing a smaller, lower-latency CLI or MCP result.Default output
{ "database": "MyDB", "container": "Products", "partitionKeyPaths": ["/category"], "documentCountEstimate": 1280, "sampleSize": 20, "sampledDocuments": 20, "indexingPolicy": { "indexingMode": "Consistent", "automatic": true, "includedPaths": 1, "excludedPaths": 1, "compositeIndexes": 0, "spatialIndexes": 0, "vectorIndexes": 0 }, "fields": [ { "path": "id", "types": ["string"], "presence": 20 }, { "path": "category", "types": ["string"], "presence": 20 }, { "path": "price", "types": ["number"], "presence": 18 } ] }Fields-only output
{ "sampledDocuments": 20, "fields": [ { "path": "id", "types": ["string"], "presence": 20 }, { "path": "category", "types": ["string"], "presence": 20 }, { "path": "price", "types": ["number"], "presence": 18 } ] }Implementation notes
Acceptance criteria
[CosmosCommand("schema")]with read-only, idempotent, open-world MCP annotationsSELECT TOP n, client page-size bound, and sample size clamped to1-100; document count comes from the quota headerValidation
Fixes #160