Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions INTEGRATION_POLICY.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,28 @@ CLI payload can be substituted for an MCP payload without adaptation. Additive
fields may appear on either surface in minor releases; consumers should ignore
unknown fields and prefer documented fields over positional assumptions.

### JSON and MCP stability contract

CodeIndex follows SemVer for the supported integration surfaces listed above.
Patch releases may fix incorrect values while preserving documented field names
and value types. Minor releases may add fields, tools, tool arguments, examples,
annotations, error `data` members, or enum values when existing consumers can
ignore them safely. Breaking removals, required-field additions, field renames,
or incompatible type changes require a major release unless the old shape was
explicitly documented as preview.

Deprecations are announced in the changelog before removal. Stable fields keep a
minimum one-major-release compatibility window; preview fields may change in a
minor release, but the release notes must say so. Tool definitions can expose
additional metadata such as examples and annotations without changing the
meaning of existing `inputSchema` entries.

Consumers should branch on documented structural fields, not prose. For MCP
errors, route on `error.code` and structured `error.data.category` when present;
do not parse `error.message`, which is diagnostic text and may be clarified in
minor or patch releases. For CLI automation, route on documented exit codes and
JSON fields rather than human output.

| Query surface | CLI `--json` shape | MCP response shape | Compatibility notes |
|---|---|---|---|
| `search` | One JSON object per result, with CLI query metadata such as `api_version`, `query`, path, line range, snippet, highlights, and truncation details. | Tool result content contains equivalent search-result objects using MCP serialization and tool-call framing. | Result semantics are shared, but the outer envelope and field casing follow the called surface. |
Expand Down
24 changes: 22 additions & 2 deletions USER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ cdidx suggestions list # Review local AI feedback history
cdidx mcp # Start MCP server for AI tools
```

78 languages supported. 24 MCP tools. Incremental updates. Zero config.
78 languages supported. 24 registered MCP tools. Incremental updates. Zero config.

| Topic | Link |
|---|---|
Expand Down Expand Up @@ -1764,7 +1764,7 @@ OpenAI Codex CLI (`codex.json` or `~/.codex/config.json`):

Once configured, the AI can directly call these tools:

The MCP `tools/list` descriptions include compact English/Japanese usage examples for the primary search and navigation tools, so AI clients can discover valid argument shapes directly from the server response.
The MCP `tools/list` response includes an `examples` array for every registered tool, so AI clients can discover valid `tools/call` argument shapes directly from the server response.

| Tool | Description |
|---|---|
Expand Down Expand Up @@ -1809,6 +1809,26 @@ Graph-oriented MCP tools such as `references`, `callers`, and `callees` also ret

All MCP tools include `annotations` (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`) so AI clients can auto-approve safe read-only queries without prompting the user.

#### MCP error responses

MCP JSON-RPC failures use the standard `error` object. Clients should route on
`error.code` and, when present, `error.data.category`; do not parse
`error.message`, which is human-facing diagnostic text.

| Code | Meaning | Client action |
|---|---|---|
| `-32700` | Parse error or frame too large | Fix the JSON/frame size before retrying |
| `-32600` | Invalid JSON-RPC request | Fix request shape before retrying |
| `-32601` | Method not found or disabled tool | Check server version and `tools/list` |
| `-32602` | Invalid params, unknown tool, or bad protocol version | Fix arguments or negotiate a supported version |
| `-32603` | Internal error | Surface the failure and inspect server stderr |
| `-32000` | Rate limited | Retry after the reported delay |
| `-32001` | Permission denied | Provide the configured auth token |
| `-32010` | Index missing | Run `cdidx index <projectPath>` first |
| `-32011` | Index stale/schema mismatch | Rebuild or refresh the index |
| `-32012` | Index corrupted/unreadable | Rebuild the index from source |
| `-32015` | Request cancelled | Retry if the client still needs the result |

#### Optional HTTP transport

By default `cdidx mcp` speaks JSON-RPC over stdin/stdout, which is what every config example above uses. AI clients that prefer to keep one warm server running across many requests — instead of paying subprocess-spawn cost per call — can switch the transport to HTTP:
Expand Down
16 changes: 16 additions & 0 deletions changelog.d/unreleased/1810.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: added
issues:
- 1810
affected:
- src/CodeIndex/Mcp/McpServer.cs
- tests/CodeIndex.Tests/McpServerTests.cs
---

## English

- **MCP tools now publish inline call examples (#1810)** — every `tools/list` tool definition includes an `examples` array with a canonical `tools/call` request shape.

## 日本語

- **MCP ツールが inline call example を公開するようになりました (#1810)** — `tools/list` の全ツール定義に、標準的な `tools/call` リクエスト形状を示す `examples` 配列を追加しました。
15 changes: 15 additions & 0 deletions changelog.d/unreleased/1820.internal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
category: internal
issues:
- 1820
affected:
- tests/CodeIndex.Tests/McpServerTests.cs
---

## English

- **MCP response shape tests now cover tool schemas and examples (#1820)** — tests assert the shared `tools/list` schema/example contract and representative MCP result envelopes.

## 日本語

- **MCP response shape テストが tool schema と example を確認するようになりました (#1820)** — `tools/list` の共通 schema/example 契約と代表的な MCP result envelope をテストで固定しました。
15 changes: 15 additions & 0 deletions changelog.d/unreleased/1902.docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
category: docs
issues:
- 1902
affected:
- INTEGRATION_POLICY.md
---

## English

- **Documented the JSON and MCP stability contract (#1902)** — the integration policy now describes SemVer expectations, additive changes, breaking changes, deprecation windows, and client routing guidance.

## 日本語

- **JSON / MCP の安定性契約を文書化しました (#1902)** — integration policy に SemVer 期待値、additive change、breaking change、deprecation window、client routing guidance を追記しました。
15 changes: 15 additions & 0 deletions changelog.d/unreleased/1911.docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
category: docs
issues:
- 1911
affected:
- USER_GUIDE.md
---

## English

- **Clarified the MCP tool count and inventory wording (#1911)** — the user guide now describes the count as registered MCP tools and points clients to the authoritative `tools/list` response.

## 日本語

- **MCP tool count と inventory の表現を明確化しました (#1911)** — USER_GUIDE で registered MCP tools として件数を表現し、権威情報が `tools/list` response であることを明示しました。
15 changes: 15 additions & 0 deletions changelog.d/unreleased/1978.docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
category: docs
issues:
- 1978
affected:
- USER_GUIDE.md
---

## English

- **Documented MCP error response handling in the user guide (#1978)** — the MCP section now lists JSON-RPC error codes, meanings, and recommended client actions.

## 日本語

- **USER_GUIDE に MCP error response の扱いを文書化しました (#1978)** — MCP セクションに JSON-RPC error code、意味、推奨される client action の表を追加しました。
63 changes: 62 additions & 1 deletion src/CodeIndex/Mcp/McpServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2559,13 +2559,74 @@ private static JsonObject CreateToolDefinition(string name, string description,
{
["name"] = name,
["description"] = AppendLanguageSupportClause(name, description),
["inputSchema"] = inputSchema
["inputSchema"] = inputSchema,
["examples"] = BuildToolExamples(name),
};
if (annotations != null)
def["annotations"] = annotations;
return def;
}

private static JsonArray BuildToolExamples(string name)
{
var args = name switch
{
"search" => new JsonObject { ["query"] = "Run", ["lang"] = "csharp", ["limit"] = 5 },
"definition" => new JsonObject { ["query"] = "App", ["exactName"] = true },
"references" => new JsonObject { ["query"] = "Run", ["kind"] = "call" },
"callers" => new JsonObject { ["query"] = "Run", ["rankBy"] = "weighted" },
"callees" => new JsonObject { ["query"] = "App.Run" },
"symbols" => new JsonObject { ["query"] = "App", ["kind"] = "class" },
"files" => new JsonObject { ["query"] = "app.cs", ["lang"] = "csharp" },
"excerpt" => new JsonObject { ["path"] = "src/app.cs", ["startLine"] = 1, ["endLine"] = 5 },
"find_in_file" => new JsonObject { ["path"] = "src/app.cs", ["query"] = "Run", ["before"] = 1, ["after"] = 1 },
"map" => new JsonObject { ["limit"] = 5, ["excludeTests"] = true },
"analyze_symbol" => new JsonObject { ["query"] = "Run", ["includeBody"] = true },
"impact_analysis" => new JsonObject { ["query"] = "Run", ["maxHops"] = 2, ["withPaths"] = true },
"status" => new JsonObject(),
"outline" => new JsonObject { ["path"] = "src/app.cs" },
"deps" => new JsonObject { ["path"] = "src/", ["reverse"] = false, ["limit"] = 10 },
"languages" => new JsonObject(),
"validate" => new JsonObject { ["kind"] = "line_too_long" },
"ping" => new JsonObject(),
"batch_query" => new JsonObject
{
["queries"] = new JsonArray
{
new JsonObject { ["tool"] = "search", ["arguments"] = new JsonObject { ["query"] = "Run", ["limit"] = 3 } },
new JsonObject { ["tool"] = "definition", ["arguments"] = new JsonObject { ["query"] = "App", ["limit"] = 3 } },
},
},
"index" => new JsonObject { ["path"] = ".", ["rebuild"] = false },
"backfill_fold" => new JsonObject(),
"symbol_hotspots" => new JsonObject { ["lang"] = "csharp", ["limit"] = 10 },
"unused_symbols" => new JsonObject { ["lang"] = "csharp", ["limit"] = 10 },
"suggest_improvement" => new JsonObject
{
["category"] = "output_format",
["description"] = "The tool response should make truncation easier to detect.",
},
_ => new JsonObject(),
};

return new JsonArray
{
new JsonObject
{
["request"] = new JsonObject
{
["method"] = "tools/call",
["params"] = new JsonObject
{
["name"] = name,
["arguments"] = args,
},
},
["response_excerpt"] = "A successful MCP tool result includes content and, when available, structuredContent.",
},
};
}

private static string AppendLanguageSupportClause(string name, string description)
{
var clause = name switch
Expand Down
57 changes: 57 additions & 0 deletions tests/CodeIndex.Tests/McpServerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,63 @@ public void Initialize_ReturnsToolsCapability()
Assert.False(response["result"]!["capabilities"]!["tools"]!["listChanged"]!.GetValue<bool>());
}

[Fact]
public void ToolsList_EachToolPublishesSchemaAndExampleContract()
{
var request = JsonNode.Parse("""{"jsonrpc":"2.0","id":1,"method":"tools/list"}""")!;
var response = _server.HandleMessage(request)!;

var tools = response["result"]!["tools"]!.AsArray();
Assert.Equal(24, tools.Count);
foreach (var tool in tools)
{
Assert.False(string.IsNullOrWhiteSpace(tool!["name"]!.GetValue<string>()));
Assert.False(string.IsNullOrWhiteSpace(tool["description"]!.GetValue<string>()));
Assert.Equal("object", tool["inputSchema"]!["type"]!.GetValue<string>());

var examples = tool["examples"]!.AsArray();
Assert.NotEmpty(examples);
foreach (var example in examples)
{
Assert.Equal("tools/call", example!["request"]!["method"]!.GetValue<string>());
Assert.Equal(tool["name"]!.GetValue<string>(), example["request"]!["params"]!["name"]!.GetValue<string>());
Assert.NotNull(example["request"]!["params"]!["arguments"]);
Assert.False(string.IsNullOrWhiteSpace(example["response_excerpt"]!.GetValue<string>()));
}
}
}

[Theory]
[InlineData("ping", """{}""")]
[InlineData("status", """{}""")]
[InlineData("search", """{"query":"Run","limit":5}""")]
public void ToolCall_ResponseShape_HasStableMcpResultEnvelope(string toolName, string argumentsJson)
{
var request = new JsonObject
{
["jsonrpc"] = "2.0",
["id"] = 1,
["method"] = "tools/call",
["params"] = new JsonObject
{
["name"] = toolName,
["arguments"] = JsonNode.Parse(argumentsJson),
},
};
var response = _server.HandleMessage(request)!;

Assert.Equal("2.0", response["jsonrpc"]!.GetValue<string>());
Assert.Equal(1, response["id"]!.GetValue<int>());
Assert.Null(response["error"]);

var result = response["result"]!;
Assert.NotNull(result["content"]);
Assert.Equal("text", result["content"]!.AsArray()[0]!["type"]!.GetValue<string>());
Assert.NotNull(result["structuredContent"]);
Assert.NotNull(result["_meta"]!["request_id"]);
Assert.NotNull(result["_meta"]!["correlation_id"]);
}

[Fact]
public void Initialize_ReturnsInstructions()
{
Expand Down
Loading