@mcp-fe/mcp-worker 0.1.2 → 0.1.4

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.
@@ -160,12 +160,110 @@ public async handleRegisterTool(toolData: Record<string, unknown>) {
160
160
 
161
161
  1. **MCP Client** calls tool via MCP protocol
162
162
  2. **Worker** receives MCP tool call
163
- 3. **Worker** sends `CALL_TOOL` message to main thread
164
- 4. **Main Thread** executes handler function
163
+ 3. **Worker** sends `CALL_TOOL` message to main thread (with targetTabId if specified)
164
+ 4. **Main Thread** (specific tab) executes handler function
165
165
  5. **Main Thread** sends `TOOL_CALL_RESULT` back
166
166
  6. **Worker** resolves promise and returns to MCP
167
167
  7. **MCP Client** receives result
168
168
 
169
+ ## Multi-Tab Support
170
+
171
+ ### Architecture
172
+
173
+ The library supports multiple browser tabs running the same application, with intelligent routing of tool calls:
174
+
175
+ ```
176
+ ┌─────────────────────┐
177
+ │ MCP Client │
178
+ │ (Claude, etc.) │
179
+ └──────────┬──────────┘
180
+ │ MCP Protocol (with optional tabId param)
181
+
182
+ ┌─────────────────────┐
183
+ │ Shared Worker │
184
+ │ │
185
+ │ Tab Registry │
186
+ │ ├─ Tab 1 (active) │
187
+ │ ├─ Tab 2 │
188
+ │ └─ Tab 3 │
189
+ │ │
190
+ │ Tool Registry │
191
+ │ └─ get_page_info │
192
+ │ ├─ Tab 1 ✓ │ ← Hybrid routing logic
193
+ │ └─ Tab 2 ✓ │
194
+ └──────────┬──────────┘
195
+ │ Route to specific tab or active tab
196
+
197
+ ┌─────────────────────┐
198
+ │ Main Threads │
199
+ │ ├─ Tab 1 (active) │ ← Focused/visible tab
200
+ │ └─ Tab 2 │
201
+ └─────────────────────┘
202
+ ```
203
+
204
+ ### Tab Management
205
+
206
+ **Automatic Tab Registration:**
207
+ - Each tab gets unique ID via `crypto.randomUUID()`
208
+ - Stored in `sessionStorage` (persists across refreshes)
209
+ - Registered with worker on init
210
+
211
+ **Focus Tracking:**
212
+ - Active tab tracked via `window.focus` and `document.visibilitychange`
213
+ - Worker's `TabManager` is the single source of truth for `activeTabId`
214
+ - Use `list_browser_tabs` tool to query which tab is currently active
215
+
216
+ ### Hybrid Routing Strategy
217
+
218
+ When a tool is called, the worker uses this intelligent logic:
219
+
220
+ 1. **Explicit `tabId` parameter**: Route to specified tab (always respected)
221
+ 2. **Only one tab has tool**: Route to that tab automatically (even if not active) ⭐
222
+ 3. **Active tab has tool**: Route to focused tab (user is likely working there)
223
+ 4. **Active tab lacks tool**: Route to first available tab with the tool
224
+ 5. **No active tab**: Route to first available tab (fallback)
225
+
226
+ **Example:**
227
+ ```typescript
228
+ // Scenario: Tab A (inactive) has toolX, Tab B (active) doesn't
229
+
230
+ // Agent calls without tabId
231
+ get_page_info()
232
+ // → Routes to Tab A automatically (only tab with the tool)
233
+ // User doesn't get an error, tool "just works"
234
+
235
+ // Agent discovers tabs first
236
+ list_browser_tabs()
237
+ // → [{ tabId: "abc-123", title: "Dashboard", isActive: false }, ...]
238
+
239
+ // Agent targets specific tab
240
+ get_page_info({ tabId: "abc-123" })
241
+ // → Routes to Dashboard tab precisely
242
+ ```
243
+
244
+ ### Tool Schema Enhancement
245
+
246
+ All tools automatically get optional `tabId` parameter:
247
+
248
+ ```json
249
+ {
250
+ "type": "object",
251
+ "properties": {
252
+ // ... your properties ...
253
+ "tabId": {
254
+ "type": "string",
255
+ "description": "Optional: Target specific tab by ID. If not provided, uses the currently focused tab."
256
+ }
257
+ }
258
+ }
259
+ ```
260
+
261
+ ### Built-in Meta Tools
262
+
263
+ **`list_browser_tabs`**: Discover available tabs
264
+ - Returns tab IDs, URLs, titles, active status
265
+ - Use before calling tools with specific tabIds
266
+
169
267
  ## Why This Works
170
268
 
171
269
  - **Worker**: Runs 24/7, maintains MCP connection
package/docs/guide.md CHANGED
@@ -409,6 +409,128 @@ function MyComponent() {
409
409
 
410
410
  See [React Hooks Guide](../../react-event-tracker/REACT_MCP_TOOLS.md) for details.
411
411
 
412
+ ## Multi-Tab Applications
413
+
414
+ The library automatically handles multiple browser tabs with intelligent routing.
415
+
416
+ ### How It Works
417
+
418
+ Each tab gets a unique ID (via `crypto.randomUUID()`) stored in `sessionStorage`. Tools are registered per-tab, and the worker routes calls intelligently.
419
+
420
+ ### Automatic Routing (Smart Strategy)
421
+
422
+ **Without `tabId` parameter**: Intelligently routes based on availability and focus
423
+
424
+ ```typescript
425
+ // In any tab
426
+ await workerClient.registerTool(
427
+ 'get_page_url',
428
+ 'Get current page URL',
429
+ { type: 'object', properties: {} },
430
+ async () => ({
431
+ content: [{
432
+ type: 'text',
433
+ text: window.location.href
434
+ }]
435
+ })
436
+ );
437
+
438
+ // Scenario 1: Only one tab has the tool
439
+ // Tab A: Has get_page_url
440
+ // Tab B: Doesn't have get_page_url (active)
441
+ get_page_url()
442
+ // → Automatically routes to Tab A (even though Tab B is active!)
443
+ // No error, tool "just works"
444
+
445
+ // Scenario 2: Multiple tabs have the tool
446
+ // Tab A: Has get_page_url
447
+ // Tab B: Has get_page_url (active)
448
+ get_page_url()
449
+ // → Routes to Tab B (active tab preferred when multiple available)
450
+ ```
451
+
452
+ **With `tabId` parameter**: Routes to specific tab precisely
453
+
454
+ ```typescript
455
+ // First, discover available tabs
456
+ list_browser_tabs()
457
+ // → [
458
+ // { tabId: "abc-123", url: "/dashboard", title: "Dashboard", isActive: true },
459
+ // { tabId: "def-456", url: "/settings", title: "Settings", isActive: false }
460
+ // ]
461
+
462
+ // Then target a specific tab
463
+ get_page_url({ tabId: "def-456" })
464
+ // → Routes to Settings tab specifically
465
+ ```
466
+
467
+ ### Built-in Meta Tool
468
+
469
+ **`list_browser_tabs`**: Always available, lists all active tabs
470
+
471
+ ```typescript
472
+ // Returns array of:
473
+ {
474
+ tabId: string; // Unique tab identifier
475
+ url: string; // Current URL
476
+ title: string; // Page title
477
+ isActive: boolean; // Is this the focused tab?
478
+ lastSeen: string; // ISO timestamp of last activity
479
+ }
480
+ ```
481
+
482
+ ### Reference Counting
483
+
484
+ When multiple tabs register the same tool:
485
+ - Tool is registered once with MCP
486
+ - Worker tracks all tabs that have the tool
487
+ - Unregistration happens when last tab unmounts
488
+ - Handler is always from the target tab's context
489
+
490
+ ### Tab Persistence
491
+
492
+ Tab IDs persist across page refreshes (stored in `sessionStorage`):
493
+ - Same tab keeps same ID after F5
494
+ - Duplicate tab (Ctrl+K) gets new ID
495
+ - New tab/window gets new ID
496
+
497
+ ### Use Cases
498
+
499
+ **1. Compare data across tabs:**
500
+ ```typescript
501
+ // Get state from multiple tabs
502
+ const dashboardState = await get_react_state({ tabId: "tab-1" });
503
+ const settingsState = await get_react_state({ tabId: "tab-2" });
504
+ ```
505
+
506
+ **2. Debug specific tab:**
507
+ ```typescript
508
+ // Agent: "Show me the state of the Settings tab"
509
+ list_browser_tabs()
510
+ // Find tabId for Settings
511
+ get_react_state({ tabId: "settings-tab-id" })
512
+ ```
513
+
514
+ **3. Focus-driven interaction:**
515
+ ```typescript
516
+ // Agent: "What's on the current page?"
517
+ get_page_info() // No tabId needed - uses focused tab
518
+ ```
519
+
520
+ ### Debugging Multi-Tab
521
+
522
+ ```typescript
523
+ import { workerClient } from '@mcp-fe/mcp-worker';
524
+
525
+ // Get current tab info
526
+ console.log(workerClient.getTabInfo());
527
+ // → { tabId: "abc-123", url: "/dashboard", title: "Dashboard" }
528
+
529
+ // Clear and regenerate tab ID (for testing)
530
+ WorkerClient.clearTabId();
531
+ // Refresh page to get new ID
532
+ ```
533
+
412
534
  ## Troubleshooting
413
535
 
414
536
  ### Tool doesn't register
package/docs/index.md CHANGED
@@ -10,6 +10,7 @@ Complete guide to all documentation and examples in the MCP Worker library.
10
10
  | **See advanced patterns** | [examples/dynamic-tools.ts](../examples/dynamic-tools.ts) |
11
11
  | **Learn step-by-step** | [Guide](./guide.md) |
12
12
  | **Complete API reference** | [API Reference](./api.md) |
13
+ | **Multi-tab applications** | [Multi-Tab Guide](./multi-tab.md) |
13
14
  | **Worker implementation** | [Worker Details](./worker-details.md) |
14
15
  | **Use with React** | [React Hooks Guide](../../react-event-tracker/REACT_MCP_TOOLS.md) |
15
16
  | **Understand architecture** | [Architecture](./architecture.md) |
@@ -25,6 +26,7 @@ libs/mcp-worker/
25
26
  │ ├── index.md ← This file
26
27
  │ ├── guide.md ← Complete guide
27
28
  │ ├── api.md ← API reference
29
+ │ ├── multi-tab.md ← Multi-tab support
28
30
  │ ├── worker-details.md ← Worker implementation
29
31
  │ ├── architecture.md ← Technical architecture
30
32
  │ └── initialization.md ← Init handling
@@ -79,6 +81,12 @@ libs/react-event-tracker/
79
81
  ### "How does the proxy pattern work?"
80
82
  → [Architecture](./architecture.md)
81
83
 
84
+ ### "How do I handle multiple tabs?"
85
+ → [Multi-Tab Guide](./multi-tab.md)
86
+
87
+ ### "What tools are built-in?"
88
+ → [Multi-Tab Guide](./multi-tab.md#built-in-meta-tool) (list_browser_tabs)
89
+
82
90
  ### "How do I handle initialization?"
83
91
  → [Initialization](./initialization.md)
84
92