@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.
- package/README.md +184 -349
- package/docs/api.md +418 -0
- package/docs/architecture.md +195 -0
- package/docs/guide.md +454 -0
- package/docs/index.md +109 -0
- package/docs/initialization.md +188 -0
- package/docs/worker-details.md +435 -0
- package/index.js +365 -5
- package/mcp-service-worker.js +505 -204
- package/mcp-shared-worker.js +487 -173
- package/package.json +1 -1
- package/src/index.d.ts +2 -1
- package/src/index.d.ts.map +1 -1
- package/src/lib/built-in-tools.d.ts +9 -0
- package/src/lib/built-in-tools.d.ts.map +1 -0
- package/src/lib/mcp-controller.d.ts +18 -0
- package/src/lib/mcp-controller.d.ts.map +1 -1
- package/src/lib/mcp-server.d.ts +11 -0
- package/src/lib/mcp-server.d.ts.map +1 -1
- package/src/lib/tool-registry.d.ts +28 -0
- package/src/lib/tool-registry.d.ts.map +1 -0
- package/src/lib/worker-client.d.ts +123 -0
- package/src/lib/worker-client.d.ts.map +1 -1
|
@@ -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
|