Skip to content

feat(mcp): MCP server, seven memory tools, and stdio integration (T10)#16

Merged
goofmint merged 6 commits into
mainfrom
feature/mcp-server
Jun 16, 2026
Merged

feat(mcp): MCP server, seven memory tools, and stdio integration (T10)#16
goofmint merged 6 commits into
mainfrom
feature/mcp-server

Conversation

@goofmint

@goofmint goofmint commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Refs #15

概要

dennoh serve で stdio transport の MCP サーバーを起動し、core/memory にブリッジする7ツールを実装。ツール単体テスト・実プロセスの stdio 統合テスト・Claude Desktop 設定ドキュメントまで揃えました。タスク表 T10.1〜T10.10 を完了

変更内容(3フェーズ)

Phase 1: サーバー基盤 + dennoh serve

  • 依存追加: @modelcontextprotocol/sdk + zod
  • src/mcp/server.ts: createMcpServer(context)(name=dennoh/version=package.json)、startStdioServer(接続が閉じるまで解決せずプロセスを生存)
  • src/cli/commands/serve.ts: config→vault→DB→stdio接続。診断は stderr のみ

Phase 2: 7ツール

  • src/mcp/tools/*.ts(個別ファイル): save/update/delete/search/list_recent/get_note/status
  • 各ツールは英語ハードコード説明文 + 実シグネチャに合わせた zod inputSchema、失敗は isError 結果で報告(プロトコル throw しない)
  • db.getIndexStats() を status 用に追加

Phase 3: テスト + ドキュメント

  • tests/mcp/: 共有ハーネス + ツール別単体テスト(正常/異常系)
  • tests/mcp/integration.test.ts: dennoh serve プロセスを spawn し initialize ハンドシェイク・複数ツール往復・実 .md 生成・stderr ログ/stdout JSON-RPC専用を検証
  • docs/claude-desktop-setup.md: claude_desktop_config.json 設定例・パス指定・動作確認手順

統合テストが実バグを検出 🐛

serve が DB を open するだけで runMigrations を呼んでおらず、新規 vault で save_memory が「no such table: notes」で失敗していたのを修正(冪等な migration を追加)。in-memory テストでは隠れていた問題を実プロセステストが発見。

残課題(このPRの範囲外)

  • T10.11 Claude Desktop 実機接続テスト — 手動確認のため未完。Refs #15 でリンクのみ(自動クローズせず)。手順は docs に記載
  • status の latestError(常にnull)/queueDepth(省略)は watcher/エラー追跡サブシステム未配線のためプレースホルダ
  • ツール description の i18n は未対応(仕様どおり英語ハードコード)

検証

  • 402 tests pass(MCP関連は単独で安定)/ typecheck・lint クリーン

🤖 Generated with Claude Code

Summary by CodeRabbit

リリースノート

  • 新機能
    • Claude Desktopとの統合により、メモリ(保存・更新・削除・検索・取得・一覧表示)がAIアシスタント経由で利用できるようになりました
    • dennoh serve でstdio経由のMCPサーバを起動できるようになりました
    • status でインデックス状況(最新更新状況含む)を確認できるようになりました
  • ドキュメント
    • Claude Desktop接続手順(設定例を含む)を追加しました
  • テスト
    • MCPツール/CLIの動作を検証するテストを追加しました

goofmint and others added 4 commits June 15, 2026 19:09
- deps: @modelcontextprotocol/sdk + zod (for future tool inputSchemas)
- src/mcp/server.ts: createMcpServer (name "dennoh" + package version) and
  startStdioServer, which connects a transport (stdio by default, injectable
  for tests) and resolves only on close so `serve` stays alive for the
  session's lifetime
- src/mcp/types.ts: StatusResult (forward type for the T10.10 status tool)
- src/mcp/index.ts: real exports replacing the stub
- src/cli/commands/serve.ts: reads config, opens the index, starts the stdio
  server; diagnostics go to stderr only (stdout is the JSON-RPC stream)
- wire `serve` into the router/help; drop the "not implemented" stub
- tests: identity handshake + connect/close lifecycle via in-memory transport;
  serve validation/config-error paths assert nothing is written to stdout

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Each tool lives in its own file under src/mcp/tools/ with a hardcoded English
description, a zod inputSchema matched to the exact core/memory signature, and a
handler that reports failures as `isError` results (never a protocol throw):

- save_memory / update_memory -> return the note metadata (read back via the row)
- delete_memory -> { id, deleted: true }
- search_memory -> { results } with project/tag/date/source filters
- list_recent  -> { notes } (metadata only)
- get_note     -> { note } or { note: null }
- status       -> { indexedCount, latestError } (queueDepth only with a watcher)

Supporting changes:
- db: getIndexStats(db) aggregate for the status tool
- mcp: McpContext (db + vaultPath); createMcpServer(context) registers all tools
  via registerAllTools; serve passes { db, vaultPath }
- shared tools/result.ts (toolOk/toolError) and tools/metadata.ts (NoteRow DTO)
- tests: full client<->server tool round-trip over an in-memory transport, plus
  tool-registration and isError-not-throw assertions

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- tests/mcp/harness.ts: shared per-test setup (temp vault: git + SQLite, linked
  in-memory client/server) + result helpers; replaces the monolithic tools.test
- per-tool files (save/update/delete/search/list-recent/get-note/status):
  happy paths plus abnormal cases (unknown id, schema-validation failures,
  NULL-byte content) — all asserting failures arrive as isError results
- tests/mcp/integration.test.ts: spawns the real `dennoh serve` over stdio via
  StdioClientTransport — initialize handshake, multi-tool scenario writing an
  actual .md file, and logs-on-stderr / JSON-RPC-only-on-stdout checks
- docs/claude-desktop-setup.md: claude_desktop_config.json examples (source +
  built), path guidance, and save_memory verification steps

fix(serve): run migrations on startup — the stdio integration test caught that
serve opened the DB without creating the schema, so save_memory failed with
"no such table: notes" on a fresh vault.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8b98c5d7-7f69-4262-a3b1-97c3ef4c3eff

📥 Commits

Reviewing files that changed from the base of the PR and between fff7aa4 and 67a17f8.

📒 Files selected for processing (1)
  • .coderabbit.yaml

📝 Walkthrough

Walkthrough

dennoh serve コマンドから stdio 経由で MCP サーバーを起動する機能を追加した。MCP 基盤型、7 つのツール実装、テストハーネス、E2E 検証、Claude Desktop セットアップドキュメントを新規追加。

Changes

MCP サーバー全体実装

Layer / File(s) Summary
共有型・結果ヘルパー・メタデータ・DB 統計
src/mcp/types.ts, src/mcp/tools/result.ts, src/mcp/tools/metadata.ts, src/db/repository.ts, src/db/index.ts
McpContextStatusResult 型、toolOktoolError ラッパー、NoteMetadataDto マッパー、getIndexStats リポジトリ関数を定義し、MCP 層の基盤契約を確立する。
MCP サーバー生成とトランスポート接続
src/mcp/server.ts, src/mcp/index.ts
createMcpServerMcpServer を構築して全ツールを登録し、startStdioServer でトランスポートを接続してクローズ検知まで待機する Promise を返す。barrel export を整備する。
7 つの MCP ツール実装
src/mcp/tools/index.ts, src/mcp/tools/save-memory.ts, src/mcp/tools/update-memory.ts, src/mcp/tools/delete-memory.ts, src/mcp/tools/get-note.ts, src/mcp/tools/search-memory.ts, src/mcp/tools/list-recent.ts, src/mcp/tools/status.ts
registerAllTools エントリポイントと全 7 ツールの登録実装を追加。各ツールは Zod スキーマで入力検証し、core 層を呼び出して toolOktoolError で結果を返す。
CLI serve コマンド配線と依存関係追加
package.json, src/cli/commands/serve.ts, src/cli/index.ts, src/cli/main.ts
serveCommand を新設して引数検証・設定読込・DB 初期化・MCP サーバー起動フローを実装し、main.ts ルーティングと index.ts 再エクスポートを更新する。@modelcontextprotocol/sdk ^1.29.0 を追加する。
テストハーネスとサーバー・CLI テスト
tests/mcp/harness.ts, tests/mcp/server.test.ts, tests/cli/serve.test.ts
インメモリ MCP クライアント・サーバーペアを自動セットアップする McpHarness を定義し、サーバー識別・全 7 ツール動作・CLI エラーパスを検証するテストスイートを追加する。
ツール単体テスト・E2E・ドキュメント
tests/mcp/save-memory.test.ts, tests/mcp/update-memory.test.ts, tests/mcp/delete-memory.test.ts, tests/mcp/get-note.test.ts, tests/mcp/search-memory.test.ts, tests/mcp/list-recent.test.ts, tests/mcp/status.test.ts, tests/mcp/integration.test.ts, docs/claude-desktop-setup.md, .tmp/tasks.md
各ツールの正常・エラーケースを単体テストで検証し、実プロセス stdio E2E で handshake とツール連鎖(save_memory → get_note → status)を確認する。Claude Desktop セットアップガイドとタスク進捗を追加する。

Sequence Diagram(s)

sequenceDiagram
  participant Claude as Claude Desktop
  participant Stdio as StdioServerTransport
  participant serveCmd as serveCommand
  participant McpServer as McpServer
  participant ToolHandler as Tool Handler
  participant DB as SQLite DB

  Claude->>Stdio: JSON-RPC initialize (stdin)
  Stdio->>serveCmd: プロセス起動 (dennoh serve)
  serveCmd->>McpServer: createMcpServer({ db, vaultPath })
  McpServer->>McpServer: registerAllTools (7 ツール登録)
  serveCmd->>Stdio: startStdioServer → server.connect(transport)
  Stdio-->>Claude: initialize レスポンス (stdout)

  Claude->>Stdio: tools/list
  Stdio-->>Claude: 7 つのツール名を返却

  Claude->>Stdio: tools/call (save_memory)
  Stdio->>McpServer: ディスパッチ
  McpServer->>ToolHandler: Zod バリデーション + 実行
  ToolHandler->>DB: saveMemory(content, source)
  DB-->>ToolHandler: NoteRow
  ToolHandler-->>McpServer: toolOk(NoteMetadataDto)
  McpServer-->>Stdio: CallToolResult (JSON テキスト)
  Stdio-->>Claude: JSON-RPC レスポンス (stdout)

  Claude->>Stdio: tools/call (search_memory)
  Stdio->>McpServer: ディスパッチ
  McpServer->>ToolHandler: Zod バリデーション + 実行
  ToolHandler->>DB: searchMemory(query, filters, limit)
  DB-->>ToolHandler: NoteRow[]
  ToolHandler-->>McpServer: toolOk({ results })
  McpServer-->>Stdio: CallToolResult
  Stdio-->>Claude: JSON-RPC レスポンス
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 耳をすませば、stdio の風
MCP の畑に、7 つのツールが芽吹いた
save して search して、delete もできる
Claude Desktop と、うさぎは繋がる
toolOk の実り、vault に刻まれる 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
コメント ⚠️ Warning Four tool files (get-note.ts, list-recent.ts, delete-memory.ts, update-memory.ts) have zero English comments explaining implementation. While core files like server.ts and serve.ts have good commen... Add English comments to the four tool files explaining the registration pattern, error handling strategy, and tool purpose. Minimal comments suffice given the repetitive structure.
インポート順 ⚠️ Warning 複数のファイルでBiome正準順に違反。特にtests/mcp/harness.tstests/mcp/integration.test.tsでは外部パッケージ(isomorphic-git)の配置、src/mcp/server.tstests/mcp/server.test.tsではpackage.jsonインポートの位置が不正です。 すべてのTypeScriptファイルのインポートを、Node.js/Bun組み込み→外部パッケージ(アルファベット順)→パスエイリアス→相対パスの順序に再配列してください。
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed タイトルは MCP サーバー実装、7 つのメモリツール、stdio 統合という主要な変更内容を明確かつ簡潔に要約しており、変更セット全体を正確に反映しています。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/mcp-server
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feature/mcp-server
  • 🛠️ コメント記述
  • 🛠️ Import

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/claude-desktop-setup.md`:
- Around line 31-33: The fenced code block containing the file path on lines
31-33 is missing a language specifier. Add `plaintext` or `text` as the language
identifier immediately after the opening triple backticks to properly format the
code block in markdown, making it more readable and semantically correct.

In `@src/cli/commands/serve.ts`:
- Around line 24-40: The database initialization calls openDatabase and
runMigrations are outside the try/catch block, so exceptions in these functions
propagate without proper error handling and resource cleanup. The finally block
only applies to the inner try block that starts the server, leaving the database
open if initialization fails. Restructure the code to move openDatabase and
runMigrations inside the outer try block, and ensure the finally block that
calls closeDatabase applies to the entire initialization and server startup
sequence, so that database resources are properly cleaned up regardless of where
exceptions occur.

In `@src/db/repository.ts`:
- Around line 136-143: The getIndexStats function uses implicit fallbacks with
the nullish coalescing operator (row?.noteCount ?? 0 and row?.lastUpdatedAt ??
null) instead of throwing explicit errors when the query returns unexpected
results. Replace these implicit fallbacks with an explicit null check that
throws an error if row is null or undefined, since the comment correctly notes
that an aggregate SELECT always returns exactly one row and a null result
indicates an unexpected condition (such as database corruption) that should fail
explicitly rather than silently returning default values.

In `@src/mcp/server.ts`:
- Around line 1-8: Reorganize the import statements in the file to follow proper
grouping guidelines. Third-party imports (McpServer, StdioServerTransport,
Transport) should be separated from local project imports by a single blank
line. The package.json import should be grouped with the other project imports
(registerAllTools and McpContext) rather than treated as a separate group, since
it is a local project file. Move the package.json import line to be adjacent
with the other local imports and remove the extra blank line so there is only
one blank line total between the third-party imports and the consolidated
project imports group.
- Around line 28-36: The code in the startStdioServer function is accessing the
internal `.server` property and its `onclose` callback, which is not part of the
public API of McpServer. Replace this private implementation detail access with
either signal handlers (SIGINT and SIGTERM) that call a cleanup/close method, or
directly use the public API methods available on the McpServer instance such as
server.close() to manage the lifecycle. Avoid accessing internal properties like
server.server.onclose and instead rely on the documented public interface of the
McpServer class.

In `@src/mcp/tools/delete-memory.ts`:
- Around line 1-7: The project imports in the delete-memory.ts file are not
sorted in alphabetical order as required by the coding guidelines. Reorder the
three project imports (the ones starting with "`@/`" and "../") so they are
alphabetically sorted by their import paths. The import of McpContext from
"../types" should come first, followed by the import of toolError and toolOk
from "./result", and finally the import of deleteMemory from "`@/core/memory`".

In `@src/mcp/tools/get-note.ts`:
- Around line 1-7: The project imports (from `@/core/memory`, `../types`, and
`./result`) violate the import order guideline by having an empty line between
them on line 5, and they are not sorted alphabetically. Remove the empty line
between the project imports to make them consecutive, and then reorder all three
project import statements so they are sorted in alphabetical order by their
import path. This applies to the imports of getNote, McpContext, and the result
utilities in the file.

In `@src/mcp/tools/result.ts`:
- Around line 8-10: The toolOk function is missing exception handling for
JSON.stringify, which can throw errors when encountering circular references,
BigInt values, or custom toJSON errors. Wrap the JSON.stringify call in a
try-catch block and return a proper tool error result (with isError: true) when
an exception occurs, ensuring that serialization errors are handled as
tool-level errors rather than propagating as MCP protocol errors.

In `@src/mcp/tools/save-memory.ts`:
- Around line 1-9: The import statements violate the project's import ordering
guidelines by including a blank line between project imports. Remove the blank
line (currently between the `@/db` import and the ../types import) to consolidate
all project imports from `@/core/memory`, `@/db`, ../types, ./metadata, and ./result
into a single consecutive group. Then sort these project imports alphabetically
within that group to comply with the coding standards.

In `@src/mcp/tools/search-memory.ts`:
- Around line 1-7: The project imports in the search-memory.ts file are not
sorted in alphabetical order according to the coding guidelines. Reorder the
three project import statements (the imports from "`@/core/memory`", "../types",
and "./result") so they follow alphabetical order. The correct order should be:
import from "../types" first, then "./result", then "`@/core/memory`" last. This
groups and sorts all project imports alphabetically as required by the coding
standards.

In `@src/mcp/tools/status.ts`:
- Around line 1-6: The project internal imports (those starting with "`@/`" and
"../" and "./") are not sorted in alphabetical order according to project
guidelines. Reorder the three project imports in the file to be alphabetically
sorted: the import from "../types" (containing McpContext and StatusResult
types) should come first, followed by the import from "./result" (containing
toolError and toolOk), and finally the import from "`@/db`" (containing
getIndexStats). Group all project imports together after the blank line
following the third-party import, maintaining the blank line between third-party
and project imports.

In `@tests/cli/serve.test.ts`:
- Around line 1-7: The imports in this file violate the import ordering
guideline. Both bun:test and node:fs, node:os, node:path belong to the standard
library group and must be sorted alphabetically. Since 'bun' comes before 'node'
alphabetically, reorder the imports so that the bun:test import appears before
all the node:* imports in the standard library group, while maintaining the
blank line separation between the standard library imports and the local imports
from `@/cli`.

In `@tests/mcp/harness.ts`:
- Around line 1-14: The import statements in the harness.ts file violate
TypeScript coding guidelines by having an unnecessary blank line that splits
third-party library imports into separate groups. Reorganize all imports to
follow the correct grouping: standard library imports (node: and bun: modules)
first, then third-party imports (`@modelcontextprotocol/sdk` and isomorphic-git)
without blank lines between them in alphabetical order, then project imports (@
paths) last. Remove the blank line after the CallToolResult import and the blank
line before the isomorphic-git import, ensuring all third-party imports are
grouped together and sorted alphabetically, with project imports in their own
group below.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: efc9a0f5-8369-4632-9f0a-87a2f8066dae

📥 Commits

Reviewing files that changed from the base of the PR and between f911907 and db707d9.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock, !bun.lock
📒 Files selected for processing (32)
  • .tmp/tasks.md
  • docs/claude-desktop-setup.md
  • package.json
  • src/cli/commands/serve.ts
  • src/cli/index.ts
  • src/cli/main.ts
  • src/db/index.ts
  • src/db/repository.ts
  • src/mcp/index.ts
  • src/mcp/server.ts
  • src/mcp/tools/delete-memory.ts
  • src/mcp/tools/get-note.ts
  • src/mcp/tools/index.ts
  • src/mcp/tools/list-recent.ts
  • src/mcp/tools/metadata.ts
  • src/mcp/tools/result.ts
  • src/mcp/tools/save-memory.ts
  • src/mcp/tools/search-memory.ts
  • src/mcp/tools/status.ts
  • src/mcp/tools/update-memory.ts
  • src/mcp/types.ts
  • tests/cli/serve.test.ts
  • tests/mcp/delete-memory.test.ts
  • tests/mcp/get-note.test.ts
  • tests/mcp/harness.ts
  • tests/mcp/integration.test.ts
  • tests/mcp/list-recent.test.ts
  • tests/mcp/save-memory.test.ts
  • tests/mcp/search-memory.test.ts
  • tests/mcp/server.test.ts
  • tests/mcp/status.test.ts
  • tests/mcp/update-memory.test.ts

Comment thread docs/claude-desktop-setup.md Outdated
Comment thread src/cli/commands/serve.ts Outdated
Comment thread src/db/repository.ts
Comment thread src/mcp/server.ts
Comment thread src/mcp/server.ts
Comment thread src/mcp/tools/save-memory.ts
Comment thread src/mcp/tools/search-memory.ts
Comment thread src/mcp/tools/status.ts
Comment thread tests/cli/serve.test.ts
Comment thread tests/mcp/harness.ts
goofmint and others added 2 commits June 16, 2026 10:58
AI Agents prompts に基づく自動修正:
- serve.ts: openDatabase/runMigrations をエラーハンドリング配下へ移動し、
  DB ハンドルが必ず close されるよう再構成(history/restore と同じパターンで
  未オープン db への closeDatabase を回避)
- db/repository.ts: getIndexStats の暗黙フォールバック (?? 0) を、行が無い場合の
  明示的エラーに置換(フォールバック禁止ポリシー準拠)
- docs/claude-desktop-setup.md: fenced code block に言語指定 (text) を追加

スキップ: インポート順の指摘8件(biome の organizeImports 正準順が既に適用済みで
変更すると lint が壊れる)、server.ts の .server アクセス(McpServer.server は
公開 API)、result.ts の JSON.stringify try/catch(呼び出し側 try/catch で既に
toolError 化される)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@goofmint goofmint merged commit 746d7a9 into main Jun 16, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant