@mimik/agent-kit 1.0.0
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 +718 -0
- package/package.json +11 -0
- package/src/agent.js +456 -0
- package/src/index.js +10 -0
- package/src/mcp-response-parser.js +177 -0
- package/src/mcp-server.js +290 -0
- package/src/oai.js +205 -0
package/README.md
ADDED
|
@@ -0,0 +1,718 @@
|
|
|
1
|
+
# agent-kit: MCP Agent Library
|
|
2
|
+
|
|
3
|
+
A powerful wrapper library for building intelligent agents that interact with multiple Model Context Protocol (MCP) servers, providing streaming capabilities, tool orchestration, and comprehensive security controls.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Installation](#installation)
|
|
8
|
+
- [Quick Start](#quick-start)
|
|
9
|
+
- [Core Concepts](#core-concepts)
|
|
10
|
+
- [Configuration](#configuration)
|
|
11
|
+
- [API Reference](#api-reference)
|
|
12
|
+
- [Streaming Events](#streaming-events)
|
|
13
|
+
- [Security Features](#security-features)
|
|
14
|
+
- [Examples](#examples)
|
|
15
|
+
- [Best Practices](#best-practices)
|
|
16
|
+
- [Error Handling](#error-handling)
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @mimik/agent-kit
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
const { Agent } = require('@mimik/agent-kit');
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
const { Agent } = require('@mimik/agent-kit');
|
|
32
|
+
|
|
33
|
+
// Create an agent instance
|
|
34
|
+
const agent = new Agent({
|
|
35
|
+
name: 'My Assistant',
|
|
36
|
+
instructions: 'You are a helpful assistant with access to MCP tools.',
|
|
37
|
+
llm: {
|
|
38
|
+
model: 'lmstudio-community/Qwen3-4B-GGUF',
|
|
39
|
+
temperature: 0.1
|
|
40
|
+
},
|
|
41
|
+
mcpEndpoints: ['http://localhost:3000/mcp'],
|
|
42
|
+
httpClient: global.http
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Initialize the agent
|
|
46
|
+
await agent.initialize();
|
|
47
|
+
|
|
48
|
+
// Run a conversation (always returns a streaming iterator)
|
|
49
|
+
const streamIterator = await agent.run('find devices around me');
|
|
50
|
+
|
|
51
|
+
for await (const event of streamIterator) {
|
|
52
|
+
if (event.type === 'content_delta') {
|
|
53
|
+
sendSSE(event.data.content);
|
|
54
|
+
} else if (event.type === 'conversation_complete') {
|
|
55
|
+
console.log('\nFinal result:', event.data.finalOutput);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Core Concepts
|
|
62
|
+
|
|
63
|
+
### Agent
|
|
64
|
+
The main orchestrator that connects to multiple MCP servers, routes tool calls, and manages conversation flow with automatic streaming execution.
|
|
65
|
+
|
|
66
|
+
### MCP Servers
|
|
67
|
+
Multiple Model Context Protocol servers that provide tools, resources, and capabilities. The agent automatically routes tool calls to the appropriate server.
|
|
68
|
+
|
|
69
|
+
### Streaming Execution
|
|
70
|
+
All agent conversations use real-time streaming for immediate feedback and responsive user experiences.
|
|
71
|
+
|
|
72
|
+
### Tool Security
|
|
73
|
+
Multi-layered security with server-level tool whitelisting and runtime tool approval callbacks.
|
|
74
|
+
|
|
75
|
+
## Configuration
|
|
76
|
+
|
|
77
|
+
### Basic Configuration
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
const agent = new Agent({
|
|
81
|
+
name: 'My Agent', // Agent name for logging
|
|
82
|
+
instructions: 'System prompt...', // System instructions
|
|
83
|
+
maxIterations: 5, // Max conversation loops
|
|
84
|
+
|
|
85
|
+
llm: {
|
|
86
|
+
model: 'lmstudio-community/Qwen3-4B-GGUF',
|
|
87
|
+
temperature: 0.1,
|
|
88
|
+
max_tokens: 2048,
|
|
89
|
+
endpoint: 'https://api.anthropic.com/v1/messages',
|
|
90
|
+
apiKey: 'your-api-key'
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
mcpEndpoints: ['http://localhost:3000/mcp'],
|
|
94
|
+
httpClient: global.http
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Advanced Configuration with Security
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
const agent = new Agent({
|
|
102
|
+
name: 'Secure Assistant',
|
|
103
|
+
instructions: 'Help users safely with controlled tool access.',
|
|
104
|
+
maxIterations: 5,
|
|
105
|
+
|
|
106
|
+
llm: {
|
|
107
|
+
model: 'lmstudio-community/Qwen3-4B-GGUF',
|
|
108
|
+
temperature: 0.1,
|
|
109
|
+
max_tokens: 4096,
|
|
110
|
+
no_think: false // Disable thinking mode
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
mcpEndpoints: [
|
|
114
|
+
// Simple endpoint - all tools allowed
|
|
115
|
+
'http://localhost:3000/mcp',
|
|
116
|
+
|
|
117
|
+
// Endpoint with tool whitelist
|
|
118
|
+
{
|
|
119
|
+
url: 'http://localhost:3001/mcp',
|
|
120
|
+
apiKey: 'server-api-key',
|
|
121
|
+
options: {
|
|
122
|
+
toolWhitelist: ['gitStatus', 'gitLog', 'gitDiff'], // Only these tools
|
|
123
|
+
whitelistMode: 'include' // Include mode
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
// Endpoint blocking dangerous tools
|
|
128
|
+
{
|
|
129
|
+
url: 'http://localhost:3002/mcp',
|
|
130
|
+
options: {
|
|
131
|
+
toolWhitelist: ['deleteFile', 'formatDisk'], // Block these tools
|
|
132
|
+
whitelistMode: 'exclude' // Exclude mode
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
],
|
|
136
|
+
|
|
137
|
+
httpClient: global.http
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Configuration Options
|
|
142
|
+
|
|
143
|
+
#### Top-Level Options
|
|
144
|
+
- `name` (string): Agent name for logging (default: 'MCP Assistant')
|
|
145
|
+
- `instructions` (string): System prompt (default: 'You are a helpful assistant...')
|
|
146
|
+
- `maxIterations` (number): Maximum conversation loops (default: 5)
|
|
147
|
+
- `mcpEndpoints` (array): MCP server configurations
|
|
148
|
+
- `httpClient` (object): HTTP client instance
|
|
149
|
+
|
|
150
|
+
#### LLM Configuration
|
|
151
|
+
- `model` (string): LLM model name
|
|
152
|
+
- `temperature` (number): Sampling temperature (0.0-1.0)
|
|
153
|
+
- `max_tokens` (number): Maximum tokens per response
|
|
154
|
+
- `endpoint` (string): LLM API endpoint
|
|
155
|
+
- `apiKey` (string): LLM API key
|
|
156
|
+
- `no_think` (boolean): Append '/no_think' to prompts for direct responses
|
|
157
|
+
|
|
158
|
+
#### MCP Endpoint Configuration
|
|
159
|
+
- **Simple**: `'http://localhost:3000/mcp'`
|
|
160
|
+
- **Advanced**: Object with `url`, `apiKey`, and `options`
|
|
161
|
+
|
|
162
|
+
#### Tool Whitelist Options
|
|
163
|
+
- `toolWhitelist` (array): Tool names to include/exclude
|
|
164
|
+
- `whitelistMode` (string): `'include'` (only listed tools) or `'exclude'` (all except listed)
|
|
165
|
+
|
|
166
|
+
## API Reference
|
|
167
|
+
|
|
168
|
+
### Agent Class
|
|
169
|
+
|
|
170
|
+
#### Constructor
|
|
171
|
+
```javascript
|
|
172
|
+
new Agent(config)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
#### Methods
|
|
176
|
+
|
|
177
|
+
##### initialize()
|
|
178
|
+
Connects to all MCP servers and loads available tools.
|
|
179
|
+
|
|
180
|
+
```javascript
|
|
181
|
+
await agent.initialize();
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
##### run(message, options)
|
|
185
|
+
Executes a conversation with streaming output.
|
|
186
|
+
|
|
187
|
+
**Parameters:**
|
|
188
|
+
- `message` (string): User message to process
|
|
189
|
+
- `options` (object): Configuration options
|
|
190
|
+
- `toolApproval` (function): Tool approval callback
|
|
191
|
+
|
|
192
|
+
**Returns:** AsyncIterator - Streaming events
|
|
193
|
+
|
|
194
|
+
```javascript
|
|
195
|
+
const streamIterator = await agent.run('find devices', {
|
|
196
|
+
toolApproval: async (toolCalls) => ({
|
|
197
|
+
stopAfterExecution: false,
|
|
198
|
+
approvals: [true, false, true] // Approve, deny, approve
|
|
199
|
+
})
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Tool Approval System
|
|
204
|
+
|
|
205
|
+
#### Callback Function
|
|
206
|
+
```javascript
|
|
207
|
+
toolApproval: async (toolCalls) => {
|
|
208
|
+
// toolCalls = [{ id, type, function: { name, arguments } }, ...]
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
stopAfterExecution: false, // Continue after execution
|
|
212
|
+
approvals: [
|
|
213
|
+
true, // Simple approval
|
|
214
|
+
false, // Simple denial
|
|
215
|
+
{ approve: true }, // Explicit approval
|
|
216
|
+
{ approve: false, reason: 'Not safe' } // Denial with reason
|
|
217
|
+
]
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### Response Format
|
|
223
|
+
- `stopAfterExecution` (boolean): End conversation after tool execution
|
|
224
|
+
- `approvals` (array): Approval decision for each tool call
|
|
225
|
+
|
|
226
|
+
#### Approval Options
|
|
227
|
+
- `true` - Approve the tool
|
|
228
|
+
- `false` - Deny the tool (default reason)
|
|
229
|
+
- `{ approve: true }` - Explicit approval
|
|
230
|
+
- `{ approve: false, reason: 'Custom reason' }` - Denial with custom reason
|
|
231
|
+
|
|
232
|
+
## Streaming Events
|
|
233
|
+
|
|
234
|
+
All agent conversations emit real-time events for responsive user experiences.
|
|
235
|
+
|
|
236
|
+
### Event Types
|
|
237
|
+
|
|
238
|
+
#### iteration_start
|
|
239
|
+
Start of each conversation loop
|
|
240
|
+
```javascript
|
|
241
|
+
{
|
|
242
|
+
type: 'iteration_start',
|
|
243
|
+
data: {
|
|
244
|
+
iteration: 1,
|
|
245
|
+
messages: [/* conversation history */]
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
#### content_delta
|
|
251
|
+
Assistant text content updates
|
|
252
|
+
```javascript
|
|
253
|
+
{
|
|
254
|
+
type: 'content_delta',
|
|
255
|
+
data: {
|
|
256
|
+
content: "I'll help you find devices..."
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
#### tool_calls_detected
|
|
262
|
+
Complete tool calls ready for execution
|
|
263
|
+
```javascript
|
|
264
|
+
{
|
|
265
|
+
type: 'tool_calls_detected',
|
|
266
|
+
data: {
|
|
267
|
+
toolCalls: [{
|
|
268
|
+
id: "call_123",
|
|
269
|
+
type: "function",
|
|
270
|
+
function: { name: "discoverLocal", arguments: "{}" }
|
|
271
|
+
}]
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
#### tool_approval_result
|
|
277
|
+
Results of tool approval decisions
|
|
278
|
+
```javascript
|
|
279
|
+
{
|
|
280
|
+
type: 'tool_approval_result',
|
|
281
|
+
data: {
|
|
282
|
+
approvalResult: {
|
|
283
|
+
stopAfterExecution: false,
|
|
284
|
+
approvals: [true, { approve: false, reason: 'Not safe' }]
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
#### tool_results
|
|
291
|
+
Results from tool execution
|
|
292
|
+
```javascript
|
|
293
|
+
{
|
|
294
|
+
type: 'tool_results',
|
|
295
|
+
data: {
|
|
296
|
+
results: [{
|
|
297
|
+
role: "tool",
|
|
298
|
+
tool_call_id: "call_123",
|
|
299
|
+
name: "discoverLocal",
|
|
300
|
+
content: JSON.stringify([/* results */])
|
|
301
|
+
}]
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
#### conversation_complete
|
|
307
|
+
Final conversation result
|
|
308
|
+
```javascript
|
|
309
|
+
{
|
|
310
|
+
type: 'conversation_complete',
|
|
311
|
+
data: {
|
|
312
|
+
finalOutput: "I found 2 devices around you...",
|
|
313
|
+
messages: [/* complete history */],
|
|
314
|
+
iterations: 2,
|
|
315
|
+
stoppedAfterToolExecution: false
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## Security Features
|
|
321
|
+
|
|
322
|
+
### Tool Whitelisting
|
|
323
|
+
|
|
324
|
+
Control which tools are available from each MCP server.
|
|
325
|
+
|
|
326
|
+
#### Include Mode (Default)
|
|
327
|
+
Only allow specific tools:
|
|
328
|
+
```javascript
|
|
329
|
+
{
|
|
330
|
+
url: 'http://localhost:3001/mcp',
|
|
331
|
+
options: {
|
|
332
|
+
toolWhitelist: ['readFile', 'listDirectory'],
|
|
333
|
+
whitelistMode: 'include'
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
#### Exclude Mode
|
|
339
|
+
Block specific dangerous tools:
|
|
340
|
+
```javascript
|
|
341
|
+
{
|
|
342
|
+
url: 'http://localhost:3002/mcp',
|
|
343
|
+
options: {
|
|
344
|
+
toolWhitelist: ['deleteFile', 'formatDisk'],
|
|
345
|
+
whitelistMode: 'exclude'
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Runtime Tool Approval
|
|
351
|
+
|
|
352
|
+
Additional security layer with approval callbacks:
|
|
353
|
+
```javascript
|
|
354
|
+
toolApproval: async (toolCalls) => ({
|
|
355
|
+
stopAfterExecution: false,
|
|
356
|
+
approvals: toolCalls.map(tool => {
|
|
357
|
+
if (tool.function.name.includes('delete')) {
|
|
358
|
+
return { approve: false, reason: 'Destructive operations not allowed' };
|
|
359
|
+
}
|
|
360
|
+
return true;
|
|
361
|
+
})
|
|
362
|
+
})
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Security Benefits
|
|
366
|
+
- **Principle of Least Privilege**: Only expose necessary tools
|
|
367
|
+
- **Defense in Depth**: Multiple security layers
|
|
368
|
+
- **Server Isolation**: Different policies per MCP server
|
|
369
|
+
- **Runtime Protection**: Dynamic approval decisions
|
|
370
|
+
|
|
371
|
+
## Examples
|
|
372
|
+
|
|
373
|
+
### Basic Usage
|
|
374
|
+
|
|
375
|
+
```javascript
|
|
376
|
+
const agent = new Agent({
|
|
377
|
+
name: 'Basic Assistant',
|
|
378
|
+
llm: { model: 'lmstudio-community/Qwen3-4B-GGUF', temperature: 0.1 },
|
|
379
|
+
mcpEndpoints: ['http://localhost:3000/mcp'],
|
|
380
|
+
httpClient: global.http
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
await agent.initialize();
|
|
384
|
+
|
|
385
|
+
const streamIterator = await agent.run('help me find local devices');
|
|
386
|
+
|
|
387
|
+
for await (const event of streamIterator) {
|
|
388
|
+
switch (event.type) {
|
|
389
|
+
case 'content_delta':
|
|
390
|
+
sendSSE(event.data.content);
|
|
391
|
+
break;
|
|
392
|
+
case 'conversation_complete':
|
|
393
|
+
console.log('\n✅ Done:', event.data.finalOutput);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Multi-Agent with Security
|
|
400
|
+
|
|
401
|
+
```javascript
|
|
402
|
+
const agent = new Agent({
|
|
403
|
+
name: 'Secure Multi-Tool Agent',
|
|
404
|
+
instructions: 'Help users with controlled access to various tools.',
|
|
405
|
+
llm: {
|
|
406
|
+
model: 'lmstudio-community/Qwen3-4B-GGUF',
|
|
407
|
+
temperature: 0.2,
|
|
408
|
+
max_tokens: 4096
|
|
409
|
+
},
|
|
410
|
+
mcpEndpoints: [
|
|
411
|
+
{
|
|
412
|
+
url: 'http://localhost:3000/mcp', // Network tools
|
|
413
|
+
options: {
|
|
414
|
+
toolWhitelist: ['discoverLocal', 'pingDevice'],
|
|
415
|
+
whitelistMode: 'include'
|
|
416
|
+
}
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
url: 'http://localhost:3001/mcp', // Git tools
|
|
420
|
+
options: {
|
|
421
|
+
toolWhitelist: ['gitStatus', 'gitLog', 'gitDiff'],
|
|
422
|
+
whitelistMode: 'include'
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
url: 'http://localhost:3002/mcp', // File system (safe)
|
|
427
|
+
options: {
|
|
428
|
+
toolWhitelist: ['deleteFile', 'formatDisk'],
|
|
429
|
+
whitelistMode: 'exclude'
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
],
|
|
433
|
+
httpClient: global.http
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
await agent.initialize();
|
|
437
|
+
|
|
438
|
+
const streamIterator = await agent.run('scan network and check git status', {
|
|
439
|
+
toolApproval: async (toolCalls) => ({
|
|
440
|
+
stopAfterExecution: false,
|
|
441
|
+
approvals: toolCalls.map(tool => {
|
|
442
|
+
// Extra safety check
|
|
443
|
+
if (tool.function.name.toLowerCase().includes('format')) {
|
|
444
|
+
return { approve: false, reason: 'Disk formatting not allowed' };
|
|
445
|
+
}
|
|
446
|
+
return true;
|
|
447
|
+
})
|
|
448
|
+
})
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
for await (const event of streamIterator) {
|
|
452
|
+
switch (event.type) {
|
|
453
|
+
case 'content_delta':
|
|
454
|
+
sendSSE(event.data.content);
|
|
455
|
+
break;
|
|
456
|
+
case 'tool_calls_detected':
|
|
457
|
+
console.log('\n🔧 Executing:',
|
|
458
|
+
event.data.toolCalls.map(tc => tc.function.name).join(', '));
|
|
459
|
+
break;
|
|
460
|
+
case 'conversation_complete':
|
|
461
|
+
console.log('\n\n📋 Final:', event.data.finalOutput);
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### No-Think Mode
|
|
468
|
+
|
|
469
|
+
For direct responses without reasoning display:
|
|
470
|
+
```javascript
|
|
471
|
+
const agent = new Agent({
|
|
472
|
+
name: 'Direct Assistant',
|
|
473
|
+
llm: {
|
|
474
|
+
model: 'lmstudio-community/Qwen3-4B-GGUF',
|
|
475
|
+
no_think: true // Enables direct responses
|
|
476
|
+
},
|
|
477
|
+
mcpEndpoints: ['http://localhost:3000/mcp'],
|
|
478
|
+
httpClient: global.http
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
// Prompts sent to LLM will include '/no_think' suffix
|
|
482
|
+
const streamIterator = await agent.run('What time is it?');
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### Web API Integration
|
|
486
|
+
|
|
487
|
+
```javascript
|
|
488
|
+
app.post('/chat', async (req, res) => {
|
|
489
|
+
const agent = new Agent({
|
|
490
|
+
name: 'API Assistant',
|
|
491
|
+
llm: {
|
|
492
|
+
model: 'lmstudio-community/Qwen3-4B-GGUF',
|
|
493
|
+
temperature: 0.1,
|
|
494
|
+
no_think: true
|
|
495
|
+
},
|
|
496
|
+
mcpEndpoints: [{
|
|
497
|
+
url: 'http://localhost:3000/mcp',
|
|
498
|
+
options: {
|
|
499
|
+
toolWhitelist: ['readFile', 'listDirectory'], // Read-only for web
|
|
500
|
+
whitelistMode: 'include'
|
|
501
|
+
}
|
|
502
|
+
}],
|
|
503
|
+
httpClient: global.http
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
await agent.initialize();
|
|
507
|
+
|
|
508
|
+
res.setHeader('Content-Type', 'text/event-stream');
|
|
509
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
510
|
+
|
|
511
|
+
try {
|
|
512
|
+
const streamIterator = await agent.run(req.body.message, {
|
|
513
|
+
toolApproval: async (toolCalls) => ({
|
|
514
|
+
stopAfterExecution: false,
|
|
515
|
+
approvals: toolCalls.map(tool => {
|
|
516
|
+
// Block write operations via web
|
|
517
|
+
if (['writeFile', 'deleteFile'].includes(tool.function.name)) {
|
|
518
|
+
return { approve: false, reason: 'Write operations not allowed via web' };
|
|
519
|
+
}
|
|
520
|
+
return true;
|
|
521
|
+
})
|
|
522
|
+
})
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
for await (const event of streamIterator) {
|
|
526
|
+
res.write(`data: ${JSON.stringify(event)}\n\n`);
|
|
527
|
+
|
|
528
|
+
if (event.type === 'conversation_complete') {
|
|
529
|
+
break;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
res.end();
|
|
534
|
+
} catch (error) {
|
|
535
|
+
res.write(`data: ${JSON.stringify({ error: error.message })}\n\n`);
|
|
536
|
+
res.end();
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
### Collecting Final Results
|
|
542
|
+
|
|
543
|
+
If you need just the final result without processing events:
|
|
544
|
+
```javascript
|
|
545
|
+
const streamIterator = await agent.run('find devices around me');
|
|
546
|
+
let finalResult = null;
|
|
547
|
+
|
|
548
|
+
for await (const event of streamIterator) {
|
|
549
|
+
if (event.type === 'conversation_complete') {
|
|
550
|
+
finalResult = event.data;
|
|
551
|
+
break;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
console.log('Final output:', finalResult.finalOutput);
|
|
556
|
+
console.log('Total iterations:', finalResult.iterations);
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
## Best Practices
|
|
560
|
+
|
|
561
|
+
### 1. Always Handle Streaming
|
|
562
|
+
Since `run()` always returns a streaming iterator, process events appropriately:
|
|
563
|
+
```javascript
|
|
564
|
+
// Good - handle all relevant events
|
|
565
|
+
for await (const event of streamIterator) {
|
|
566
|
+
switch (event.type) {
|
|
567
|
+
case 'content_delta':
|
|
568
|
+
displayContent(event.data.content);
|
|
569
|
+
break;
|
|
570
|
+
case 'tool_calls_detected':
|
|
571
|
+
showToolExecution(event.data.toolCalls);
|
|
572
|
+
break;
|
|
573
|
+
case 'conversation_complete':
|
|
574
|
+
return event.data.finalOutput;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// Avoid - only handling one event type
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
### 2. Layer Security Controls
|
|
582
|
+
Combine whitelisting with runtime approval:
|
|
583
|
+
```javascript
|
|
584
|
+
// Server-level whitelist
|
|
585
|
+
{
|
|
586
|
+
url: 'http://localhost:3000/mcp',
|
|
587
|
+
options: {
|
|
588
|
+
toolWhitelist: ['readFile', 'writeFile', 'deleteFile'],
|
|
589
|
+
whitelistMode: 'include'
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// Runtime approval for additional safety
|
|
594
|
+
toolApproval: async (toolCalls) => ({
|
|
595
|
+
approvals: toolCalls.map(tool => {
|
|
596
|
+
if (tool.function.name === 'deleteFile') {
|
|
597
|
+
return { approve: false, reason: 'Delete operations require manual approval' };
|
|
598
|
+
}
|
|
599
|
+
return true;
|
|
600
|
+
})
|
|
601
|
+
})
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
### 3. Organize Tools by Domain
|
|
605
|
+
Use multiple MCP servers for different tool categories:
|
|
606
|
+
```javascript
|
|
607
|
+
mcpEndpoints: [
|
|
608
|
+
'http://localhost:3000/mcp', // Network tools
|
|
609
|
+
'http://localhost:3001/mcp', // File system tools
|
|
610
|
+
'http://localhost:3002/mcp', // Git tools
|
|
611
|
+
'http://localhost:3003/mcp' // System tools
|
|
612
|
+
]
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
### 4. Set Appropriate Limits
|
|
616
|
+
Prevent infinite loops while allowing complex tasks:
|
|
617
|
+
```javascript
|
|
618
|
+
{
|
|
619
|
+
maxIterations: 10, // Allow complex multi-step tasks
|
|
620
|
+
llm: {
|
|
621
|
+
max_tokens: 4096, // Sufficient for detailed responses
|
|
622
|
+
temperature: 0.1 // Consistent behavior
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
### 5. Use No-Think Mode Appropriately
|
|
628
|
+
Enable for more direct responses when reasoning isn't needed:
|
|
629
|
+
```javascript
|
|
630
|
+
// For APIs or when you want concise responses
|
|
631
|
+
llm: { no_think: true }
|
|
632
|
+
|
|
633
|
+
// For interactive assistants where reasoning helps users
|
|
634
|
+
llm: { no_think: false }
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
### 6. Handle Errors Gracefully
|
|
638
|
+
Always wrap agent operations in try-catch:
|
|
639
|
+
```javascript
|
|
640
|
+
try {
|
|
641
|
+
const streamIterator = await agent.run(userMessage);
|
|
642
|
+
// Process stream...
|
|
643
|
+
} catch (error) {
|
|
644
|
+
console.error('Agent error:', error.message);
|
|
645
|
+
// Handle error appropriately
|
|
646
|
+
}
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
## Error Handling
|
|
650
|
+
|
|
651
|
+
### Common Error Types
|
|
652
|
+
|
|
653
|
+
#### Connection Errors
|
|
654
|
+
```javascript
|
|
655
|
+
// Server unavailable
|
|
656
|
+
try {
|
|
657
|
+
await agent.initialize();
|
|
658
|
+
} catch (error) {
|
|
659
|
+
console.error('Failed to connect to MCP servers:', error.message);
|
|
660
|
+
}
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
#### Tool Execution Errors
|
|
664
|
+
Tool errors are returned in tool results, conversation continues:
|
|
665
|
+
```javascript
|
|
666
|
+
{
|
|
667
|
+
type: 'tool_results',
|
|
668
|
+
data: {
|
|
669
|
+
results: [{
|
|
670
|
+
role: "tool",
|
|
671
|
+
tool_call_id: "call_123",
|
|
672
|
+
name: "failingTool",
|
|
673
|
+
content: "Error: Tool execution failed"
|
|
674
|
+
}]
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
#### Validation Errors
|
|
680
|
+
Invalid configurations throw errors during initialization:
|
|
681
|
+
```javascript
|
|
682
|
+
// Invalid endpoint format
|
|
683
|
+
mcpEndpoints: ['invalid-url'] // Throws error
|
|
684
|
+
|
|
685
|
+
// Missing required HTTP client
|
|
686
|
+
httpClient: undefined // Throws error
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
#### LLM Errors
|
|
690
|
+
LLM failures are propagated to the caller:
|
|
691
|
+
```javascript
|
|
692
|
+
try {
|
|
693
|
+
const streamIterator = await agent.run('test message');
|
|
694
|
+
} catch (error) {
|
|
695
|
+
if (error.message.includes('API key')) {
|
|
696
|
+
console.error('LLM authentication failed');
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
### Error Recovery Strategies
|
|
702
|
+
|
|
703
|
+
1. **Server Failures**: Agent continues with available servers
|
|
704
|
+
2. **Tool Failures**: Returned as error messages, conversation continues
|
|
705
|
+
3. **Approval Callback Errors**: Defaults to denying all tools for safety
|
|
706
|
+
4. **Parsing Errors**: Logged and skipped, processing continues
|
|
707
|
+
|
|
708
|
+
## Performance Considerations
|
|
709
|
+
|
|
710
|
+
- **Parallel Initialization**: All MCP servers connect concurrently
|
|
711
|
+
- **Efficient Tool Routing**: O(1) lookup for tool-to-server mapping
|
|
712
|
+
- **Streaming**: Real-time events with minimal buffering
|
|
713
|
+
- **Memory Management**: Conversation history accumulates; consider limits for long conversations
|
|
714
|
+
- **No-Think Mode**: Reduces response time and token usage when appropriate
|
|
715
|
+
|
|
716
|
+
---
|
|
717
|
+
|
|
718
|
+
**Need help?** Check the examples above or refer to the MCP Kit documentation for server-side tool development.
|
package/package.json
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mimik/agent-kit",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "./src/index.js",
|
|
5
|
+
"scripts": {
|
|
6
|
+
|
|
7
|
+
},
|
|
8
|
+
"author": "mimik",
|
|
9
|
+
"license": "ISC",
|
|
10
|
+
"description": "A powerful wrapper library for building intelligent agents that interact with multiple Model Context Protocol (MCP) servers, providing streaming capabilities, tool orchestration, and comprehensive security controls."
|
|
11
|
+
}
|