Skip to main content

Agent Kit

@mimik/agent-kit provides the agentic loop that powers AI Agent mims. It handles LLM communication, MCP tool discovery, function calling orchestration, and streaming, so you can focus on configuring your agent's behavior.

For the concepts behind agent-kit, see How AI Agent mims Work.

mimOE JavaScript Runtime

This library is designed to work within the mimOE JavaScript runtime (Duktape ES5). It uses global.http for HTTP requests and global.context for runtime APIs. See Create an AI Agent for a hands-on tutorial.

Installation

npm install @mimik/agent-kit
const { Agent, AGENT_EVENT } = require('@mimik/agent-kit');

Quick Start

const { Agent, AGENT_EVENT } = require('@mimik/agent-kit');

const { httpPort } = global.context.info;
const { INFERENCE_API_KEY } = global.context.env;

const agent = new Agent({
name: 'My Assistant',
instructions: 'You are a helpful assistant with access to MCP tools.',
llm: {
endpoint: `http://127.0.0.1:${httpPort}/mimik-ai/openai/v1/chat/completions`,
apiKey: `Bearer ${INFERENCE_API_KEY}`,
model: 'qwen3-1.7b',
temperature: 0.1
},
mcpEndpoints: ['http://localhost:3000/mcp'],
httpClient: global.http
});

// Run a conversation (returns streaming iterator)
const stream = await agent.run('find devices around me');

for await (const event of stream) {
if (event.type === AGENT_EVENT.CONTENT_DELTA) {
console.log(event.data.content);
} else if (event.type === AGENT_EVENT.CONVERSATION_COMPLETE) {
console.log('Done:', event.data.finalOutput);
break;
}
}

Agent Class

Constructor

new Agent(config)

Creates a new Agent instance.

Configuration Options

PropertyTypeRequiredDefaultDescription
namestringNo'MCP Assistant'Agent name for logging
instructionsstringNo'You are a helpful assistant...'System prompt
maxIterationsnumberNo5Maximum conversation loops
mcpEndpointsarrayNo[]MCP server configurations
httpClientobjectYes-HTTP client instance (global.http)
llmobjectNo-LLM configuration

LLM Configuration

PropertyTypeDefaultDescription
endpointstring-LLM API endpoint URL
apiKeystring-LLM API key (include Bearer prefix)
modelstring'qwen3-1.7b'Model name
temperaturenumber0.1Sampling temperature (0.0-1.0)
max_tokensnumber2048Maximum tokens per response
no_thinkbooleanfalseAppend /no_think to prompts (Qwen3)

Methods

initialize()

Connects to all MCP servers and loads available tools. Called automatically on first run() if not called explicitly.

await agent.initialize();

run(input, options)

Executes a conversation with streaming output.

Parameters:

ParameterTypeDescription
inputstring | arrayUser message string, or array of OpenAI-format messages for conversation history
options.toolApprovalfunctionOptional tool approval callback

Returns: AsyncIterator (streaming events)

// Simple string message
const stream = await agent.run('help me find devices');

// Or with conversation history (OpenAI messages format)
const stream = await agent.run([
{ role: 'user', content: 'What devices are on my network?' },
{ role: 'assistant', content: 'I found 3 devices: ...' },
{ role: 'user', content: 'Tell me more about the first one' }
], {
toolApproval: async (toolCalls) => ({
stopAfterExecution: false,
approvals: toolCalls.map(() => true)
})
});

When passing a messages array, the agent's system instructions are automatically prepended.


MCP Endpoints Configuration

MCP endpoints can be configured as simple strings or objects with advanced options.

Simple Configuration

mcpEndpoints: [
'http://localhost:3000/mcp',
'http://localhost:3001/mcp'
]

Advanced Configuration

mcpEndpoints: [
// Simple endpoint - all tools allowed
'http://localhost:3000/mcp',

// Endpoint with API key
{
url: 'http://localhost:3001/mcp',
apiKey: 'server-api-key'
},

// Endpoint with tool whitelist (include mode)
{
url: 'http://localhost:3002/mcp',
options: {
toolWhitelist: ['readFile', 'listDirectory'],
whitelistMode: 'include' // Only these tools allowed
}
},

// Endpoint blocking specific tools (exclude mode)
{
url: 'http://localhost:3003/mcp',
options: {
toolWhitelist: ['deleteFile', 'formatDisk'],
whitelistMode: 'exclude' // All tools except these
}
}
]

Endpoint Options

PropertyTypeDescription
urlstringMCP server URL
apiKeystringOptional API key for the server
options.toolWhitelistarrayTool names to include/exclude
options.whitelistModestring'include' or 'exclude'

Streaming Events

All agent conversations emit real-time events. Event types are available as constants via the AGENT_EVENT export:

const { Agent, AGENT_EVENT } = require('@mimik/agent-kit');

Event Constants

ConstantValueDescription
AGENT_EVENT.ITERATION_START'iteration_start'Start of each conversation loop
AGENT_EVENT.RAW_MODEL_STREAM_EVENT'raw_model_stream_event'Raw chunk from the LLM stream
AGENT_EVENT.CONTENT_DELTA'content_delta'Assistant text content update
AGENT_EVENT.TOOL_CALL_DELTA'tool_call_delta'Streaming tool call fragment
AGENT_EVENT.TOOL_CALLS_DETECTED'tool_calls_detected'Complete tool calls ready for execution
AGENT_EVENT.TOOL_APPROVAL_RESULT'tool_approval_result'Results of tool approval decisions
AGENT_EVENT.TOOL_RESULTS'tool_results'Results from tool execution
AGENT_EVENT.CONVERSATION_COMPLETE'conversation_complete'Final conversation result
AGENT_EVENT.MAX_ITERATIONS_REACHED'max_iterations_reached'Max iteration limit hit

Event Payloads

ITERATION_START

{
type: AGENT_EVENT.ITERATION_START,
data: {
iteration: 1,
messages: [/* conversation history */]
}
}

CONTENT_DELTA

{
type: AGENT_EVENT.CONTENT_DELTA,
data: {
content: "I'll help you find devices..."
}
}

TOOL_CALLS_DETECTED

{
type: AGENT_EVENT.TOOL_CALLS_DETECTED,
data: {
toolCalls: [{
id: "call_123",
type: "function",
function: { name: "discoverLocal", arguments: "{}" }
}]
}
}

TOOL_APPROVAL_RESULT

{
type: AGENT_EVENT.TOOL_APPROVAL_RESULT,
data: {
approvalResult: {
stopAfterExecution: false,
approvals: [true, { approve: false, reason: 'Not allowed' }]
}
}
}

TOOL_RESULTS

{
type: AGENT_EVENT.TOOL_RESULTS,
data: {
results: [{
role: "tool",
tool_call_id: "call_123",
name: "discoverLocal",
content: JSON.stringify([/* results */])
}]
}
}

CONVERSATION_COMPLETE

{
type: AGENT_EVENT.CONVERSATION_COMPLETE,
data: {
finalOutput: "I found 2 devices around you...",
messages: [/* complete history */],
iterations: 2,
stoppedAfterToolExecution: false
}
}

MAX_ITERATIONS_REACHED

{
type: AGENT_EVENT.MAX_ITERATIONS_REACHED,
data: {
maxIterations: 5,
finalOutput: "..."
}
}

Tool Approval

Control which tools the agent can execute at runtime.

Approval Callback

const stream = await agent.run(message, {
toolApproval: async (toolCalls) => {
// toolCalls = [{ id, type, function: { name, arguments } }, ...]

return {
stopAfterExecution: false, // Continue conversation after execution
approvals: [
true, // Approve first tool
false, // Deny second tool
{ approve: true }, // Explicit approval
{ approve: false, reason: 'Not safe' } // Denial with reason
]
};
}
});

Approval Response Format

PropertyTypeDescription
stopAfterExecutionbooleanEnd conversation after tool execution
approvalsarrayApproval 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

Example: Block Destructive Operations

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;
})
})

Examples

Basic Usage

const { Agent, AGENT_EVENT } = require('@mimik/agent-kit');

async function* runAgent(userMessage) {
const { httpPort } = global.context.info;
const { INFERENCE_API_KEY } = global.context.env;

const agent = new Agent({
name: 'Basic Assistant',
instructions: 'You are a helpful assistant.',
llm: {
endpoint: `http://127.0.0.1:${httpPort}/mimik-ai/openai/v1/chat/completions`,
apiKey: `Bearer ${INFERENCE_API_KEY}`,
model: 'qwen3-1.7b',
temperature: 0.1
},
mcpEndpoints: ['http://localhost:3000/mcp'],
httpClient: global.http
});

const stream = await agent.run(userMessage);

for await (const event of stream) {
if (event.type === AGENT_EVENT.CONTENT_DELTA) {
yield { type: 'content', content: event.data.content };
} else if (event.type === AGENT_EVENT.CONVERSATION_COMPLETE) {
yield { type: 'done', finalOutput: event.data.finalOutput };
break;
}
}
}

Multi-Server with Security

const agent = new Agent({
name: 'Secure Agent',
instructions: 'Help users with controlled tool access.',
llm: {
endpoint: `http://127.0.0.1:${httpPort}/mimik-ai/openai/v1/chat/completions`,
apiKey: `Bearer ${INFERENCE_API_KEY}`,
model: 'qwen3-1.7b',
temperature: 0.1,
max_tokens: 4096
},
mcpEndpoints: [
// Network tools - only discovery
{
url: 'http://localhost:3000/mcp',
options: {
toolWhitelist: ['discoverLocal', 'pingDevice'],
whitelistMode: 'include'
}
},
// File tools - block destructive
{
url: 'http://localhost:3001/mcp',
options: {
toolWhitelist: ['deleteFile', 'formatDisk'],
whitelistMode: 'exclude'
}
}
],
httpClient: global.http
});

Qwen3 No-Think Mode

For faster, more direct responses without reasoning display:

const agent = new Agent({
name: 'Direct Assistant',
llm: {
endpoint: `http://127.0.0.1:${httpPort}/mimik-ai/openai/v1/chat/completions`,
apiKey: `Bearer ${INFERENCE_API_KEY}`,
model: 'qwen3-1.7b',
no_think: true // Appends /no_think to prompts
},
mcpEndpoints: ['http://localhost:3000/mcp'],
httpClient: global.http
});

Collecting Final Result Only

const stream = await agent.run('find devices around me');
let finalResult = null;

for await (const event of stream) {
if (event.type === AGENT_EVENT.CONVERSATION_COMPLETE) {
finalResult = event.data;
break;
}
}

console.log('Output:', finalResult.finalOutput);
console.log('Iterations:', finalResult.iterations);

Error Handling

Connection Errors

try {
await agent.initialize();
} catch (error) {
console.error('Failed to connect to MCP servers:', error.message);
}

Tool Execution Errors

Tool errors are returned in results; the conversation continues:

{
type: AGENT_EVENT.TOOL_RESULTS,
data: {
results: [{
role: "tool",
tool_call_id: "call_123",
name: "failingTool",
content: JSON.stringify({ error: "Tool execution failed" })
}]
}
}

Error Recovery

  • 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

Best Practices

1. Always Handle Streaming

for await (const event of stream) {
switch (event.type) {
case AGENT_EVENT.CONTENT_DELTA:
displayContent(event.data.content);
break;
case AGENT_EVENT.TOOL_CALLS_DETECTED:
showToolExecution(event.data.toolCalls);
break;
case AGENT_EVENT.CONVERSATION_COMPLETE:
return event.data.finalOutput;
}
}

2. Layer Security Controls

Combine whitelisting with runtime approval:

// Server-level whitelist
{
url: 'http://localhost:3000/mcp',
options: {
toolWhitelist: ['readFile', 'writeFile'],
whitelistMode: 'include'
}
}

// Runtime approval for additional safety
toolApproval: async (toolCalls) => ({
approvals: toolCalls.map(tool => {
if (tool.function.name === 'writeFile') {
return { approve: false, reason: 'Write requires manual approval' };
}
return true;
})
})

3. Use Dynamic Port and API Keys

const { httpPort } = global.context.info;
const { INFERENCE_API_KEY } = global.context.env;

llm: {
endpoint: `http://127.0.0.1:${httpPort}/mimik-ai/openai/v1/chat/completions`,
apiKey: `Bearer ${INFERENCE_API_KEY}`
}

4. Set Appropriate Limits

{
maxIterations: 10, // Allow complex multi-step tasks
llm: {
max_tokens: 4096,
temperature: 0.1
}
}