Naki MCP Tool Writer
Base directory: {baseDir}
<IMPORTANT> **MCP 調用規則**: 測試新建的 MCP 工具時,使用 `/naki-mcp-proxy` skill 調用。 </IMPORTANT>This skill helps create and modify MCP (Model Context Protocol) tools for the Naki project using the Protocol-based architecture.
Architecture Overview
Naki uses a Protocol-based MCP architecture:
command/Services/MCP/
├── MCPTool.swift - Protocol 定義 + Schema 類型
├── MCPContext.swift - 執行上下文 (async/await 支持)
├── MCPToolRegistry.swift - 工具註冊表 (單例)
├── MCPHandler.swift - MCP 協議處理器
└── Tools/
├── SystemTools.swift - 系統類工具 (get_status, get_help, get_logs, clear_logs)
├── BotTools.swift - Bot 控制工具 (bot_status, bot_trigger, bot_ops, bot_deep, bot_chi, bot_pon, bot_sync)
├── GameTools.swift - 遊戲狀態工具 (game_state, game_hand, game_ops, game_discard, game_action)
└── UITools.swift - UI 操作工具 (execute_js, detect, explore, test_indicators, click, calibrate, ui_names_*)
Current Registered Tools (47 total)
| Category | Count | Examples |
|---|---|---|
| System | 4 | get_status, get_help, get_logs, clear_logs |
| Bot | 7 | bot_status, bot_trigger, bot_ops, bot_deep, bot_chi, bot_pon, bot_sync |
| Game | 6 | game_state, game_hand, game_ops, game_discard, game_action, game_emoji |
| Highlight | 6 | highlight_tile, highlight_status, show_recommendations, hide_highlight |
| Emoji | 4 | game_emoji, game_emoji_list, game_emoji_random |
| Lobby | 9 | lobby_status, lobby_navigate, lobby_start_match, lobby_cancel_match |
| UI | 11 | execute_js, detect, explore, click, calibrate, ui_names_* |
See /naki-mcp-proxy for complete tool catalog.
How to Create a New MCP Tool
Step 1: Define the Tool Struct
Create a new struct implementing MCPTool protocol in the appropriate Tools/*.swift file:
swift1struct MyNewTool: MCPTool { 2 // 1. 工具名稱 (唯一標識符) 3 static let name = "my_new_tool" 4 5 // 2. 工具描述 (給 AI 看的說明) 6 static let description = "描述這個工具做什麼,何時使用" 7 8 // 3. 輸入參數 Schema 9 static let inputSchema = MCPInputSchema( 10 properties: [ 11 "param1": .string("參數1的描述"), 12 "param2": .integer("參數2的描述") 13 ], 14 required: ["param1"] // 必填參數 15 ) 16 17 // 4. 上下文 (用於訪問 JS、Bot 等) 18 private let context: MCPContext 19 20 init(context: MCPContext) { 21 self.context = context 22 } 23 24 // 5. 執行邏輯 25 func execute(arguments: [String: Any]) async throws -> Any { 26 guard let param1 = arguments["param1"] as? String else { 27 throw MCPToolError.missingParameter("param1") 28 } 29 30 // 執行邏輯... 31 32 return ["success": true, "result": "..."] 33 } 34}
Step 2: Register the Tool
在 MCPToolRegistry.swift:142-182 的 registerBuiltInTools() 方法中添加:
swift1register(MyNewTool.self)
注意: Tools 列表會自動從 Registry 生成,無需手動維護 JSON 檔案。
Input Schema Types
swift1// 無參數 2static let inputSchema = MCPInputSchema.empty 3 4// 有參數 5static let inputSchema = MCPInputSchema( 6 properties: [ 7 "stringParam": .string("字串參數描述"), 8 "intParam": .integer("整數參數描述"), 9 "numberParam": .number("數字參數描述"), 10 "boolParam": .boolean("布林參數描述"), 11 "objectParam": .object("物件參數描述") 12 ], 13 required: ["stringParam"] // 必填參數列表 14)
Context API
工具可以通過 context 訪問以下功能(定義在 MCPContext.swift:15-38):
swift1// 執行 JavaScript(async/await) 2let result = try await context.executeJavaScript("return document.title") 3 4// 獲取 Bot 狀態 5let status = context.getBotStatus() 6 7// 觸發自動打牌 8context.triggerAutoPlay() 9 10// 日誌操作 11let logs = context.getLogs() 12context.clearLogs() 13context.log("記錄訊息") 14 15// 服務器埠號 16let port = context.serverPort
⚠️ JavaScript 執行注意事項
重要:context.executeJavaScript() 必須使用 return 語句才能正確返回值!
swift1// ✅ 正確:使用 return 語句 2let title = try await context.executeJavaScript("return document.title") 3let sum = try await context.executeJavaScript("return 1 + 1") 4let json = try await context.executeJavaScript("return JSON.stringify({a:1})") 5 6// ❌ 錯誤:沒有 return,結果為 nil 7let title = try await context.executeJavaScript("document.title") // 返回 nil!
常見模式:
swift1// 調用遊戲 API 並返回 JSON 2let script = "return JSON.stringify(window.__nakiGameAPI.getGameState())" 3let result = try await context.executeJavaScript(script) 4 5// 執行操作並返回布林值 6let script = "return window.__nakiGameAPI.discardTile(0)" 7let success = try await context.executeJavaScript(script) as? Bool ?? false 8 9// 檢查 API 是否存在 10let script = "return typeof window.__nakiGameAPI !== 'undefined'" 11let exists = try await context.executeJavaScript(script) as? Bool ?? false
Error Handling
使用 MCPToolError(定義在 MCPTool.swift:129-147)處理錯誤:
swift1throw MCPToolError.missingParameter("paramName") 2throw MCPToolError.invalidParameter("paramName", expected: "string") 3throw MCPToolError.executionFailed("原因描述") 4throw MCPToolError.notAvailable("資源名稱")
Tool Categories & File Locations
| Category | File | When to Add Here |
|---|---|---|
| 系統 | SystemTools.swift | Server status, logs, help |
| Bot | BotTools.swift | Bot control, AI inference |
| 遊戲 | GameTools.swift | Game state, hand, actions |
| UI | UITools.swift | JS execution, clicks, detection |
Checklist for New Tools
- 定義唯一的
name(snake_case 格式) - 寫清楚的
description(給 AI 理解,包含何時使用) - 定義正確的
inputSchema - 實現
execute()方法(async throws) - 處理所有錯誤情況(使用 MCPToolError)
- 在
MCPToolRegistry.swift:142-182中註冊 - 構建測試通過
- 使用 MCP 工具測試功能
Testing
構建並測試:
bash1# 構建 2xcodebuild build -project Naki.xcodeproj -scheme Naki 3 4# 啟動應用後,使用 MCP 工具測試 5mcp__naki__<tool_name>
Reference Documentation
For detailed specifications and more examples, see:
- Protocol Reference - Complete MCPTool protocol, context API, schema types, and code examples