opencodekit 0.9.2 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/index.js +1 -1
  2. package/dist/template/.opencode/AGENTS.md +116 -47
  3. package/dist/template/.opencode/agent/build.md +16 -48
  4. package/dist/template/.opencode/agent/explore.md +13 -34
  5. package/dist/template/.opencode/agent/planner.md +41 -11
  6. package/dist/template/.opencode/agent/review.md +2 -23
  7. package/dist/template/.opencode/agent/rush.md +24 -65
  8. package/dist/template/.opencode/agent/scout.md +5 -21
  9. package/dist/template/.opencode/agent/vision.md +0 -14
  10. package/dist/template/.opencode/command/accessibility-check.md +293 -30
  11. package/dist/template/.opencode/command/analyze-mockup.md +406 -20
  12. package/dist/template/.opencode/command/analyze-project.md +439 -30
  13. package/dist/template/.opencode/command/brainstorm.md +288 -5
  14. package/dist/template/.opencode/command/commit.md +226 -17
  15. package/dist/template/.opencode/command/create.md +138 -35
  16. package/dist/template/.opencode/command/design-audit.md +477 -29
  17. package/dist/template/.opencode/command/design.md +609 -6
  18. package/dist/template/.opencode/command/edit-image.md +223 -20
  19. package/dist/template/.opencode/command/finish.md +162 -71
  20. package/dist/template/.opencode/command/fix-ci.md +296 -24
  21. package/dist/template/.opencode/command/fix-types.md +345 -13
  22. package/dist/template/.opencode/command/fix-ui.md +293 -13
  23. package/dist/template/.opencode/command/fix.md +256 -9
  24. package/dist/template/.opencode/command/generate-diagram.md +327 -26
  25. package/dist/template/.opencode/command/generate-icon.md +266 -22
  26. package/dist/template/.opencode/command/generate-image.md +232 -12
  27. package/dist/template/.opencode/command/generate-pattern.md +234 -20
  28. package/dist/template/.opencode/command/generate-storyboard.md +231 -21
  29. package/dist/template/.opencode/command/handoff.md +202 -30
  30. package/dist/template/.opencode/command/implement.md +162 -50
  31. package/dist/template/.opencode/command/import-plan.md +247 -51
  32. package/dist/template/.opencode/command/init.md +154 -35
  33. package/dist/template/.opencode/command/integration-test.md +405 -24
  34. package/dist/template/.opencode/command/issue.md +171 -21
  35. package/dist/template/.opencode/command/new-feature.md +382 -54
  36. package/dist/template/.opencode/command/plan.md +144 -118
  37. package/dist/template/.opencode/command/pr.md +229 -28
  38. package/dist/template/.opencode/command/quick-build.md +234 -5
  39. package/dist/template/.opencode/command/research-and-implement.md +436 -12
  40. package/dist/template/.opencode/command/research-ui.md +444 -34
  41. package/dist/template/.opencode/command/research.md +173 -45
  42. package/dist/template/.opencode/command/restore-image.md +416 -22
  43. package/dist/template/.opencode/command/resume.md +439 -63
  44. package/dist/template/.opencode/command/revert-feature.md +341 -64
  45. package/dist/template/.opencode/command/review-codebase.md +193 -4
  46. package/dist/template/.opencode/command/skill-create.md +506 -14
  47. package/dist/template/.opencode/command/skill-optimize.md +487 -16
  48. package/dist/template/.opencode/command/status.md +320 -60
  49. package/dist/template/.opencode/command/summarize.md +374 -33
  50. package/dist/template/.opencode/command/triage.md +355 -0
  51. package/dist/template/.opencode/command/ui-review.md +292 -25
  52. package/dist/template/.opencode/plugin/README.md +110 -98
  53. package/dist/template/.opencode/plugin/compactor.ts +95 -171
  54. package/dist/template/.opencode/plugin/enforcer.ts +177 -127
  55. package/dist/template/.opencode/plugin/injector.ts +150 -0
  56. package/dist/template/.opencode/plugin/lib/notify.ts +86 -0
  57. package/dist/template/.opencode/plugin/notification.ts +57 -123
  58. package/dist/template/.opencode/plugin/truncator.ts +60 -166
  59. package/dist/template/.opencode/skill/mqdh/SKILL.md +161 -0
  60. package/dist/template/.opencode/skill/playwriter/SKILL.md +148 -0
  61. package/dist/template/.opencode/skill/v0/SKILL.md +154 -0
  62. package/package.json +1 -1
@@ -1,130 +1,64 @@
1
1
  /**
2
2
  * OpenCode Notification Plugin
3
3
  * Sends native notifications when sessions complete
4
- *
5
- * Cross-platform support:
6
- * - macOS: Built-in (osascript)
7
- * - Linux: notify-send (install: sudo apt install libnotify-bin)
8
- * - WSL: notify-send + dunst (requires setup)
9
4
  */
10
5
 
11
6
  import type { Plugin } from "@opencode-ai/plugin";
12
- import { exec } from "child_process";
13
- import { readFileSync } from "fs";
14
-
15
- // Notification helpers
16
- function isWSL(): boolean {
17
- try {
18
- const release = readFileSync("/proc/version", "utf8").toLowerCase();
19
- return release.includes("microsoft") || release.includes("wsl");
20
- } catch {
21
- return false;
22
- }
23
- }
24
-
25
- function escapeShell(str: string): string {
26
- return str.replace(/"/g, '\\"').replace(/\$/g, "\\$").replace(/`/g, "\\`");
27
- }
28
-
29
- function notify(title: string, message: string): void {
30
- const platform = process.platform;
31
- const safeTitle = title ? String(title) : "Notification";
32
- const safeMessage = message ? String(message) : "";
33
- const escapedTitle = escapeShell(safeTitle);
34
- const escapedMessage = escapeShell(safeMessage);
35
-
36
- let command: string;
37
-
38
- if (platform === "darwin") {
39
- command = `osascript -e 'display notification "${escapedMessage}" with title "${escapedTitle}"'`;
40
- } else if (platform === "linux") {
41
- command = `notify-send "${escapedTitle}" "${escapedMessage}"`;
42
- if (isWSL()) {
43
- command = `(${command}) 2>&1 || echo "WSL notification failed. Ensure dunst is running: dunst >/dev/null 2>&1 &"`;
44
- }
45
- } else if (platform === "win32") {
46
- command = `powershell -Command "Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show('${escapedMessage}', '${escapedTitle}')"`;
47
- } else {
48
- return;
49
- }
50
-
51
- exec(command, () => {});
52
- }
53
-
54
- export const NotificationPlugin: Plugin = async ({ client }) => {
55
- const notifiedSessions = new Set<string>();
56
-
57
- client.app
58
- .log({
59
- body: {
60
- service: "notification-plugin",
61
- level: "info",
62
- message: "🔔 Notification Plugin loaded",
63
- },
64
- })
65
- .catch(() => {});
66
-
67
- return {
68
- event: async ({ event }) => {
69
- if (event.type === "session.idle") {
70
- const sessionId = event.properties?.sessionID;
71
-
72
- if (!sessionId || notifiedSessions.has(sessionId)) {
73
- return;
74
- }
75
- notifiedSessions.add(sessionId);
76
-
77
- setTimeout(async () => {
78
- try {
79
- let summary = "Session completed";
80
-
81
- const messagesResponse = await client.session.messages({
82
- path: { id: sessionId },
83
- });
84
-
85
- if (messagesResponse.data && Array.isArray(messagesResponse.data)) {
86
- const lastUserMessage = messagesResponse.data
87
- .filter((m) => m.info.role === "user")
88
- .pop();
89
-
90
- const messageSummary = lastUserMessage?.info?.summary;
91
- if (
92
- messageSummary &&
93
- typeof messageSummary === "object" &&
94
- messageSummary !== null
95
- ) {
96
- if ("body" in messageSummary && messageSummary.body) {
97
- summary = String(messageSummary.body).trim().slice(0, 100);
98
- } else if ("title" in messageSummary && messageSummary.title) {
99
- summary = String(messageSummary.title).trim();
100
- }
101
- }
102
- }
103
-
104
- notify("OpenCode", summary);
105
-
106
- client.app
107
- .log({
108
- body: {
109
- service: "notification-plugin",
110
- level: "info",
111
- message: `✅ Notification sent: ${summary}`,
112
- },
113
- })
114
- .catch(() => {});
115
- } catch (error) {
116
- client.app
117
- .log({
118
- body: {
119
- service: "notification-plugin",
120
- level: "warn",
121
- message: `⚠️ Notification failed: ${(error as Error).message}`,
122
- },
123
- })
124
- .catch(() => {});
125
- }
126
- }, 2000);
127
- }
128
- },
129
- };
7
+ import { notify } from "./lib/notify";
8
+
9
+ export const NotificationPlugin: Plugin = async ({ client, $ }) => {
10
+ const notifiedSessions = new Set<string>();
11
+
12
+ return {
13
+ event: async ({ event }) => {
14
+ if (event.type === "session.idle") {
15
+ const props = event.properties as Record<string, unknown>;
16
+ const sessionId = props?.sessionID as string | undefined;
17
+
18
+ if (!sessionId || notifiedSessions.has(sessionId)) return;
19
+ notifiedSessions.add(sessionId);
20
+
21
+ setTimeout(async () => {
22
+ try {
23
+ let summary = "Session completed";
24
+
25
+ const messagesResponse = await client.session.messages({
26
+ path: { id: sessionId },
27
+ });
28
+
29
+ if (messagesResponse.data && Array.isArray(messagesResponse.data)) {
30
+ const lastUserMessage = messagesResponse.data
31
+ .filter((m) => m.info.role === "user")
32
+ .pop();
33
+
34
+ const messageSummary = lastUserMessage?.info?.summary;
35
+ if (
36
+ messageSummary &&
37
+ typeof messageSummary === "object" &&
38
+ messageSummary !== null
39
+ ) {
40
+ if ("body" in messageSummary && messageSummary.body) {
41
+ summary = String(messageSummary.body).trim().slice(0, 100);
42
+ } else if ("title" in messageSummary && messageSummary.title) {
43
+ summary = String(messageSummary.title).trim();
44
+ }
45
+ }
46
+ }
47
+
48
+ await notify($, "OpenCode", summary);
49
+ } catch (error) {
50
+ client.app
51
+ .log({
52
+ body: {
53
+ service: "notification",
54
+ level: "warn",
55
+ message: `Notification failed: ${(error as Error).message}`,
56
+ },
57
+ })
58
+ .catch(() => {});
59
+ }
60
+ }, 2000);
61
+ }
62
+ },
63
+ };
130
64
  };
@@ -1,190 +1,84 @@
1
1
  /**
2
2
  * OpenCode Truncator Plugin
3
- * Dynamic output truncation utilities - smarter than fixed limits
3
+ * Monitors tool output sizes and warns about large outputs
4
4
  *
5
- * Inspired by oh-my-opencode's grep-output-truncator and tool-output-truncator
6
- *
7
- * NOTE: OpenCode doesn't currently expose tool.execute.before/after events for
8
- * output modification. This plugin provides utility functions that can be used
9
- * by other plugins or integrated when the API supports it.
5
+ * NOTE: tool.execute.after hook is observation-only (returns void).
6
+ * Actual truncation would require OpenCode core changes.
7
+ * This plugin logs warnings when outputs are large under context pressure.
10
8
  */
11
9
 
12
10
  import type { Plugin } from "@opencode-ai/plugin";
13
-
14
- // Configuration
15
- const CONFIG = {
16
- // Base limits (chars) - adjusted dynamically based on context usage
17
- BASE_LIMITS: {
18
- grep: 15000,
19
- glob: 10000,
20
- read: 30000,
21
- bash: 20000,
22
- default: 25000,
23
- } as Record<string, number>,
24
- // Context percentage thresholds for scaling
25
- SCALE_FACTORS: [
26
- { threshold: 95, factor: 0.3 },
27
- { threshold: 85, factor: 0.5 },
28
- { threshold: 70, factor: 0.7 },
29
- { threshold: 50, factor: 1.0 },
30
- ],
31
- // Minimum output to preserve (chars)
32
- MIN_OUTPUT: 2000,
33
- };
34
-
35
- /**
36
- * Get scale factor based on context usage percentage
37
- */
38
- function getScaleFactor(contextPct: number): number {
39
- for (const { threshold, factor } of CONFIG.SCALE_FACTORS) {
40
- if (contextPct >= threshold) {
41
- return factor;
42
- }
43
- }
44
- return 1.0;
45
- }
46
-
47
- /**
48
- * Get dynamic limit for a tool based on context usage
49
- */
50
- export function getLimit(tool: string, contextPct: number): number {
51
- const baseLimit = CONFIG.BASE_LIMITS[tool] || CONFIG.BASE_LIMITS.default;
52
- const scaleFactor = getScaleFactor(contextPct);
53
- return Math.max(CONFIG.MIN_OUTPUT, Math.floor(baseLimit * scaleFactor));
54
- }
55
-
56
- /**
57
- * Ensure output is a string - handles objects, arrays, null, undefined
58
- */
59
- function ensureString(output: unknown): string {
60
- if (typeof output === "string") {
61
- return output;
62
- }
63
- if (output === null || output === undefined) {
64
- return "";
65
- }
66
- if (typeof output === "object") {
67
- try {
68
- return JSON.stringify(output, null, 2);
69
- } catch {
70
- return String(output);
71
- }
72
- }
73
- return String(output);
74
- }
75
-
76
- /**
77
- * Smart truncation with context preservation
78
- */
79
- export function smartTruncate(
80
- output: unknown,
81
- limit: number,
82
- tool: string,
83
- ): string {
84
- // Ensure we're working with a string
85
- const str = ensureString(output);
86
-
87
- // Return as-is if within limit or empty
88
- if (!str || str.length <= limit) return str;
89
-
90
- const truncatedChars = str.length - limit;
91
- const truncationMsg = `\n\n[... truncated ${truncatedChars} chars to save context ...]`;
92
-
93
- // Smart truncation strategies based on tool type
94
- if (tool === "grep" || tool === "glob") {
95
- // For search results: keep first and last results
96
- const lines = str.split("\n");
97
- const targetLines = Math.floor(limit / 80); // Assume ~80 chars per line
98
-
99
- if (lines.length > targetLines && targetLines > 0) {
100
- const keepStart = Math.max(1, Math.floor(targetLines * 0.7));
101
- const keepEnd = Math.max(1, targetLines - keepStart);
102
- return [
103
- ...lines.slice(0, keepStart),
104
- `\n... [${lines.length - keepStart - keepEnd} lines truncated] ...\n`,
105
- ...lines.slice(-keepEnd),
106
- ].join("\n");
107
- }
108
- }
109
-
110
- if (tool === "read") {
111
- // For file reads: keep beginning and end
112
- const keepStart = Math.floor(limit * 0.7);
113
- const keepEnd = limit - keepStart;
114
- if (keepStart > 0 && keepEnd > 0) {
115
- return str.slice(0, keepStart) + truncationMsg + str.slice(-keepEnd);
116
- }
117
- }
118
-
119
- if (tool === "bash") {
120
- // For bash: prefer keeping the end (usually most relevant)
121
- const keepStart = Math.floor(limit * 0.3);
122
- const keepEnd = limit - keepStart;
123
- if (keepStart > 0 && keepEnd > 0) {
124
- return str.slice(0, keepStart) + truncationMsg + str.slice(-keepEnd);
125
- }
126
- }
127
-
128
- // Default: balanced truncation
129
- const keepStart = Math.floor(limit * 0.6);
130
- const keepEnd = limit - keepStart;
131
- if (keepStart > 0 && keepEnd > 0) {
132
- return str.slice(0, keepStart) + truncationMsg + str.slice(-keepEnd);
133
- }
134
-
135
- // Fallback: just take first `limit` chars
136
- return str.slice(0, limit) + truncationMsg;
11
+ import {
12
+ THRESHOLDS,
13
+ type TokenStats,
14
+ getContextPercentage,
15
+ } from "./lib/notify";
16
+
17
+ // Warning thresholds for output size (chars)
18
+ const OUTPUT_WARN = {
19
+ MODERATE: 20000, // Warn if output > 20k at 70%+ context
20
+ URGENT: 10000, // Warn if output > 10k at 85%+ context
21
+ CRITICAL: 5000, // Warn if output > 5k at 95%+ context
22
+ } as const;
23
+
24
+ function getOutputThreshold(percentage: number): number | null {
25
+ if (percentage >= THRESHOLDS.CRITICAL) return OUTPUT_WARN.CRITICAL;
26
+ if (percentage >= THRESHOLDS.URGENT) return OUTPUT_WARN.URGENT;
27
+ if (percentage >= THRESHOLDS.MODERATE) return OUTPUT_WARN.MODERATE;
28
+ return null; // No warning under 70%
137
29
  }
138
30
 
139
31
  export const TruncatorPlugin: Plugin = async ({ client }) => {
140
- // Track current context usage for external access
141
- let currentContextPct = 0;
142
-
143
- client.app
144
- .log({
145
- body: {
146
- service: "truncator-plugin",
147
- level: "info",
148
- message:
149
- "✂️ Truncator Plugin loaded - dynamic truncation utilities available",
150
- },
151
- })
152
- .catch(() => {});
32
+ // Track context percentage per session
33
+ const sessionContext = new Map<string, number>();
153
34
 
154
35
  return {
155
36
  event: async ({ event }) => {
156
37
  const props = event.properties as Record<string, unknown>;
157
38
 
158
- // Track context usage from session updates
39
+ // Update context tracking from session updates
159
40
  if (event.type === "session.updated") {
160
41
  const info = props?.info as Record<string, unknown> | undefined;
161
42
  const tokenStats = (info?.tokens || props?.tokens) as
162
- | { percentage?: number }
43
+ | TokenStats
163
44
  | undefined;
45
+ const sessionId = (info?.id || props?.sessionID) as string | undefined;
164
46
 
165
- if (tokenStats?.percentage) {
166
- const prevPct = currentContextPct;
167
- currentContextPct = tokenStats.percentage;
168
-
169
- // Log when crossing thresholds
170
- const thresholds = [50, 70, 85, 95];
171
- for (const t of thresholds) {
172
- if (prevPct < t && currentContextPct >= t) {
173
- const limit = getLimit("default", currentContextPct);
174
- client.app
175
- .log({
176
- body: {
177
- service: "truncator-plugin",
178
- level: "debug",
179
- message: `✂️ Context at ${currentContextPct}% - dynamic limit now ${limit} chars`,
180
- },
181
- })
182
- .catch(() => {});
183
- break;
184
- }
185
- }
47
+ if (sessionId && tokenStats?.used && tokenStats?.limit) {
48
+ sessionContext.set(sessionId, getContextPercentage(tokenStats));
186
49
  }
187
50
  }
51
+
52
+ if (event.type === "session.deleted") {
53
+ const sessionId = props?.sessionID as string | undefined;
54
+ if (sessionId) sessionContext.delete(sessionId);
55
+ }
56
+ },
57
+
58
+ "tool.execute.after": async (input, output) => {
59
+ const toolName = input.tool;
60
+ const sessionId = input.sessionID;
61
+
62
+ // Get current context pressure
63
+ const percentage = sessionContext.get(sessionId) || 0;
64
+ const threshold = getOutputThreshold(percentage);
65
+
66
+ // Only check when under pressure
67
+ if (!threshold) return;
68
+
69
+ // Check output size
70
+ const outputStr = output.output || "";
71
+ if (outputStr.length > threshold) {
72
+ client.app
73
+ .log({
74
+ body: {
75
+ service: "truncator",
76
+ level: percentage >= THRESHOLDS.CRITICAL ? "warn" : "info",
77
+ message: `Large output from ${toolName}: ${outputStr.length} chars (threshold: ${threshold}, context: ${percentage}%)`,
78
+ },
79
+ })
80
+ .catch(() => {});
81
+ }
188
82
  },
189
83
  };
190
84
  };
@@ -0,0 +1,161 @@
1
+ ---
2
+ name: mqdh
3
+ description: Meta Quest Developer Hub MCP for VR/AR development. Access Meta Horizon OS docs, ADB tools, device management. Use when building Quest apps or need Meta XR documentation.
4
+ mcp:
5
+ mqdh:
6
+ command: "${MQDH_MCP_PATH}"
7
+ args: []
8
+ ---
9
+
10
+ # Meta Quest Developer Hub MCP
11
+
12
+ Access Meta Horizon OS development tools via the MQDH MCP server. This MCP is **bundled with the Meta Quest Developer Hub application** (v6.2.1+).
13
+
14
+ ## Prerequisites
15
+
16
+ ### 1. Install MQDH
17
+
18
+ Download and install Meta Quest Developer Hub v6.2.1 or later:
19
+
20
+ - **macOS**: [Download MQDH for Mac](https://developers.meta.com/horizon/documentation/android-apps/meta-quest-developer-hub)
21
+ - **Windows**: [Download MQDH for Windows](https://developers.meta.com/horizon/documentation/android-apps/meta-quest-developer-hub)
22
+
23
+ ### 2. Set MCP Path Environment Variable
24
+
25
+ The MCP server is bundled with MQDH. Set the path to the MCP executable:
26
+
27
+ **macOS:**
28
+
29
+ ```bash
30
+ export MQDH_MCP_PATH="/Applications/Meta Quest Developer Hub.app/Contents/Resources/mcp-server"
31
+ ```
32
+
33
+ **Windows:**
34
+
35
+ ```powershell
36
+ $env:MQDH_MCP_PATH = "C:\Program Files\Meta Quest Developer Hub\resources\mcp-server.exe"
37
+ ```
38
+
39
+ > **Note**: Paths may vary based on your installation. Check MQDH's AI Tools settings tab for the exact path.
40
+
41
+ ### 3. Alternative: Use MQDH's Built-in Setup
42
+
43
+ MQDH v6.2.1+ includes an **AI Tools settings tab** with:
44
+
45
+ - One-click install for **Cursor** and **VS Code**
46
+ - Guided setup for Claude Desktop, Gemini CLI, Android Studio
47
+ - Manual configuration export for other tools
48
+
49
+ ## Quick Start
50
+
51
+ After setting up the environment variable and loading this skill:
52
+
53
+ ```
54
+ skill_mcp(skill_name="mqdh", list_tools=true)
55
+ ```
56
+
57
+ Then invoke tools:
58
+
59
+ ```
60
+ skill_mcp(skill_name="mqdh", tool_name="fetch_meta_quest_doc", arguments='{"query": "hand tracking setup"}')
61
+ ```
62
+
63
+ ## Available Tools
64
+
65
+ ### fetch_meta_quest_doc
66
+
67
+ Search and retrieve Meta Horizon OS documentation.
68
+
69
+ | Parameter | Type | Required | Description |
70
+ | --------- | ------ | -------- | -------------------------- |
71
+ | `query` | string | Yes | Documentation search query |
72
+
73
+ **Example:**
74
+
75
+ ```
76
+ skill_mcp(skill_name="mqdh", tool_name="fetch_meta_quest_doc", arguments='{"query": "passthrough API Unity"}')
77
+ ```
78
+
79
+ ### get_adb_path
80
+
81
+ Get the path to the bundled ADB executable.
82
+
83
+ **Example:**
84
+
85
+ ```
86
+ skill_mcp(skill_name="mqdh", tool_name="get_adb_path", arguments='{}')
87
+ ```
88
+
89
+ ### device_list
90
+
91
+ List connected Quest devices.
92
+
93
+ **Example:**
94
+
95
+ ```
96
+ skill_mcp(skill_name="mqdh", tool_name="device_list", arguments='{}')
97
+ ```
98
+
99
+ ### install_apk
100
+
101
+ Install an APK to a connected Quest device.
102
+
103
+ | Parameter | Type | Required | Description |
104
+ | ----------- | ------ | -------- | ---------------- |
105
+ | `apk_path` | string | Yes | Path to APK file |
106
+ | `device_id` | string | No | Target device ID |
107
+
108
+ **Example:**
109
+
110
+ ```
111
+ skill_mcp(skill_name="mqdh", tool_name="install_apk", arguments='{"apk_path": "/path/to/app.apk"}')
112
+ ```
113
+
114
+ ## Use Cases
115
+
116
+ - **Documentation Lookup**: Quickly search Meta Horizon OS docs for APIs, best practices
117
+ - **Device Management**: List devices, install APKs, manage Quest headsets
118
+ - **Development Workflow**: Integrate ADB operations into AI-assisted development
119
+ - **Troubleshooting**: Find solutions in Meta's documentation
120
+
121
+ ## Workflow Examples
122
+
123
+ ### 1. Look Up API Documentation
124
+
125
+ ```
126
+ # Search for hand tracking documentation
127
+ skill_mcp(skill_name="mqdh", tool_name="fetch_meta_quest_doc", arguments='{"query": "hand tracking gesture detection"}')
128
+
129
+ # Search for passthrough setup
130
+ skill_mcp(skill_name="mqdh", tool_name="fetch_meta_quest_doc", arguments='{"query": "mixed reality passthrough Unity"}')
131
+ ```
132
+
133
+ ### 2. Device Operations
134
+
135
+ ```
136
+ # List connected devices
137
+ skill_mcp(skill_name="mqdh", tool_name="device_list", arguments='{}')
138
+
139
+ # Install a build
140
+ skill_mcp(skill_name="mqdh", tool_name="install_apk", arguments='{"apk_path": "/builds/myapp.apk", "device_id": "1234567890"}')
141
+ ```
142
+
143
+ ## Transport
144
+
145
+ This MCP uses **STDIO** transport to communicate with the LLM agent.
146
+
147
+ ## Troubleshooting
148
+
149
+ **"Command not found"**: Verify `MQDH_MCP_PATH` points to the correct executable. Check MQDH's AI Tools settings for the exact path.
150
+
151
+ **"MQDH not installed"**: Download MQDH v6.2.1+ from [Meta Developer Portal](https://developers.meta.com/horizon/documentation/android-apps/meta-quest-developer-hub).
152
+
153
+ **"Device not found"**: Ensure your Quest is connected via USB and developer mode is enabled.
154
+
155
+ **One-click setup preferred**: Use MQDH's built-in AI Tools settings tab for automatic configuration with Cursor or VS Code.
156
+
157
+ ## References
158
+
159
+ - [MQDH MCP Documentation](https://developers.meta.com/horizon/documentation/unity/ts-mqdh-mcp/)
160
+ - [Install MQDH](https://developers.meta.com/horizon/documentation/android-apps/meta-quest-developer-hub)
161
+ - [Meta Horizon OS Developer Docs](https://developers.meta.com/horizon/documentation/)