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.
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
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | No | 'MCP Assistant' | Agent name for logging |
instructions | string | No | 'You are a helpful assistant...' | System prompt |
maxIterations | number | No | 5 | Maximum conversation loops |
mcpEndpoints | array | No | [] | MCP server configurations |
httpClient | object | Yes | - | HTTP client instance (global.http) |
llm | object | No | - | LLM configuration |
LLM Configuration
| Property | Type | Default | Description |
|---|---|---|---|
endpoint | string | - | LLM API endpoint URL |
apiKey | string | - | LLM API key (include Bearer prefix) |
model | string | 'qwen3-1.7b' | Model name |
temperature | number | 0.1 | Sampling temperature (0.0-1.0) |
max_tokens | number | 2048 | Maximum tokens per response |
no_think | boolean | false | Append /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:
| Parameter | Type | Description |
|---|---|---|
input | string | array | User message string, or array of OpenAI-format messages for conversation history |
options.toolApproval | function | Optional 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
| Property | Type | Description |
|---|---|---|
url | string | MCP server URL |
apiKey | string | Optional API key for the server |
options.toolWhitelist | array | Tool names to include/exclude |
options.whitelistMode | string | '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
| Constant | Value | Description |
|---|---|---|
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
| Property | Type | Description |
|---|---|---|
stopAfterExecution | boolean | End conversation after tool execution |
approvals | 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
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
}
}
Related
- How AI Agent mims Work: Understand the architecture and concepts
- Create an AI Agent: Hands-on tutorial
- Inference API: AI Foundation inference endpoints
- context.http: HTTP client for mims