@mcp-fe/mcp-worker 0.1.7 → 0.1.9

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 (46) hide show
  1. package/README.md +26 -0
  2. package/docs/index.md +15 -4
  3. package/docs/initialization.md +2 -2
  4. package/docs/project-structure.md +172 -0
  5. package/index.js +45 -251
  6. package/mcp-service-worker.js +526 -7468
  7. package/mcp-shared-worker.js +528 -7470
  8. package/package.json +1 -1
  9. package/src/client/index.d.ts +10 -0
  10. package/src/client/index.d.ts.map +1 -0
  11. package/src/{lib → client}/worker-client.d.ts +8 -0
  12. package/src/client/worker-client.d.ts.map +1 -0
  13. package/src/index.d.ts +3 -7
  14. package/src/index.d.ts.map +1 -1
  15. package/src/shared/database.d.ts +8 -0
  16. package/src/shared/database.d.ts.map +1 -0
  17. package/src/shared/logger.d.ts.map +1 -0
  18. package/src/{lib/tool-registry.d.ts → shared/types.d.ts} +27 -13
  19. package/src/shared/types.d.ts.map +1 -0
  20. package/src/worker/built-in-tools.d.ts.map +1 -0
  21. package/src/worker/index.d.ts +12 -0
  22. package/src/worker/index.d.ts.map +1 -0
  23. package/src/{lib → worker}/mcp-controller.d.ts +2 -1
  24. package/src/worker/mcp-controller.d.ts.map +1 -0
  25. package/src/worker/mcp-server.d.ts.map +1 -0
  26. package/src/{lib → worker}/tab-manager.d.ts +2 -5
  27. package/src/worker/tab-manager.d.ts.map +1 -0
  28. package/src/worker/tool-registry.d.ts +17 -0
  29. package/src/worker/tool-registry.d.ts.map +1 -0
  30. package/src/worker/validation.d.ts +31 -0
  31. package/src/worker/validation.d.ts.map +1 -0
  32. package/src/worker/websocket-transport.d.ts.map +1 -0
  33. package/src/lib/built-in-tools.d.ts.map +0 -1
  34. package/src/lib/database.d.ts +0 -27
  35. package/src/lib/database.d.ts.map +0 -1
  36. package/src/lib/logger.d.ts.map +0 -1
  37. package/src/lib/mcp-controller.d.ts.map +0 -1
  38. package/src/lib/mcp-server.d.ts.map +0 -1
  39. package/src/lib/tab-manager.d.ts.map +0 -1
  40. package/src/lib/tool-registry.d.ts.map +0 -1
  41. package/src/lib/websocket-transport.d.ts.map +0 -1
  42. package/src/lib/worker-client.d.ts.map +0 -1
  43. /package/src/{lib → shared}/logger.d.ts +0 -0
  44. /package/src/{lib → worker}/built-in-tools.d.ts +0 -0
  45. /package/src/{lib → worker}/mcp-server.d.ts +0 -0
  46. /package/src/{lib → worker}/websocket-transport.d.ts +0 -0
package/README.md CHANGED
@@ -67,6 +67,31 @@ Frontend App ←→ WorkerClient ←→ Web Worker ←→ WebSocket ←→ MCP P
67
67
  5. **MCP Proxy** - Bridges browser with AI agents
68
68
  6. **AI Agent** - Queries your app via MCP protocol
69
69
 
70
+ ### Project Structure
71
+
72
+ The library is organized into three main directories:
73
+
74
+ ```
75
+ libs/mcp-worker/src/
76
+ ├── client/ # Client-side code (application runtime)
77
+ │ ├── worker-client.ts # Main WorkerClient class
78
+ │ └── index.ts # Client API exports
79
+ ├── worker/ # Worker-side code (background processing)
80
+ │ ├── mcp-controller.ts # MCP server controller
81
+ │ ├── mcp-server.ts # MCP server setup
82
+ │ ├── tab-manager.ts # Multi-tab coordination
83
+ │ ├── tool-registry.ts # Dynamic tool management
84
+ │ └── built-in-tools.ts # Default MCP tools
85
+ └── shared/ # Shared code (both contexts)
86
+ ├── types.ts # TypeScript type definitions
87
+ ├── logger.ts # Logging utilities
88
+ └── database.ts # IndexedDB operations
89
+ ```
90
+
91
+ **Entry points:**
92
+ - `mcp-shared-worker.ts` - SharedWorker implementation (preferred)
93
+ - `mcp-service-worker.ts` - ServiceWorker fallback
94
+
70
95
  ## Quick Start
71
96
 
72
97
  ### Installation
@@ -130,6 +155,7 @@ await workerClient.registerTool(
130
155
 
131
156
  - **[Quick Start Guide](./docs/guide.md)** - Complete guide to dynamic tool registration
132
157
  - **[API Reference](./docs/api.md)** - Full API documentation
158
+ - **[Project Structure](./docs/project-structure.md)** - Codebase organization explained
133
159
  - **[Worker Details](./docs/worker-details.md)** - Implementation details
134
160
  - **[Architecture](./docs/architecture.md)** - How the proxy pattern works
135
161
  - **[Initialization](./docs/initialization.md)** - Init queue handling
package/docs/index.md CHANGED
@@ -12,6 +12,7 @@ Complete guide to all documentation and examples in the MCP Worker library.
12
12
  | **Complete API reference** | [API Reference](./api.md) |
13
13
  | **Multi-tab applications** | [Multi-Tab Guide](./multi-tab.md) |
14
14
  | **Worker implementation** | [Worker Details](./worker-details.md) |
15
+ | **Understand codebase structure** | [Project Structure](./project-structure.md) |
15
16
  | **Use with React** | [React Hooks Guide](../../react-event-tracker/REACT_MCP_TOOLS.md) |
16
17
  | **Understand architecture** | [Architecture](./architecture.md) |
17
18
  | **Handle initialization** | [Initialization](./initialization.md) |
@@ -29,16 +30,26 @@ libs/mcp-worker/
29
30
  │ ├── multi-tab.md ← Multi-tab support
30
31
  │ ├── worker-details.md ← Worker implementation
31
32
  │ ├── architecture.md ← Technical architecture
32
- └── initialization.md ← Init handling
33
+ ├── initialization.md ← Init handling
34
+ │ ├── project-structure.md ← Codebase organization
35
+ │ └── tab-manager.md ← Tab management
33
36
 
34
37
  ├── examples/ ← Code examples
35
38
  │ ├── README.md ← Examples guide
36
39
  │ ├── quick-start.ts ← Simple examples
37
- └── dynamic-tools.ts ← Advanced patterns
40
+ ├── dynamic-tools.ts ← Advanced patterns
41
+ │ └── structured-output.ts ← Structured outputs
38
42
 
39
43
  └── src/ ← Source code
40
- └── lib/
41
- └── worker-client.ts
44
+ ├── client/ ← Application runtime
45
+ └── worker-client.ts
46
+ ├── worker/ ← Worker implementation
47
+ │ ├── mcp-controller.ts
48
+ │ └── ...
49
+ └── shared/ ← Shared utilities
50
+ ├── types.ts
51
+ ├── logger.ts
52
+ └── database.ts
42
53
 
43
54
  libs/react-event-tracker/
44
55
  ├── REACT_MCP_TOOLS.md ← React hooks docs
@@ -182,7 +182,7 @@ For contributors:
182
182
  - Queues are processed in order (FIFO)
183
183
 
184
184
  See source code for implementation details:
185
- - `libs/mcp-worker/src/lib/worker-client.ts`
186
- - `libs/mcp-worker/src/lib/mcp-controller.ts`
185
+ - `libs/mcp-worker/src/client/worker-client.ts`
186
+ - `libs/mcp-worker/src/worker/mcp-controller.ts`
187
187
 
188
188
 
@@ -0,0 +1,172 @@
1
+ # Project Structure
2
+
3
+ This document explains the organization of the `@mcp-fe/mcp-worker` codebase.
4
+
5
+ ## Directory Layout
6
+
7
+ ```
8
+ libs/mcp-worker/src/
9
+ ├── index.ts # Main entry point (re-exports from client/)
10
+ ├── mcp-shared-worker.ts # SharedWorker entry point
11
+ ├── mcp-service-worker.ts # ServiceWorker entry point
12
+ ├── client/ # Client-side code (application runtime)
13
+ │ ├── index.ts # Client API exports
14
+ │ └── worker-client.ts # Main WorkerClient class
15
+ ├── worker/ # Worker-side code (background processing)
16
+ │ ├── index.ts # Worker internal exports
17
+ │ ├── mcp-controller.ts # MCP server controller & lifecycle
18
+ │ ├── mcp-server.ts # MCP server setup & handlers
19
+ │ ├── websocket-transport.ts # WebSocket transport for MCP
20
+ │ ├── tool-registry.ts # Dynamic tool registration
21
+ │ ├── tab-manager.ts # Multi-tab coordination
22
+ │ ├── built-in-tools.ts # Default MCP tools
23
+ │ └── tab-manager.spec.ts # Tests for TabManager
24
+ └── shared/ # Shared code (both contexts)
25
+ ├── types.ts # TypeScript type definitions
26
+ ├── logger.ts # Logging utilities
27
+ └── database.ts # IndexedDB operations
28
+ ```
29
+
30
+ ## Module Responsibilities
31
+
32
+ ### Client (`client/`)
33
+
34
+ **Purpose:** Code that runs in the main browser thread (your application).
35
+
36
+ **Key Files:**
37
+ - `worker-client.ts` - Main API for communicating with workers
38
+ - Handles worker initialization (SharedWorker vs ServiceWorker)
39
+ - Manages tool registration and lifecycle
40
+ - Handles multi-tab coordination
41
+ - Provides request/response messaging
42
+
43
+ **Used by:** Your application code
44
+
45
+ **Example:**
46
+ ```typescript
47
+ import { workerClient } from '@mcp-fe/mcp-worker';
48
+ await workerClient.init();
49
+ ```
50
+
51
+ ### Worker (`worker/`)
52
+
53
+ **Purpose:** Code that runs inside Web Workers (background processing).
54
+
55
+ **Key Files:**
56
+ - `mcp-controller.ts` - Main controller for MCP server lifecycle
57
+ - WebSocket connection management
58
+ - Tool call routing and execution
59
+ - Tab management coordination
60
+ - Event storage and querying
61
+
62
+ - `mcp-server.ts` - MCP server setup using @modelcontextprotocol/sdk
63
+ - Request handlers (ListTools, CallTool)
64
+ - Server configuration and capabilities
65
+
66
+ - `tool-registry.ts` - Dynamic tool management
67
+ - Tool definition storage
68
+ - Handler registration and lookup
69
+ - Tool lifecycle management
70
+
71
+ - `tab-manager.ts` - Multi-tab coordination
72
+ - Tab registration and tracking
73
+ - Active tab management
74
+ - Smart tool routing across tabs
75
+
76
+ - `built-in-tools.ts` - Default MCP tools
77
+ - Event querying tools
78
+ - Tab listing tools
79
+ - Navigation history tools
80
+
81
+ **Used by:** Worker entry points (`mcp-shared-worker.ts`, `mcp-service-worker.ts`)
82
+
83
+ ### Shared (`shared/`)
84
+
85
+ **Purpose:** Code used by both client and worker contexts.
86
+
87
+ **Key Files:**
88
+ - `types.ts` - TypeScript type definitions
89
+ - `UserEvent`, `ToolDefinition`, `ToolHandler`
90
+ - `TabInfo`, `EventFilters`, etc.
91
+ - Ensures type consistency across contexts
92
+
93
+ - `logger.ts` - Logging utilities
94
+ - Environment-aware logging (dev vs production)
95
+ - Consistent logging interface
96
+ - Works in both main thread and workers
97
+
98
+ - `database.ts` - IndexedDB operations
99
+ - Event storage and retrieval
100
+ - Query filtering and pagination
101
+ - Available in both contexts (IndexedDB works everywhere)
102
+
103
+ **Used by:** Both client and worker code
104
+
105
+ ## Communication Flow
106
+
107
+ ```
108
+ Application Code
109
+ ↓ (imports)
110
+ client/worker-client.ts
111
+ ↓ (postMessage)
112
+ mcp-shared-worker.ts or mcp-service-worker.ts
113
+ ↓ (uses)
114
+ worker/mcp-controller.ts
115
+ ↓ (uses)
116
+ worker/mcp-server.ts
117
+ ↓ (uses)
118
+ worker/tool-registry.ts
119
+ ↓ (WebSocket)
120
+ MCP Proxy Server
121
+ ```
122
+
123
+ ## Import Patterns
124
+
125
+ ### For Application Code
126
+
127
+ ```typescript
128
+ // Import from the main package
129
+ import { workerClient, type ToolDefinition } from '@mcp-fe/mcp-worker';
130
+ ```
131
+
132
+ ### Internal Worker Code
133
+
134
+ ```typescript
135
+ // Worker modules import from shared/
136
+ import { logger } from '../shared/logger';
137
+ import type { UserEvent } from '../shared/types';
138
+
139
+ // Worker modules import from other worker modules
140
+ import { toolRegistry } from './tool-registry';
141
+ import { TabManager } from './tab-manager';
142
+ ```
143
+
144
+ ### Internal Client Code
145
+
146
+ ```typescript
147
+ // Client modules import from shared/
148
+ import { logger } from '../shared/logger';
149
+ import type { ToolDefinition } from '../shared/types';
150
+ ```
151
+
152
+ ## Why This Structure?
153
+
154
+ ### Clear Separation of Concerns
155
+ - **Client code** only deals with communication and API
156
+ - **Worker code** handles MCP protocol and business logic
157
+ - **Shared code** provides common utilities and types
158
+
159
+ ### Better Tree-Shaking
160
+ - Applications only import client code
161
+ - Worker bundles only include worker code
162
+ - No unnecessary code in either bundle
163
+
164
+ ### Maintainability
165
+ - Easy to find where specific functionality lives
166
+ - Clear boundaries between contexts
167
+ - Prevents accidental mixing of client/worker code
168
+
169
+ ### Future-Proof
170
+ - Ready for splitting into separate npm packages if needed
171
+ - Can add more worker types (e.g., dedicated workers)
172
+ - Easy to add more shared utilities
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- // libs/mcp-worker/src/lib/logger.ts
1
+ // libs/mcp-worker/src/shared/logger.ts
2
2
  var isProduction = typeof process !== "undefined" && true;
3
3
  var mcpDebug = typeof process !== "undefined" && process.env?.["MCP_DEBUG"];
4
4
  var debugEnabled = mcpDebug === "true" || !isProduction && mcpDebug !== "false";
@@ -26,7 +26,7 @@ var logger = {
26
26
  }
27
27
  };
28
28
 
29
- // libs/mcp-worker/src/lib/worker-client.ts
29
+ // libs/mcp-worker/src/client/worker-client.ts
30
30
  var WorkerClient = class _WorkerClient {
31
31
  // Configurable worker script URLs (defaults kept for backward compatibility)
32
32
  sharedWorkerUrl = "/mcp-shared-worker.js";
@@ -870,7 +870,7 @@ var WorkerClient = class _WorkerClient {
870
870
  // Tell worker which tab registered this
871
871
  });
872
872
  this.toolRegistry.set(name, {
873
- refCount: 1,
873
+ name,
874
874
  description,
875
875
  inputSchema: enhancedSchema,
876
876
  outputSchema: options?.outputSchema,
@@ -879,6 +879,7 @@ var WorkerClient = class _WorkerClient {
879
879
  _meta: options?._meta,
880
880
  icons: options?.icons,
881
881
  title: options?.title,
882
+ refCount: 1,
882
883
  isRegistered: true
883
884
  });
884
885
  logger.log(
@@ -974,6 +975,15 @@ var WorkerClient = class _WorkerClient {
974
975
  isRegistered: info.isRegistered
975
976
  };
976
977
  }
978
+ /**
979
+ * Get complete tool details from registry
980
+ */
981
+ getToolDetails(toolName) {
982
+ const info = this.toolRegistry.get(toolName);
983
+ if (!info)
984
+ return null;
985
+ return info;
986
+ }
977
987
  /**
978
988
  * Get all registered tool names
979
989
  */
@@ -1046,7 +1056,10 @@ var WorkerClient = class _WorkerClient {
1046
1056
  }
1047
1057
  };
1048
1058
 
1049
- // libs/mcp-worker/src/lib/database.ts
1059
+ // libs/mcp-worker/src/client/index.ts
1060
+ var workerClient = new WorkerClient();
1061
+
1062
+ // libs/mcp-worker/src/shared/database.ts
1050
1063
  var DB_NAME = "user-activity-db";
1051
1064
  var DB_VERSION = 1;
1052
1065
  var STORE_NAME = "user-events";
@@ -1066,6 +1079,33 @@ async function initDB() {
1066
1079
  };
1067
1080
  });
1068
1081
  }
1082
+ async function storeEvent(event) {
1083
+ const db = await initDB();
1084
+ const transaction = db.transaction([STORE_NAME], "readwrite");
1085
+ const store = transaction.objectStore(STORE_NAME);
1086
+ const eventWithId = {
1087
+ ...event,
1088
+ id: `${event.timestamp}-${Math.random().toString(36).substr(2, 9)}`
1089
+ };
1090
+ await new Promise((resolve, reject) => {
1091
+ const request = store.add(eventWithId);
1092
+ request.onsuccess = () => resolve();
1093
+ request.onerror = () => reject(request.error);
1094
+ });
1095
+ const countRequest = store.count();
1096
+ countRequest.onsuccess = () => {
1097
+ if (countRequest.result > 1e3) {
1098
+ const index = store.index("timestamp");
1099
+ const getAllRequest = index.getAll();
1100
+ getAllRequest.onsuccess = () => {
1101
+ const events = getAllRequest.result;
1102
+ events.sort((a, b) => a.timestamp - b.timestamp);
1103
+ const toDelete = events.slice(0, events.length - 1e3);
1104
+ toDelete.forEach((event2) => store.delete(event2.id));
1105
+ };
1106
+ }
1107
+ };
1108
+ }
1069
1109
  async function queryEvents(filters) {
1070
1110
  const db = await initDB();
1071
1111
  const transaction = db.transaction([STORE_NAME], "readonly");
@@ -1096,256 +1136,10 @@ async function queryEvents(filters) {
1096
1136
  request.onerror = () => reject(request.error);
1097
1137
  });
1098
1138
  }
1099
-
1100
- // libs/mcp-worker/src/lib/tab-manager.ts
1101
- var TabManager = class {
1102
- // Registry of all active tabs
1103
- tabRegistry = /* @__PURE__ */ new Map();
1104
- // Currently active/focused tab
1105
- activeTabId = null;
1106
- // Tool handlers per tab: Map<ToolName, Set<TabId>>
1107
- toolHandlersByTab = /* @__PURE__ */ new Map();
1108
- /**
1109
- * Register a new tab
1110
- */
1111
- registerTab(tabId, url, title) {
1112
- if (!tabId) {
1113
- logger.warn("[TabManager] Cannot register tab: missing tabId");
1114
- return;
1115
- }
1116
- this.tabRegistry.set(tabId, {
1117
- url: url || "",
1118
- title: title || "",
1119
- lastSeen: Date.now()
1120
- });
1121
- logger.log(`[TabManager] Registered tab: ${tabId} (${title})`);
1122
- }
1123
- /**
1124
- * Set the active/focused tab
1125
- */
1126
- setActiveTab(tabId) {
1127
- if (!tabId) {
1128
- logger.warn("[TabManager] Cannot set active tab: missing tabId");
1129
- return;
1130
- }
1131
- this.activeTabId = tabId;
1132
- logger.log(`[TabManager] Active tab changed: ${tabId}`);
1133
- const tab = this.tabRegistry.get(tabId);
1134
- if (tab) {
1135
- tab.lastSeen = Date.now();
1136
- }
1137
- }
1138
- /**
1139
- * Get the currently active tab ID
1140
- */
1141
- getActiveTabId() {
1142
- return this.activeTabId;
1143
- }
1144
- /**
1145
- * Get all registered tabs
1146
- */
1147
- getAllTabs() {
1148
- return Array.from(this.tabRegistry.entries()).map(([tabId, info]) => ({
1149
- tabId,
1150
- ...info
1151
- }));
1152
- }
1153
- /**
1154
- * Get tab info by ID
1155
- */
1156
- getTabInfo(tabId) {
1157
- return this.tabRegistry.get(tabId);
1158
- }
1159
- /**
1160
- * Check if tab exists
1161
- */
1162
- hasTab(tabId) {
1163
- return this.tabRegistry.has(tabId);
1164
- }
1165
- /**
1166
- * Remove a tab from registry
1167
- */
1168
- removeTab(tabId) {
1169
- const existed = this.tabRegistry.delete(tabId);
1170
- if (existed) {
1171
- logger.log(`[TabManager] Removed tab: ${tabId}`);
1172
- if (this.activeTabId === tabId) {
1173
- this.activeTabId = null;
1174
- }
1175
- this.cleanupTabTools(tabId);
1176
- }
1177
- return existed;
1178
- }
1179
- /**
1180
- * Register a tool for a specific tab
1181
- */
1182
- registerToolForTab(toolName, tabId) {
1183
- if (!this.toolHandlersByTab.has(toolName)) {
1184
- this.toolHandlersByTab.set(toolName, /* @__PURE__ */ new Set());
1185
- }
1186
- const tabHandlers = this.toolHandlersByTab.get(toolName);
1187
- const isNewTab = !tabHandlers.has(tabId);
1188
- tabHandlers.add(tabId);
1189
- if (isNewTab) {
1190
- logger.log(
1191
- `[TabManager] Tab ${tabId} registered tool '${toolName}' (${tabHandlers.size} tab(s) total)`
1192
- );
1193
- } else {
1194
- logger.log(
1195
- `[TabManager] Tab ${tabId} re-registered tool '${toolName}' (already tracked)`
1196
- );
1197
- }
1198
- return isNewTab;
1199
- }
1200
- /**
1201
- * Unregister a tool from a specific tab
1202
- */
1203
- unregisterToolFromTab(toolName, tabId) {
1204
- const tabHandlers = this.toolHandlersByTab.get(toolName);
1205
- if (!tabHandlers || !tabHandlers.has(tabId)) {
1206
- return { wasRemoved: false, remainingTabs: 0, wasActiveTab: false };
1207
- }
1208
- const wasActiveTab = tabId === this.activeTabId;
1209
- tabHandlers.delete(tabId);
1210
- const remainingTabs = tabHandlers.size;
1211
- logger.log(
1212
- `[TabManager] Removed tab ${tabId} from tool '${toolName}' (${remainingTabs} tab(s) remaining)`
1213
- );
1214
- if (remainingTabs === 0) {
1215
- this.toolHandlersByTab.delete(toolName);
1216
- }
1217
- return { wasRemoved: true, remainingTabs, wasActiveTab };
1218
- }
1219
- /**
1220
- * Get all tabs that have a specific tool
1221
- */
1222
- getTabsForTool(toolName) {
1223
- return this.toolHandlersByTab.get(toolName) || /* @__PURE__ */ new Set();
1224
- }
1225
- /**
1226
- * Check if a tab has a specific tool
1227
- */
1228
- tabHasTool(toolName, tabId) {
1229
- const tabHandlers = this.toolHandlersByTab.get(toolName);
1230
- return tabHandlers ? tabHandlers.has(tabId) : false;
1231
- }
1232
- /**
1233
- * Smart routing: determine which tab should handle a tool call
1234
- *
1235
- * Priority:
1236
- * 1. Explicit tabId parameter (if provided and valid)
1237
- * 2. Only one tab has tool -> use it (regardless of focus)
1238
- * 3. Active tab has tool -> use it
1239
- * 4. Active tab doesn't have tool -> use first available
1240
- * 5. No active tab -> use first available
1241
- */
1242
- routeToolCall(toolName, explicitTabId) {
1243
- const tabHandlers = this.toolHandlersByTab.get(toolName);
1244
- if (!tabHandlers || tabHandlers.size === 0) {
1245
- return null;
1246
- }
1247
- if (explicitTabId) {
1248
- if (tabHandlers.has(explicitTabId)) {
1249
- return {
1250
- targetTabId: explicitTabId,
1251
- reason: "explicit tabId parameter"
1252
- };
1253
- } else {
1254
- return null;
1255
- }
1256
- }
1257
- if (tabHandlers.size === 1) {
1258
- const targetTabId = tabHandlers.values().next().value;
1259
- return {
1260
- targetTabId,
1261
- reason: "only one tab has tool"
1262
- };
1263
- }
1264
- if (this.activeTabId && tabHandlers.has(this.activeTabId)) {
1265
- return {
1266
- targetTabId: this.activeTabId,
1267
- reason: "active tab has tool"
1268
- };
1269
- }
1270
- const firstTab = tabHandlers.values().next().value;
1271
- const reason = this.activeTabId ? "active tab lacks tool, using first available" : "no active tab, using first available";
1272
- return {
1273
- targetTabId: firstTab,
1274
- reason
1275
- };
1276
- }
1277
- /**
1278
- * Get routing statistics for debugging
1279
- */
1280
- getRoutingInfo(toolName) {
1281
- const tabHandlers = this.toolHandlersByTab.get(toolName);
1282
- const tabsWithTool = tabHandlers ? Array.from(tabHandlers) : [];
1283
- return {
1284
- toolExists: tabsWithTool.length > 0,
1285
- tabsWithTool,
1286
- activeTabHasTool: this.activeTabId ? this.tabHasTool(toolName, this.activeTabId) : false,
1287
- recommendedTab: this.routeToolCall(toolName)?.targetTabId || null
1288
- };
1289
- }
1290
- /**
1291
- * Clean up all tools for a specific tab
1292
- * @private
1293
- */
1294
- cleanupTabTools(tabId) {
1295
- const removedTools = [];
1296
- for (const [toolName, tabHandlers] of this.toolHandlersByTab.entries()) {
1297
- if (tabHandlers.has(tabId)) {
1298
- tabHandlers.delete(tabId);
1299
- removedTools.push(toolName);
1300
- if (tabHandlers.size === 0) {
1301
- this.toolHandlersByTab.delete(toolName);
1302
- }
1303
- }
1304
- }
1305
- if (removedTools.length > 0) {
1306
- logger.log(
1307
- `[TabManager] Cleaned up ${removedTools.length} tool(s) for tab ${tabId}: ${removedTools.join(", ")}`
1308
- );
1309
- }
1310
- }
1311
- /**
1312
- * Get statistics for monitoring
1313
- */
1314
- getStats() {
1315
- const toolsPerTab = {};
1316
- for (const [tabId] of this.tabRegistry) {
1317
- let toolCount = 0;
1318
- for (const tabHandlers of this.toolHandlersByTab.values()) {
1319
- if (tabHandlers.has(tabId)) {
1320
- toolCount++;
1321
- }
1322
- }
1323
- toolsPerTab[tabId] = toolCount;
1324
- }
1325
- return {
1326
- totalTabs: this.tabRegistry.size,
1327
- activeTabId: this.activeTabId,
1328
- totalTools: this.toolHandlersByTab.size,
1329
- toolsPerTab
1330
- };
1331
- }
1332
- /**
1333
- * Clear all data (for testing)
1334
- */
1335
- clear() {
1336
- this.tabRegistry.clear();
1337
- this.activeTabId = null;
1338
- this.toolHandlersByTab.clear();
1339
- logger.log("[TabManager] Cleared all data");
1340
- }
1341
- };
1342
-
1343
- // libs/mcp-worker/src/index.ts
1344
- var workerClient = new WorkerClient();
1345
1139
  export {
1346
- TabManager,
1347
1140
  WorkerClient,
1348
1141
  logger,
1349
1142
  queryEvents,
1143
+ storeEvent,
1350
1144
  workerClient
1351
1145
  };