❤️

いつのまにか「Claude CodeをMCPサーバー化」してClaude Desktopから利用できる神機能が生えてた件について

2025/03/19に公開
78

説明はほぼ不要かなと思うのですが、表題の通りです。

https://x.com/kazuph/status/1894241508859285986

上記は2月に投稿した内容ですが、なんと・・・!ありました!嬉しい!!

Claude CodeをMCPにする設定

ドキュメントに書いてありました(いつから??最初から??)。

https://docs.anthropic.com/ja/docs/agents-and-tools/claude-code/tutorials#claude-code-mcp

/Users/<user_name>/Library/Application\ Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "claude_code": {
      "command": "claude",
      "args": ["mcp", "serve"],
      "env": {}
    }
  }
}

このように設定ファイルを書きます。
ですが、僕の環境だとこれだとエラーになったので、フルパスで claude コマンドを書いて上げたら動きました。

{
  "mcpServers": {
    "claude_code": {
      "command": "/Users/kazuph/.local/share/mise/installs/node/20.18.2/bin/claude",
      "args": ["mcp", "serve"],
      "env": {}
    }
  }
}

MCPサーバーとして利用できるtool群

Claude自身にmcpに説明させると以下の内容が返ってきました。

# Claude Codeの機能
Claude Codeは、Anthropicが提供する研究プレビュー段階のエージェントコマンドラインツールで、以下のことができます:

コード生成と実装 - 仕様に基づいた新しいコードの作成
バグ修正と問題解決 - 既存コードの問題を特定し修正
コード理解と説明 - 複雑なコードベースの解析と説明
リファクタリング - コードを最適化・改善
ライブラリ統合 - 新しいライブラリやAPIの統合サポート
テスト作成 - ユニットテストや統合テストの作成
ドキュメント生成 - コメントや文書の作成・更新
設計アシスタント - 新機能やシステムの設計支援

抽象的なので具体的に表形式でtoolsの説明してもらいました。

ツール名 説明 使い方 利用シーン
Bash シェルコマンドを実行するツール(注:「Invalid API key · Please run /login」と表示されています) Bash コマンドを指定して実行 コマンドラインコマンドの実行、シェルスクリプトの動作
dispatch_agent 新しいタスクを起動するツール dispatch_agent プロンプトを指定して実行 サブタスクの作成、並列処理の実行
Edit ファイルを編集するツール Edit ファイルパス、置換前テキスト、置換後テキストを指定 特定のテキスト部分を検索して置換する場合
GlobTool ファイルパターンマッチングツール GlobTool パターン(例:**/*.js)を指定 特定のパターンに一致するファイルのパスを検索
GrepTool ファイル内容を正規表現で検索するツール GrepTool 正規表現パターンを指定(例:log.*Error コードベース内で特定のパターンを含むファイルを探す
LS ファイルとディレクトリを一覧表示 LS 絶対パスを指定 ディレクトリ内のファイル構造を把握する
Replace ローカルファイルシステムにファイルを書き込む Replace ファイルパスと内容を指定 既存ファイルの内容を完全に置き換える
View ローカルファイルシステムからファイルを読み取る View ファイルパスを指定 ファイルの内容を確認する

なるほど、これがあれば全般的なAI駆動開発ができそうです。
Bashにエラーが書いてありますが、普通に実行できました(Claudeが先に/loginしろって言ってきたけどいいからやってと一悶着)。

使ってみる

では、実際にmac上にあるプロジェクトに対してClaude CodeをClaude Desktopをインターフェースにして使ってみます。

とフルパスでディレクトリを指定して開始です。MCPの設定で指定する必要はないみたいです(いや設定した方が怖くないが)。

初手でLSとViewを使って把握をはじめました。

出力結果: 🖥️ CommandVプロジェクトの概要

🖥️ CommandVプロジェクトの概要

CommandVは、Claude Artifactsのためのリアルタイムプレビューツールです。ReactコンポーネントコードをWebアプリケーションに貼り付けるだけで、即座にレンダリングされた結果を確認できます。

主な機能

  1. 即時プレビュー: Reactコンポーネントコードを貼り付けるだけで、すぐに結果が表示されます
  2. シンタックスハイライト: 内蔵されたコードエディタ(Monaco Editor)で編集可能
  3. ライブラリサポート:
    • recharts(データ可視化)
    • lodash(ユーティリティ関数)
    • papaparse(CSV解析)
    • React Icons(各種アイコンセット)
  4. 画像エクスポート: プレビューをPNG画像として保存可能
  5. セットアップ不要: ブラウザですぐに使える
  6. モダンUI: Appleにインスパイアされたクリーンなデザイン

技術スタック

  • フロントエンド: React、TailwindCSS
  • バックエンド: Hono(Cloudflare Workersフレームワーク)
  • エディタ: Monaco Editor(VS Codeと同じエディタエンジン)
  • ビルドツール: Vite
  • デプロイ先: Cloudflare Workers
  • トランスパイラ: Babel(コンポーネントのコンパイルに使用)
  • 画像変換: html-to-image(高品質なプレビュー画像の生成)

プロジェクト構造

  • src/components/

    • ComponentPreviewer.tsx: メインのプレビュー機能
    • WelcomeScreen.tsx: 初期画面
    • SampleCounter.tsx: サンプルコンポーネント
    • AppleLogo.tsx: Appleスタイルのロゴ
  • src/styles/

    • tailwind.css、reset.css、custom.css: スタイリング用CSS
  • src/

    • client.tsx: クライアントサイドエントリーポイント
    • index.tsx: サーバーサイドレンダリング用エントリーポイント

開発方法

  1. 依存関係のインストール: pnpm install
  2. 開発サーバーの起動: pnpm run dev
  3. 本番用ビルド: pnpm run build
  4. Cloudflare Workersへのデプロイ: pnpm run deploy

実装のポイント

  1. コンポーネントのコンパイルと実行はcompileJSX関数で行われており、BabelとFunction constructorを使用してReactコンポーネントをランタイムで評価・実行しています。

  2. ペースト検知はグローバルなpasteイベントリスナーで実装されています。エディタ以外の場所へのペーストはプレビュー対象のコードとして処理されます。

  3. プレビュー画像のエクスポートはhtml-to-imageライブラリを使用し、グラデーションなども正確に表現できるよう工夫されています。

今後の開発方針

このプロジェクトをさらに発展させるには、以下のような機能追加や改善が考えられます:

  1. より多くのライブラリのサポート
  2. コンポーネントの保存・共有機能
  3. モバイル対応の強化
  4. エラーメッセージの改善
  5. テスト機能の追加

何から始めればよいでしょうか?

概要を把握したので雑に依頼してみます。Bashの使用許可を求められたので許可します。

え…。エラーの原因はClaude Codeのmcpサーバーが返却してくれないみたいです。あとで自作します。それはいいとして、このあと依存がinstallされていないことを確認まではしましたが、Bashの権限がないと勘違いして pnpm installしてくれませんでした

ので、促します。

成功しました。どうやらBashが成功した場合はレスポンスが正しく返却されるみたいです。
(じゃああらかじめBashコマンドを使う前に必ず成功するようにラップしてって説明すれば良さそうですね、だるいけど)

ですが、そのままサーバーを起動するコマンドを実行しようとしてます。これは問題です。
数分間?くらい待ったあとおそらくタイムアウトで失敗しました。

起動し続ける系のコマンドをそのまま実行して自爆しているのですが気づきません。
これも & 付けて実行してしまう(あとで都度killする)か、 pnpm run dev / pnpm run preview 等のコマンドはこちらで実行する旨を最初に伝えた方が良さそうです。

せめてエラーの原因をMCPサーバーがレスポンスしてくれればいいのですが…。

という依頼をしたらあっさり実装してきました。

{
  `command`: `cd /Users/kazuph/src/github.com/kazuph/commandv && { pnpm run dev & pid=$!; sleep 10; kill $pid; } > >(cat) 2>&1 || true`,
  `timeout`: 15000
}
{"stdout":"> commandv@1.0.0 dev /Users/kazuph/src/github.com/kazuph/commandv\n> vite\n\nPort 3000 is in use, trying another one...\nPort 3001 is in use, trying another one...\n(!) Could not auto-determine entry point from rollupOptions or html files and there are no explicit optimizeDeps.include patterns. Skipping dependency pre-bundling.\n\n  VITE v5.4.14  ready in 507 ms\n\n  ➜  Local:   http://localhost:3002/\n  ➜  Network: use --host to expose","stdoutLines":11,"stderr":"","stderrLines":1,"interrupted":false,"isImage":false}

良いですね!開発サーバーが正常に起動し、ポート3002で動作していることが確認できました。

とのことです。

うん、いい感じですね。

気を取り直してコードの編集です。今回はsvg製のロゴアイコンを編集させます。

↑です。

さてどうなるかな?

完了したみたいです。

ここで今MCPで利用したReplace(全置換)コマンドを眺めてみます。JSONはサンプルとして簡略化してます。

リクエスト内容

{
  "command": "Replace",
  "file_path": "/Users/.../AppleLogo.tsx",
  "content": "import React, { useState, useEffect } from 'react';...中略...export default AppleLogo;"
}

ファイルパスと置き換えたい全コードを送っているようです。

レスポンス内容

{
  "type": "update",
  "filePath": "/Users/.../AppleLogo.tsx",
  "content": "import React, { useState, useEffect }...",
  "structuredPatch": [
    {
      "oldStart": 1,        // 変更開始行(元ファイル)
      "oldLines": 23,       // 元ファイルの行数
      "newStart": 1,        // 変更開始行(新ファイル)
      "newLines": 1,        // 新ファイルの行数(実際は多いが簡略化)
      "lines": [
        "-import React from 'react';",
        "-// 古いコード...",
        "+import React, { useState, useEffect } from 'react';",
        "+// 新しいコード..."
      ]
    }
  ]
}

ちょっとレスポンスが多いし重複してそうですが、詳細を得られるという意味ではいいのかもしれません。トークンは節約してほしい。

次にMCPを使ってEditしてほしいのでサイトのボタンをアイコン化させます。

Editの中身も見てみます。

リクエスト

{
  `file_path`: `/Users/kazuph/src/github.com/kazuph/commandv/src/components/ComponentPreviewer.tsx`,
  `old_string`: `          <button 
            className=\"px-3 py-1 flex items-center justify-center rounded-md bg-gray-100 hover:bg-gray-200 transition-colors text-sm\"
            onClick={() => setShowCode(!showCode)}
          >
            {showCode ? \"Hide Code\" : \"Show Code\"}`,
  `new_string`: `          <button 
            className=\"w-10 h-10 flex items-center justify-center rounded-full bg-gray-100 hover:bg-gray-200 transition-colors\"
            onClick={() => setShowCode(!showCode)}
            title={showCode ? \"Hide Code\" : \"Show Code\"}
            aria-label={showCode ? \"Hide Code\" : \"Show Code\"}
          >
            {showCode ? <BsCodeSlash size={20} /> : <BsCode size={20} />}`
}

old_stringを指定してnew_stringに置換する指示のようです。コーディングエージェントだと定番の方法ですね。

レスポンスは…

{
  "filePath": "/Users/.../ComponentPreviewer.tsx",
  "oldString": "... (古い文字列) ...",
  "newString": "... (新しい文字列) ...",
  "structuredPatch": [
    {
      "oldStart": 453,    // 変更開始行
      "oldLines": 10,     // 変更された行数
      "newStart": 453,    // 新しい開始行
      "newLines": 12,     // 新しい行数
      "lines": [
        "         ",
        "         <div className=\"flex items-center gap-4\">",
        "           <button ",
        "-            className=\"px-3 py-1 flex items-center justify-center rounded-md bg-gray-100 hover:bg-gray-200 transition-colors text-sm\"",
        "+            className=\"w-10 h-10 flex items-center justify-center rounded-full bg-gray-100 hover:bg-gray-200 transition-colors\"",
        "             onClick={() => setShowCode(!showCode)}",
        "+            title={showCode ? \"Hide Code\" : \"Show Code\"}",
        "+            aria-label={showCode ? \"Hide Code\" : \"Show Code\"}",
        "           >",
        "-            {showCode ? \"Hide Code\" : \"Show Code\"}",
        "+            {showCode ? <BsCodeSlash size={20} /> : <BsCode size={20} />}",
        "           </button>",
        "           ",
        "           <button"
      ]
    }
  ],
  "originalFile": "... (元のファイル全体 - 非常に長いので省略) ..."
}

Claudeさん曰く

とのことなんですが、originalFile、Claudeさんまじやめよう。自分の首を締めてる。
(と思うんですが、これがないとその後の進行の精度が下がるのでしょうか?)

よし、じゃあ最後にdeployして確認しましょう!

無事に変更できます!(ロゴとボタンのアイコン化)

本当はデプロイまでに一悶着

Claude Codeを使っているけどAPI利用料金はかかるの?

これが僕的には一番気になるぽいんです。

Claude Code自体はAPI利用料金がかかるツールですが、これがMCPサーバーとして動く場合はどうでしょうか?

結論: 料金かかってないです!

管理コンソールのLogsは空、Usageも見ていますが 0 でした。時間経過で変わる可能性があるので、実は請求されていたとわかったら更新します。

まとめ

Claude CodeをMCPサーバーにしてClaude Desktopで操作できることが検証できました。

自分はWindsurf / Clineを普段使っているのですが、これで第三の選択肢が増えました。
特にClaudeで長考する場合のトークンは、上記の2つは限られていると思うので、月額が定額なDesktopアプリ版のClaudeでAI駆動開発できるのはまじで嬉しいです。

一つだけ小文字の dispatch_agent が気になるのでこのあと試してみます。

https://x.com/kazuph/status/1894222377397227601

良かった、本家も受け入れたわけじゃなかった!

Let's Claude Code!

78

Discussion