@mcp-fe/mcp-worker 0.1.11 → 0.2.2
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.
- package/LICENSE +27 -29
- package/docs/index.md +1 -0
- package/docs/multi-tab.md +637 -637
- package/docs/native-webmcp.md +232 -0
- package/docs/project-structure.md +172 -172
- package/docs/tab-manager.md +150 -150
- package/index.js +356 -59
- package/mcp-service-worker.js +43 -2
- package/mcp-shared-worker.js +43 -2
- package/package.json +1 -1
- package/src/client/index.d.ts +2 -0
- package/src/client/index.d.ts.map +1 -1
- package/src/client/web-mcp-adapter.d.ts +97 -0
- package/src/client/web-mcp-adapter.d.ts.map +1 -0
- package/src/client/web-mcp-types.d.ts +122 -0
- package/src/client/web-mcp-types.d.ts.map +1 -0
- package/src/client/worker-client.d.ts +31 -0
- package/src/client/worker-client.d.ts.map +1 -1
- package/src/worker/mcp-controller.d.ts +5 -0
- package/src/worker/mcp-controller.d.ts.map +1 -1
package/docs/tab-manager.md
CHANGED
|
@@ -1,150 +1,150 @@
|
|
|
1
|
-
# TabManager
|
|
2
|
-
|
|
3
|
-
Manages browser tabs and tool registration routing.
|
|
4
|
-
|
|
5
|
-
## API
|
|
6
|
-
|
|
7
|
-
### Tab Management
|
|
8
|
-
|
|
9
|
-
```typescript
|
|
10
|
-
// Register tab
|
|
11
|
-
tabManager.registerTab(tabId, url, title);
|
|
12
|
-
|
|
13
|
-
// Set active tab
|
|
14
|
-
tabManager.setActiveTab(tabId);
|
|
15
|
-
|
|
16
|
-
// Get active tab
|
|
17
|
-
const activeId = tabManager.getActiveTabId(); // → string | null
|
|
18
|
-
|
|
19
|
-
// Get all tabs
|
|
20
|
-
const tabs = tabManager.getAllTabs(); // → TabInfo[]
|
|
21
|
-
|
|
22
|
-
// Remove tab
|
|
23
|
-
tabManager.removeTab(tabId); // → boolean
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Tool Registration
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
// Register tool for tab
|
|
30
|
-
const isNew = tabManager.registerToolForTab(toolName, tabId);
|
|
31
|
-
|
|
32
|
-
// Unregister tool from tab
|
|
33
|
-
const result = tabManager.unregisterToolFromTab(toolName, tabId);
|
|
34
|
-
// → { wasRemoved, remainingTabs, wasActiveTab }
|
|
35
|
-
|
|
36
|
-
// Get tabs with tool
|
|
37
|
-
const tabs = tabManager.getTabsForTool(toolName); // → Set<string>
|
|
38
|
-
|
|
39
|
-
// Check if tab has tool
|
|
40
|
-
const has = tabManager.tabHasTool(toolName, tabId); // → boolean
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### Smart Routing
|
|
44
|
-
|
|
45
|
-
```typescript
|
|
46
|
-
const route = tabManager.routeToolCall(toolName, explicitTabId?);
|
|
47
|
-
// → { targetTabId: string, reason: string } | null
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
**Priority:**
|
|
51
|
-
1. Explicit `tabId` (if valid)
|
|
52
|
-
2. Only one tab has tool → use it
|
|
53
|
-
3. Active tab has tool → use it
|
|
54
|
-
4. Use first available
|
|
55
|
-
|
|
56
|
-
### Diagnostics
|
|
57
|
-
|
|
58
|
-
```typescript
|
|
59
|
-
// Debug routing
|
|
60
|
-
const info = tabManager.getRoutingInfo(toolName);
|
|
61
|
-
|
|
62
|
-
// Get stats
|
|
63
|
-
const stats = tabManager.getStats();
|
|
64
|
-
|
|
65
|
-
// Clear all (testing)
|
|
66
|
-
tabManager.clear();
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Usage
|
|
70
|
-
|
|
71
|
-
```typescript
|
|
72
|
-
import { TabManager } from '@mcp-fe/mcp-worker';
|
|
73
|
-
|
|
74
|
-
const tabs = new TabManager();
|
|
75
|
-
|
|
76
|
-
// Register tabs
|
|
77
|
-
tabs.registerTab('tab-1', '/dashboard', 'Dashboard');
|
|
78
|
-
tabs.registerTab('tab-2', '/settings', 'Settings');
|
|
79
|
-
|
|
80
|
-
// Register tools
|
|
81
|
-
tabs.registerToolForTab('get_data', 'tab-1');
|
|
82
|
-
tabs.registerToolForTab('get_data', 'tab-2');
|
|
83
|
-
|
|
84
|
-
// Set active
|
|
85
|
-
tabs.setActiveTab('tab-1');
|
|
86
|
-
|
|
87
|
-
// Route
|
|
88
|
-
const route = tabs.routeToolCall('get_data');
|
|
89
|
-
// → { targetTabId: 'tab-1', reason: 'active tab has tool' }
|
|
90
|
-
|
|
91
|
-
// Route to specific tab
|
|
92
|
-
const route2 = tabs.routeToolCall('get_data', 'tab-2');
|
|
93
|
-
// → { targetTabId: 'tab-2', reason: 'explicit tabId parameter' }
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## Integration
|
|
97
|
-
|
|
98
|
-
MCPController uses TabManager internally:
|
|
99
|
-
|
|
100
|
-
```typescript
|
|
101
|
-
class MCPController {
|
|
102
|
-
private tabManager = new TabManager();
|
|
103
|
-
|
|
104
|
-
handleRegisterTab(data) {
|
|
105
|
-
this.tabManager.registerTab(data.tabId, data.url, data.title);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
async handleRegisterToolInternal(toolData) {
|
|
109
|
-
const isNew = this.tabManager.registerToolForTab(toolData.name, toolData.tabId);
|
|
110
|
-
|
|
111
|
-
if (!isNew) return;
|
|
112
|
-
|
|
113
|
-
// Create handler with routing
|
|
114
|
-
const handler = async (args) => {
|
|
115
|
-
const route = this.tabManager.routeToolCall(toolData.name, args.tabId);
|
|
116
|
-
if (!route) throw new Error('Tool not available');
|
|
117
|
-
|
|
118
|
-
return this.sendToolCall(route.targetTabId, args);
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
toolRegistry.register({ name: toolData.name }, handler);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
## Why Separate Class?
|
|
127
|
-
|
|
128
|
-
- **Separation of Concerns**: Tab logic separate from MCP protocol
|
|
129
|
-
- **Testable**: Easy to unit test without MCP dependencies
|
|
130
|
-
- **Reusable**: Can be used in other contexts
|
|
131
|
-
- **Type Safe**: Strong typing throughout
|
|
132
|
-
|
|
133
|
-
```typescript
|
|
134
|
-
// Example test
|
|
135
|
-
test('routes to only available tab', () => {
|
|
136
|
-
const tabs = new TabManager();
|
|
137
|
-
tabs.registerTab('tab-1', '/page', 'Page');
|
|
138
|
-
tabs.registerTab('tab-2', '/page', 'Page');
|
|
139
|
-
tabs.registerToolForTab('tool', 'tab-1');
|
|
140
|
-
tabs.setActiveTab('tab-2'); // Active tab doesn't have tool
|
|
141
|
-
|
|
142
|
-
const route = tabs.routeToolCall('tool');
|
|
143
|
-
expect(route.targetTabId).toBe('tab-1');
|
|
144
|
-
});
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## See Also
|
|
148
|
-
|
|
149
|
-
- [Multi-Tab Guide](./multi-tab.md) - Complete multi-tab docs
|
|
150
|
-
- [Architecture](./architecture.md) - System architecture
|
|
1
|
+
# TabManager
|
|
2
|
+
|
|
3
|
+
Manages browser tabs and tool registration routing.
|
|
4
|
+
|
|
5
|
+
## API
|
|
6
|
+
|
|
7
|
+
### Tab Management
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// Register tab
|
|
11
|
+
tabManager.registerTab(tabId, url, title);
|
|
12
|
+
|
|
13
|
+
// Set active tab
|
|
14
|
+
tabManager.setActiveTab(tabId);
|
|
15
|
+
|
|
16
|
+
// Get active tab
|
|
17
|
+
const activeId = tabManager.getActiveTabId(); // → string | null
|
|
18
|
+
|
|
19
|
+
// Get all tabs
|
|
20
|
+
const tabs = tabManager.getAllTabs(); // → TabInfo[]
|
|
21
|
+
|
|
22
|
+
// Remove tab
|
|
23
|
+
tabManager.removeTab(tabId); // → boolean
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Tool Registration
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
// Register tool for tab
|
|
30
|
+
const isNew = tabManager.registerToolForTab(toolName, tabId);
|
|
31
|
+
|
|
32
|
+
// Unregister tool from tab
|
|
33
|
+
const result = tabManager.unregisterToolFromTab(toolName, tabId);
|
|
34
|
+
// → { wasRemoved, remainingTabs, wasActiveTab }
|
|
35
|
+
|
|
36
|
+
// Get tabs with tool
|
|
37
|
+
const tabs = tabManager.getTabsForTool(toolName); // → Set<string>
|
|
38
|
+
|
|
39
|
+
// Check if tab has tool
|
|
40
|
+
const has = tabManager.tabHasTool(toolName, tabId); // → boolean
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Smart Routing
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
const route = tabManager.routeToolCall(toolName, explicitTabId?);
|
|
47
|
+
// → { targetTabId: string, reason: string } | null
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Priority:**
|
|
51
|
+
1. Explicit `tabId` (if valid)
|
|
52
|
+
2. Only one tab has tool → use it
|
|
53
|
+
3. Active tab has tool → use it
|
|
54
|
+
4. Use first available
|
|
55
|
+
|
|
56
|
+
### Diagnostics
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
// Debug routing
|
|
60
|
+
const info = tabManager.getRoutingInfo(toolName);
|
|
61
|
+
|
|
62
|
+
// Get stats
|
|
63
|
+
const stats = tabManager.getStats();
|
|
64
|
+
|
|
65
|
+
// Clear all (testing)
|
|
66
|
+
tabManager.clear();
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Usage
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { TabManager } from '@mcp-fe/mcp-worker';
|
|
73
|
+
|
|
74
|
+
const tabs = new TabManager();
|
|
75
|
+
|
|
76
|
+
// Register tabs
|
|
77
|
+
tabs.registerTab('tab-1', '/dashboard', 'Dashboard');
|
|
78
|
+
tabs.registerTab('tab-2', '/settings', 'Settings');
|
|
79
|
+
|
|
80
|
+
// Register tools
|
|
81
|
+
tabs.registerToolForTab('get_data', 'tab-1');
|
|
82
|
+
tabs.registerToolForTab('get_data', 'tab-2');
|
|
83
|
+
|
|
84
|
+
// Set active
|
|
85
|
+
tabs.setActiveTab('tab-1');
|
|
86
|
+
|
|
87
|
+
// Route
|
|
88
|
+
const route = tabs.routeToolCall('get_data');
|
|
89
|
+
// → { targetTabId: 'tab-1', reason: 'active tab has tool' }
|
|
90
|
+
|
|
91
|
+
// Route to specific tab
|
|
92
|
+
const route2 = tabs.routeToolCall('get_data', 'tab-2');
|
|
93
|
+
// → { targetTabId: 'tab-2', reason: 'explicit tabId parameter' }
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Integration
|
|
97
|
+
|
|
98
|
+
MCPController uses TabManager internally:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
class MCPController {
|
|
102
|
+
private tabManager = new TabManager();
|
|
103
|
+
|
|
104
|
+
handleRegisterTab(data) {
|
|
105
|
+
this.tabManager.registerTab(data.tabId, data.url, data.title);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async handleRegisterToolInternal(toolData) {
|
|
109
|
+
const isNew = this.tabManager.registerToolForTab(toolData.name, toolData.tabId);
|
|
110
|
+
|
|
111
|
+
if (!isNew) return;
|
|
112
|
+
|
|
113
|
+
// Create handler with routing
|
|
114
|
+
const handler = async (args) => {
|
|
115
|
+
const route = this.tabManager.routeToolCall(toolData.name, args.tabId);
|
|
116
|
+
if (!route) throw new Error('Tool not available');
|
|
117
|
+
|
|
118
|
+
return this.sendToolCall(route.targetTabId, args);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
toolRegistry.register({ name: toolData.name }, handler);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Why Separate Class?
|
|
127
|
+
|
|
128
|
+
- **Separation of Concerns**: Tab logic separate from MCP protocol
|
|
129
|
+
- **Testable**: Easy to unit test without MCP dependencies
|
|
130
|
+
- **Reusable**: Can be used in other contexts
|
|
131
|
+
- **Type Safe**: Strong typing throughout
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
// Example test
|
|
135
|
+
test('routes to only available tab', () => {
|
|
136
|
+
const tabs = new TabManager();
|
|
137
|
+
tabs.registerTab('tab-1', '/page', 'Page');
|
|
138
|
+
tabs.registerTab('tab-2', '/page', 'Page');
|
|
139
|
+
tabs.registerToolForTab('tool', 'tab-1');
|
|
140
|
+
tabs.setActiveTab('tab-2'); // Active tab doesn't have tool
|
|
141
|
+
|
|
142
|
+
const route = tabs.routeToolCall('tool');
|
|
143
|
+
expect(route.targetTabId).toBe('tab-1');
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## See Also
|
|
148
|
+
|
|
149
|
+
- [Multi-Tab Guide](./multi-tab.md) - Complete multi-tab docs
|
|
150
|
+
- [Architecture](./architecture.md) - System architecture
|