初めてのMCPサーバー開発 - jrnl-mcpを作ってみた

Table of Contents

Model Context Protocol(MCP)を使って、コマンドラインジャーナルツール「jrnl」とClaudeを連携させるMCPサーバーを開発しました。初めてのMCPサーバー開発の体験記として、選んだ理由から実装のポイント、学んだことまでを詳しく紹介します。

はじめに - MCPサーバーを作ってみたい

Model Context Protocol(MCP)の登場以来、Claudeとさまざまなツールやサービス をつなげるMCPサーバーが次々と公開されています。GitHubを眺めていると、ファ イルシステムやデータベース、各種APIとの連携など、実に多様なMCPサーバーが 開発されているのを見て、「自分でも何か作ってみたい」という気持ちが湧いてきま した。

MCPサーバーを作ることで、自分の日常的なワークフローにAIを組み込めるだけで なく、MCPというプロトコルの仕組みを手を動かしながら理解できる良い機会になる と考えました。

MCPサーバーの題材選び - なぜjrnlを選んだのか

MCPサーバーの題材を考えるにあたって、以下の条件を満たすものを探しました。

  • 日常的に使っているツールであること
  • CLIツールでシンプルなインターフェースを持つこと
  • 読み取り専用でも十分に価値があること
  • プライバシーに配慮が必要なデータを扱うこと

これらの条件にぴったり当てはまったのが、コマンドラインジャーナルツールの 「jrnl」でした。

jrnlは、ターミナルから素早く日記を書けるPython製のツールで、タグ付けや検 索機能も備えています。私は日々の作業ログや思考の記録に使っており、「Claude がこのジャーナルのデータにアクセスできたら、過去の記録を踏まえたより良いアド バイスがもらえるのでは」と考えました。

また、jrnlは構造化されたデータ(日付、タグ、本文)を持ちながらも、実装がシ ンプルで、初めてのMCPサーバー開発の題材として適していると判断しました。

そして作成したのが、「jrnl-mcp」です。

Claude Codeと一緒に開発スタート

開発はClaude Codeをペアプログラミングパートナーとして進めました。まず最初 に、MCPサーバーの基本的な構造についてClaudeに相談し、必要なファイル構成を 決めました。

jrnl-mcp/
├── src/
│   └── index.ts      # メインのサーバー実装
├── package.json      # プロジェクト設定
├── tsconfig.json     # TypeScript設定
└── README.md         # ドキュメント

TypeScriptを選んだのは、MCPのSDKが型定義を提供しており、開発時の補完やエラーチェックが効くためです。Claude Codeと一緒に、まずは最小限の「Hello World」的なMCPサーバーを作り、それが動作することを確認してから機能を追加していくアプローチを取りました。

開発中、特に助かったのは以下の点です。

  • エラーメッセージの解釈と対処法の提案
  • jrnlコマンドの出力パースロジックの実装
  • TypeScriptの型定義の最適化
  • エラーハンドリングのベストプラクティス

jrnl-mcpの実装と機能

最終的に実装した機能は以下の5つです。

機能説明
search_entries - エントリ検索日付範囲、タグ、検索キーワードを指定してジャーナルエントリを検索できます。例えば「先週の@work タグが付いた記事」といった柔軟な検索が可能です。
list_tags - タグ一覧使用しているすべてのタグとその使用回数を取得します。どんなテーマについて多く書いているかが一目でわかります。
get_statistics - 統計情報総エントリ数、平均文字数、最もよく書いている時間帯など、ジャーナルの統計情報を取得します。
analyze_tag_cooccurrence - タグ共起分析どのタグとどのタグが一緒に使われることが多いかを分析します。思考のパターンや関心事の関連性が見えてきます。
list_journals & set_journal - ジャーナル切り替えjrnl は複数のジャーナルを管理できるので、それらを切り替える機能も実装しました。

すべての機能は読み取り専用にしました。これは、誤ってジャーナルを変更してしまうリスクを避けるためと、MCP サーバーの初回実装としてシンプルに保つためです。

開発中に学んだMCPの仕組み

MCPサーバーの開発を通じて、以下のような仕組みを理解できました。

リソースとツールの違い

MCPには「リソース」と「ツール」という2つの概念があります。 jrnl-mcpではツールのみを実装しましたが、 リソースを使えば「最新の10エントリ」のような動的なコンテンツを提供も可能です。

非同期処理の重要性

jrnlコマンドの実行は外部プロセスの起動を伴うため、すべての処理を非同期で実装する必要がありました。Node.jsのchild_process.execをPromiseでラップして使用しています。

エラーハンドリング

MCPサーバーは、エラーが発生してもクライアント(Claude Desktop)に適切にエラーを伝える必要があります。try-catchブロックでエラーをキャッチし、意味のあるエラーメッセージを返すようにしました。

型安全性

TypeScriptとMCP SDKの型定義のおかげで、ツールの引数や戻り値の型が明確になり、実装ミスを防げました。

セットアップと動作確認

開発したMCPサーバーをClaude Desktopで使うためのセットアップ手順は以下の通りです。

  1. リポジトリをクローンしてビルド
git clone https://github.com/yostos/jrnl-mcp
cd jrnl-mcp
npm install
npm run build
  1. グローバルコマンドとしてインストール
npm link
  1. Claude Desktopの設定ファイルに追加
{
  "mcpServers": {
    "jrnl": {
      "command": "jrnl-mcp"
    }
  }
}

npm linkを使うことで、jrnl-mcpというコマンドがグローバルで使えるようになり、設定がシンプルになります。

動作確認では、「jrnlを使って先週の日記を見せて」「@projectタグの統計を教え て」といったプロンプトで、実際にClaudeがジャーナルのデータにアクセスできる ことを確認しました。

作ってみて分かったMCPサーバー開発のポイント

実際に開発してみて気づいたポイントをまとめます。

  • 小さく始める
    • 最初から全機能を実装しようとせず、最小限の機能から始めることが重要である 。動作確認ができてから機能を追加していく方が、デバッグも楽になる。
  • ログの活用
    • 開発中はconsole.errorでログを出力すると、Claude Desktopのログに表示さ れるので、デバッグに役立つ。
  • 既存ツールのラッパーとしての設計
    • jrnl-mcpは基本的にjrnlコマンドのラッパーとして動作する。既存のCLIツ ールを活用することで、複雑な実装を避けられる。
  • ドキュメントの重要性
    • READMEにセットアップ手順と使用例を明記することで、将来の自分や他の人が使いやすくなる。
  • テストの実装
    • 今回は時間の都合で省略したが、MCPサーバーのテストも重要である。特に外部 コマンドを実行する部分はモックを使ったテストが有効であろう。

まとめ

初めてのMCPサーバー開発は、思っていた以上にスムーズに進みました。Claude Codeのサポートもあり、半日程度で基本的な機能を持つMCPサーバーを作ることが できました。

jrnl-mcpを作ってみて、個人のツールやワークフローとAIを連携させることの可 能性を実感しました。読み取り専用という制限はありますが、過去の記録を活用した アドバイスや分析ができるようになったのは大きな価値です。

MCPは、AIと既存のツールやサービスをつなぐ橋渡し役として、今後ますます重要 になっていくでしょう。この経験を活かして、他のツールとの連携も試してみたいと 思います。

もしMCPサーバー開発に興味がある方は、ぜひ身近なツールから始めてみることを お勧めします。思っているより簡単に、自分だけのAI連携ツールが作れるはずです 。