@mcp-fe/mcp-worker 0.0.17 → 0.1.1

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.
@@ -0,0 +1,188 @@
1
+ # Initialization Handling
2
+
3
+ How the library handles tool registration before worker initialization is complete.
4
+
5
+ ## Problem
6
+
7
+ Tool registration could fail if called before the worker was fully initialized, causing:
8
+ - Registration failures
9
+ - Lost registrations
10
+ - Race conditions
11
+
12
+ ## Solution
13
+
14
+ Two-level protection ensures registrations never fail:
15
+
16
+ ## Solution
17
+
18
+ Two-level protection ensures registrations never fail:
19
+
20
+ ### 1. WorkerClient Level
21
+
22
+ Queues registrations if worker isn't initialized yet:
23
+
24
+ ```typescript
25
+ public async registerTool(...) {
26
+ if (!this.isInitialized) {
27
+ // Queue for later processing
28
+ return new Promise((resolve, reject) => {
29
+ this.pendingRegistrations.push({ name, ..., resolve, reject });
30
+ });
31
+ }
32
+
33
+ // Already initialized - register immediately
34
+ return this.registerToolInternal(...);
35
+ }
36
+ ```
37
+
38
+ When init completes, all queued registrations are processed automatically.
39
+
40
+ ### 2. MCPController Level
41
+
42
+ Queues registrations if MCP server isn't connected yet:
43
+
44
+ ```typescript
45
+ public async handleRegisterTool(toolData) {
46
+ if (!this.isMCPServerReady) {
47
+ // Queue until WebSocket connects
48
+ return new Promise((resolve, reject) => {
49
+ this.pendingToolRegistrations.push({ toolData, resolve, reject });
50
+ });
51
+ }
52
+
53
+ // Server ready - register immediately
54
+ return this.handleRegisterToolInternal(toolData);
55
+ }
56
+ ```
57
+
58
+ When WebSocket connects, queued registrations are processed.
59
+
60
+ When WebSocket connects, queued registrations are processed.
61
+
62
+ ## Registration Flow
63
+
64
+ ```
65
+ Tool Registration Called
66
+
67
+ Worker Initialized?
68
+ ├─ NO → Queue registration → Wait for init → Process queue
69
+ └─ YES → Send to worker
70
+
71
+ MCP Server Ready?
72
+ ├─ NO → Queue in controller → Wait for connect → Process queue
73
+ └─ YES → Register tool immediately
74
+
75
+ ✅ Tool Active
76
+ ```
77
+
78
+ ## API
79
+
80
+ ### Check if Initialized
81
+
82
+ ```typescript
83
+ // Check worker state
84
+ if (workerClient.initialized) {
85
+ console.log('Worker ready');
86
+ }
87
+ ```
88
+
89
+ ### Wait for Initialization
90
+
91
+ ```typescript
92
+ // Wait for worker to be ready
93
+ await workerClient.waitForInit();
94
+ await workerClient.registerTool(...);
95
+ ```
96
+
97
+ ## Usage
98
+
99
+ ### Automatic (Recommended)
100
+
101
+ Just call `registerTool()` - queueing is handled automatically:
102
+
103
+ ```typescript
104
+ // Works even if worker isn't initialized yet!
105
+ await workerClient.registerTool('my_tool', ...);
106
+ ```
107
+
108
+ ### React Hook
109
+
110
+ Use `useMCPTool` - it handles everything:
111
+
112
+ ```typescript
113
+ function MyComponent() {
114
+ useMCPTool({
115
+ name: 'my_tool',
116
+ // ... automatically waits for init
117
+ });
118
+ }
119
+ ```
120
+
121
+ ## Scenarios
122
+
123
+ ### Early Registration
124
+
125
+ ```typescript
126
+ // Component mounts before worker init
127
+ function App() {
128
+ useMCPTool({ name: 'tool1', ... }); // ← Before init
129
+ }
130
+
131
+ // Flow:
132
+ // 1. Tool registration queued
133
+ // 2. Worker initializes in background
134
+ // 3. Queue processed automatically
135
+ // 4. Tool registered ✅
136
+ ```
137
+
138
+ ### Late Registration
139
+
140
+ ```typescript
141
+ // Worker already initialized
142
+ workerClient.init(); // ← Finishes
143
+
144
+ // Later...
145
+ useMCPTool({ name: 'tool2', ... }); // ← After init
146
+
147
+ // Flow:
148
+ // 1. Worker already ready
149
+ // 2. Registers immediately ✅
150
+ ```
151
+
152
+ ### Multiple Parallel Registrations
153
+
154
+ ```typescript
155
+ // Multiple components mount simultaneously
156
+ <>
157
+ <ComponentA /> {/* useMCPTool('tool1') */}
158
+ <ComponentB /> {/* useMCPTool('tool2') */}
159
+ <ComponentC /> {/* useMCPTool('tool3') */}
160
+ </>
161
+
162
+ // Flow:
163
+ // 1. All queue registrations
164
+ // 2. Init completes
165
+ // 3. All process together ✅
166
+ ```
167
+
168
+ ## Benefits
169
+
170
+ - ✅ **No race conditions** - Always works regardless of timing
171
+ - ✅ **Automatic queueing** - No manual coordination needed
172
+ - ✅ **Transparent** - User doesn't need to know about init
173
+ - ✅ **No lost registrations** - Everything gets processed
174
+
175
+ ## Implementation Notes
176
+
177
+ For contributors:
178
+
179
+ - **WorkerClient** queues at `registerTool()` level
180
+ - **MCPController** queues at `handleRegisterTool()` level
181
+ - Both use Promise-based queues for clean async handling
182
+ - Queues are processed in order (FIFO)
183
+
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`
187
+
188
+
@@ -0,0 +1,435 @@
1
+ # Worker Implementation Details
2
+
3
+ Technical details about how the MCP Worker implementation works under the hood.
4
+
5
+ ## Worker Architecture
6
+
7
+ ### SharedWorker vs ServiceWorker
8
+
9
+ The library uses a **dual worker strategy** with automatic fallback:
10
+
11
+ #### SharedWorker (Preferred)
12
+
13
+ **Advantages:**
14
+ - Single instance shared across all browser windows/tabs on the same origin
15
+ - Maintains persistent WebSocket connection even when tabs are closed
16
+ - Better for multi-tab applications
17
+ - Lower resource usage (one instance for all tabs)
18
+
19
+ **Browser Support:**
20
+ - ✅ Chrome/Chromium
21
+ - ✅ Firefox
22
+ - ✅ Safari (16.4+)
23
+ - ✅ Edge (Chromium-based)
24
+
25
+ **Requirements:**
26
+ - HTTPS in production (localhost works without HTTPS)
27
+ - Not available in private/incognito mode in some browsers
28
+ - May be blocked by enterprise policies
29
+
30
+ #### ServiceWorker (Fallback)
31
+
32
+ **Advantages:**
33
+ - Runs in background with browser-managed lifecycle
34
+ - Works in incognito mode
35
+ - Universal browser support
36
+ - Handles offline scenarios
37
+
38
+ **Considerations:**
39
+ - Separate instance per browser context
40
+ - May be terminated by browser when inactive
41
+ - Requires additional setup for multi-tab coordination
42
+
43
+ ### Automatic Selection
44
+
45
+ The `WorkerClient` automatically chooses the best available option:
46
+
47
+ ```typescript
48
+ await workerClient.init(); // Tries SharedWorker first, falls back to ServiceWorker
49
+ ```
50
+
51
+ **Selection logic:**
52
+ 1. Check if `SharedWorker` is available
53
+ 2. Try to initialize SharedWorker
54
+ 3. If fails, fall back to ServiceWorker
55
+ 4. If both fail, throw error
56
+
57
+ You can see which worker is being used:
58
+
59
+ ```typescript
60
+ // Check in browser console
61
+ console.log('[WorkerClient] Using SharedWorker'); // or
62
+ console.log('[WorkerClient] Using ServiceWorker (fallback)');
63
+ ```
64
+
65
+ ## Data Storage
66
+
67
+ ### IndexedDB Schema
68
+
69
+ Events are stored in IndexedDB for persistence and efficient querying.
70
+
71
+ **Database:** `mcp-fe-events`
72
+ **Object Store:** `events`
73
+
74
+ **Schema:**
75
+ ```typescript
76
+ interface UserEvent {
77
+ id: string; // UUID
78
+ type: 'navigation' | 'click' | 'input' | 'custom';
79
+ timestamp: number; // Unix timestamp in ms
80
+
81
+ // Navigation events
82
+ path?: string;
83
+ from?: string; // Previous route
84
+ to?: string; // Current route
85
+
86
+ // Interaction events
87
+ element?: string; // Element tag name (e.g., 'button')
88
+ elementId?: string; // Element ID attribute
89
+ elementClass?: string; // Element class attribute
90
+ elementText?: string; // Element text content
91
+
92
+ // Custom data
93
+ metadata?: Record<string, unknown>;
94
+ }
95
+ ```
96
+
97
+ **Indexes:**
98
+ - `by-type` - Query by event type
99
+ - `by-timestamp` - Query by time range
100
+ - `by-path` - Query by page path
101
+
102
+ ### Storage Limits
103
+
104
+ - **Quota:** Browser-dependent (typically 10-50% of available disk space)
105
+ - **Auto-cleanup:** Old events may be removed based on storage pressure
106
+ - **Manual cleanup:** Not currently implemented (TODO)
107
+
108
+ ## WebSocket Connection
109
+
110
+ ### Connection Management
111
+
112
+ The worker maintains a persistent WebSocket connection to the MCP proxy server.
113
+
114
+ **Connection lifecycle:**
115
+ 1. Worker initializes
116
+ 2. WebSocket connects to `backendWsUrl`
117
+ 3. Connection maintained with heartbeat
118
+ 4. Auto-reconnect on disconnect
119
+ 5. Events queued during disconnection
120
+
121
+ ### Message Protocol
122
+
123
+ **From Worker to Proxy:**
124
+ ```typescript
125
+ {
126
+ type: 'mcp_request',
127
+ id: 'unique-request-id',
128
+ method: 'tools/call',
129
+ params: {
130
+ name: 'get_user_events',
131
+ arguments: { limit: 10 }
132
+ }
133
+ }
134
+ ```
135
+
136
+ **From Proxy to Worker:**
137
+ ```typescript
138
+ {
139
+ type: 'mcp_response',
140
+ id: 'unique-request-id',
141
+ result: {
142
+ content: [{
143
+ type: 'text',
144
+ text: '...'
145
+ }]
146
+ }
147
+ }
148
+ ```
149
+
150
+ ### Authentication
151
+
152
+ Authentication token is sent on connection:
153
+
154
+ ```typescript
155
+ {
156
+ type: 'auth',
157
+ token: 'Bearer jwt-token-here'
158
+ }
159
+ ```
160
+
161
+ Token can be updated at runtime:
162
+
163
+ ```typescript
164
+ workerClient.setAuthToken('Bearer new-token');
165
+ ```
166
+
167
+ ## Message Passing
168
+
169
+ ### WorkerClient ↔ Worker Communication
170
+
171
+ The WorkerClient uses MessageChannel for request/response pattern:
172
+
173
+ **Request flow:**
174
+ ```
175
+ 1. WorkerClient creates MessageChannel
176
+ 2. Sends message with port2
177
+ 3. Worker receives message with port2
178
+ 4. Worker processes request
179
+ 5. Worker sends response via port2
180
+ 6. WorkerClient receives response on port1
181
+ ```
182
+
183
+ **Benefits:**
184
+ - Dedicated channel per request
185
+ - No message mixing
186
+ - Built-in timeout handling
187
+ - Clean async/await pattern
188
+
189
+ ### SharedWorker Communication
190
+
191
+ ```typescript
192
+ // In WorkerClient
193
+ const port = sharedWorker.port;
194
+ port.start();
195
+ port.postMessage({ type: 'INIT', backendUrl: '...' });
196
+ port.onmessage = (event) => {
197
+ // Handle messages
198
+ };
199
+ ```
200
+
201
+ ### ServiceWorker Communication
202
+
203
+ ```typescript
204
+ // In WorkerClient
205
+ const registration = await navigator.serviceWorker.register('/sw.js');
206
+ navigator.serviceWorker.controller.postMessage({ type: 'INIT' });
207
+ navigator.serviceWorker.addEventListener('message', (event) => {
208
+ // Handle messages
209
+ });
210
+ ```
211
+
212
+ ## Worker Lifecycle
213
+
214
+ ### SharedWorker Lifecycle
215
+
216
+ ```
217
+ Browser Start
218
+
219
+ First Page Load
220
+
221
+ SharedWorker Created
222
+
223
+ Stays Active (even if all tabs closed)
224
+
225
+ Browser Close → Worker Terminated
226
+ ```
227
+
228
+ **Important:**
229
+ - Lives beyond page lifecycle
230
+ - Shared across all tabs of same origin
231
+ - Not terminated when all tabs close (in most browsers)
232
+
233
+ ### ServiceWorker Lifecycle
234
+
235
+ ```
236
+ Page Load
237
+
238
+ ServiceWorker Registered
239
+
240
+ Installing → Installed → Activating → Activated
241
+
242
+ Handles requests
243
+
244
+ Goes idle after period of inactivity
245
+
246
+ Woken up when needed
247
+ ```
248
+
249
+ **Important:**
250
+ - Browser controls lifecycle
251
+ - May be terminated when idle
252
+ - Automatically restarted when needed
253
+
254
+ ## Performance Considerations
255
+
256
+ ### Memory Usage
257
+
258
+ **SharedWorker:**
259
+ - ~2-5 MB baseline
260
+ - + event storage in IndexedDB
261
+ - + WebSocket connection overhead
262
+
263
+ **ServiceWorker:**
264
+ - Similar to SharedWorker
265
+ - Additional service worker cache (if used)
266
+
267
+ ### CPU Usage
268
+
269
+ - **Idle:** Minimal (WebSocket heartbeat only)
270
+ - **Event storage:** <1ms per event
271
+ - **Event query:** 1-10ms depending on query complexity
272
+
273
+ ### Network Usage
274
+
275
+ - **WebSocket:** ~1 KB/minute (heartbeat)
276
+ - **Events:** Varies by application usage
277
+ - **Reconnection:** Automatic with exponential backoff
278
+
279
+ ## Browser Compatibility
280
+
281
+ ### Full Feature Support
282
+
283
+ - ✅ Chrome/Chromium 80+
284
+ - ✅ Firefox 78+
285
+ - ✅ Safari 16.4+
286
+ - ✅ Edge 80+ (Chromium-based)
287
+
288
+ ### Minimum Requirements
289
+
290
+ - ES2020+ support
291
+ - WebWorker API
292
+ - IndexedDB API
293
+ - WebSocket API
294
+ - MessageChannel API
295
+
296
+ ### Feature Detection
297
+
298
+ The library automatically detects and uses available features:
299
+
300
+ ```typescript
301
+ // SharedWorker detection
302
+ if (typeof SharedWorker !== 'undefined') {
303
+ // Use SharedWorker
304
+ } else {
305
+ // Fall back to ServiceWorker
306
+ }
307
+ ```
308
+
309
+ ## Security Considerations
310
+
311
+ ### Origin Isolation
312
+
313
+ Workers are isolated by origin:
314
+ - SharedWorker: Shared only within same origin
315
+ - ServiceWorker: Scoped to registration path
316
+
317
+ ### Authentication
318
+
319
+ - Token-based authentication via `setAuthToken()`
320
+ - Token transmitted over WebSocket (use WSS in production)
321
+ - Token stored in memory only (not persisted)
322
+
323
+ ### Data Privacy
324
+
325
+ - Events stored in IndexedDB (per-origin storage)
326
+ - No cross-origin data access
327
+ - Events cleared when user clears browser data
328
+
329
+ ### Content Security Policy (CSP)
330
+
331
+ Required CSP directives:
332
+
333
+ ```http
334
+ Content-Security-Policy:
335
+ worker-src 'self';
336
+ connect-src 'self' ws://localhost:3001 wss://your-proxy.com;
337
+ ```
338
+
339
+ ## Debugging
340
+
341
+ ### Enable Debug Logs
342
+
343
+ The worker logs important events to console:
344
+
345
+ ```
346
+ [WorkerClient] init() called
347
+ [WorkerClient] Using SharedWorker
348
+ [WorkerClient] Worker initialized
349
+ [MCPController] WebSocket connected
350
+ [MCPController] Registered tool: get_user_events
351
+ ```
352
+
353
+ ### Inspect Worker
354
+
355
+ **Chrome DevTools:**
356
+ 1. Open DevTools
357
+ 2. Go to Application tab
358
+ 3. Select "Service Workers" or "Shared Workers"
359
+ 4. Find your worker
360
+ 5. Click "inspect" to open dedicated DevTools
361
+
362
+ **Firefox:**
363
+ 1. Open about:debugging
364
+ 2. Click "This Firefox"
365
+ 3. Find your worker in "Shared Workers" or "Service Workers"
366
+ 4. Click "Inspect"
367
+
368
+ ### Monitor WebSocket
369
+
370
+ 1. Open Network tab in DevTools
371
+ 2. Filter by "WS" (WebSocket)
372
+ 3. Click on the WebSocket connection
373
+ 4. View Messages tab to see all messages
374
+
375
+ ### Query IndexedDB
376
+
377
+ 1. Open Application tab in DevTools
378
+ 2. Expand "IndexedDB"
379
+ 3. Find "mcp-fe-events" database
380
+ 4. Browse stored events
381
+
382
+ ## Troubleshooting
383
+
384
+ ### SharedWorker Not Available
385
+
386
+ **Symptoms:** Falls back to ServiceWorker immediately
387
+
388
+ **Causes:**
389
+ - Browser doesn't support SharedWorker
390
+ - Private/incognito mode
391
+ - Enterprise policy blocking
392
+ - HTTP instead of HTTPS (in production)
393
+
394
+ **Solution:** Library automatically uses ServiceWorker fallback
395
+
396
+ ### WebSocket Connection Fails
397
+
398
+ **Symptoms:** `getConnectionStatus()` returns `false`
399
+
400
+ **Causes:**
401
+ - Proxy server not running
402
+ - Wrong WebSocket URL
403
+ - CORS/network issues
404
+ - Firewall blocking WebSocket
405
+
406
+ **Solution:**
407
+ ```typescript
408
+ // Check connection in DevTools Network tab
409
+ // Verify proxy server is running:
410
+ // curl http://localhost:3001/health
411
+ ```
412
+
413
+ ### Events Not Storing
414
+
415
+ **Symptoms:** `GET_EVENTS` returns empty array
416
+
417
+ **Causes:**
418
+ - Worker not initialized
419
+ - IndexedDB quota exceeded
420
+ - Browser blocking IndexedDB
421
+
422
+ **Solution:**
423
+ ```typescript
424
+ // Check worker is initialized
425
+ console.log(workerClient.initialized);
426
+
427
+ // Check for quota errors in console
428
+ // Check IndexedDB in DevTools Application tab
429
+ ```
430
+
431
+ ## See Also
432
+
433
+ - [API Reference](./api.md) - Complete API documentation
434
+ - [Architecture](./architecture.md) - High-level architecture
435
+ - [Guide](./guide.md) - Dynamic tool registration