STUDIO TAMA


thumbnail

投稿日:2025-07-05

Claude DesktopのMCPでRhinocerosを自然言語操作する

  • #Rhinoceros

  • #AI

AI技術が日々すさまじい速度で進歩する中、キャッチアップが非常に大変ですが、 少し遅れながらもClaude DesktopのMCPを使ってみようと思います。

少し前になりますが、Blender MCPが話題になりましたね。 BlenderをClaude Desktopから操作するという画期的な取り組みでした。 今回は、それのRhinocerosバージョンを実装してみます。

MCPは様々な言語で実装できるよう、 多言語対応のSDKが提供されています。 今回はTypeScriptを選択して、基本的な最小コードで実装しました。

■ この記事のゴール: Claude Desktopから自然言語で指示を出すだけで、Rhinocerosが実際に図形を描画する環境を構築することです。 「円を描いて」「Sin波を描いて」といった簡単な指示で、Rhinoを操作できるところまでやっていきます。

■ 注意 : 今回はWindowsを想定しています。Macだとプログラムが多少変わる部分があると思います。

■ 動作状況 :

準備

まず、Claude Desktopをインストールしてください。

ブラウザのClaudeではできませんのでご注意ください。

最終コード

このプロジェクトのGitHubリポジトリはこちら。

GitHub - shuya-tamaru/rhino-mcp

Contribute to shuya-tamaru/rhino-mcp development by creating an account on GitHub.

Typescriptプロジェクトの立上げ

まずは基本的なTypeScriptプロジェクトを作成します。

1mkdir rhino-mcp
2cd rhino-mcp
3npm init -y

必要なパッケージをインストールします。

1# MCP SDK
2npm install @modelcontextprotocol/sdk
3
4# Rhino操作用(Windows COM)
5npm install winax
6
7# TypeScript関連
8npm install -D typescript @types/node

TypeScript設定ファイルを作成します。

1npx tsc --init

tsconfig.json を以下のように設定します:

1{
2  "compilerOptions": {
3    "target": "ES2022",
4    "module": "ES2022",
5    "moduleResolution": "node",
6    "esModuleInterop": true,
7    "allowSyntheticDefaultImports": true,
8    "strict": true,
9    "skipLibCheck": true,
10    "forceConsistentCasingInFileNames": true,
11    "outDir": "./dist",
12    "rootDir": "./src"
13  },
14  "include": ["src/**/*"],
15  "exclude": ["node_modules", "dist"]
16}
17

package.json にES Modules設定を追加します:

1{
2  "type": "module",
3  "scripts": {
4    "build": "tsc",
5    "start": "node dist/index.js"
6  }
7}

プロジェクト構造を作成します:

1mkdir src
2mkdir dist
3touch src/index.ts

メインコードの実装

src/index.ts に以下のコードを実装します。

【必要なモジュールのインポート】

index.ts

1import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3import { z } from "zod";
4import winax from 'winax';
5import fs from 'fs';
6import path from 'path';
  • McpServer: MCPサーバーの本体
  • StdioServerTransport: Claude Desktopとの通信を担当
  • winax: Windows COM経由でRhinoを操作
  • zod: 入力スキーマの型検証

【MCPサーバーの初期化】

index.ts

1const server = new McpServer({
2  name: "rhino-server",
3  version: "1.0.0"
4});

Claude Desktopから認識される名前を設定します。

【Rhinoインスタンス管理】

index.ts

1let rhinoInstance: any = null;
2
3async function getRhinoInstance() {
4  if (rhinoInstance) {
5    try {
6      rhinoInstance.Visible;
7      return rhinoInstance;
8    } catch {
9      rhinoInstance = null;
10    }
11  }
12  
13  try {
14    rhinoInstance = new winax.Object('Rhino.Application');
15    rhinoInstance.Visible = true;
16    await new Promise(resolve => setTimeout(resolve, 3000));
17    return rhinoInstance;
18  } catch (error) {
19    console.error('Failed to create Rhino instance:', error);
20    throw error;
21  }
22}

この関数が今回の実装のキーポイントです:

  • 既存のRhinoインスタンスがあれば再利用
  • インスタンスが無効になっていたら新しく作成
  • COM経由でRhinoを起動し、表示状態にする
  • 3秒待機してRhinoの完全起動を待つ

【ツールの登録】

index.ts

1server.registerTool("rhino_execute", {
2  title: "Execute RhinoPython Script",
3  description: "Execute Python script that interacts with Rhino",
4  inputSchema: { pythonScript: z.string() }
5}, async ({ pythonScript }) => {
6  try {
7    const rhino = await getRhinoInstance();
8
9    const tempDir = path.join(process.cwd(), "temp-scripts");
10            
11    if (!fs.existsSync(tempDir)) {
12        fs.mkdirSync(tempDir, { recursive: true });
13    }
14    
15    const scriptFile = path.join(tempDir, `script_${Date.now()}.py`);
16    fs.writeFileSync(scriptFile, pythonScript);
17    
18    const result = rhino.RunScript(`-_RunPythonScript "${scriptFile}"`, 0);
19    
20    setTimeout(() => {
21        if (fs.existsSync(scriptFile)) {
22            fs.unlinkSync(scriptFile);
23        }
24    }, 1000);
25    
26    return { 
27      content: [{ 
28        type: "text", 
29        text: `Python script executed successfully.\nResult: ${result || 'Script completed'}`
30      }] 
31    };
32  } catch (error: any) {
33    return {
34      content: [{
35        type: "text",
36        text: `Error executing Grasshopper script: ${error.message}`
37      }]
38    };
39  }
40});

Claude DesktopからPythonスクリプトを受け取り、 Rhinoで実行するツールを登録します。

スクリプト実行の流れ

  1. 一時ファイル作成: 受け取ったPythonコードを一時ファイルに保存
  2. Rhinoで実行: -_RunPythonScript コマンドでファイルを実行
  3. ファイル削除: 1秒後に一時ファイルを削除
  4. 結果返却: 実行結果をClaude Desktopに返す

【サーバー起動】

index.ts

1const transport = new StdioServerTransport();
2await server.connect(transport);

標準入出力を使ってClaude Desktopとの通信を開始します。 この約80行のコードだけで、 自然言語によるRhino操作が実現できます。

Claude Desktop側の設定

Claude Desktop側の設定 MCPサーバーを作成したら、 Claude Desktopから利用できるように設定を行います。

■ 設定方法

  1. Claude Desktopを開く
  2. 左上の三本線をクリック
  3. 「開発者」タブを選択
  4. 「アプリ設定ファイルを開く」をクリック
  5. laude_desktop_config.jsonが開くのでそこに設定を書いていきます。

以下の設定を追加します:

1json{
2  "mcpServers": {
3    "rhino-server": {
4      "command": "node",
5      "args": ["C:/Users/YourUsername/path/to/rhino-mcp/dist/index.js"]
6    }
7  }
8}

"rhino-server" は src/index.ts で設定したサーバー名と一致させる args のパスは自分の環境に合わせて絶対パスで指定 ファイルパスはスラッシュ(/)で区切る

■ コンパイルと動作確認 設定前に、TypeScriptをコンパイルしておきます:

1npm run build
2dist/index.js が生成されることを確認してください。

■ Claude Desktopの再起動 設定ファイルを保存したら、 Claude Desktopを完全に終了して再起動します。 タスクマネージャーで Claude Desktopのプロセスが 完全に終了していることを確認してから再起動してください。

■ 接続テスト Claude Desktopが起動したら、以下のようにClaudeに"rhino-server"が使えるか効いてみましょう。

1「rhino-serverを使って円を描いてください」

正常に動作していれば、Rhinoが起動し、 円が描画されるはずです。 これで基本的な設定は完了です!

動作状況

こんな感じでClaude Desktopで自然言語で指示を出せば動くかと思います。

thumbnail

【参考】

目 次