Claude Codeのサブエージェント間でコンテキストを共有できるMCPサーバー「sqlew」を作りました

ClaudeCodeのサブエージェント同士、あまり情報のやり取りが出来ていない&他のサブエージェントが何をやっているのか理解していなそうな動きをしているのが気になりまして。

「サブエージェント同士が同じレイヤーで何をしているか」を把握しやすいようなツールを探していましたが、無いので作りました。人生初npm公開。

注意:標準的なMCPサーバなのでどのAIエージェントでも動くと思いますが、いまのところClaudeCodeのみ対応とさせていただきます。Codexなどでは一切テストしていませんので動作保証ナシの自己責任でご使用ください。

マルチエージェントの問題

Claude Codeでサブエージェントを使った開発をしていると、エージェント間でのコンテキスト共有が課題になることがあります。従来のJSON形式でのやり取りだと、トークンを大量に消費してしまうんですよね。

またそれぞれのエージェントは「フラットな状態」で起動します。過去のプロンプトでのやり取りや別エージェントの試行錯誤がノウハウとして伝わっていない状態なので、並列処理で同じファイルを編集合戦してしまうこともあったりします。

問題としては

  • エージェント同士のやり取りがテキストベース
    • LLMで処理するので理解に差がある
    • 引き継ぎにけっこうなトークン消費
  • エージェント同士が”作業が終わったタイミング”でしか通信できない
    • ”今何をやっているか”を把握する手段がないっぽい

課題を書き出してみて、なんとなく似てる問題の構造を経験したことがありました。ECサイトのショッピングカートのトランザクション問題とかグループウェアのチャット機能とか。ということはSQLで工夫すれば解消できるのでは・・・?と思って作ったのが「sqlew(スクリュー)」です。

sqlew 何するものぞ

sqlewロゴ

コイツ単体はSQLiteのAPIなのでClaudeCodeが無いと何にもできません。

すっっっごい噛み砕いて言うと、

です。

難しく言うと

です。このブログでも紹介したことがあるSerenaというMCPサーバに着想を得ています。

SerenaではPCの構造解析ソフトのデータベースを使ってソースコードの検索ができるようになっています。serena memoryという機能で作業報告などをMarkdownで保存してサブエージェント間でも共有知識として使うこともできるんですけど、その分結構な量のコンテキストを使うことになります。

「それをSQLでやれば必要な情報だけ引き出せてトークン激減するんじゃね?」というのがこのツールのコンセプトです。

sqlewではサブエージェントの死活管理やコミュニケーションの登録・検索・抽出を目的としています。MySQLなどを使えばもっと高等なこともできそうですが、ワンライナーで環境が作れるようにSQLite専用にしています。

デフォルトではプロジェクトフォルダのルートに.sqlewフォルダを作り、SQLiteのデータベースファイルを作成してデータを蓄積します。外部へのデータ送信は一切ありませんのでご安心ください。

トークン削減効果

もともとの私のメインプロジェクトがエージェントファイルやらserena memoryやらMarkdownだらけなせいもあると思いますが、claude codeにベンチマーク取らせたら「72%トークン削減ができた」っていうのでそのまま書きました(小並)

どういう原理で減っているかというと、もともとはサブエージェントへのデータはJSON形式で送っています。~/.claude/projet/{project-name}/*.jsonlを開いてみるとClaudeCode内部でどんな情報をやり取りしているかを見ることができますが、概ねこんな感じです。

{
    "parentUuid": "30f86b08-ca2b-4bd6-a8b5-ef3f59cad14e",
    "isSidechain": false,
    "userType": "external",
    "cwd": "/home/username/projectdir/project-name",
    "sessionId": "b63f7a3e-cc50-4267-9251-3e2624b459c6",
    "version": "2.0.10",
    "gitBranch": "dev/main",
    "message": {
        "model": "claude-sonnet-4-5-20250929",
        "id": "msg_01AzFUYN2P5pmGxeiMi6VWyk",
        "type": "message",
        "role": "assistant",
        "content": [
            {
                "type": "text",
                "text": "Excellent observation! You're absolutely...."
            }
        ],
        "stop_reason": null,
        "stop_sequence": null,
        "usage": {
            "input_tokens": 10,
            "cache_creation_input_tokens": 83968,
            "cache_read_input_tokens": 0,
            "cache_creation": {
                "ephemeral_5m_input_tokens": 83968,
                "ephemeral_1h_input_tokens": 0
            },
            "output_tokens": 5,
            "service_tier": "standard"
        }
    },
    "requestId": "req_011CTuJbvbifwQACsU6a2dvQ",
    "type": "assistant",
    "uuid": "c9f50ff5-5c69-4086-84d9-772a6e6f4966",
    "timestamp": "2025-10-08T07:03:50.292Z"
}

Before

17行目の message.content[].text が各エージェントに渡される指令なわけですが、ご覧の通り生テキストです。実際にログファイルを開いてみるとわかると思うんですけど、8000文字で当たり前、プランモードの出力のような長い文章だと1.6万文字とかになります。

テキスト量=コンテキスト量=金

短いテキストなら良いんですが、その膨大な量のテキストがサブエージェント間で何度も行き来する事を想像するだけでお財布が痛くなります。

After

実際使うときはAIのLLM自体に、

  • IDベースの正規化: 文字列を一度だけ保存し、整数IDで参照
  • 整数型の列挙型: ステータス、優先度、メッセージタイプなどを文字列ではなく整数(1-4)で表現
  • 事前集計ビュー: よく使うクエリの結果を事前計算
  • 型ベースのテーブル: 数値と文字列を別々に保存

こういう風にメッセージを構造化データに分割してもらってSQLiteに保存、エージェント同士の通信では

「このIDで保存しといたから見てね」

を実現しています。

トランザクションのデータ例
本体のテキスト

従来の生テキスト形式では1000トークン必要だったデータが、sqlewでは280トークンで済むようになる計算です。まぁぱっと見で7行のが2行になってるので、だいたい3割であってる感じします。雑。

単純な計算では文字の量が72%減らせるという意味で、英語で入力している場合は1単語≒1トークンなので、厳密にはトークンはそこまで減って無いかもしれません。あくまでClaude調べです。

しかし日本語の場合は1文字1トークンなので、72%以上削減できるケースもあるかもしれないです。誰か計測してください。

コンテキスト管理

コンテキストの減量はsqlewの嬉しい副作用みたいなもので、ほんとはこっちがメイン機能です。

コンテキストの構造化

sqlewではエージェント間のメッセージを、レイヤーでコードを分類します。

  • presentation: UI、APIエンドポイント、ビュー
  • business: ビジネスロジック、サービス、ユースケース
  • data: リポジトリ、データベースアクセス
  • infrastructure: 設定、外部サービス
  • cross-cutting: ログ、セキュリティ、ユーティリティ

これをAIに自己判断してもらってカテゴリ分けして登録させています。担当レイヤー以外の情報をフィルタできるのでコンテキストの浪費も防げますし、デバッグの際など効率的に変更箇所を探すことができるようになります。

優先順位付け・メッセージカテゴリ・タグ

特定のエージェント向けに「この機能が動かなくてブロックされてる」といったメッセージングも可能です。サブエージェント同士のチャットみたいなものですね。

デフォルト状態だとエージェントが気づくかどうかはマチマチです。CLAUDE.mdに「サブエージェントは作業完了時にsqlewツールで自分宛てのメッセージが来ていないか確認する」というような宣言を追加しておくと良いかもです。この辺は私も手探りです。

コンテキストデータの永続化

物忘れが酷いうえにmemoryって言ってもメモを読まないAIちゃん、そんな彼らの思考データの永続化にも使用できます。これはサブエージェント用のGitみたいなものと思ってもらえればいいかも。

明示的に「決定事項(decision)」と指定するとバージョン履歴付きで永続化されます。プロンプト上は「この変更を決定事項としてマークしてください」とかで永続化できます。カスタムの値だったり型の定義だったり、しょっちゅう再発するバグの情報などは永続化しておくと良さげです。まだ活躍する機会がなかったので制作者本人もこれは未知数です。

データベースの肥大化を防ぐため、重要度が低いメッセージは24時間、ファイル変更履歴は7日後に自動削除されます。(今のところ固定のタイムスパンですが、今後のバージョンアップで設定ファイルや環境変数などで保存時間を変えられるようにしたり、土日はカウントしないような設定を追加していこうと思います。)

使い方・インストール法

npmがインストール済みならnpxで動作可能です。プロジェクトの.mcp.json、ユーザフォルダの.claude.jsonなどMCP設定が書けるところに下記のように追加してください。

{
  "mcpServers": {
    "sqlew": {
      "command": "npx",
      "args": ["sqlew"]
    }
  }
}

使用しているデータベースがSQLiteなので、起動した場所に.sqlewフォルダが作成され、SQLiteのバイナリファイルが生成されます。他のPCでも作業したい場合やバージョン管理を汚したくない場合はパスを指定できます。

{
  "mcpServers": {
    "sqlew": {
      "command": "npx",
      "args": ["sqlew", "/path/to/database.db"]
    }
  }
}

一応、ClaudeCodeでテストをさせてみてください。

sqlew mcp をインストールしました。機能テストをしてみてください。

より詳しい使い方はGithubをご覧ください。(英語のみ)

npmはこちら

利用者の声

Sonnet4.5様からの喜びの声を頂いております。

まぁ実装したの君だけどね。

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です