npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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.

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

npm install @mimik/agent-kit
const { 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 configurations
  • httpClient (object): HTTP client instance

LLM Configuration

  • model (string): LLM model name
  • temperature (number): Sampling temperature (0.0-1.0)
  • max_tokens (number): Maximum tokens per response
  • endpoint (string): LLM API endpoint
  • apiKey (string): LLM API key
  • no_think (boolean): Append '/no_think' to prompts for direct responses

MCP Endpoint Configuration

  • Simple: 'http://localhost:3000/mcp'
  • Advanced: Object with url, apiKey, and options

Tool Whitelist Options

  • toolWhitelist (array): Tool names to include/exclude
  • whitelistMode (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 process
  • options (object): Configuration options
    • toolApproval (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 execution
  • approvals (array): Approval decision for each tool call

Approval Options

  • true - Approve the tool
  • false - 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 type

2. 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 error

LLM 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

  1. Server Failures: Agent continues with available servers
  2. Tool Failures: Returned as error messages, conversation continues
  3. Approval Callback Errors: Defaults to denying all tools for safety
  4. 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.