@mimik/agent-kit
v1.0.0
Published
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.
Keywords
Readme
agent-kit: MCP Agent Library
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.
Table of Contents
- Installation
- Quick Start
- Core Concepts
- Configuration
- API Reference
- Streaming Events
- Security Features
- Examples
- Best Practices
- Error Handling
Installation
npm install @mimik/agent-kitconst { Agent } = require('@mimik/agent-kit');Quick Start
const { Agent } = require('@mimik/agent-kit');
// Create an agent instance
const agent = new Agent({
name: 'My Assistant',
instructions: 'You are a helpful assistant with access to MCP tools.',
llm: {
model: 'lmstudio-community/Qwen3-4B-GGUF',
temperature: 0.1
},
mcpEndpoints: ['http://localhost:3000/mcp'],
httpClient: global.http
});
// Initialize the agent
await agent.initialize();
// Run a conversation (always returns a streaming iterator)
const streamIterator = await agent.run('find devices around me');
for await (const event of streamIterator) {
if (event.type === 'content_delta') {
sendSSE(event.data.content);
} else if (event.type === 'conversation_complete') {
console.log('\nFinal result:', event.data.finalOutput);
break;
}
}Core Concepts
Agent
The main orchestrator that connects to multiple MCP servers, routes tool calls, and manages conversation flow with automatic streaming execution.
MCP Servers
Multiple Model Context Protocol servers that provide tools, resources, and capabilities. The agent automatically routes tool calls to the appropriate server.
Streaming Execution
All agent conversations use real-time streaming for immediate feedback and responsive user experiences.
Tool Security
Multi-layered security with server-level tool whitelisting and runtime tool approval callbacks.
Configuration
Basic Configuration
const agent = new Agent({
name: 'My Agent', // Agent name for logging
instructions: 'System prompt...', // System instructions
maxIterations: 5, // Max conversation loops
llm: {
model: 'lmstudio-community/Qwen3-4B-GGUF',
temperature: 0.1,
max_tokens: 2048,
endpoint: 'https://api.anthropic.com/v1/messages',
apiKey: 'your-api-key'
},
mcpEndpoints: ['http://localhost:3000/mcp'],
httpClient: global.http
});Advanced Configuration with Security
const agent = new Agent({
name: 'Secure Assistant',
instructions: 'Help users safely with controlled tool access.',
maxIterations: 5,
llm: {
model: 'lmstudio-community/Qwen3-4B-GGUF',
temperature: 0.1,
max_tokens: 4096,
no_think: false // Disable thinking mode
},
mcpEndpoints: [
// Simple endpoint - all tools allowed
'http://localhost:3000/mcp',
// Endpoint with tool whitelist
{
url: 'http://localhost:3001/mcp',
apiKey: 'server-api-key',
options: {
toolWhitelist: ['gitStatus', 'gitLog', 'gitDiff'], // Only these tools
whitelistMode: 'include' // Include mode
}
},
// Endpoint blocking dangerous tools
{
url: 'http://localhost:3002/mcp',
options: {
toolWhitelist: ['deleteFile', 'formatDisk'], // Block these tools
whitelistMode: 'exclude' // Exclude mode
}
}
],
httpClient: global.http
});Configuration Options
Top-Level Options
name(string): Agent name for logging (default: 'MCP Assistant')instructions(string): System prompt (default: 'You are a helpful assistant...')maxIterations(number): Maximum conversation loops (default: 5)mcpEndpoints(array): MCP server configurationshttpClient(object): HTTP client instance
LLM Configuration
model(string): LLM model nametemperature(number): Sampling temperature (0.0-1.0)max_tokens(number): Maximum tokens per responseendpoint(string): LLM API endpointapiKey(string): LLM API keyno_think(boolean): Append '/no_think' to prompts for direct responses
MCP Endpoint Configuration
- Simple:
'http://localhost:3000/mcp' - Advanced: Object with
url,apiKey, andoptions
Tool Whitelist Options
toolWhitelist(array): Tool names to include/excludewhitelistMode(string):'include'(only listed tools) or'exclude'(all except listed)
API Reference
Agent Class
Constructor
new Agent(config)Methods
initialize()
Connects to all MCP servers and loads available tools.
await agent.initialize();run(message, options)
Executes a conversation with streaming output.
Parameters:
message(string): User message to processoptions(object): Configuration optionstoolApproval(function): Tool approval callback
Returns: AsyncIterator - Streaming events
const streamIterator = await agent.run('find devices', {
toolApproval: async (toolCalls) => ({
stopAfterExecution: false,
approvals: [true, false, true] // Approve, deny, approve
})
});Tool Approval System
Callback Function
toolApproval: async (toolCalls) => {
// toolCalls = [{ id, type, function: { name, arguments } }, ...]
return {
stopAfterExecution: false, // Continue after execution
approvals: [
true, // Simple approval
false, // Simple denial
{ approve: true }, // Explicit approval
{ approve: false, reason: 'Not safe' } // Denial with reason
]
};
}Response Format
stopAfterExecution(boolean): End conversation after tool executionapprovals(array): Approval decision for each tool call
Approval Options
true- Approve the toolfalse- Deny the tool (default reason){ approve: true }- Explicit approval{ approve: false, reason: 'Custom reason' }- Denial with custom reason
Streaming Events
All agent conversations emit real-time events for responsive user experiences.
Event Types
iteration_start
Start of each conversation loop
{
type: 'iteration_start',
data: {
iteration: 1,
messages: [/* conversation history */]
}
}content_delta
Assistant text content updates
{
type: 'content_delta',
data: {
content: "I'll help you find devices..."
}
}tool_calls_detected
Complete tool calls ready for execution
{
type: 'tool_calls_detected',
data: {
toolCalls: [{
id: "call_123",
type: "function",
function: { name: "discoverLocal", arguments: "{}" }
}]
}
}tool_approval_result
Results of tool approval decisions
{
type: 'tool_approval_result',
data: {
approvalResult: {
stopAfterExecution: false,
approvals: [true, { approve: false, reason: 'Not safe' }]
}
}
}tool_results
Results from tool execution
{
type: 'tool_results',
data: {
results: [{
role: "tool",
tool_call_id: "call_123",
name: "discoverLocal",
content: JSON.stringify([/* results */])
}]
}
}conversation_complete
Final conversation result
{
type: 'conversation_complete',
data: {
finalOutput: "I found 2 devices around you...",
messages: [/* complete history */],
iterations: 2,
stoppedAfterToolExecution: false
}
}Security Features
Tool Whitelisting
Control which tools are available from each MCP server.
Include Mode (Default)
Only allow specific tools:
{
url: 'http://localhost:3001/mcp',
options: {
toolWhitelist: ['readFile', 'listDirectory'],
whitelistMode: 'include'
}
}Exclude Mode
Block specific dangerous tools:
{
url: 'http://localhost:3002/mcp',
options: {
toolWhitelist: ['deleteFile', 'formatDisk'],
whitelistMode: 'exclude'
}
}Runtime Tool Approval
Additional security layer with approval callbacks:
toolApproval: async (toolCalls) => ({
stopAfterExecution: false,
approvals: toolCalls.map(tool => {
if (tool.function.name.includes('delete')) {
return { approve: false, reason: 'Destructive operations not allowed' };
}
return true;
})
})Security Benefits
- Principle of Least Privilege: Only expose necessary tools
- Defense in Depth: Multiple security layers
- Server Isolation: Different policies per MCP server
- Runtime Protection: Dynamic approval decisions
Examples
Basic Usage
const agent = new Agent({
name: 'Basic Assistant',
llm: { model: 'lmstudio-community/Qwen3-4B-GGUF', temperature: 0.1 },
mcpEndpoints: ['http://localhost:3000/mcp'],
httpClient: global.http
});
await agent.initialize();
const streamIterator = await agent.run('help me find local devices');
for await (const event of streamIterator) {
switch (event.type) {
case 'content_delta':
sendSSE(event.data.content);
break;
case 'conversation_complete':
console.log('\n✅ Done:', event.data.finalOutput);
return;
}
}Multi-Agent with Security
const agent = new Agent({
name: 'Secure Multi-Tool Agent',
instructions: 'Help users with controlled access to various tools.',
llm: {
model: 'lmstudio-community/Qwen3-4B-GGUF',
temperature: 0.2,
max_tokens: 4096
},
mcpEndpoints: [
{
url: 'http://localhost:3000/mcp', // Network tools
options: {
toolWhitelist: ['discoverLocal', 'pingDevice'],
whitelistMode: 'include'
}
},
{
url: 'http://localhost:3001/mcp', // Git tools
options: {
toolWhitelist: ['gitStatus', 'gitLog', 'gitDiff'],
whitelistMode: 'include'
}
},
{
url: 'http://localhost:3002/mcp', // File system (safe)
options: {
toolWhitelist: ['deleteFile', 'formatDisk'],
whitelistMode: 'exclude'
}
}
],
httpClient: global.http
});
await agent.initialize();
const streamIterator = await agent.run('scan network and check git status', {
toolApproval: async (toolCalls) => ({
stopAfterExecution: false,
approvals: toolCalls.map(tool => {
// Extra safety check
if (tool.function.name.toLowerCase().includes('format')) {
return { approve: false, reason: 'Disk formatting not allowed' };
}
return true;
})
})
});
for await (const event of streamIterator) {
switch (event.type) {
case 'content_delta':
sendSSE(event.data.content);
break;
case 'tool_calls_detected':
console.log('\n🔧 Executing:',
event.data.toolCalls.map(tc => tc.function.name).join(', '));
break;
case 'conversation_complete':
console.log('\n\n📋 Final:', event.data.finalOutput);
break;
}
}No-Think Mode
For direct responses without reasoning display:
const agent = new Agent({
name: 'Direct Assistant',
llm: {
model: 'lmstudio-community/Qwen3-4B-GGUF',
no_think: true // Enables direct responses
},
mcpEndpoints: ['http://localhost:3000/mcp'],
httpClient: global.http
});
// Prompts sent to LLM will include '/no_think' suffix
const streamIterator = await agent.run('What time is it?');Web API Integration
app.post('/chat', async (req, res) => {
const agent = new Agent({
name: 'API Assistant',
llm: {
model: 'lmstudio-community/Qwen3-4B-GGUF',
temperature: 0.1,
no_think: true
},
mcpEndpoints: [{
url: 'http://localhost:3000/mcp',
options: {
toolWhitelist: ['readFile', 'listDirectory'], // Read-only for web
whitelistMode: 'include'
}
}],
httpClient: global.http
});
await agent.initialize();
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
try {
const streamIterator = await agent.run(req.body.message, {
toolApproval: async (toolCalls) => ({
stopAfterExecution: false,
approvals: toolCalls.map(tool => {
// Block write operations via web
if (['writeFile', 'deleteFile'].includes(tool.function.name)) {
return { approve: false, reason: 'Write operations not allowed via web' };
}
return true;
})
})
});
for await (const event of streamIterator) {
res.write(`data: ${JSON.stringify(event)}\n\n`);
if (event.type === 'conversation_complete') {
break;
}
}
res.end();
} catch (error) {
res.write(`data: ${JSON.stringify({ error: error.message })}\n\n`);
res.end();
}
});Collecting Final Results
If you need just the final result without processing events:
const streamIterator = await agent.run('find devices around me');
let finalResult = null;
for await (const event of streamIterator) {
if (event.type === 'conversation_complete') {
finalResult = event.data;
break;
}
}
console.log('Final output:', finalResult.finalOutput);
console.log('Total iterations:', finalResult.iterations);Best Practices
1. Always Handle Streaming
Since run() always returns a streaming iterator, process events appropriately:
// Good - handle all relevant events
for await (const event of streamIterator) {
switch (event.type) {
case 'content_delta':
displayContent(event.data.content);
break;
case 'tool_calls_detected':
showToolExecution(event.data.toolCalls);
break;
case 'conversation_complete':
return event.data.finalOutput;
}
}
// Avoid - only handling one event type2. Layer Security Controls
Combine whitelisting with runtime approval:
// Server-level whitelist
{
url: 'http://localhost:3000/mcp',
options: {
toolWhitelist: ['readFile', 'writeFile', 'deleteFile'],
whitelistMode: 'include'
}
}
// Runtime approval for additional safety
toolApproval: async (toolCalls) => ({
approvals: toolCalls.map(tool => {
if (tool.function.name === 'deleteFile') {
return { approve: false, reason: 'Delete operations require manual approval' };
}
return true;
})
})3. Organize Tools by Domain
Use multiple MCP servers for different tool categories:
mcpEndpoints: [
'http://localhost:3000/mcp', // Network tools
'http://localhost:3001/mcp', // File system tools
'http://localhost:3002/mcp', // Git tools
'http://localhost:3003/mcp' // System tools
]4. Set Appropriate Limits
Prevent infinite loops while allowing complex tasks:
{
maxIterations: 10, // Allow complex multi-step tasks
llm: {
max_tokens: 4096, // Sufficient for detailed responses
temperature: 0.1 // Consistent behavior
}
}5. Use No-Think Mode Appropriately
Enable for more direct responses when reasoning isn't needed:
// For APIs or when you want concise responses
llm: { no_think: true }
// For interactive assistants where reasoning helps users
llm: { no_think: false }6. Handle Errors Gracefully
Always wrap agent operations in try-catch:
try {
const streamIterator = await agent.run(userMessage);
// Process stream...
} catch (error) {
console.error('Agent error:', error.message);
// Handle error appropriately
}Error Handling
Common Error Types
Connection Errors
// Server unavailable
try {
await agent.initialize();
} catch (error) {
console.error('Failed to connect to MCP servers:', error.message);
}Tool Execution Errors
Tool errors are returned in tool results, conversation continues:
{
type: 'tool_results',
data: {
results: [{
role: "tool",
tool_call_id: "call_123",
name: "failingTool",
content: "Error: Tool execution failed"
}]
}
}Validation Errors
Invalid configurations throw errors during initialization:
// Invalid endpoint format
mcpEndpoints: ['invalid-url'] // Throws error
// Missing required HTTP client
httpClient: undefined // Throws errorLLM Errors
LLM failures are propagated to the caller:
try {
const streamIterator = await agent.run('test message');
} catch (error) {
if (error.message.includes('API key')) {
console.error('LLM authentication failed');
}
}Error Recovery Strategies
- Server Failures: Agent continues with available servers
- Tool Failures: Returned as error messages, conversation continues
- Approval Callback Errors: Defaults to denying all tools for safety
- Parsing Errors: Logged and skipped, processing continues
Performance Considerations
- Parallel Initialization: All MCP servers connect concurrently
- Efficient Tool Routing: O(1) lookup for tool-to-server mapping
- Streaming: Real-time events with minimal buffering
- Memory Management: Conversation history accumulates; consider limits for long conversations
- No-Think Mode: Reduces response time and token usage when appropriate
Need help? Check the examples above or refer to the MCP Kit documentation for server-side tool development.
