# Kachaka MCP サーバー > [!WARNING] > 現在このリポジトリにあるコードは実験的なものであり、正常に動作しない可能性があります。 ## 1. 概要 Kachaka MCPサーバー(kachaka-mcp)は、[Kachaka](https://kachaka.life/home/)の機能をModel Context Protocol(MCP)を通じて様々なAIモデルに提供するサーバーです。このサーバーにより、Claude、GPT-4、ローカルLLMなどのAIモデルがKachakaの状態を把握し、制御することができるようになります。 ## 2. デプロイメント ### 2.1 uv syncを使ったインストール [uv](https://docs.astral.sh/uv/)をインストールします。(まだインストールしていない場合) kachaka-mcpを以下の手順でインストールします。 ```bash git clone https://github.com/pf-robotics/kachaka-mcp.git cd kachaka-mcp # インストール uv sync # または開発用依存関係も含めてインストール uv sync --all ``` ### 2.2 Claude Desktopからの使用方法 `claude_desktop_config.json` に以下の記述を追加してください: ```json { "mcpServers": { "kachaka-mcp": { "command": "uv", "args": [ "--directory", "", "run", "python", "-m", "kachaka_mcp.server" ], "env": { "KACHAKA_HOST": "" } } } } ``` ここで、kachaka-mcpのディレクトリや`KACHAKA_HOST`の値は、お使いの環境に合わせて変更してください。 記述例: ```json { "mcpServers": { "kachaka-mcp": { "command": "uv", "args": [ "--directory", "C:\\kachaka-mcp", "run", "python", "-m", "kachaka_mcp.server" ], "env": { "KACHAKA_HOST": "192.168.1.100:26400" } } } } ``` ## 2.3 MCP Inspectorを使ったデバッグ [MCP Inspector](https://github.com/modelcontextprotocol/inspector)を使ってデバッグする場合は以下のようにします。 ```bash npx @modelcontextprotocol/inspector -e KACHAKA_HOST=192.168.1.100:26400 uv run python -m kachaka_mcp.server ``` ### 2.4 直接実行(すべてのプラットフォーム) ```bash # インストール pip install -e . # 設定 export KACHAKA_HOST="192.168.1.100:26400" # Kachakaのホスト(Linux/macOS) # または set KACHAKA_HOST=192.168.1.100:26400 # Kachakaのホスト(Windows CMD) # または $env:KACHAKA_HOST = "192.168.1.100:26400" # Kachakaのホスト(Windows PowerShell) # 実行 python -m kachaka_mcp.server # または mcp run kachaka_mcp.server # 開発モードで実行(MCP Inspector付き) mcp dev kachaka_mcp.server # Claude Desktopにインストール mcp install kachaka_mcp.server --name "Kachaka Robot" -v KACHAKA_HOST=192.168.1.100:26400 ``` ## 3. 設定ファイルの使用 環境変数の代わりに設定ファイルを使用することもできます。設定ファイルは `~/.kachaka-mcp/config.json`(Linux/macOS)または `%USERPROFILE%\.kachaka-mcp\config.json`(Windows)に配置します。 ```json { "kachaka_host": "192.168.1.100:26400", "server_name": "My Kachaka Robot", "log_level": "INFO", "auth_enabled": false, "api_keys": [] } ``` 設定ファイルの場所は環境変数 `KACHAKA_MCP_CONFIG` で変更できます: ```bash # Linux/macOS export KACHAKA_MCP_CONFIG="/path/to/config.json" # Windows CMD set KACHAKA_MCP_CONFIG=C:\path\to\config.json # Windows PowerShell $env:KACHAKA_MCP_CONFIG = "C:\path\to\config.json" ``` ## 4. アーキテクチャ ```mermaid graph TD A[AIモデル] <-->|MCP| B[kachaka-mcp サーバー] B <-->|gRPC| C[Kachaka] subgraph "AIモデル" A1[Claude] --- A A2[GPT-4] --- A A3[ローカルLLM] --- A end subgraph "kachaka-mcp" D[リソース層] --> F[Kachaka API クライアント] E[ツール層] --> F G[プロンプト層] --> F H[認証・セキュリティ層] end ``` ## 5. 主要コンポーネント ### 5.1 Kachaka API クライアント - Kachaka APIとの通信を担当 - KachakaApiClientを使用してKachaakaと通信 - 同期・非同期両方のインターフェースをサポート - ネットワーク接続の管理と再接続機能 ### 5.2 リソース層 Kachakaの状態情報をMCPリソースとして公開します: #### 5.2.1 Kachaaka情報リソース - `robot://status` - Kachaakaの現在の状態(位置、バッテリー、エラーなど) - `robot://version` - Kachaakaのバージョン情報 - `robot://serial` - シリアル番号 - `robot://command` - 現在実行中のコマンド情報 #### 5.2.2 マップリソース - `map://current` - 現在のマップ情報(PNG形式) - `map://locations/{location_id?}` - 登録された場所の情報 - `map://shelves/{shelf_id?}` - 棚の情報と位置 - `map://list` - 利用可能なマップのリスト #### 5.2.3 センサーリソース - `sensors://camera/front` - 前面カメラ画像 - `sensors://camera/back` - 背面カメラ画像 - `sensors://camera/tof` - ToFカメラ画像 - `sensors://laser` - レーザースキャンデータ - `sensors://imu` - IMUデータ - `sensors://odometry` - オドメトリデータ - `sensors://object_detection` - 物体検出結果 ### 5.3 ツール層 Kachakaの操作機能をMCPツールとして公開します: #### 5.3.1 移動ツール - `move_to_location(location_name: str)` - 指定した場所に移動 - `move_to_pose(x: float, y: float, yaw: float)` - 指定した座標に移動 - `return_home()` - ホームに戻る - `move_forward(distance_meter: float, speed: float)` - 指定した距離前進 - `rotate_in_place(angle_radian: float)` - その場で回転 - `set_robot_velocity(linear: float, angular: float)` - Kachaakaの速度を設定 #### 5.3.2 棚操作ツール - `move_shelf(shelf_name: str, location_name: str)` - 棚を指定した場所に移動 - `return_shelf(shelf_name: str)` - 棚を元の場所に戻す - `dock_shelf()` - 棚にドッキング - `undock_shelf()` - 棚からアンドック - `dock_any_shelf_with_registration(location_name: str, dock_forward: bool)` - 任意の棚にドッキングして登録 #### 5.3.3 システム操作ツール - `speak(text: str)` - テキストを音声で発話 - `cancel_command()` - 実行中のコマンドをキャンセル - `proceed()` - 次のステップに進む - `lock(duration_sec: float)` - 指定した時間ロックする - `set_auto_homing_enabled(enable: bool)` - 自動ホーミングの有効/無効を設定 - `set_manual_control_enabled(enable: bool)` - 手動制御の有効/無効を設定 - `set_speaker_volume(volume: int)` - スピーカーの音量を設定 - `restart_robot()` - Kachaakaを再起動 #### 5.3.4 マップ操作ツール - `switch_map(map_id: str)` - マップを切り替える - `export_map(map_id: str, output_file_path: str)` - マップをエクスポート - `import_map(target_file_path: str)` - マップをインポート - `set_robot_pose(pose: dict)` - Kachaakaの位置を設定 ### 5.4 プロンプト層 AIモデルとの対話を効率化するためのプロンプトテンプレートを提供します: - `robot_control_prompt()` - Kachaaka制御のための基本プロンプト - `shelf_operation_prompt()` - 棚操作のための基本プロンプト - `navigation_prompt()` - ナビゲーションのための基本プロンプト - `error_handling_prompt()` - エラー処理のための基本プロンプト ### 5.5 認証・セキュリティ層 - APIキーベースの認証 - アクセス制御と権限管理 - 操作ログの記録 ## 6. 実装計画 ### 6.1 プロジェクト構造 ``` kachaka-mcp/ ├── README.md # プロジェクト概要 ├── pyproject.toml # プロジェクト設定 ├── requirements.txt # 依存関係 ├── src/ │ └── kachaka_mcp/ │ ├── __init__.py │ ├── server.py # MCPサーバーのメイン実装 │ ├── resources.py # リソース定義 │ ├── tools.py # ツール定義 │ ├── prompts.py # プロンプト定義 │ ├── client.py # Kachaka APIクライアントラッパー │ ├── auth.py # 認証・セキュリティ │ └── utils/ │ ├── __init__.py │ ├── config.py # 設定管理 │ └── logging.py # ロギング ├── scripts/ │ ├── install.sh # インストールスクリプト │ └── run.sh # 実行スクリプト └── tests/ ├── __init__.py ├── test_server.py ├── test_resources.py └── test_tools.py ``` ### 6.2 依存関係 ```toml [project] name = "kachaka-mcp" version = "0.1.0" description = "MCP server for Kachaka robot" requires-python = ">=3.10" dependencies = [ "mcp[cli]>=1.7.1", "kachaka-api@git+https://github.com/pf-robotics/kachaka-api", "grpcio", "pydantic", "pillow", "numpy", "loguru", "protobuf==5.27.2" ] [project.optional-dependencies] dev = [ "pytest", "black", "isort", "mypy", "ruff", ] ``` ### 6.3 サーバー実装 #### 6.3.1 メインサーバークラス ```python # server.py import asyncio from contextlib import asynccontextmanager from typing import AsyncIterator, Optional from kachaka_api.aio import KachakaApiClient from mcp.server.fastmcp import Context, FastMCP from .resources import register_resources from .tools import register_tools from .prompts import register_prompts from .auth import KachakaAuthProvider class KachakaMCPContext: """Kachaka MCP サーバーのコンテキスト""" def __init__(self, kachaka_client: KachakaApiClient): self.kachaka_client = kachaka_client @asynccontextmanager async def kachaka_lifespan(server: FastMCP) -> AsyncIterator[KachakaMCPContext]: """Kachaka MCP サーバーのライフスパン管理""" # 設定の読み込み from .utils.config import load_config config = load_config() # Kachaka APIクライアントの初期化 kachaka_client = KachakaApiClient(target=config.kachaka_host) try: # コンテキストの作成と提供 context = KachakaMCPContext(kachaka_client) yield context finally: # クリーンアップ処理 pass def create_server(server_name: str = "Kachaka Robot") -> FastMCP: """Kachaka MCP サーバーを作成""" # MCPサーバーの作成 mcp = FastMCP( server_name, lifespan=kachaka_lifespan, auth_provider=KachakaAuthProvider(), ) # リソース、ツール、プロンプトの登録 register_resources(mcp) register_tools(mcp) register_prompts(mcp) return mcp def main(): """メイン関数""" server = create_server() server.run() if __name__ == "__main__": main() ``` #### 6.3.2 リソース実装例 ```python # resources.py from mcp.server.fastmcp import FastMCP, Context, Image from PIL import Image as PILImage import io import json def register_resources(mcp: FastMCP): """リソースの登録""" @mcp.resource("robot://status") async def get_robot_status(ctx: Context) -> str: """Kachaakaの現在の状態を取得""" kachaka_client = ctx.request_context.lifespan_context.kachaka_client # 各種情報の取得 pose = await kachaka_client.get_robot_pose() battery_info = await kachaka_client.get_battery_info() command_state, command = await kachaka_client.get_command_state() # JSONとして返す status = { "pose": { "x": pose.x, "y": pose.y, "yaw": pose.yaw }, "battery": { "percentage": battery_info[0], "status": str(battery_info[1]) }, "command_state": str(command_state), "command": { "type": command.WhichOneof("command"), "id": command_state.command_id if command_state.command_id else "" } } return json.dumps(status, indent=2) @mcp.resource("map://current") async def get_current_map(ctx: Context) -> Image: """現在のマップ画像を取得""" kachaka_client = ctx.request_context.lifespan_context.kachaka_client # マップの取得 map_data = await kachaka_client.get_png_map() # 画像として返す return Image(data=map_data.data, format="png") # 他のリソースも同様に実装... ``` #### 6.3.3 ツール実装例 ```python # tools.py from mcp.server.fastmcp import FastMCP, Context from typing import Dict, Any def register_tools(mcp: FastMCP): """ツールの登録""" @mcp.tool() async def move_to_location(location_name: str, ctx: Context) -> str: """指定した場所にKachaakaを移動させる""" kachaka_client = ctx.request_context.lifespan_context.kachaka_client # 進捗報告の設定 ctx.info(f"Moving to location: {location_name}") # 移動コマンドの実行 result = await kachaka_client.move_to_location( location_name, wait_for_completion=True ) # 結果の返却 if result.success: return f"Successfully moved to {location_name}" else: return f"Failed to move to {location_name}: {result.message}" @mcp.tool() async def speak(text: str, ctx: Context) -> str: """テキストを音声で発話する""" kachaka_client = ctx.request_context.lifespan_context.kachaka_client # 発話コマンドの実行 result = await kachaka_client.speak(text, wait_for_completion=True) # 結果の返却 if result.success: return f"Successfully spoke: {text}" else: return f"Failed to speak: {result.message}" # 他のツールも同様に実装... ``` #### 6.3.4 プロンプト実装例 ```python # prompts.py from mcp.server.fastmcp import FastMCP from mcp.server.fastmcp.prompts import base def register_prompts(mcp: FastMCP): """プロンプトの登録""" @mcp.prompt() def robot_control_prompt() -> list[base.Message]: """Kachaaka制御のための基本プロンプト""" return [ base.SystemMessage( "あなたはKachakaを制御するアシスタントです。" "以下のツールを使ってKachaakaを操作できます:" "- move_to_location: 指定した場所に移動" "- return_home: ホームに戻る" "- speak: テキストを音声で発話" "など" ), base.UserMessage("Kachakaを操作するのを手伝ってください。"), ] # 他のプロンプトも同様に実装... ``` ### 6.4 設定管理 以降に出てくる`kachaka_host`や`KACHAKA_HOST`の値は「[PythonでカチャカAPIを利用する](https://github.com/pf-robotics/kachaka-api/blob/main/docs/PYTHON.md)」に記載されている`target=`に続く値と同じ値が入ります。 なお`26400`は[Kachaka APIサーバー (gRPC)](https://github.com/pf-robotics/kachaka-api/blob/main/docs/PLAYGROUND.md#playground%E3%81%AE%E4%BB%95%E6%A7%98)のポート番号です。 ```python # utils/config.py from pydantic import BaseModel import os import json from pathlib import Path class KachakaMCPConfig(BaseModel): """Kachaka MCP サーバーの設定""" kachaka_host: str = "192.168.1.100:26400" # デフォルトのKachakaホスト server_name: str = "Kachaka Robot" log_level: str = "INFO" auth_enabled: bool = False api_keys: list[str] = [] def load_config() -> KachakaMCPConfig: """設定を読み込む""" # 環境変数から設定を読み込む config_path = os.environ.get("KACHAKA_MCP_CONFIG", "~/.kachaka-mcp/config.json") config_path = Path(config_path).expanduser() # デフォルト設定 config = KachakaMCPConfig() # 設定ファイルが存在する場合は読み込む if config_path.exists(): with open(config_path, "r") as f: config_data = json.load(f) config = KachakaMCPConfig(**config_data) # 環境変数で上書き if os.environ.get("KACHAKA_HOST"): config.kachaka_host = os.environ.get("KACHAKA_HOST") return config ``` ### 6.5 認証実装 ```python # auth.py from mcp.server.auth import OAuthServerProvider, ClientRegistrationOptions, RevocationOptions from typing import Dict, List, Optional class KachakaAuthProvider(OAuthServerProvider): """Kachaka MCP サーバーの認証プロバイダー""" def __init__(self): from .utils.config import load_config self.config = load_config() self.api_keys = set(self.config.api_keys) async def validate_client_credentials(self, client_id: str, client_secret: str) -> bool: """クライアント認証情報の検証""" if not self.config.auth_enabled: return True return client_secret in self.api_keys # 他の認証メソッドも実装... ``` ## 7. テスト計画 ### 7.1 単体テスト - リソース機能のテスト - ツール機能のテスト - 認証機能のテスト ### 7.2 統合テスト - サーバー起動と終了のテスト - AIモデルとの連携テスト - エラー処理のテスト ### 7.3 エンドツーエンドテスト - 実際のKachakaとの連携テスト - 様々なAIモデルからのアクセステスト ## 8. 今後の拡張性 ### 8.1 短期的な拡張計画 - WebUIの追加(サーバー状態の監視、設定変更など) - 複数Kachaakaの管理機能 - カスタムコマンドのサポート ### 8.2 中長期的な拡張計画 - 高度なスケジューリング機能 - ユーザー定義のワークフロー - 他のロボットプラットフォームとの連携 ## 9. セキュリティ考慮事項 - ネットワークセキュリティ(TLS/SSL対応) - アクセス制御と認証 - 安全な操作の確保(危険な操作の制限) - ログ記録と監査 ## 10. ライセンス [Apache License 2.0](LICENSE)