MCP Servers

模型上下文协议服务器、框架、SDK 和模板的综合目录。

MCP server by rassi0429

创建于 1/8/2026
更新于 1 day ago
Repository documentation and setup instructions

ResoniteLink MCP

ResoniteLink WebSocket プロトコルを使用して Resonite VR ワールドを操作するための MCP サーバ & CLI ツール。

インストール

npm install
npm run build

MCP サーバとして使用

Claude Code 設定

プロジェクトルートの .mcp.json に設定済み。Claude Code を再起動すると自動的にMCPサーバーが利用可能になります。

Claude Desktop 設定

claude_desktop_config.json に以下を追加:

{
  "mcpServers": {
    "resonitelink": {
      "command": "node",
      "args": ["C:/Users/neo/GitHub/resolink_mcp/dist/mcp-server.js"],
      "env": {
        "RESONITE_WS_URL": "ws://localhost:29551"
      }
    }
  }
}

利用可能なツール

| ツール | 説明 | |--------|------| | connect | Resonite に接続 | | disconnect | 接続を切断 | | get_slot | スロット情報を取得 | | find_slot | 名前でスロットを検索 | | add_slot | スロットを追加 | | remove_slot | スロットを削除 | | update_slot | スロットを更新 | | add_component | コンポーネントを追加 | | get_component | コンポーネント情報を取得 | | update_component | コンポーネントを更新 | | remove_component | コンポーネントを削除 | | search_components | コンポーネントを検索 | | get_component_info | コンポーネント詳細を取得 | | list_categories | カテゴリ一覧 | | search_by_category | カテゴリで検索 | | search_by_member | メンバー名で検索 | | get_component_source | ソースコードを取得 | | grep_source | ソースを全文検索 |

CLI として使用

WebSocket URL の指定方法

CLI は WebSocket URL を以下の優先順位で決定します:

  1. コマンドライン引数 --url (最優先)
  2. 環境変数 RESONITELINK_URL
  3. デフォルト値: ws://localhost:29551

環境変数で設定する例:

# Windows (PowerShell)
$env:RESONITELINK_URL = "ws://localhost:29469"

# Windows (コマンドプロンプト)
set RESONITELINK_URL=ws://localhost:29469

# Linux/Mac
export RESONITELINK_URL=ws://localhost:29469

環境変数を設定すれば、毎回 --url オプションを指定する必要がなくなります。

基本的なコマンド

# Rootスロット情報を取得
node dist/cli.js root --depth 1

# 特定のスロット情報を取得
node dist/cli.js get-slot --id <slotId> --depth 1

# コンポーネント情報も含めて取得
node dist/cli.js get-slot --id <slotId> --components

# 名前でスロットを検索
node dist/cli.js find --name MyObject

# スロットを追加
node dist/cli.js add-slot --name NewSlot --position 0,1,0

# 親スロットを指定してスロットを追加
node dist/cli.js add-slot --parent <parentId> --name MySlot --position 0,1,0 --scale 1,1,1

# コンポーネントを追加
node dist/cli.js add-component --slot <slotId> --type "[FrooxEngine]FrooxEngine.BoxMesh"

# スロットを更新
node dist/cli.js update-slot --id <slotId> --name NewName --position 0,2,0

# スロットを削除
node dist/cli.js remove-slot --id <slotId>

# コンポーネントを取得
node dist/cli.js get-component --id <componentId>

# コンポーネントを削除
node dist/cli.js remove-component --id <componentId>

# スロット階層をツリー表示
node dist/cli.js tree --depth 3

# WebSocket URLを指定(異なるポートの場合)
node dist/cli.js root --url ws://localhost:9422 --depth 2

ライブラリとして使用

import { ResoniteLinkClient } from './src/index.js';

const client = new ResoniteLinkClient({ url: 'ws://localhost:29551' });
await client.connect();

// スロットを追加
await client.addSlot({ name: 'MyObject', position: { x: 0, y: 1, z: 0 } });

// コンポーネントを追加
await client.addComponent({
  containerSlotId: slotId,
  componentType: '[FrooxEngine]FrooxEngine.BoxMesh'
});

client.disconnect();

クライアントオプション

const client = new ResoniteLinkClient({
  url: 'ws://localhost:29551',  // WebSocket URL(必須)
  debug: true,                   // コンソールにログ出力
  logFile: 'debug.log',          // ファイルにログ出力
  requestTimeout: 30000,         // リクエストタイムアウト(ミリ秒、デフォルト: 30000)
  autoReconnect: false,          // 自動再接続
  reconnectInterval: 5000,       // 再接続間隔(ミリ秒)
});

デバッグログ

問題が発生した場合、デバッグログを有効にすると SEND/RECV メッセージを確認できます:

const client = new ResoniteLinkClient({
  url: 'ws://localhost:29551',
  debug: true,           // コンソール出力
  logFile: 'debug.log',  // ファイル出力
});

ログ例:

[2026-01-08T06:10:24.504Z] SEND: { "$type": "addSlot", "messageId": "..." }
[2026-01-08T06:10:24.506Z] RECV: { "success": true, "messageId": "...", "error": null }

リクエストタイムアウト

レスポンスが返らない場合(不正な形式のデータ送信時など)、タイムアウトでエラーが発生します:

const client = new ResoniteLinkClient({
  url: 'ws://localhost:29551',
  requestTimeout: 10000,  // 10秒でタイムアウト
});

タイムアウト発生時は Error: Request timeout after 10000ms: updateComponent (...) のようなエラーがスローされます。

重要: ワールドシステムオブジェクト

Resonite ワールドの Root 以下には、削除してはいけないシステムオブジェクトがあります。

削除禁止オブジェクト

| オブジェクト名 | 説明 | |--------------|------| | Controllers | コントローラー入力システム | | Roles | ユーザーロール管理 | | SpawnArea | ユーザーのスポーン位置 | | Light | ワールドの照明 | | Skybox | 空・背景 | | User <...> | 接続中のユーザー(削除するとキックされる) | | __TEMP | 一時オブジェクト管理 | | Undo Manager | アンドゥ履歴 | | Assets | 共有アセット | | Clipboard Importer | クリップボードインポート機能 |

安全な削除方法

const SYSTEM_OBJECTS = [
  'Controllers', 'Roles', 'SpawnArea', 'Light', 'Skybox',
  '__TEMP', 'Undo Manager', 'Assets', 'Clipboard Importer'
];

// システムオブジェクトとUserはスキップ
if (SYSTEM_OBJECTS.includes(name) || name.startsWith('User ')) {
  continue;
}

コンポーネントタイプの書式

[FrooxEngine]FrooxEngine.ComponentName

よく使うコンポーネント

| コンポーネント | 用途 | |--------------|------| | BoxMesh | 直方体メッシュ | | SphereMesh | 球体メッシュ | | CylinderMesh | 円柱メッシュ | | ConeMesh | 円錐メッシュ | | BevelBoxMesh | 角丸直方体 | | RampMesh | スロープ | | FrameMesh | フレーム | | TorusMesh | トーラス | | CapsuleMesh | カプセル | | MeshRenderer | メッシュ描画 | | PBS_Metallic | PBRマテリアル | | Light | ライト |

マテリアルの設定例

await client.updateComponent({
  id: materialId,
  members: {
    AlbedoColor: { $type: 'colorX', value: { r: 1, g: 0, b: 0, a: 1, profile: 'sRGB' } },
    Smoothness: { $type: 'float', value: 0.5 },
    Metallic: { $type: 'float', value: 0.2 },
  }
});

Enum型の設定(BlendMode, LightType など)

Enum 型のメンバーを更新する場合、以下の形式を使用する必要があります:

{
  $type: 'enum',      // 小文字の 'enum'
  value: 'Alpha',     // 文字列で値を指定(数値ではない)
  enumType: 'BlendMode'  // Enum の型名
}

BlendMode の値

| 値 | 説明 | |----|------| | Opaque | 不透明(デフォルト) | | Cutout | カットアウト(アルファテスト) | | Alpha | 半透明(アルファブレンド) |

半透明マテリアルの例

await client.updateComponent({
  id: materialId,
  members: {
    BlendMode: { $type: 'enum', value: 'Alpha', enumType: 'BlendMode' },
    AlbedoColor: { $type: 'colorX', value: { r: 0.6, g: 0.75, b: 0.9, a: 0.3, profile: 'sRGB' } },
  }
});

LightType の値

| 値 | 説明 | |----|------| | Directional | ディレクショナルライト | | Point | ポイントライト | | Spot | スポットライト |

await client.updateComponent({
  id: lightId,
  members: {
    LightType: { $type: 'enum', value: 'Point', enumType: 'LightType' },
    Intensity: { $type: 'float', value: 2.0 },
    Range: { $type: 'float', value: 10.0 },
  }
});

注意事項

  • $type は必ず小文字の 'enum''Enum' ではない)
  • value は数値ではなく文字列で指定
  • enumType を省略すると動作しない場合がある
  • 正しくない形式を送信するとレスポンスが返らずタイムアウトする

メンバーの型一覧

| $type | 説明 | 例 | |-------|------|-----| | float | 浮動小数点 | { $type: 'float', value: 0.5 } | | int | 整数 | { $type: 'int', value: 10 } | | bool | 真偽値 | { $type: 'bool', value: true } | | float2 | 2Dベクトル | { $type: 'float2', value: { x: 1, y: 1 } } | | float3 | 3Dベクトル | { $type: 'float3', value: { x: 1, y: 2, z: 3 } } | | floatQ | クォータニオン | { $type: 'floatQ', value: { x: 0, y: 0, z: 0, w: 1 } } | | colorX | 色 | { $type: 'colorX', value: { r: 1, g: 0, b: 0, a: 1, profile: 'sRGB' } } | | enum | 列挙型 | { $type: 'enum', value: 'Alpha', enumType: 'BlendMode' } | | reference | 参照 | { $type: 'reference', targetId: 'Reso_XXXXX' } | | list | リスト | { $type: 'list', elements: [...] } |

Materials リストの更新(2段階)

MeshRenderer の Materials リストを更新するには2段階の操作が必要です。

なぜ2段階必要か

ResoniteLink の制限により、リスト要素への参照設定は以下の動作をします:

  1. 1回目の更新: リストに新しい要素が追加されるが、targetIdnull になる
  2. 2回目の更新: 要素の id を指定することで、既存要素の targetId を設定できる

つまり、要素の追加と参照の設定は別々の操作として行う必要があります。

コード例

// 1. まずリストに要素を追加(この時点では targetId は null になる)
await client.updateComponent({
  id: rendererId,
  members: {
    Materials: {
      $type: 'list',
      elements: [{ $type: 'reference', targetId: materialId }]
    }
  }
});

// 2. 追加された要素のIDを取得
const rendererData = await client.getComponent(rendererId);
const elementId = rendererData.data.members.Materials.elements[0].id;

// 3. 要素のIDを指定して、参照を設定
await client.updateComponent({
  id: rendererId,
  members: {
    Materials: {
      $type: 'list',
      elements: [{ $type: 'reference', id: elementId, targetId: materialId }]
    }
  }
});

重要なポイント

  • id フィールドを省略すると、新しい要素が追加される(既存要素は更新されない)
  • id フィールドを指定すると、その ID を持つ既存要素が更新される
  • 1回目で targetId を指定しても無視され、null になる

ProtoFlux コンポーネントの追加

ProtoFlux ノード(ジェネリック型コンポーネント)を追加するには、特定の形式が必要です。

正しい形式

[ProtoFluxBindings]FrooxEngine.FrooxEngine.ProtoFlux.CoreNodes.<コンポーネント名><型>

ポイント

| 項目 | 正しい形式 | 間違った形式 | |------|-----------|-------------| | アセンブリ名 | [ProtoFluxBindings] | [FrooxEngine] | | 名前空間 | FrooxEngine.FrooxEngine.ProtoFlux.CoreNodes | FrooxEngine.ProtoFlux.CoreNodes | | ジェネリック型 | <bool>, <int>, <float> | <System.Boolean>, `1[System.Boolean] |

  • 名前空間: FrooxEngine が2回繰り返される
  • 型指定: C# エイリアス(bool, int, float)を使用する(System.Boolean ではない)
  • 記法: <> 形式を使用する(.NET のバッククォート記法 `1[...] ではない)

複合型パラメータ(Slot, User など)

スロットやユーザーなどの複合型を型パラメータに使う場合は、アセンブリ名付きの完全修飾名を使用する:

[ProtoFluxBindings]...RefObjectInput<[FrooxEngine]FrooxEngine.Slot>

| 型 | 正しい形式 | 間違った形式 | |----|-----------|-------------| | Slot | <[FrooxEngine]FrooxEngine.Slot> | <Slot>, <FrooxEngine.Slot> | | User | <[FrooxEngine]FrooxEngine.User> | <User> | | IButton | <[FrooxEngine]FrooxEngine.IButton> | <IButton> |

重要: プリミティブ型(int, float, bool など)はエイリアスをそのまま使い、複合型(Slot, User など)は [FrooxEngine]FrooxEngine.TypeName 形式を使う。

動作確認済みコンポーネント

| ノード | componentType | |--------|---------------| | ValueInput<int> | [ProtoFluxBindings]FrooxEngine.ProtoFlux.Runtimes.Execution.Nodes.ValueInput<int> | | ValueAdd<int> | [ProtoFluxBindings]FrooxEngine.ProtoFlux.Runtimes.Execution.Nodes.Operators.ValueAdd<int> | | ValueDisplay<int> | [ProtoFluxBindings]FrooxEngine.ProtoFlux.Runtimes.Execution.Nodes.ValueDisplay<int> | | WorldTimeFloat | [ProtoFluxBindings]FrooxEngine.ProtoFlux.Runtimes.Execution.Nodes.FrooxEngine.Time.WorldTimeFloat | | AxisAngle_floatQ | [ProtoFluxBindings]FrooxEngine.ProtoFlux.Runtimes.Execution.Nodes.Math.Quaternions.AxisAngle_floatQ | | HSV_ToColorX | [ProtoFluxBindings]FrooxEngine.ProtoFlux.Runtimes.Execution.Nodes.Color.HSV_ToColorX | | ValueFieldDrive<floatQ> | [ProtoFluxBindings]FrooxEngine.FrooxEngine.ProtoFlux.CoreNodes.ValueFieldDrive<floatQ> | | ValueFieldDrive<colorX> | [ProtoFluxBindings]FrooxEngine.FrooxEngine.ProtoFlux.CoreNodes.ValueFieldDrive<colorX> | | ValueFieldDrive<bool> | [ProtoFluxBindings]FrooxEngine.FrooxEngine.ProtoFlux.CoreNodes.ValueFieldDrive<bool> |

コード例

// ValueFieldDrive<floatQ> を追加(回転ドライブ用)
await client.addComponent({
  containerSlotId: slotId,
  componentType: '[ProtoFluxBindings]FrooxEngine.FrooxEngine.ProtoFlux.CoreNodes.ValueFieldDrive<floatQ>'
});

// WorldTimeFloat を追加(時間取得用)
await client.addComponent({
  containerSlotId: slotId,
  componentType: '[ProtoFluxBindings]FrooxEngine.ProtoFlux.Runtimes.Execution.Nodes.FrooxEngine.Time.WorldTimeFloat'
});

// HSV_ToColorX を追加(色変換用)
await client.addComponent({
  containerSlotId: slotId,
  componentType: '[ProtoFluxBindings]FrooxEngine.ProtoFlux.Runtimes.Execution.Nodes.Color.HSV_ToColorX'
});

ProtoFlux ノード間の接続

// ValueAdd の A, B 入力に ValueInput ノードを接続
await client.updateComponent({
  id: addCompId,
  members: {
    A: { $type: 'reference', targetId: input1CompId },
    B: { $type: 'reference', targetId: input2CompId },
  }
});

// ValueDisplay の Input に ValueAdd の出力を接続
await client.updateComponent({
  id: displayCompId,
  members: {
    Input: { $type: 'reference', targetId: addCompId },
  }
});

よく使う ProtoFlux ノード

| コンポーネント | 用途 | |--------------|------| | ValueFieldDrive<T> | フィールドをドライブ | | ReferenceFieldDrive<T> | 参照フィールドをドライブ | | GlobalValue<T> | グローバル値 | | GlobalReference<T> | グローバル参照 |

ProtoFlux ノードの配置

ProtoFlux ノードを追加する際は、各ノードを別々のスロットに配置し、適切な位置に並べることで視認性が向上します。

座標系

Resonite の座標系:

  • X軸: 左右(右が正)
  • Y軸: 上下(上が正)
  • Z軸: 前後(手前が正)

ProtoFlux ノードは**左から右(X軸方向)**に配置するのが一般的です。

配置の基本パターン

左 ────────────────────────────────────────────→ 右 (X軸)

[入力ノード群]  →  [処理ノード]  →  [出力ノード]  →  [ドライブノード]
   x=-1.5            x=-1.0           x=-0.5            x=0

複数入力がある場合

Y軸で上下にずらして配置:

// 入力1(上側)
await client.addSlot({ name: 'Input1', position: { x: -1.5, y: 0.15, z: 0 } });

// 入力2(下側)
await client.addSlot({ name: 'Input2', position: { x: -1.5, y: -0.15, z: 0 } });

// 処理ノード(中央)
await client.addSlot({ name: 'Process', position: { x: -1.0, y: 0, z: 0 } });

実践例: 回転するボックス

// 親スロット
const fluxSlot = await client.addSlot({ name: 'Flux', position: { x: 0, y: 2, z: 0 } });

// 各ノードを左から右に配置
const nodes = [
  { name: 'AxisInput',      x: -0.6, y: 0.15 },  // 回転軸入力
  { name: 'TimeNode',       x: -0.6, y: -0.15 }, // 時間取得
  { name: 'AxisAngleNode',  x: -0.3, y: 0 },     // 軸角度→クォータニオン変換
  { name: 'DriveNode',      x: 0,    y: 0 },     // 回転ドライブ
];

for (const node of nodes) {
  await client.addSlot({
    name: node.name,
    parentId: fluxSlot.data.id,
    position: { x: node.x, y: node.y, z: 0 }
  });
}

配置のコツ

| 項目 | 推奨値 | |------|--------| | ノード間の水平間隔 | 0.3〜0.5 | | 分岐時の垂直間隔 | 0.15〜0.3 | | 親スロットからの相対座標 | 使用する |

  • 親スロット(例: Flux)を作成し、その下に各ノードを配置
  • 位置は親スロットからの相対座標になる
  • データフローが左から右に流れるように配置
  • 分岐がある場合は Y軸で上下にずらす

制限事項

一部の ProtoFlux ノードは追加できない場合があります:

  • 複雑なジェネリック制約を持つノード
  • 特殊な初期化が必要なノード

回避策:

  • Resonite 内で手動で ProtoFlux を作成
  • 既存の ProtoFlux をテンプレートとして複製
  • PackedObject として保存したものをインポート

デコンパイル検索 (CLI)

# コンポーネント名で検索
node dist/cli.js search --query Mesh

# コンポーネント詳細を表示
node dist/cli.js info --name PBS_Metallic

# カテゴリ一覧
node dist/cli.js categories

# カテゴリで検索
node dist/cli.js category --query "Materials"

# メンバー名で検索
node dist/cli.js member --query Smoothness

# ソースコード全文検索
node dist/cli.js grep --query "SyncPlayback"

# ソースコード表示
node dist/cli.js source --name BoxMesh

サンプルスクリプト

# ProtoFlux 1+1 を作成(ValueInput → ValueAdd → ValueDisplay)
node dist/scripts/create-flux-add.js ws://localhost:58971

# 東京タワー(詳細版)を作成
node dist/scripts/create-tokyo-tower-detailed.js ws://localhost:58971

# 東京スカイツリーを作成
node dist/scripts/create-skytree.js ws://localhost:58971

# 東京タワーを削除
node dist/scripts/delete-tokyo-tower.js ws://localhost:58971

# モダンハウス(内装付き)を作成
node dist/scripts/create-house3.js

# 街を作成
node dist/scripts/create-town.js

# 雲を作成
node dist/scripts/create-clouds.js

# すべて削除して床だけにする
node dist/scripts/reset-to-floor.js

License

MIT

快速设置
此服务器的安装指南

安装包 (如果需要)

npx @modelcontextprotocol/server-resolink-mcp

Cursor 配置 (mcp.json)

{ "mcpServers": { "rassi0429-resolink-mcp": { "command": "npx", "args": [ "rassi0429-resolink-mcp" ] } } }