@opentabs-dev/mcp-server 0.0.66 → 0.0.68

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 (123) hide show
  1. package/dist/browser-tools/analyze-site.d.ts.map +1 -1
  2. package/dist/browser-tools/analyze-site.js +3 -1
  3. package/dist/browser-tools/analyze-site.js.map +1 -1
  4. package/dist/browser-tools/extension-get-logs.d.ts +2 -2
  5. package/dist/browser-tools/get-console-logs.d.ts +2 -2
  6. package/dist/extension-handlers.d.ts +2 -1
  7. package/dist/extension-handlers.d.ts.map +1 -1
  8. package/dist/extension-handlers.js +22 -1
  9. package/dist/extension-handlers.js.map +1 -1
  10. package/dist/extension-protocol.d.ts.map +1 -1
  11. package/dist/extension-protocol.js +6 -1
  12. package/dist/extension-protocol.js.map +1 -1
  13. package/dist/mcp-setup.d.ts +1 -13
  14. package/dist/mcp-setup.d.ts.map +1 -1
  15. package/dist/mcp-setup.js +4 -96
  16. package/dist/mcp-setup.js.map +1 -1
  17. package/dist/reload.js +5 -5
  18. package/dist/reload.js.map +1 -1
  19. package/package.json +3 -1
  20. package/dist/browser-tool-names.d.ts +0 -14
  21. package/dist/browser-tool-names.d.ts.map +0 -1
  22. package/dist/browser-tool-names.js +0 -55
  23. package/dist/browser-tool-names.js.map +0 -1
  24. package/dist/discovery-legacy.d.ts +0 -32
  25. package/dist/discovery-legacy.d.ts.map +0 -1
  26. package/dist/discovery-legacy.js +0 -415
  27. package/dist/discovery-legacy.js.map +0 -1
  28. package/dist/manifest-schema.d.ts +0 -14
  29. package/dist/manifest-schema.d.ts.map +0 -1
  30. package/dist/manifest-schema.js +0 -51
  31. package/dist/manifest-schema.js.map +0 -1
  32. package/dist/mcp-prompts.d.ts +0 -71
  33. package/dist/mcp-prompts.d.ts.map +0 -1
  34. package/dist/mcp-prompts.js +0 -248
  35. package/dist/mcp-prompts.js.map +0 -1
  36. package/dist/mcp-resources.d.ts +0 -53
  37. package/dist/mcp-resources.d.ts.map +0 -1
  38. package/dist/mcp-resources.js +0 -139
  39. package/dist/mcp-resources.js.map +0 -1
  40. package/dist/permissions.d.ts +0 -59
  41. package/dist/permissions.d.ts.map +0 -1
  42. package/dist/permissions.js +0 -144
  43. package/dist/permissions.js.map +0 -1
  44. package/dist/prompts/audit-ai-docs.d.ts +0 -6
  45. package/dist/prompts/audit-ai-docs.d.ts.map +0 -1
  46. package/dist/prompts/audit-ai-docs.js +0 -155
  47. package/dist/prompts/audit-ai-docs.js.map +0 -1
  48. package/dist/prompts/build-plugin.d.ts +0 -3
  49. package/dist/prompts/build-plugin.d.ts.map +0 -1
  50. package/dist/prompts/build-plugin.js +0 -455
  51. package/dist/prompts/build-plugin.js.map +0 -1
  52. package/dist/prompts/contribute-learnings.d.ts +0 -12
  53. package/dist/prompts/contribute-learnings.d.ts.map +0 -1
  54. package/dist/prompts/contribute-learnings.js +0 -107
  55. package/dist/prompts/contribute-learnings.js.map +0 -1
  56. package/dist/prompts/plugin-icon.d.ts +0 -5
  57. package/dist/prompts/plugin-icon.d.ts.map +0 -1
  58. package/dist/prompts/plugin-icon.js +0 -147
  59. package/dist/prompts/plugin-icon.js.map +0 -1
  60. package/dist/prompts/setup-plugin.d.ts +0 -3
  61. package/dist/prompts/setup-plugin.d.ts.map +0 -1
  62. package/dist/prompts/setup-plugin.js +0 -197
  63. package/dist/prompts/setup-plugin.js.map +0 -1
  64. package/dist/prompts/troubleshoot.d.ts +0 -3
  65. package/dist/prompts/troubleshoot.d.ts.map +0 -1
  66. package/dist/prompts/troubleshoot.js +0 -191
  67. package/dist/prompts/troubleshoot.js.map +0 -1
  68. package/dist/resources/browser-tools.d.ts +0 -3
  69. package/dist/resources/browser-tools.d.ts.map +0 -1
  70. package/dist/resources/browser-tools.js +0 -100
  71. package/dist/resources/browser-tools.js.map +0 -1
  72. package/dist/resources/cli.d.ts +0 -3
  73. package/dist/resources/cli.d.ts.map +0 -1
  74. package/dist/resources/cli.js +0 -217
  75. package/dist/resources/cli.js.map +0 -1
  76. package/dist/resources/plugin-development.d.ts +0 -3
  77. package/dist/resources/plugin-development.d.ts.map +0 -1
  78. package/dist/resources/plugin-development.js +0 -596
  79. package/dist/resources/plugin-development.js.map +0 -1
  80. package/dist/resources/quick-start.d.ts +0 -3
  81. package/dist/resources/quick-start.d.ts.map +0 -1
  82. package/dist/resources/quick-start.js +0 -210
  83. package/dist/resources/quick-start.js.map +0 -1
  84. package/dist/resources/sdk-api.d.ts +0 -3
  85. package/dist/resources/sdk-api.d.ts.map +0 -1
  86. package/dist/resources/sdk-api.js +0 -199
  87. package/dist/resources/sdk-api.js.map +0 -1
  88. package/dist/resources/self-improvement.d.ts +0 -10
  89. package/dist/resources/self-improvement.d.ts.map +0 -1
  90. package/dist/resources/self-improvement.js +0 -91
  91. package/dist/resources/self-improvement.js.map +0 -1
  92. package/dist/resources/status.d.ts +0 -5
  93. package/dist/resources/status.d.ts.map +0 -1
  94. package/dist/resources/status.js +0 -27
  95. package/dist/resources/status.js.map +0 -1
  96. package/dist/resources/troubleshooting.d.ts +0 -3
  97. package/dist/resources/troubleshooting.d.ts.map +0 -1
  98. package/dist/resources/troubleshooting.js +0 -167
  99. package/dist/resources/troubleshooting.js.map +0 -1
  100. package/dist/sanitize-tool-output.d.ts +0 -20
  101. package/dist/sanitize-tool-output.d.ts.map +0 -1
  102. package/dist/sanitize-tool-output.js +0 -52
  103. package/dist/sanitize-tool-output.js.map +0 -1
  104. package/dist/skip-confirmation.d.ts +0 -15
  105. package/dist/skip-confirmation.d.ts.map +0 -1
  106. package/dist/skip-confirmation.js +0 -16
  107. package/dist/skip-confirmation.js.map +0 -1
  108. package/dist/skip-permissions.d.ts +0 -11
  109. package/dist/skip-permissions.d.ts.map +0 -1
  110. package/dist/skip-permissions.js +0 -12
  111. package/dist/skip-permissions.js.map +0 -1
  112. package/dist/skip-sanitization.d.ts +0 -17
  113. package/dist/skip-sanitization.d.ts.map +0 -1
  114. package/dist/skip-sanitization.js +0 -18
  115. package/dist/skip-sanitization.js.map +0 -1
  116. package/dist/skip-verification.d.ts +0 -11
  117. package/dist/skip-verification.d.ts.map +0 -1
  118. package/dist/skip-verification.js +0 -12
  119. package/dist/skip-verification.js.map +0 -1
  120. package/dist/verify-plugin.d.ts +0 -53
  121. package/dist/verify-plugin.d.ts.map +0 -1
  122. package/dist/verify-plugin.js +0 -123
  123. package/dist/verify-plugin.js.map +0 -1
@@ -1,455 +0,0 @@
1
- /** Prompt text for the `build_plugin` prompt — full plugin development workflow. */
2
- export const buildPluginPromptText = (url, name) => {
3
- const nameClause = name ? `The plugin name should be \`${name}\`.` : '';
4
- return `Build a production-ready OpenTabs plugin for ${url}. ${nameClause}
5
-
6
- Follow the complete workflow below. Each phase builds on the previous one — do not skip phases.
7
-
8
- ---
9
-
10
- ## Prerequisites
11
-
12
- - The user has the target web app open in a browser tab at ${url}
13
- - The MCP server is running (you are connected to it)
14
- - You have access to the filesystem for creating plugin source files
15
-
16
- ### Browser Tool Permissions
17
-
18
- Plugin development requires heavy use of browser tools (\`browser_execute_script\`, \`browser_navigate_tab\`, \`browser_get_tab_content\`, etc.). By default, tools have permission \`'off'\` (disabled) or \`'ask'\` (requires human approval).
19
-
20
- Ask the user if they want to enable \`skipPermissions\` to bypass approval prompts during development. Set the env var: \`OPENTABS_DANGEROUSLY_SKIP_PERMISSIONS=1\`. Warn them this bypasses human approval and should only be used during active plugin development.
21
-
22
- ---
23
-
24
- ## Core Principle: Use the Real APIs, Never the DOM
25
-
26
- Every plugin tool must use the web app's own APIs — the same HTTP endpoints, WebSocket channels, or internal RPC methods that the web app's JavaScript calls. DOM scraping is never acceptable as a tool implementation strategy. It is fragile (breaks on any UI change), limited (cannot access data not rendered on screen), and slow (parsing HTML is orders of magnitude slower than a JSON API call).
27
-
28
- When an API is hard to discover, spend time reverse-engineering it (network capture, XHR interception, source code reading). Do not fall back to DOM scraping because it is faster to implement.
29
-
30
- **Only three uses of the DOM are acceptable:**
31
- 1. \`isReady()\` — checking authentication signals (meta tags, page globals, indicator cookies)
32
- 2. URL hash navigation — triggering client-side route changes
33
- 3. Last-resort compose flows — when the app has no API for creating content and the UI is the only path (rare)
34
-
35
- ---
36
-
37
- ## Phase 1: Research the Codebase
38
-
39
- Before writing any code, study the existing plugin infrastructure using the filesystem:
40
-
41
- 1. **Study the Plugin SDK** — read \`platform/plugin-sdk/CLAUDE.md\` and key source files (\`src/index.ts\`, \`src/plugin.ts\`, \`src/tool.ts\`). Understand:
42
- - \`OpenTabsPlugin\` abstract base class (name, displayName, description, urlPatterns, tools, isReady)
43
- - \`defineTool({ name, displayName, description, icon, input, output, handle })\` factory
44
- - \`ToolError\` static factories: \`.auth()\`, \`.notFound()\`, \`.rateLimited()\`, \`.timeout()\`, \`.validation()\`, \`.internal()\`
45
- - SDK utilities: \`fetchJSON\`, \`postJSON\`, \`getLocalStorage\`, \`waitForSelector\`, \`retry\`, \`sleep\`, \`log\`
46
- - All plugin code runs in the **browser page context** (not server-side)
47
-
48
- 2. **Study an existing plugin** (e.g., \`plugins/slack/\`) as the canonical reference:
49
- - \`src/index.ts\` — plugin class, imports all tools
50
- - \`src/slack-api.ts\` — API wrapper with auth extraction + error classification
51
- - \`src/tools/\` — one file per tool, shared schemas
52
- - \`package.json\` — the opentabs field, dependency versions, scripts
53
-
54
- 3. **Study \`plugins/CLAUDE.md\`** — plugin isolation rules and conventions
55
-
56
- ---
57
-
58
- ## Phase 2: Explore the Target Web App
59
-
60
- This is the most critical phase. Use browser tools to understand how the web app works.
61
-
62
- ### Step 1: Find the Tab
63
-
64
- \`\`\`
65
- plugin_list_tabs or browser_list_tabs → find the tab for ${url}
66
- \`\`\`
67
-
68
- ### Step 2: Analyze the Site
69
-
70
- \`\`\`
71
- plugin_analyze_site(url: "${url}")
72
- \`\`\`
73
-
74
- This gives you a comprehensive report: auth methods, API endpoints, framework detection, storage keys, and concrete tool suggestions.
75
-
76
- ### Step 3: Enable Network Capture and Explore
77
-
78
- \`\`\`
79
- browser_enable_network_capture(tabId, urlFilter: "/api")
80
- \`\`\`
81
-
82
- Navigate around in the app to trigger API calls, then read them:
83
-
84
- \`\`\`
85
- browser_get_network_requests(tabId)
86
- \`\`\`
87
-
88
- Study the captured traffic to understand:
89
- - API base URL
90
- - Whether the API is same-origin or cross-origin (critical for CORS)
91
- - Request format (JSON body vs form-encoded)
92
- - Required headers (content-type, custom headers)
93
- - Response shapes for each endpoint
94
- - Error response format
95
-
96
- ### Step 4: Check CORS Policy (for Cross-Origin APIs)
97
-
98
- If the API is on a different subdomain, verify CORS behavior:
99
-
100
- \`\`\`bash
101
- curl -sI -X OPTIONS https://api.example.com/endpoint \\
102
- -H "Origin: ${url}" \\
103
- -H "Access-Control-Request-Method: GET" \\
104
- -H "Access-Control-Request-Headers: Authorization,Content-Type" \\
105
- | grep -i "access-control"
106
- \`\`\`
107
-
108
- ### Step 5: Discover Auth Token
109
-
110
- **First, always check cookies with \`browser_get_cookies\`** to understand the auth model. Then probe the page:
111
-
112
- - **localStorage**: Direct access or iframe fallback if the app deletes \`window.localStorage\`
113
- - **Page globals**: \`window.__APP_STATE__\`, \`window.boot_data\`, \`window.__NEXT_DATA__\`
114
- - **Webpack module stores**: For React/webpack SPAs
115
- - **Cookies**: \`document.cookie\` for non-HttpOnly tokens
116
- - **Script tags**: Inline \`<script>\` tags with embedded config
117
-
118
- ### Step 6: Test the API
119
-
120
- Once you have the token, make a test API call with \`browser_execute_script\`:
121
-
122
- \`\`\`javascript
123
- const resp = await fetch('https://example.com/api/v2/me', {
124
- headers: { Authorization: 'Bearer ' + token },
125
- credentials: 'include',
126
- });
127
- const data = await resp.json();
128
- return data;
129
- \`\`\`
130
-
131
- ### Step 7: Intercept Internal API Traffic (for apps without clean REST APIs)
132
-
133
- Some web apps do not expose clean REST or GraphQL APIs. Instead they use internal RPC endpoints, obfuscated paths, or proprietary protocols that are hard to discover via network capture alone. For these apps, monkey-patch \`XMLHttpRequest\` and \`fetch\` to intercept all API traffic and capture auth headers at runtime.
134
-
135
- Install the interceptor at adapter load time to capture auth tokens from early boot requests. Store captured data on \`globalThis\` so it survives adapter re-injection.
136
-
137
- \`\`\`javascript
138
- // XHR interceptor — captures internal API requests and auth headers
139
- const captured = { authHeader: null, requests: [] };
140
-
141
- const origOpen = XMLHttpRequest.prototype.open;
142
- const origSetHeader = XMLHttpRequest.prototype.setRequestHeader;
143
- const origSend = XMLHttpRequest.prototype.send;
144
-
145
- XMLHttpRequest.prototype.open = function (method, url) {
146
- this._method = method;
147
- this._url = url;
148
- return origOpen.apply(this, arguments);
149
- };
150
-
151
- XMLHttpRequest.prototype.setRequestHeader = function (name, value) {
152
- if (/auth|token|x-api|x-csrf/i.test(name)) {
153
- captured.authHeader = { name, value };
154
- }
155
- return origSetHeader.apply(this, arguments);
156
- };
157
-
158
- XMLHttpRequest.prototype.send = function (body) {
159
- captured.requests.push({ method: this._method, url: this._url });
160
- return origSend.apply(this, arguments);
161
- };
162
- \`\`\`
163
-
164
- Use this when:
165
- - The app uses internal RPC endpoints not visible in standard network capture
166
- - Auth tokens are computed by obfuscated JavaScript and cannot be extracted from storage
167
- - You need to discover which headers the app sends on its own API calls
168
-
169
- ### Step 8: Map the API Surface
170
-
171
- Discover the key endpoints: user/profile, list resources, get single resource, create/update/delete, search, messaging, reactions.
172
-
173
- ---
174
-
175
- ## Phase 3: Scaffold the Plugin
176
-
177
- \`\`\`bash
178
- cd plugins/
179
- opentabs plugin create <name> --domain <domain> --display <DisplayName> --description "OpenTabs plugin for <DisplayName>"
180
- \`\`\`
181
-
182
- After scaffolding, compare \`package.json\` with an existing plugin (e.g., \`plugins/slack/package.json\`) and align:
183
- - Package name: \`@opentabs-dev/opentabs-plugin-<name>\` for official plugins
184
- - Version: Match the current platform version
185
- - Add: \`publishConfig\`, \`check\` script
186
- - Dependency versions: Match \`@opentabs-dev/plugin-sdk\` and \`@opentabs-dev/plugin-tools\` versions
187
-
188
- ---
189
-
190
- ## Phase 4: Design the Tool Set
191
-
192
- **Maximize API coverage.** Add as many tools as the API supports. A typical production plugin has 15-25+ tools across these categories:
193
-
194
- - **Content**: send, edit, delete, read/list, search
195
- - **Resources/Containers**: list, get info, create, update, delete
196
- - **Users/Members**: list, get profile
197
- - **Interactions**: reactions, pins, bookmarks
198
- - **Platform-specific**: threads, DMs, file uploads, etc.
199
-
200
- For each API resource, ask: can the user list it, get one, create one, update one, delete one, and search it? If the API supports it, add the tool.
201
-
202
- ---
203
-
204
- ## Phase 5: Implement
205
-
206
- ### File Structure
207
-
208
- \`\`\`
209
- src/
210
- index.ts # Plugin class — imports all tools, implements isReady()
211
- <name>-api.ts # API wrapper — auth extraction + error classification
212
- tools/
213
- schemas.ts # Shared Zod schemas + defensive mappers
214
- send-message.ts # One file per tool
215
- ...
216
- \`\`\`
217
-
218
- ### API Wrapper Pattern (\`<name>-api.ts\`)
219
-
220
- The API wrapper handles auth extraction, request construction, and error classification:
221
-
222
- \`\`\`typescript
223
- import { ToolError } from '@opentabs-dev/plugin-sdk';
224
-
225
- interface AppAuth {
226
- token: string;
227
- }
228
-
229
- const getAuth = (): AppAuth | null => {
230
- // Check globalThis persistence first (survives adapter re-injection)
231
- // Then try localStorage, page globals, cookies
232
- // Return null if not authenticated
233
- };
234
-
235
- export const isAuthenticated = (): boolean => getAuth() !== null;
236
-
237
- export const waitForAuth = (): Promise<boolean> =>
238
- new Promise((resolve) => {
239
- let elapsed = 0;
240
- const interval = 500;
241
- const maxWait = 5000;
242
- const timer = setInterval(() => {
243
- elapsed += interval;
244
- if (isAuthenticated()) { clearInterval(timer); resolve(true); return; }
245
- if (elapsed >= maxWait) { clearInterval(timer); resolve(false); }
246
- }, interval);
247
- });
248
-
249
- export const api = async <T extends Record<string, unknown>>(
250
- endpoint: string,
251
- options: { method?: string; body?: Record<string, unknown>; query?: Record<string, string | number | boolean | undefined> } = {},
252
- ): Promise<T> => {
253
- const auth = getAuth();
254
- if (!auth) throw ToolError.auth('Not authenticated — please log in.');
255
-
256
- let url = \\\`https://example.com/api\\\${endpoint}\\\`;
257
- if (options.query) {
258
- const params = new URLSearchParams();
259
- for (const [key, value] of Object.entries(options.query)) {
260
- if (value !== undefined) params.append(key, String(value));
261
- }
262
- const qs = params.toString();
263
- if (qs) url += \\\`?\\\${qs}\\\`;
264
- }
265
-
266
- const headers: Record<string, string> = { Authorization: \\\`Bearer \\\${auth.token}\\\` };
267
- let fetchBody: string | undefined;
268
- if (options.body) {
269
- headers['Content-Type'] = 'application/json';
270
- fetchBody = JSON.stringify(options.body);
271
- }
272
-
273
- let response: Response;
274
- try {
275
- response = await fetch(url, {
276
- method: options.method ?? 'GET', headers, body: fetchBody,
277
- credentials: 'include', signal: AbortSignal.timeout(30_000),
278
- });
279
- } catch (err: unknown) {
280
- if (err instanceof DOMException && err.name === 'TimeoutError')
281
- throw ToolError.timeout(\\\`API request timed out: \\\${endpoint}\\\`);
282
- throw new ToolError(
283
- \\\`Network error: \\\${err instanceof Error ? err.message : String(err)}\\\`,
284
- 'network_error', { category: 'internal', retryable: true },
285
- );
286
- }
287
-
288
- if (!response.ok) {
289
- const errorBody = (await response.text().catch(() => '')).substring(0, 512);
290
- if (response.status === 429) throw ToolError.rateLimited(\\\`Rate limited: \\\${endpoint}\\\`);
291
- if (response.status === 401 || response.status === 403)
292
- throw ToolError.auth(\\\`Auth error (\\\${response.status}): \\\${errorBody}\\\`);
293
- if (response.status === 404) throw ToolError.notFound(\\\`Not found: \\\${endpoint}\\\`);
294
- throw ToolError.internal(\\\`API error (\\\${response.status}): \\\${endpoint} — \\\${errorBody}\\\`);
295
- }
296
-
297
- if (response.status === 204) return {} as T;
298
- return (await response.json()) as T;
299
- };
300
- \`\`\`
301
-
302
- ### Tool Pattern (one file per tool)
303
-
304
- \`\`\`typescript
305
- import { defineTool } from '@opentabs-dev/plugin-sdk';
306
- import { z } from 'zod';
307
- import { api } from '../<name>-api.js';
308
-
309
- export const sendMessage = defineTool({
310
- name: 'send_message',
311
- displayName: 'Send Message',
312
- description: 'Send a message to a channel. Supports markdown formatting.',
313
- summary: 'Send a message to a channel',
314
- icon: 'send',
315
- input: z.object({
316
- channel: z.string().describe('Channel ID to send the message to'),
317
- content: z.string().describe('Message text content'),
318
- }),
319
- output: z.object({
320
- id: z.string().describe('Message ID'),
321
- }),
322
- handle: async (params) => {
323
- const data = await api<Record<string, unknown>>(
324
- '/channels/' + params.channel + '/messages',
325
- { method: 'POST', body: { content: params.content } },
326
- );
327
- return { id: (data.id as string) ?? '' };
328
- },
329
- });
330
- \`\`\`
331
-
332
- ### Plugin Class Pattern (\`index.ts\`)
333
-
334
- \`\`\`typescript
335
- import { OpenTabsPlugin } from '@opentabs-dev/plugin-sdk';
336
- import type { ToolDefinition } from '@opentabs-dev/plugin-sdk';
337
- import { isAuthenticated, waitForAuth } from './<name>-api.js';
338
- import { sendMessage } from './tools/send-message.js';
339
-
340
- class MyPlugin extends OpenTabsPlugin {
341
- readonly name = '<name>';
342
- readonly description = 'OpenTabs plugin for <DisplayName>';
343
- override readonly displayName = '<DisplayName>';
344
- readonly urlPatterns = ['*://*.example.com/*'];
345
- readonly tools: ToolDefinition[] = [sendMessage];
346
-
347
- async isReady(): Promise<boolean> {
348
- if (isAuthenticated()) return true;
349
- return waitForAuth();
350
- }
351
- }
352
-
353
- export default new MyPlugin();
354
- \`\`\`
355
-
356
- ---
357
-
358
- ## Phase 6: Build and Test
359
-
360
- ### Build
361
-
362
- \`\`\`bash
363
- cd plugins/<name>
364
- npm install
365
- npm run build
366
- \`\`\`
367
-
368
- ### Full Check Suite
369
-
370
- \`\`\`bash
371
- npm run check # build + type-check + lint + format:check
372
- \`\`\`
373
-
374
- **Every command must exit 0.** Fix any failures before proceeding.
375
-
376
- ### Mandatory Tool Verification
377
-
378
- **The plugin is not done until every tool has been called against the live browser.** Tools that have not been verified may have wrong field mappings, broken endpoints, or incorrect response parsing.
379
-
380
- 1. **Verify plugin loaded**: \`plugin_list_tabs(plugin: "<name>")\` — must show \`state: "ready"\`
381
- 2. **Call every read-only tool** (list, get, search) — verify response contains real data with correct field mappings
382
- 3. **Call every write tool** with round-trip tests (create → verify → delete → verify)
383
- 4. **Test error classification** — call a tool with an invalid ID, verify \`ToolError.notFound\` is returned
384
- 5. **Fix every failure** — use \`browser_execute_script\` to inspect raw API responses and fix mappers
385
-
386
- **A plugin with untested tools is worse than a plugin with fewer tools.** Remove tools you cannot verify rather than shipping them broken.
387
-
388
- ---
389
-
390
- ## Key Conventions
391
-
392
- - **One file per tool** in \`src/tools/\`
393
- - **Every Zod field gets \`.describe()\`** — this is what AI agents see in the tool schema
394
- - **\`description\` is for AI clients** — detailed, informative. \`summary\` is for humans — short, under 80 chars
395
- - **Defensive mapping** with fallback defaults (\`data.field ?? ''\`) — never trust API shapes
396
- - **Error classification is critical** — use \`ToolError\` factories, never throw raw errors
397
- - **\`credentials: 'include'\`** on all fetch calls
398
- - **30-second timeout** via \`AbortSignal.timeout(30_000)\`
399
- - **\`.js\` extension** on all imports (ESM requirement)
400
- - **No \`.transform()\`/\`.pipe()\`/\`.preprocess()\`** in Zod schemas (breaks JSON Schema serialization)
401
-
402
- ---
403
-
404
- ## Common Gotchas
405
-
406
- 1. **All plugin code runs in the browser** — no Node.js APIs
407
- 2. **SPAs hydrate asynchronously** — \`isReady()\` must poll (500ms interval, 5s max)
408
- 3. **Some apps delete browser APIs** — use iframe fallback for \`localStorage\`
409
- 4. **Tokens must persist on \`globalThis.__openTabs.tokenCache.<pluginName>\`** — module-level variables reset on extension reload
410
- 5. **HttpOnly cookies are invisible to plugin code** — use \`credentials: 'include'\` for the browser to send them automatically, detect auth status from DOM signals
411
- 6. **Parse error response bodies before classifying by HTTP status** — many apps reuse 403 for both auth and permission errors
412
- 7. **Cross-origin API + cookies: check CORS before choosing fetch strategy**
413
- 8. **Always run \`npm run format\` after writing code** — Biome config uses single quotes
414
- 9. **Adapter injection timing** — adapters are injected at \`loading\` (before page JS runs) and \`complete\` (after full load). \`isReady()\` is called at both points. Cache tokens from localStorage at loading time before the host app deletes them.
415
- 10. **Token persistence on \`globalThis\` survives re-injection** — use \`globalThis.__openTabs.tokenCache.<pluginName>\` to persist auth tokens. Module-level variables reset when the extension reloads. Clear the persisted token on 401 responses to handle token rotation.
416
- 11. **Error classification: parse body before HTTP status** — many apps return JSON error codes in the response body that distinguish auth errors from permission errors. Parse the body first, then fall back to HTTP status classification.
417
- 12. **Cookie-based auth may require CSRF tokens for writes** — apps using HttpOnly session cookies often require a CSRF token header for non-GET requests. The CSRF token is typically in a non-HttpOnly cookie. Check \`window.__initialData.csrfCookieName\` or similar bootstrap globals to discover the cookie name.
418
- 13. **Check bootstrap globals for auth signals** — \`window.__initialData\`, \`window.__INITIAL_STATE__\`, \`window.boot_data\` are more reliable than DOM for auth detection. Inspect these early during exploration.
419
- 14. **Some apps use internal APIs instead of public REST** — the public API may require OAuth2, but the web client uses internal same-origin endpoints with cookie auth. Look for internal endpoints when public API rejects auth.
420
- 15. **Intercepted headers must survive adapter re-injection** — store captured tokens on \`globalThis.__<pluginName>CapturedTokens\`. Re-patch XHR on each adapter load. Avoid stale \`if (installed) return\` guards that skip re-patching after re-injection.
421
- 16. **Trusted Types CSP blocks \`innerHTML\`** — use regex \`html.replace(/<[^>]+>/g, '')\` for HTML-to-text conversion instead. Never use \`innerHTML\`, \`outerHTML\`, or \`insertAdjacentHTML\` in plugin code.
422
- 17. **Opaque auth headers can only be captured, not generated** — some apps use cryptographic tokens computed by obfuscated JS. Capture them from the XHR interceptor and implement a polling wait with timeout for the header to appear.
423
- 18. **When one API path is blocked, find another** — if a write operation requires an undocumented cryptographic payload, don't give up. Explore the web app's internal extension APIs, JavaScript-exposed programmatic interfaces, or other internal endpoints. Complex apps usually expose higher-level APIs for extensions/accessibility. Use \`browser_execute_script\` to enumerate non-standard page globals.
424
- 19. **Web apps expose programmatic extension APIs on the page** — complex web apps often expose internal scripting APIs on \`window\` that provide higher-level operations than raw XHR endpoints. Discovery: use \`browser_execute_script\` with \`Object.keys(window).filter(...)\` to find non-standard globals, then explore their methods.
425
- 20. **Internal API endpoints can be deprecated without warning** — when building plugins for web apps with multiple API generations, test each endpoint independently. If an endpoint returns 404 or 403, it may be deprecated for that account or region. Remove tools that depend on deprecated endpoints rather than shipping broken tools.
426
-
427
- ---
428
-
429
- ## Phase 7: Write Learnings Back (Mandatory)
430
-
431
- Every plugin build surfaces new patterns, gotchas, and techniques. You **must** write them back so the next AI session benefits automatically.
432
-
433
- ### Contribution Checklist
434
-
435
- Review your session and check each item:
436
-
437
- - **Auth extraction pattern** — did you discover a new way to extract tokens (cookie, header interception, window globals, localStorage)? → Add to \`plugin-development.ts\` under "Auth Token Extraction" or "Advanced Auth Patterns"
438
- - **New gotcha encountered** — did you hit an error not in the Common Gotchas list above? If you encountered an error that is not in the Common Gotchas list, ADD IT. → Number it sequentially after the last entry in the gotcha list in \`build-plugin.ts\`
439
- - **API discovery technique** — did you find a new way to discover or enumerate API endpoints (network capture patterns, global inspection, extension APIs)? → Add to Phase 2 of this prompt
440
- - **CORS workaround** — did you work around a CORS issue (proxy, same-origin internal endpoints, cookie forwarding)? → Add to \`troubleshooting.ts\`
441
- - **Zod schema pattern** — did you use a Zod pattern worth documenting (discriminated unions, lazy schemas, transform pipelines, coercion)? → Add to \`plugin-development.ts\` under "Zod Schema Rules"
442
- - **Error handling pattern** — did you handle a non-obvious error (HTML error responses, rate limiting, auth expiry mid-session)? → Add to \`troubleshooting.ts\` or the Common Gotchas list
443
-
444
- ### Invoke the Contribution Workflow
445
-
446
- **Invoke the \`contribute_learnings\` prompt now** with the task description (e.g., \`contribute_learnings(task: "built a plugin for <DisplayName>")\`). That prompt provides the complete self-improvement workflow: which files to edit, the file-to-resource mapping, rules for deduplication, and verification steps.
447
-
448
- The specific files to check when contributing:
449
- - \`platform/mcp-server/src/prompts/build-plugin.ts\` — for workflow improvements and new gotchas
450
- - \`platform/mcp-server/src/resources/plugin-development.ts\` — for patterns, auth techniques, and Zod rules
451
- - \`platform/mcp-server/src/resources/troubleshooting.ts\` — for error resolutions and CORS workarounds
452
-
453
- Do not skip this phase. The source files you edit compile into the MCP resources and prompts this server serves. You are reading this prompt because a previous session wrote or improved it — your additions reach the next agent the same way.`;
454
- };
455
- //# sourceMappingURL=build-plugin.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"build-plugin.js","sourceRoot":"","sources":["../../src/prompts/build-plugin.ts"],"names":[],"mappings":"AAAA,oFAAoF;AAEpF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,GAAW,EAAE,IAAY,EAAU,EAAE;IACzE,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,+BAA+B,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAExE,OAAO,gDAAgD,GAAG,KAAK,UAAU;;;;;;;;6DAQd,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+DAqDD,GAAG;;;;;;4BAMtC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBA+Bf,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iPA+V8N,CAAC;AAClP,CAAC,CAAC"}
@@ -1,12 +0,0 @@
1
- /**
2
- * contribute_learnings prompt — standalone workflow for writing learnings back
3
- * into the MCP server source code after completing any task.
4
- *
5
- * This prompt enables the self-improvement loop: AI agents that complete tasks
6
- * (plugin development, troubleshooting, setup, etc.) write their discoveries
7
- * back into the source files that compile into resources and prompts served
8
- * by this MCP server. Every future AI session then receives those learnings
9
- * automatically.
10
- */
11
- export declare const contributeLearningsPromptText: (task: string) => string;
12
- //# sourceMappingURL=contribute-learnings.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"contribute-learnings.d.ts","sourceRoot":"","sources":["../../src/prompts/contribute-learnings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,eAAO,MAAM,6BAA6B,GAAI,MAAM,MAAM,KAAG,MAgG5D,CAAC"}
@@ -1,107 +0,0 @@
1
- /**
2
- * contribute_learnings prompt — standalone workflow for writing learnings back
3
- * into the MCP server source code after completing any task.
4
- *
5
- * This prompt enables the self-improvement loop: AI agents that complete tasks
6
- * (plugin development, troubleshooting, setup, etc.) write their discoveries
7
- * back into the source files that compile into resources and prompts served
8
- * by this MCP server. Every future AI session then receives those learnings
9
- * automatically.
10
- */
11
- export const contributeLearningsPromptText = (task) => {
12
- const taskClause = task
13
- ? `You just completed a task: "${task}"\n\nReview what you learned and write it back into the appropriate source files.`
14
- : 'Review your recent session for new patterns, gotchas, and techniques, then write them back into the appropriate source files.';
15
- return `${taskClause}
16
-
17
- The embedded \`opentabs://guide/self-improvement\` resource below contains the complete file-to-content mapping, contribution rules, and architecture explanation. Read it first.
18
-
19
- ---
20
-
21
- ## Step 1: Identify What You Learned
22
-
23
- Check your tool call history in this session — failed calls, retries, and workarounds are the richest source of learnings.
24
-
25
- Review your session for:
26
-
27
- - **New patterns** — auth extraction techniques, API discovery methods, Zod schema tricks
28
- - **Gotchas** — things that didn't work as expected, subtle bugs, non-obvious behaviors
29
- - **Resolution steps** — how you fixed an error that isn't documented yet
30
- - **Missing documentation** — things you had to figure out that should have been written down
31
- - **Workflow improvements** — steps that should be added to existing prompts
32
-
33
- ### Session Review Checklist
34
-
35
- - Check your tool call history for failed calls and how you fixed them
36
- - Check for API endpoints you discovered through network capture
37
- - Check for auth patterns that worked (or didn't)
38
- - Check for Zod schema patterns you used
39
- - Check for error messages you encountered and resolved
40
-
41
- If you have not yet called contribute_learnings during this session, do it now — this is your opportunity.
42
-
43
- ---
44
-
45
- ## Step 2: Choose the Right File
46
-
47
- Consult the file-to-content mapping in the embedded \`opentabs://guide/self-improvement\` resource to find the correct source file for your learnings.
48
-
49
- ### Contribution Examples
50
-
51
- **Good contributions** — specific, actionable, reusable:
52
-
53
- \`\`\`
54
- ## Common Gotchas
55
-
56
- 19. **API returns HTML on 500 errors** — wrap response.json() in try-catch and parse the text body for error details when JSON parsing fails.
57
- \`\`\`
58
-
59
- \`\`\`
60
- ### Cookie-Based Auth with CSRF
61
-
62
- Some apps store the CSRF cookie name in window.__initialData.csrfCookieName — check bootstrap globals before hardcoding cookie names.
63
- \`\`\`
64
-
65
- **Bad contributions** — too vague or too app-specific:
66
-
67
- - "Added better error handling" — no actionable information, no one can use this
68
- - "Notion uses space IDs in the format xxx-xxx" — too app-specific, not reusable across plugins
69
-
70
- ---
71
-
72
- ## Step 3: Write the Learnings
73
-
74
- **Rules:**
75
- 1. **Check for duplicates** — read the target file first; scan existing content before adding
76
- 2. **Keep learnings generic** — no app-specific details (e.g., no "Notion uses space IDs")
77
- 3. **Be concise and factual** — write for AI consumption, not human narratives
78
- 4. **Add to the right section** — place gotchas in gotcha lists, patterns in pattern sections
79
- 5. **Preserve existing structure** — match the formatting and style of surrounding content
80
-
81
- When adding a gotcha, number it sequentially after the last existing entry. When adding a pattern, add it to the relevant subsection with a code example.
82
-
83
- ---
84
-
85
- ## Step 4: Verify
86
-
87
- After editing, verify the server builds:
88
-
89
- \`\`\`bash
90
- cd platform/mcp-server && npm run build
91
- \`\`\`
92
-
93
- The build must succeed. If it fails, fix the issue before committing.
94
-
95
- ---
96
-
97
- ## Step 5: Do NOT Write to Local Files
98
-
99
- Write learnings ONLY to the TypeScript source files listed in the self-improvement guide. Do NOT write to:
100
- - Local markdown files or skill files
101
- - \`CLAUDE.md\` files (those are for platform contributors, not MCP-served content)
102
- - Documentation site (\`docs/\`) — that's for humans, not AI agents
103
- - Temporary files or scratch notes
104
-
105
- The reason: only the source files in \`platform/mcp-server/src/\` compile into MCP content. Anything written elsewhere is invisible to future AI sessions.`;
106
- };
107
- //# sourceMappingURL=contribute-learnings.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"contribute-learnings.js","sourceRoot":"","sources":["../../src/prompts/contribute-learnings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,IAAY,EAAU,EAAE;IACpE,MAAM,UAAU,GAAG,IAAI;QACrB,CAAC,CAAC,+BAA+B,IAAI,mFAAmF;QACxH,CAAC,CAAC,+HAA+H,CAAC;IAEpI,OAAO,GAAG,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2JA0FqI,CAAC;AAC5J,CAAC,CAAC"}
@@ -1,5 +0,0 @@
1
- /**
2
- * plugin_icon prompt — workflow for adding or updating an SVG icon for an OpenTabs plugin.
3
- */
4
- export declare const pluginIconPromptText: (plugin: string) => string;
5
- //# sourceMappingURL=plugin-icon.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugin-icon.d.ts","sourceRoot":"","sources":["../../src/prompts/plugin-icon.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,MAAM,KACb,MA8IwJ,CAAC"}