初めてのMCPサーバー開発 - jrnl-mcpを作ってみた
Model Context Protocol(MCP)を使って、コマンドラインジャーナルツール「jrnl」とClaudeを連携させるMCPサーバーを開発しました。初めてのMCPサーバー開発の体験記として、選んだ理由から実装のポイント、学んだことまでを詳しく紹介します。
By Toshiyuki Yoshida
はじめに - 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 で使うためのセットアップ手順は以下の通りです。
- リポジトリをクローンしてビルド
git clone https://github.com/yostos/jrnl-mcp
cd jrnl-mcp
npm install
npm run build
- グローバルコマンドとしてインストール
npm link
- 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 連携ツールが作れるはずです 。