From eacb5880ed295f0bd8d6811d3bcd27a9dcfa3b5e Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 25 May 2026 16:39:09 +0900 Subject: [PATCH 1/6] Fix MCP initialized notification for #1780 --- DEVELOPER_GUIDE.md | 3 ++ changelog.d/unreleased/1780.fixed.md | 18 ++++++++++ src/CodeIndex/Mcp/McpServer.cs | 45 +++++++++++++++++++++++ tests/CodeIndex.Tests/McpServerTests.cs | 47 +++++++++++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 changelog.d/unreleased/1780.fixed.md diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index ffc858c18c..4f49d7eec4 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -1502,6 +1502,9 @@ Piping `{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}` into `serverInfo.name`, `serverInfo.version` (read via `ConsoleUi.LoadVersion()` — the same `version.json` source), and the long `instructions` string that guides AI clients on tool selection. + After that response is written, the server emits one + `notifications/initialized` notification per session so clients that wait + for a server-side ready signal can proceed without optimistic polling. - The advertised capability surface includes `tools`, `resources`, and `prompts`. `resources/list` pages indexed files as `cdidx://file/` URIs and `resources/read` reconstructs file text from indexed chunks. diff --git a/changelog.d/unreleased/1780.fixed.md b/changelog.d/unreleased/1780.fixed.md new file mode 100644 index 0000000000..cdd0164f77 --- /dev/null +++ b/changelog.d/unreleased/1780.fixed.md @@ -0,0 +1,18 @@ +--- +category: fixed +issues: + - 1780 +affected: + - src/CodeIndex/Mcp/McpServer.cs + - tests/CodeIndex.Tests/McpServerTests.cs + - DEVELOPER_GUIDE.md + - README.md +--- + +## English + +- **MCP initialize now emits the ready notification (#1780)** — after the `initialize` response is written, the server sends one `notifications/initialized` notification per session for clients that wait for a server-side ready signal. + +## 日本語 + +- **MCP initialize が ready 通知を送るようになりました (#1780)** — `initialize` レスポンスを書き終えた後、サーバー側の ready signal を待つクライアント向けに、セッションごとに 1 回だけ `notifications/initialized` を送信します。 diff --git a/src/CodeIndex/Mcp/McpServer.cs b/src/CodeIndex/Mcp/McpServer.cs index 7c011969e5..562b066b3b 100644 --- a/src/CodeIndex/Mcp/McpServer.cs +++ b/src/CodeIndex/Mcp/McpServer.cs @@ -63,6 +63,8 @@ public partial class McpServer : IDisposable private readonly AsyncLocal?> _deferredFrameLogs = new(); private static readonly AsyncLocal CurrentCorrelationContext = new(); private bool _running = true; + private bool _initializedNotificationPending; + private bool _initializedNotificationSent; // Per-session DbContext reused across MCP tool calls. Holding the connection open // avoids reopening SQLite, reapplying pragmas, and re-registering every SQL function // on each invocation (issue #1494). @@ -456,6 +458,7 @@ internal async Task RunAsync(IMcpTransport transport, CancellationToken cancella } await WriteFrameSafelyAsync(transport, response, loopToken).ConfigureAwait(false); + await EmitInitializedNotificationIfPendingAsync(transport, loopToken).ConfigureAwait(false); FlushDeferredFrameLogs(); // `notifications/shutdown` flips `_running` inside `HandleMessage`; exit the loop @@ -576,6 +579,7 @@ private async Task RunConcurrentFrameLoopAsync(IMcpTransport transport, Cancella try { await WriteFrameSafelyAsync(transport, response, loopToken).ConfigureAwait(false); + await EmitInitializedNotificationIfPendingAsync(transport, loopToken).ConfigureAwait(false); FlushDeferredFrameLogs(); } finally @@ -611,6 +615,7 @@ internal async Task ProcessLineAsync(string line, TextWriter writer) try { await WriteJsonLineAsync(writer, response).ConfigureAwait(false); + await EmitInitializedNotificationIfPendingAsync(writer).ConfigureAwait(false); FlushDeferredFrameLogs(); } catch (Exception ex) when (ex is IOException or ObjectDisposedException or OperationCanceledException) @@ -644,6 +649,44 @@ private static async Task WriteFrameSafelyAsync(IMcpTransport transport, string? } } + private async Task EmitInitializedNotificationIfPendingAsync(IMcpTransport transport, CancellationToken cancellationToken) + { + var notification = ConsumeInitializedNotification(); + if (notification is null) + return; + if (transport is IOutOfBandMcpTransport outOfBandTransport) + { + await outOfBandTransport.WriteOutOfBandFrameAsync(notification, cancellationToken).ConfigureAwait(false); + return; + } + await WriteFrameSafelyAsync(transport, notification, cancellationToken).ConfigureAwait(false); + } + + private async Task EmitInitializedNotificationIfPendingAsync(TextWriter writer) + { + var notification = ConsumeInitializedNotification(); + if (notification is null) + return; + await WriteJsonLineAsync(writer, notification).ConfigureAwait(false); + } + + private string? ConsumeInitializedNotification() + { + if (!_initializedNotificationPending) + return null; + _initializedNotificationPending = false; + if (_initializedNotificationSent) + return null; + _initializedNotificationSent = true; + var notification = new JsonObject + { + ["jsonrpc"] = "2.0", + ["method"] = "notifications/initialized", + ["params"] = new JsonObject() + }; + return notification.ToJsonString(_jsonOptions); + } + private string BuildInvalidUtf8ParseErrorResponse(DecoderFallbackException ex) { DeferFrameLog(BuildInvalidUtf8ErrorLog(ex.Message)); @@ -1287,6 +1330,8 @@ private JsonNode HandleInitialize(JsonNode? id, JsonNode? _params) // サーバー指示 — AIクライアント向けツール選択ガイダンス ["instructions"] = BuildInstructions() }; + if (!_initializedNotificationSent) + _initializedNotificationPending = true; return CreateSuccessResponse(true, id, result); } diff --git a/tests/CodeIndex.Tests/McpServerTests.cs b/tests/CodeIndex.Tests/McpServerTests.cs index 27599343e6..c93c3b6476 100644 --- a/tests/CodeIndex.Tests/McpServerTests.cs +++ b/tests/CodeIndex.Tests/McpServerTests.cs @@ -237,6 +237,21 @@ public void Initialize_ReturnsProtocolVersion() Assert.Equal(ConsoleUi.LoadVersion(), response["result"]!["serverInfo"]!["version"]!.GetValue()); } + [Fact] + public async Task RunAsync_InitializeEmitsInitializedNotificationAfterResponseOnlyOnce() + { + var transport = new QueueMcpTransport( + """{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"clientInfo":{"name":"test-client","version":"1.0"}}}""", + """{"jsonrpc":"2.0","id":2,"method":"initialize","params":{"clientInfo":{"name":"test-client","version":"1.0"}}}"""); + + await _server.RunAsync(transport, CancellationToken.None); + + Assert.Equal(3, transport.WrittenFrames.Count); + Assert.Equal(1, JsonNode.Parse(transport.WrittenFrames[0])!["id"]!.GetValue()); + Assert.Equal("notifications/initialized", JsonNode.Parse(transport.WrittenFrames[1])!["method"]!.GetValue()); + Assert.Equal(2, JsonNode.Parse(transport.WrittenFrames[2])!["id"]!.GetValue()); + } + [Fact] public void Initialize_AdvertisesResourcesAndPrompts() { @@ -9538,6 +9553,38 @@ public ValueTask DisposeAsync() } } + private sealed class QueueMcpTransport : IMcpTransport, IOutOfBandMcpTransport + { + private readonly Queue _frames; + + public QueueMcpTransport(params string[] frames) + { + _frames = new Queue(frames); + } + + public string Name => "memory"; + public string Endpoint => "memory://test"; + public List WrittenFrames { get; } = []; + + public Task ReadFrameAsync(CancellationToken cancellationToken) + => Task.FromResult(_frames.Count == 0 ? null : _frames.Dequeue()); + + public Task WriteFrameAsync(string? frame, CancellationToken cancellationToken) + { + if (frame is not null) + WrittenFrames.Add(frame); + return Task.CompletedTask; + } + + public Task WriteOutOfBandFrameAsync(string frame, CancellationToken cancellationToken) + { + WrittenFrames.Add(frame); + return Task.CompletedTask; + } + + public ValueTask DisposeAsync() => ValueTask.CompletedTask; + } + // The shutdown helper is the heart of the #1573 fix: cancelling the CTS through Console.CancelKeyPress // (and PosixSignal.SIGTERM on Unix) must trip the loop. This test exercises the cross-platform // Ctrl+C path by raising the .NET CancelKeyPress event directly via reflection — the test cannot From 8855b1c1f8adbd7018ef30553a559c591d7a38b7 Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 25 May 2026 16:40:15 +0900 Subject: [PATCH 2/6] Surface MCP client info in status for #1739 --- AGENT_GUIDE.md | 2 +- DEVELOPER_GUIDE.md | 2 +- README.md | 2 +- changelog.d/unreleased/1739.fixed.md | 19 +++++++++++++++++++ src/CodeIndex/Mcp/McpToolHandlers.cs | 9 +++++++++ tests/CodeIndex.Tests/McpServerTests.cs | 4 +++- 6 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 changelog.d/unreleased/1739.fixed.md diff --git a/AGENT_GUIDE.md b/AGENT_GUIDE.md index 3da9313f86..1253f6eafa 100644 --- a/AGENT_GUIDE.md +++ b/AGENT_GUIDE.md @@ -138,7 +138,7 @@ CI watching must be bounded. Do not loop indefinitely. - `status` also surfaces `.cdidx` data-directory permissions via `data_dir_mode` on POSIX filesystems. New `.cdidx` data directories are forced to `0700`; the field is omitted on Windows, URI DBs, or when the directory mode cannot be inspected. - `status` also surfaces filesystem case-sensitivity via `path_case_sensitive`, stamped on every successful `cdidx index` run (full scan AND partial update, plus MCP-driven indexes) from `core.ignorecase` + a live filesystem probe. `true` means the volume is case-sensitive (`Foo.cs` and `foo.cs` are distinct); `false` means case-insensitive. Omitted on legacy DBs that predate the stamp. Use it to audit path-equality decisions on case-sensitive APFS, WSL NTFS / dev-drive, and ReFS mounts where the prior OS-keyed heuristic could mis-classify the workspace (#1546). - `status` also surfaces Linux mandatory-access-control context via `mac_profile` when `/proc/self/attr/current` or `/proc/self/attr/exec` indicates an AppArmor or SELinux profile. It is omitted on non-Linux hosts, unconstrained processes, or unreadable proc attributes (#1768). -- MCP `status` also surfaces session diagnostics via `mcp_session`. It is not persisted DB state; it includes the current `log_level`, captured `roots`, and optional `client_capabilities`. +- MCP `status` also surfaces session diagnostics via `mcp_session`. It is not persisted DB state; it includes the current `log_level`, captured `roots`, optional `client_info`, and optional `client_capabilities`. - Keep `README.md`, `DEVELOPER_GUIDE.md`, and this file synchronized if this contract changes. ## Reference Extraction diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index 4f49d7eec4..53f6bc5b0a 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -786,7 +786,7 @@ Adding `--json-envelope` to a query command (`search`, `definition`, `references Every top-level CLI/MCP JSON DTO (`StatusResult`, `RepoMapResult`, `SymbolAnalysisResult`, `ImpactAnalysisResult`, `OutlineResult`, `FileExcerptResult`, `CompactSearchResult`, `SymbolResult`, `DefinitionResult`, `UnusedSymbolResult`, `ReferenceResult`, `CallerResult`, `CalleeResult`, `FileResult`, `FileFindResult`) carries an `api_version` string field stamped from `JsonOutputContract.ApiVersion`. The same value is mirrored on the `--json-envelope` `metadata` block. This describes the JSON output contract, not the cdidx binary version (which is still surfaced via `version.json` and `cdidx --version`). Bump `JsonOutputContract.ApiVersion` only on **breaking** shape changes — renames, removals, or type changes of an existing field. Additive changes (new optional fields, new readiness flags, new enum values) keep the version stable so older consumers continue to parse the payload. Strict downstream consumers should pin against the major value and degrade gracefully when it changes. Issue #1555. -The documented `status --json` trust contract spans `fold_ready`, `fold_ready_reason`, `graph_table_available`, `issues_table_available`, `sql_graph_contract_ready`, `sql_graph_contract_degraded_reason`, `hotspot_family_ready`, `hotspot_family_degraded_reason`, `csharp_symbol_name_ready`, `csharp_metadata_target_ready`, `csharp_metadata_target_degraded_reason`, `indexed_head_commit`, `worktree_head_changed`, `indexed_head_sha`, `indexed_head_branch`, `indexed_head_timestamp`, `commits_ahead_of_indexed_head`, `index_writer_version`, `index_newer_than_reader`, `index_newer_than_reader_reason`, `unknown_extension_file_count`, `path_case_sensitive`, `data_dir_mode`, `mac_profile`, `stale_after_seconds`, `index_age_seconds`, plus the fold-only and C# metadata-target-only remediation fields `degraded_reason`, `recommended_action`, `alternative_action`, and MCP-only `mcp_session`. MCP `mcp_session` is session-scoped diagnostics, not persisted DB state, and contains `log_level`, `roots`, and optional `client_capabilities`. Keep this list synchronized with `README.md` and `AGENT_GUIDE.md`; `DocumentationStatusContractTests` fails when any required field is missing from one of those docs. +The documented `status --json` trust contract spans `fold_ready`, `fold_ready_reason`, `graph_table_available`, `issues_table_available`, `sql_graph_contract_ready`, `sql_graph_contract_degraded_reason`, `hotspot_family_ready`, `hotspot_family_degraded_reason`, `csharp_symbol_name_ready`, `csharp_metadata_target_ready`, `csharp_metadata_target_degraded_reason`, `indexed_head_commit`, `worktree_head_changed`, `indexed_head_sha`, `indexed_head_branch`, `indexed_head_timestamp`, `commits_ahead_of_indexed_head`, `index_writer_version`, `index_newer_than_reader`, `index_newer_than_reader_reason`, `unknown_extension_file_count`, `path_case_sensitive`, `data_dir_mode`, `mac_profile`, `stale_after_seconds`, `index_age_seconds`, plus the fold-only and C# metadata-target-only remediation fields `degraded_reason`, `recommended_action`, `alternative_action`, and MCP-only `mcp_session`. MCP `mcp_session` is session-scoped diagnostics, not persisted DB state, and contains `log_level`, `roots`, optional `client_info`, and optional `client_capabilities`. Keep this list synchronized with `README.md` and `AGENT_GUIDE.md`; `DocumentationStatusContractTests` fails when any required field is missing from one of those docs. `references` already prefixes each human-readable row with `reference_kind`, and `callers` does the same for its grouped caller rows. When one grouped container mixes kinds (for example `call` and `subscribe` on the same event member), the human-readable label joins the distinct kinds with `+` (for example `call+subscribe`) instead of collapsing to a single preferred label, and the reference-kind column widens dynamically to fit the longest label in the batch so mixed rows do not overrun the neighbouring column. JSON output for `callers` and `callees` keeps the scalar `reference_kind` for back-compat (it reports the preferred summary kind `instantiate` > `subscribe` > `MIN(call)`) and adds a sorted `reference_kinds` array plus a `has_mixed_reference_kinds` bool so consumers can detect mixed containers without trusting a single collapsed label. This lets terminal users distinguish `call` / `instantiate` / `subscribe` / mixed without re-running the command with `--json` and lets AI clients answer mixed-kind questions without chasing a second `--exact` query. diff --git a/README.md b/README.md index 604acb0336..aa6e53a178 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ The documented `status --json` trust contract covers these fields: -For MCP `status`, `mcp_session` is session-scoped diagnostic data rather than persisted index state. It includes `log_level`, `roots`, and optional `client_capabilities`. +For MCP `status`, `mcp_session` is session-scoped diagnostic data rather than persisted index state. It includes `log_level`, `roots`, optional `client_info`, and optional `client_capabilities`. `hotspot_family_degraded_reason` uses these values: diff --git a/changelog.d/unreleased/1739.fixed.md b/changelog.d/unreleased/1739.fixed.md new file mode 100644 index 0000000000..5115cb6ea4 --- /dev/null +++ b/changelog.d/unreleased/1739.fixed.md @@ -0,0 +1,19 @@ +--- +category: fixed +issues: + - 1739 +affected: + - src/CodeIndex/Mcp/McpToolHandlers.cs + - tests/CodeIndex.Tests/McpServerTests.cs + - DEVELOPER_GUIDE.md + - AGENT_GUIDE.md + - README.md +--- + +## English + +- **MCP status now surfaces initialize client identity (#1739)** — `status` tool responses include optional `mcp_session.client_info` with the captured `clientInfo.name` and `clientInfo.version` for session diagnostics. + +## 日本語 + +- **MCP status に initialize のクライアント識別情報を出すようになりました (#1739)** — `status` ツール応答の `mcp_session.client_info` に、取得済みの `clientInfo.name` と `clientInfo.version` を診断情報として任意で含めます。 diff --git a/src/CodeIndex/Mcp/McpToolHandlers.cs b/src/CodeIndex/Mcp/McpToolHandlers.cs index 8e8a11fee7..bdb4c4278e 100644 --- a/src/CodeIndex/Mcp/McpToolHandlers.cs +++ b/src/CodeIndex/Mcp/McpToolHandlers.cs @@ -1377,6 +1377,15 @@ private JsonObject BuildMcpSessionStatus() ["log_level"] = _mcpLogLevel, ["roots"] = roots, }; + if (_clientName is not null || _clientVersion is not null) + { + var clientInfo = new JsonObject(); + if (_clientName is not null) + clientInfo["name"] = _clientName; + if (_clientVersion is not null) + clientInfo["version"] = _clientVersion; + session["client_info"] = clientInfo; + } if (_clientCapabilities is not null) session["client_capabilities"] = _clientCapabilities.DeepClone(); return session; diff --git a/tests/CodeIndex.Tests/McpServerTests.cs b/tests/CodeIndex.Tests/McpServerTests.cs index c93c3b6476..1d233ac085 100644 --- a/tests/CodeIndex.Tests/McpServerTests.cs +++ b/tests/CodeIndex.Tests/McpServerTests.cs @@ -270,7 +270,7 @@ public void Initialize_AdvertisesResourcesAndPrompts() [Fact] public void Initialize_CapturesClientCapabilitiesAndRootsForSessionStatus() { - var request = JsonNode.Parse("""{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"capabilities":{"experimental":{"progress":true}},"rootUri":"file:///workspace","roots":[{"uri":"file:///workspace/src"}]}}""")!; + var request = JsonNode.Parse("""{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"clientInfo":{"name":"codex","version":"5.0"},"capabilities":{"experimental":{"progress":true}},"rootUri":"file:///workspace","roots":[{"uri":"file:///workspace/src"}]}}""")!; _server.HandleMessage(request); Assert.True(_server.ClientCapabilitiesForTests!["experimental"]!["progress"]!.GetValue()); @@ -281,6 +281,8 @@ public void Initialize_CapturesClientCapabilitiesAndRootsForSessionStatus() var session = response["result"]!["structuredContent"]!["mcp_session"]!; Assert.True(session["client_capabilities"]!["experimental"]!["progress"]!.GetValue()); + Assert.Equal("codex", session["client_info"]!["name"]!.GetValue()); + Assert.Equal("5.0", session["client_info"]!["version"]!.GetValue()); Assert.Equal("file:///workspace", session["roots"]!.AsArray()[0]!.GetValue()); Assert.Equal("info", session["log_level"]!.GetValue()); } From e696d425a8fe5569854e317a3850d40e5437f6f9 Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 25 May 2026 16:40:36 +0900 Subject: [PATCH 3/6] Document MCP logging capability for #1688 --- DEVELOPER_GUIDE.md | 7 +++++-- README.md | 2 +- changelog.d/unreleased/1688.fixed.md | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 changelog.d/unreleased/1688.fixed.md diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index 53f6bc5b0a..a10a4c1162 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -1510,7 +1510,9 @@ Piping `{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}` into URIs and `resources/read` reconstructs file text from indexed chunks. `prompts/list` exposes the built-in `summarize_file`, `find_unused`, and `impact_of_changing` prompts; `prompts/get` returns a user-message template - that directs clients toward the matching cdidx tools. + that directs clients toward the matching cdidx tools. `logging` advertises + MCP `notifications/message`; `logging/setLevel` accepts `debug`, `info`, + `notice`, `warning`, `error`, `critical`, `alert`, and `emergency`. - `protocolVersion` is **negotiated**, not hardcoded (#1554). The server maintains `McpServer.SupportedProtocolVersions` (newest first: `2025-03-26`, `2024-11-05`), reads the client's requested @@ -2838,7 +2840,8 @@ sequenceDiagram - `McpServer` が stdin/stdout を持ち、JSON-RPC 2.0 フレームを解析する。 - レスポンス構築は `JsonSerializer.Serialize(...)` ではなく、`System.Text.Json.Nodes.JsonObject` / `JsonArray` を**手組み**する。これが、トリミング済みバイナリでリフレクションベースのシリアライズが無効でも MCP パスが動き続ける理由。 -- `initialize` レスポンスは `protocolVersion`、`capabilities`、`serverInfo.name`、`serverInfo.version`(`ConsoleUi.LoadVersion()` — `version.json` が源)、および AI クライアントにツール選択を案内する長い `instructions` 文字列を返す。 +- `initialize` レスポンスは `protocolVersion`、`capabilities`、`serverInfo.name`、`serverInfo.version`(`ConsoleUi.LoadVersion()` — `version.json` が源)、および AI クライアントにツール選択を案内する長い `instructions` 文字列を返す。レスポンスを書き終えた後、サーバーはセッションごとに 1 回だけ `notifications/initialized` を送るため、サーバー側の ready signal を待つクライアントも optimistic polling なしで進める。 +- advertised capability には `tools`、`resources`、`prompts`、`logging` が含まれる。`logging` は MCP `notifications/message` を示し、`logging/setLevel` は `debug`、`info`、`notice`、`warning`、`error`、`critical`、`alert`、`emergency` を受け付ける。 - `protocolVersion` は**ハードコードではなく交渉**で決まる(#1554)。サーバーは `McpServer.SupportedProtocolVersions`(新しい順: `2025-03-26`, `2024-11-05`)を保持し、`initialize` パラメータからクライアント要求バージョンを読み取って、対応集合にあればそれを返し(合意)、未指定/非文字列なら既定の最新バージョンに fallback し、対応外なら `error.data` に `requestedVersion` と `supportedVersions` を入れた JSON-RPC `-32602` で拒否する。これにより将来 MCP 仕様が改訂されても、wire format が黙ってずれるのではなく actionable な handshake 失敗として表面化する。配列を新バージョンで更新する際は `ProtocolVersion` を先頭エントリと揃えて意図的に bump する。 - **認証ミドルウェア**(#1559)。`McpServer` はパース済み JSON-RPC リクエストごとに、メソッド抽出 *後*・dispatch *前* で `IMcpAuthenticator` を呼ぶ。既定の `LocalStdioAuthenticator` は permissive で(従来の stdio 動作を維持し、呼び出し元を `stdio` / `local` でタグ付けする)、`CDIDX_MCP_AUTH_TOKEN` を設定すると `TokenMcpAuthenticator` に切り替わる。`TokenMcpAuthenticator` は応答が必要な全リクエストに対し、`params.auth.token` が一致することを要求し、比較は `CryptographicOperations.FixedTimeEquals` による定数時間比較で行う。失敗は統一された JSON-RPC `-32001 "Unauthorized"` を返し(#1530 の sanitization 方針に従い、ワイヤでは未提示と不一致を区別しない)、`BuildAuthFailureLog` が詳細を stderr に書き出す。通知(`notifications/initialized`、`notifications/cancelled`)は応答もエラーコードも持たないため、ゲート *より前* で short-circuit する。このミドルウェアが将来 transport の差し替え seam になる — ネットワーク listener は別の `IMcpAuthenticator` を提供しつつ、`McpCallerIdentity`(`Source` + `Subject`)の形を保ち、監査ログ(#1562)から再利用できる。 diff --git a/README.md b/README.md index aa6e53a178..3255f1d3f4 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ file completion. | Search surfaces | CLI-first output for humans and machines; full-text, symbol, reference, caller/callee, dependency, map, inspect, and excerpt commands. | | Ranking and filters | Public/exported symbol matches rank ahead of protected, internal, and private matches. Use `--no-visibility-rank` for legacy order, and `--visibility` / `--exclude-visibility` with `symbols`, `definition`, `unused`, and `hotspots`. Query defaults can be adjusted with `CDIDX_DEFAULT_LIMIT`, `CDIDX_DEFAULT_SNIPPET_LINES`, and `CDIDX_DEFAULT_MAX_LINE_WIDTH`; explicit CLI flags still win. | | Project scoping | `.sln` / `.csproj`-aware --project <name|path> filters for indexing and queries, plus `--solution ` when a workspace has multiple solution files. | -| MCP integration | MCP server support for AI clients such as Claude Code, Cursor, and Windsurf, including tools, indexed-file resources, starter prompts, and `Language support:` descriptions sourced from the same registries as `cdidx languages`. | +| MCP integration | MCP server support for AI clients such as Claude Code, Cursor, and Windsurf, including tools, indexed-file resources, starter prompts, logging, server-side `notifications/initialized`, and `Language support:` descriptions sourced from the same registries as `cdidx languages`. | | Freshness | Parallel full-scan extraction with `--parallelism`, incremental refreshes with `--files` and `--commits`, continuous `--watch`, exact `status --check`, and configurable stale thresholds via `--stale-after` / `CDIDX_STALE_AFTER`. | | Storage | Local-first `.cdidx/codeindex.db` storage. Query commands run from nested directories prefer the outermost ancestor `.cdidx/codeindex.db` before falling back to the current directory. `--data-dir `, `CDIDX_DATA_DIR`, or `XDG_DATA_HOME` can move default SQLite storage outside the workspace; explicit `--db ` still wins. | | DB maintenance | New indexes use SQLite incremental auto-vacuum. `cdidx vacuum` reclaims free pages from existing DBs, including a one-time full `VACUUM` conversion for legacy no-autovacuum DBs, and `status --json` reports metrics under `db_pragma_settings`. | diff --git a/changelog.d/unreleased/1688.fixed.md b/changelog.d/unreleased/1688.fixed.md new file mode 100644 index 0000000000..33522351d4 --- /dev/null +++ b/changelog.d/unreleased/1688.fixed.md @@ -0,0 +1,16 @@ +--- +category: fixed +issues: + - 1688 +affected: + - DEVELOPER_GUIDE.md + - README.md +--- + +## English + +- **MCP logging capability is documented (#1688)** — the developer contract now records that the MCP server advertises `logging`, supports `logging/setLevel`, and can emit `notifications/message`. + +## 日本語 + +- **MCP logging capability を文書化しました (#1688)** — MCP サーバーが `logging` を advertise し、`logging/setLevel` と `notifications/message` に対応することを開発者向け契約に明記しました。 From bbfb0bda086ddd16608beac445ce4fe72b326f61 Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 25 May 2026 18:03:33 +0900 Subject: [PATCH 4/6] Clarify HTTP initialized notification for #1780 --- DEVELOPER_GUIDE.md | 7 ++-- README.md | 2 +- changelog.d/unreleased/1780.fixed.md | 5 +-- .../CodeIndex.Tests/HttpMcpTransportTests.cs | 34 +++++++++++++++++++ 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index 579e3e18a3..7597ffee0b 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -1512,7 +1512,10 @@ Piping `{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}` into long `instructions` string that guides AI clients on tool selection. After that response is written, the server emits one `notifications/initialized` notification per session so clients that wait - for a server-side ready signal can proceed without optimistic polling. + for a server-side ready signal can proceed without optimistic polling. On + HTTP transport, out-of-band notifications are delivered only to connected + `/events` SSE streams; POST-only clients receive the initialize response but + no separate notification frame. - The advertised capability surface includes `tools`, `resources`, and `prompts`. `resources/list` pages indexed files as `cdidx://file/` URIs and `resources/read` reconstructs file text from indexed chunks. @@ -2848,7 +2851,7 @@ sequenceDiagram - `McpServer` が stdin/stdout を持ち、JSON-RPC 2.0 フレームを解析する。 - レスポンス構築は `JsonSerializer.Serialize(...)` ではなく、`System.Text.Json.Nodes.JsonObject` / `JsonArray` を**手組み**する。これが、トリミング済みバイナリでリフレクションベースのシリアライズが無効でも MCP パスが動き続ける理由。 -- `initialize` レスポンスは `protocolVersion`、`capabilities`、`serverInfo.name`、`serverInfo.version`(`ConsoleUi.LoadVersion()` — `version.json` が源)、および AI クライアントにツール選択を案内する長い `instructions` 文字列を返す。レスポンスを書き終えた後、サーバーはセッションごとに 1 回だけ `notifications/initialized` を送るため、サーバー側の ready signal を待つクライアントも optimistic polling なしで進める。 +- `initialize` レスポンスは `protocolVersion`、`capabilities`、`serverInfo.name`、`serverInfo.version`(`ConsoleUi.LoadVersion()` — `version.json` が源)、および AI クライアントにツール選択を案内する長い `instructions` 文字列を返す。レスポンスを書き終えた後、サーバーはセッションごとに 1 回だけ `notifications/initialized` を送るため、サーバー側の ready signal を待つクライアントも optimistic polling なしで進める。HTTP transport では out-of-band 通知は接続済みの `/events` SSE stream にだけ配送され、POST のみのクライアントは initialize response だけを受け取り、別通知 frame は受け取らない。 - advertised capability には `tools`、`resources`、`prompts`、`logging` が含まれる。`logging` は MCP `notifications/message` を示し、`logging/setLevel` は `debug`、`info`、`notice`、`warning`、`error`、`critical`、`alert`、`emergency` を受け付ける。 - `protocolVersion` は**ハードコードではなく交渉**で決まる(#1554)。サーバーは `McpServer.SupportedProtocolVersions`(新しい順: `2025-03-26`, `2024-11-05`)を保持し、`initialize` パラメータからクライアント要求バージョンを読み取って、対応集合にあればそれを返し(合意)、未指定/非文字列なら既定の最新バージョンに fallback し、対応外なら `error.data` に `requestedVersion` と `supportedVersions` を入れた JSON-RPC `-32602` で拒否する。これにより将来 MCP 仕様が改訂されても、wire format が黙ってずれるのではなく actionable な handshake 失敗として表面化する。配列を新バージョンで更新する際は `ProtocolVersion` を先頭エントリと揃えて意図的に bump する。 - **認証ミドルウェア**(#1559)。`McpServer` はパース済み JSON-RPC リクエストごとに、メソッド抽出 *後*・dispatch *前* で `IMcpAuthenticator` を呼ぶ。既定の `LocalStdioAuthenticator` は permissive で(従来の stdio 動作を維持し、呼び出し元を `stdio` / `local` でタグ付けする)、`CDIDX_MCP_AUTH_TOKEN` を設定すると `TokenMcpAuthenticator` に切り替わる。`TokenMcpAuthenticator` は応答が必要な全リクエストに対し、`params.auth.token` が一致することを要求し、比較は `CryptographicOperations.FixedTimeEquals` による定数時間比較で行う。失敗は統一された JSON-RPC `-32001 "Unauthorized"` を返し(#1530 の sanitization 方針に従い、ワイヤでは未提示と不一致を区別しない)、`BuildAuthFailureLog` が詳細を stderr に書き出す。通知(`notifications/initialized`、`notifications/cancelled`)は応答もエラーコードも持たないため、ゲート *より前* で short-circuit する。このミドルウェアが将来 transport の差し替え seam になる — ネットワーク listener は別の `IMcpAuthenticator` を提供しつつ、`McpCallerIdentity`(`Source` + `Subject`)の形を保ち、監査ログ(#1562)から再利用できる。 diff --git a/README.md b/README.md index e345ccf651..9268b27a76 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ file completion. | Search surfaces | CLI-first output for humans and machines; full-text, symbol, reference, caller/callee, dependency, map, inspect, and excerpt commands. | | Ranking and filters | Public/exported symbol matches rank ahead of protected, internal, and private matches. Use `--no-visibility-rank` for legacy order, and `--visibility` / `--exclude-visibility` with `symbols`, `definition`, `unused`, and `hotspots`. Query defaults can be adjusted with `CDIDX_DEFAULT_LIMIT`, `CDIDX_DEFAULT_SNIPPET_LINES`, and `CDIDX_DEFAULT_MAX_LINE_WIDTH`; explicit CLI flags still win. | | Project scoping | `.sln` / `.csproj`-aware --project <name|path> filters for indexing and queries, plus `--solution ` when a workspace has multiple solution files. | -| MCP integration | MCP server support for AI clients such as Claude Code, Cursor, and Windsurf, including tools, indexed-file resources, starter prompts, logging, server-side `notifications/initialized`, and `Language support:` descriptions sourced from the same registries as `cdidx languages`. | +| MCP integration | MCP server support for AI clients such as Claude Code, Cursor, and Windsurf, including tools, indexed-file resources, starter prompts, logging, server-side `notifications/initialized` on stdio or HTTP `/events` streams, and `Language support:` descriptions sourced from the same registries as `cdidx languages`. | | Freshness | Parallel full-scan extraction with `--parallelism`, incremental refreshes with `--files` and `--commits`, continuous `--watch`, exact `status --check`, and configurable stale thresholds via `--stale-after` / `CDIDX_STALE_AFTER`. | | Storage | Local-first `.cdidx/codeindex.db` storage. Query commands run from nested directories prefer the outermost ancestor `.cdidx/codeindex.db` before falling back to the current directory. `--data-dir `, `CDIDX_DATA_DIR`, or `XDG_DATA_HOME` can move default SQLite storage outside the workspace; explicit `--db ` still wins. | | DB maintenance | New indexes use SQLite incremental auto-vacuum. `cdidx vacuum` reclaims free pages from existing DBs, including a one-time full `VACUUM` conversion for legacy no-autovacuum DBs, and `status --json` reports metrics under `db_pragma_settings`. | diff --git a/changelog.d/unreleased/1780.fixed.md b/changelog.d/unreleased/1780.fixed.md index cdd0164f77..a0013fbc89 100644 --- a/changelog.d/unreleased/1780.fixed.md +++ b/changelog.d/unreleased/1780.fixed.md @@ -5,14 +5,15 @@ issues: affected: - src/CodeIndex/Mcp/McpServer.cs - tests/CodeIndex.Tests/McpServerTests.cs + - tests/CodeIndex.Tests/HttpMcpTransportTests.cs - DEVELOPER_GUIDE.md - README.md --- ## English -- **MCP initialize now emits the ready notification (#1780)** — after the `initialize` response is written, the server sends one `notifications/initialized` notification per session for clients that wait for a server-side ready signal. +- **MCP initialize now emits the ready notification (#1780)** — after the `initialize` response is written, the server sends one `notifications/initialized` notification per session for clients that wait for a server-side ready signal; HTTP clients receive it through a connected `/events` stream. ## 日本語 -- **MCP initialize が ready 通知を送るようになりました (#1780)** — `initialize` レスポンスを書き終えた後、サーバー側の ready signal を待つクライアント向けに、セッションごとに 1 回だけ `notifications/initialized` を送信します。 +- **MCP initialize が ready 通知を送るようになりました (#1780)** — `initialize` レスポンスを書き終えた後、サーバー側の ready signal を待つクライアント向けに、セッションごとに 1 回だけ `notifications/initialized` を送信します。HTTP クライアントは接続済みの `/events` stream から受信します。 diff --git a/tests/CodeIndex.Tests/HttpMcpTransportTests.cs b/tests/CodeIndex.Tests/HttpMcpTransportTests.cs index a3679ba946..7e5419a071 100644 --- a/tests/CodeIndex.Tests/HttpMcpTransportTests.cs +++ b/tests/CodeIndex.Tests/HttpMcpTransportTests.cs @@ -50,6 +50,40 @@ public async Task HttpTransport_PostInitialize_ReturnsHandshakeResult() Assert.Equal("2025-03-26", root.GetProperty("result").GetProperty("protocolVersion").GetString()); } + [Fact] + public async Task HttpTransport_PostInitializeWithoutEventsStream_ReturnsOnlyHandshakeResult() + { + await using var harness = await McpHttpHarness.StartAsync(_dbPath); + + var response = await harness.PostJsonAsync("""{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}"""); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var body = await response.Content.ReadAsStringAsync(); + Assert.DoesNotContain("notifications/initialized", body, StringComparison.Ordinal); + using var doc = JsonDocument.Parse(body); + Assert.Equal(1, doc.RootElement.GetProperty("id").GetInt32()); + } + + [Fact] + public async Task HttpTransport_PostInitializeWithEventsStream_EmitsInitializedNotification() + { + await using var harness = await McpHttpHarness.StartAsync(_dbPath); + + using var client = new HttpClient(); + using var events = await client.GetAsync(new Uri(new Uri(harness.Endpoint), "events"), HttpCompletionOption.ResponseHeadersRead); + Assert.Equal(HttpStatusCode.OK, events.StatusCode); + + await using var eventStream = await events.Content.ReadAsStreamAsync(); + using var reader = new StreamReader(eventStream, Encoding.UTF8, leaveOpen: true); + var initializedTask = ReadUntilAsync(reader, "notifications/initialized"); + + var response = await harness.PostJsonAsync("""{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}"""); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var initializedFrame = await initializedTask.WaitAsync(TimeSpan.FromSeconds(5)); + Assert.Contains("\"method\":\"notifications/initialized\"", initializedFrame, StringComparison.Ordinal); + } + [Fact] public async Task HttpTransport_PostNotification_Returns204NoContent() { From 59c2278ab363a534b369a7fea4306e566df3b69d Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 25 May 2026 19:03:27 +0900 Subject: [PATCH 5/6] Sync Japanese README MCP notes for #1780 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 144541f511..50af19c255 100644 --- a/README.md +++ b/README.md @@ -312,7 +312,7 @@ cdidx mcp | 検索面 | CLI-first の人間向け / 機械処理向け出力。全文検索、シンボル、参照、caller/callee、依存関係、map、inspect、excerpt コマンドを提供します。 | | 順位と filter | public/exported なシンボル一致を protected、internal、private より優先します。従来順は `--no-visibility-rank`、可視性の include / exclude は `symbols`、`definition`、`unused`、`hotspots` の `--visibility` / `--exclude-visibility` で指定できます。query 既定値は `CDIDX_DEFAULT_LIMIT`、`CDIDX_DEFAULT_SNIPPET_LINES`、`CDIDX_DEFAULT_MAX_LINE_WIDTH` で調整でき、明示 CLI flag が常に優先されます。 | | project scope | `.sln` / `.csproj` を使った --project <name|path> filter で index と query を .NET project 配下へ絞り込めます。workspace に solution が複数ある場合は `--solution ` を指定します。 | -| MCP 連携 | Claude Code、Cursor、Windsurf などの AI クライアント向け MCP server。tools、インデックス済みファイル resources、starter prompts、ローカル引数検証用の schema constraints、text content block の `mimeType`、`cdidx languages` と同じ言語レジストリ由来の `Language support:` 説明を提供します。 | +| MCP 連携 | Claude Code、Cursor、Windsurf などの AI クライアント向け MCP server。tools、インデックス済みファイル resources、starter prompts、ローカル引数検証用の schema constraints、text content block の `mimeType`、logging、stdio または HTTP `/events` stream 上の server-side `notifications/initialized`、`cdidx languages` と同じ言語レジストリ由来の `Language support:` 説明を提供します。 | | freshness | `--parallelism` による parallel full-scan、`--files` / `--commits` による差分更新、`--watch` による継続更新、`status --check` による完全一致確認、`--stale-after` / `CDIDX_STALE_AFTER` による age threshold 上書きに対応します。 | | storage | `.cdidx/codeindex.db` に保存する local-first 設計。ネストしたディレクトリからの query コマンドは、current directory にフォールバックする前に最上位祖先の `.cdidx/codeindex.db` を優先します。既定の SQLite 保存先は `--data-dir `、`CDIDX_DATA_DIR`、`XDG_DATA_HOME` で workspace 外へ移せます。明示的な `--db ` は引き続き最優先です。 | | DB maintenance | 新規 index DB は SQLite incremental auto-vacuum を使います。既存 DB は `cdidx vacuum` で free page を回収でき、legacy no-autovacuum DB は初回だけ full `VACUUM` で変換します。`status --json` は `db_pragma_settings` 配下に metrics を出力します。 | From 200a3079fd634d4a077f4b5aa0799f809643bcac Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 25 May 2026 19:11:12 +0900 Subject: [PATCH 6/6] Document MCP initialized compatibility signal for #1780 --- DEVELOPER_GUIDE.md | 13 ++++++++----- README.md | 6 +++--- changelog.d/unreleased/1780.fixed.md | 4 ++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index 21629739d2..e31bef8ade 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -1512,10 +1512,13 @@ Piping `{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}` into `serverInfo.name`, `serverInfo.version` (read via `ConsoleUi.LoadVersion()` — the same `version.json` source), and the long `instructions` string that guides AI clients on tool selection. - After that response is written, the server emits one - `notifications/initialized` notification per session so clients that wait - for a server-side ready signal can proceed without optimistic polling. On - HTTP transport, out-of-band notifications are delivered only to connected + After that response is written, the server emits one compatibility + `notifications/initialized` ready signal per session so clients that wait for + a server-side ready signal can proceed without optimistic polling (#1780). + MCP also defines `notifications/initialized` as a client-to-server + notification; cdidx still accepts that direction as a no-op, and the + server-origin emission is intentionally limited to this compatibility signal. + On HTTP transport, out-of-band notifications are delivered only to connected `/events` SSE streams; POST-only clients receive the initialize response but no separate notification frame. - The advertised capability surface includes `tools`, `resources`, and @@ -2859,7 +2862,7 @@ sequenceDiagram - `McpServer` が stdin/stdout を持ち、JSON-RPC 2.0 フレームを解析する。 - レスポンス構築は `JsonSerializer.Serialize(...)` ではなく、`System.Text.Json.Nodes.JsonObject` / `JsonArray` を**手組み**する。これが、トリミング済みバイナリでリフレクションベースのシリアライズが無効でも MCP パスが動き続ける理由。 -- `initialize` レスポンスは `protocolVersion`、`capabilities`、`serverInfo.name`、`serverInfo.version`(`ConsoleUi.LoadVersion()` — `version.json` が源)、および AI クライアントにツール選択を案内する長い `instructions` 文字列を返す。レスポンスを書き終えた後、サーバーはセッションごとに 1 回だけ `notifications/initialized` を送るため、サーバー側の ready signal を待つクライアントも optimistic polling なしで進める。HTTP transport では out-of-band 通知は接続済みの `/events` SSE stream にだけ配送され、POST のみのクライアントは initialize response だけを受け取り、別通知 frame は受け取らない。 +- `initialize` レスポンスは `protocolVersion`、`capabilities`、`serverInfo.name`、`serverInfo.version`(`ConsoleUi.LoadVersion()` — `version.json` が源)、および AI クライアントにツール選択を案内する長い `instructions` 文字列を返す。レスポンスを書き終えた後、サーバーはセッションごとに 1 回だけ互換性用の `notifications/initialized` ready signal を送るため、サーバー側の ready signal を待つクライアントも optimistic polling なしで進める(#1780)。MCP は `notifications/initialized` を client-to-server 通知としても定義しており、cdidx はその方向も no-op として受理する。server-origin emission はこの互換性 signal に限定する。HTTP transport では out-of-band 通知は接続済みの `/events` SSE stream にだけ配送され、POST のみのクライアントは initialize response だけを受け取り、別通知 frame は受け取らない。 - advertised capability には `tools`、`resources`、`prompts`、`logging` が含まれる。`logging` は MCP `notifications/message` を示し、`logging/setLevel` は `debug`、`info`、`notice`、`warning`、`error`、`critical`、`alert`、`emergency` を受け付ける。 - `protocolVersion` は**ハードコードではなく交渉**で決まる(#1554)。サーバーは `McpServer.SupportedProtocolVersions`(新しい順: `2025-03-26`, `2024-11-05`)を保持し、`initialize` パラメータからクライアント要求バージョンを読み取って、対応集合にあればそれを返し(合意)、未指定/非文字列なら既定の最新バージョンに fallback し、対応外なら `error.data` に `requestedVersion` と `supportedVersions` を入れた JSON-RPC `-32602` で拒否する。これにより将来 MCP 仕様が改訂されても、wire format が黙ってずれるのではなく actionable な handshake 失敗として表面化する。配列を新バージョンで更新する際は `ProtocolVersion` を先頭エントリと揃えて意図的に bump する。 - **認証ミドルウェア**(#1559)。`McpServer` はパース済み JSON-RPC リクエストごとに、メソッド抽出 *後*・dispatch *前* で `IMcpAuthenticator` を呼ぶ。既定の `LocalStdioAuthenticator` は permissive で(従来の stdio 動作を維持し、呼び出し元を `stdio` / `local` でタグ付けする)、`CDIDX_MCP_AUTH_TOKEN` を設定すると `TokenMcpAuthenticator` に切り替わる。`TokenMcpAuthenticator` は応答が必要な全リクエストに対し、`params.auth.token` が一致することを要求し、比較は `CryptographicOperations.FixedTimeEquals` による定数時間比較で行う。失敗は統一された JSON-RPC `-32001 "Unauthorized"` を返し(#1530 の sanitization 方針に従い、ワイヤでは未提示と不一致を区別しない)、`BuildAuthFailureLog` が詳細を stderr に書き出す。通知(`notifications/initialized`、`notifications/cancelled`)は応答もエラーコードも持たないため、ゲート *より前* で short-circuit する。このミドルウェアが将来 transport の差し替え seam になる — ネットワーク listener は別の `IMcpAuthenticator` を提供しつつ、`McpCallerIdentity`(`Source` + `Subject`)の形を保ち、監査ログ(#1562)から再利用できる。 diff --git a/README.md b/README.md index 50af19c255..fdb362a64b 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ file completion. | Search surfaces | CLI-first output for humans and machines; full-text, symbol, reference, caller/callee, dependency, map, inspect, and excerpt commands. | | Ranking and filters | Public/exported symbol matches rank ahead of protected, internal, and private matches. Use `--no-visibility-rank` for legacy order, and `--visibility` / `--exclude-visibility` with `symbols`, `definition`, `unused`, and `hotspots`. Query defaults can be adjusted with `CDIDX_DEFAULT_LIMIT`, `CDIDX_DEFAULT_SNIPPET_LINES`, and `CDIDX_DEFAULT_MAX_LINE_WIDTH`; explicit CLI flags still win. | | Project scoping | `.sln` / `.csproj`-aware --project <name|path> filters for indexing and queries, plus `--solution ` when a workspace has multiple solution files. | -| MCP integration | MCP server support for AI clients such as Claude Code, Cursor, and Windsurf, including tools, indexed-file resources, starter prompts, schema constraints for local argument validation, `mimeType` on text content blocks, logging, server-side `notifications/initialized` on stdio or HTTP `/events` streams, and `Language support:` descriptions sourced from the same registries as `cdidx languages`. | +| MCP integration | MCP server support for AI clients such as Claude Code, Cursor, and Windsurf, including tools, indexed-file resources, starter prompts, schema constraints for local argument validation, `mimeType` on text content blocks, logging, a compatibility server-side `notifications/initialized` ready signal on stdio or HTTP `/events` streams, and `Language support:` descriptions sourced from the same registries as `cdidx languages`. | | Freshness | Parallel full-scan extraction with `--parallelism`, incremental refreshes with `--files` and `--commits`, continuous `--watch`, exact `status --check`, and configurable stale thresholds via `--stale-after` / `CDIDX_STALE_AFTER`. | | Storage | Local-first `.cdidx/codeindex.db` storage. Query commands run from nested directories prefer the outermost ancestor `.cdidx/codeindex.db` before falling back to the current directory. `--data-dir `, `CDIDX_DATA_DIR`, or `XDG_DATA_HOME` can move default SQLite storage outside the workspace; explicit `--db ` still wins. | | DB maintenance | New indexes use SQLite incremental auto-vacuum. `cdidx vacuum` reclaims free pages from existing DBs, including a one-time full `VACUUM` conversion for legacy no-autovacuum DBs, and `status --json` reports metrics under `db_pragma_settings`. | @@ -312,7 +312,7 @@ cdidx mcp | 検索面 | CLI-first の人間向け / 機械処理向け出力。全文検索、シンボル、参照、caller/callee、依存関係、map、inspect、excerpt コマンドを提供します。 | | 順位と filter | public/exported なシンボル一致を protected、internal、private より優先します。従来順は `--no-visibility-rank`、可視性の include / exclude は `symbols`、`definition`、`unused`、`hotspots` の `--visibility` / `--exclude-visibility` で指定できます。query 既定値は `CDIDX_DEFAULT_LIMIT`、`CDIDX_DEFAULT_SNIPPET_LINES`、`CDIDX_DEFAULT_MAX_LINE_WIDTH` で調整でき、明示 CLI flag が常に優先されます。 | | project scope | `.sln` / `.csproj` を使った --project <name|path> filter で index と query を .NET project 配下へ絞り込めます。workspace に solution が複数ある場合は `--solution ` を指定します。 | -| MCP 連携 | Claude Code、Cursor、Windsurf などの AI クライアント向け MCP server。tools、インデックス済みファイル resources、starter prompts、ローカル引数検証用の schema constraints、text content block の `mimeType`、logging、stdio または HTTP `/events` stream 上の server-side `notifications/initialized`、`cdidx languages` と同じ言語レジストリ由来の `Language support:` 説明を提供します。 | +| MCP 連携 | Claude Code、Cursor、Windsurf などの AI クライアント向け MCP server。tools、インデックス済みファイル resources、starter prompts、ローカル引数検証用の schema constraints、text content block の `mimeType`、logging、stdio または HTTP `/events` stream 上の互換性用 server-side `notifications/initialized` ready signal、`cdidx languages` と同じ言語レジストリ由来の `Language support:` 説明を提供します。 | | freshness | `--parallelism` による parallel full-scan、`--files` / `--commits` による差分更新、`--watch` による継続更新、`status --check` による完全一致確認、`--stale-after` / `CDIDX_STALE_AFTER` による age threshold 上書きに対応します。 | | storage | `.cdidx/codeindex.db` に保存する local-first 設計。ネストしたディレクトリからの query コマンドは、current directory にフォールバックする前に最上位祖先の `.cdidx/codeindex.db` を優先します。既定の SQLite 保存先は `--data-dir `、`CDIDX_DATA_DIR`、`XDG_DATA_HOME` で workspace 外へ移せます。明示的な `--db ` は引き続き最優先です。 | | DB maintenance | 新規 index DB は SQLite incremental auto-vacuum を使います。既存 DB は `cdidx vacuum` で free page を回収でき、legacy no-autovacuum DB は初回だけ full `VACUUM` で変換します。`status --json` は `db_pragma_settings` 配下に metrics を出力します。 | @@ -339,7 +339,7 @@ cdidx mcp -MCP `status` の `mcp_session` は永続化された index 状態ではなく、セッション単位の診断情報です。`log_level`、`roots`、任意の `client_capabilities` を含みます。 +MCP `status` の `mcp_session` は永続化された index 状態ではなく、セッション単位の診断情報です。`log_level`、`roots`、任意の `client_info`、任意の `client_capabilities` を含みます。 `hotspot_family_degraded_reason` は次の値を使います。 diff --git a/changelog.d/unreleased/1780.fixed.md b/changelog.d/unreleased/1780.fixed.md index a0013fbc89..1f8da0a59f 100644 --- a/changelog.d/unreleased/1780.fixed.md +++ b/changelog.d/unreleased/1780.fixed.md @@ -12,8 +12,8 @@ affected: ## English -- **MCP initialize now emits the ready notification (#1780)** — after the `initialize` response is written, the server sends one `notifications/initialized` notification per session for clients that wait for a server-side ready signal; HTTP clients receive it through a connected `/events` stream. +- **MCP initialize now emits the ready notification (#1780)** — after the `initialize` response is written, the server sends one compatibility `notifications/initialized` ready signal per session for clients that wait for a server-side ready signal; HTTP clients receive it through a connected `/events` stream. ## 日本語 -- **MCP initialize が ready 通知を送るようになりました (#1780)** — `initialize` レスポンスを書き終えた後、サーバー側の ready signal を待つクライアント向けに、セッションごとに 1 回だけ `notifications/initialized` を送信します。HTTP クライアントは接続済みの `/events` stream から受信します。 +- **MCP initialize が ready 通知を送るようになりました (#1780)** — `initialize` レスポンスを書き終えた後、サーバー側の ready signal を待つクライアント向けに、セッションごとに 1 回だけ互換性用の `notifications/initialized` ready signal を送信します。HTTP クライアントは接続済みの `/events` stream から受信します。