chieftecho/budgie
If you are the rightful owner of budgie and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.
Budgie is a Go-based MCP server that integrates Kiro agents as MCP tools for orchestration.
Budgie - Kiro (CLI) Sub-Agents MCP Server
A Go-based MCP server that exposes Kiro agents as MCP tools for orchestration.
Introduction
This MCP server makes sub-agents available to kiro-cli through the Model Context Protocol. I'm aware this may become obsolete when kiro-cli natively supports sub-agents in the future. Yes, other tools already support sub-agents, but I wanted to use kiro-cli.
This is a 5-6 hour personal side project—don't expect enterprise-grade code. I made it work on my old MacBook. You're free to make it work for you and suggest improvements.
Features
- Auto-discovers agents from
~/.kiro/agents/*.json - Filters agents with "sub-agent:" prefix in description
- Creates isolated session workspaces:
~/.kiro/sub-agents/sessions/<uuid> - Multi-turn conversation support via sessionId with
--resumeflag - Health monitoring with automatic timeout detection and retry logic
- Automatic retries on timeout or process crash (1 retry with 2s backoff)
- Health metrics tracking success rate, duration, and failures per agent
- Mandatory directory parameter for security and explicit working directory control
- Response file decoupling - agent responses written to session directory, not working directory
Installation
go build -o budgie ./cmd/server
Usage
As MCP Server
Add to your orchestrator agent's mcpServers configuration:
{
"mcpServers": {
"kiro-subagents": {
"command": "/path/to/budgie",
"args": [],
"type": "stdio"
}
},
"tools": ["@kiro-subagents"]
}
Command-Line Options
# Default usage
./budgie
# Custom timeout (default: 10 minutes)
./budgie --agent-timeout 5m
# Custom paths
./budgie --agents-dir /custom/agents \
--sessions-dir /tmp/sessions \
--prompts-dir /custom/prompts
# Custom kiro-cli binary
./budgie --kiro-binary /usr/local/bin/kiro-cli
# Custom tool prefix (default: kiro-subagents.)
./budgie --tool-prefix my-agents.
# Debug mode (print tool info and exit)
./budgie --debug
Tool Interface
Each agent becomes a tool named kiro-subagents.<agent-name>:
Input:
{
"prompt": "Your task description",
"sessionId": "optional-uuid-for-continuation",
"directory": "required-absolute-path-to-working-directory"
}
Output:
{
"response": "Agent's response",
"sessionId": "uuid-for-this-session"
}
Important: The directory parameter is MANDATORY. Calls without it will fail with an error.
Health Monitoring
Budgie automatically monitors agent health and provides recovery:
- Timeouts: Agent calls timeout after 10 minutes (configurable with
--agent-timeout) - Retries: Automatic retry on timeout or crash (1 retry with 2s backoff)
- Health Metrics: Track success rate, duration, and failures per agent
- Enhanced Errors: Failures include health context for better debugging
Health Check Tool
Query health metrics via kiro-subagents.health-check:
Response:
{
"overall": {
"totalCalls": 42,
"successCalls": 38,
"successRate": "90.5%"
},
"agents": [
{
"agent": "codebase-analyzer",
"totalCalls": 10,
"successCalls": 9,
"failedCalls": 1,
"timeoutCalls": 0,
"successRate": "90.0%",
"avgDuration": "15.3s",
"lastSuccess": "2025-12-10T19:25:00Z",
"lastFailure": "2025-12-10T18:30:00Z",
"lastError": ""
}
]
}
Agent Configuration
Agent JSON Files (~/.kiro/agents/)
Agents are discovered by loading JSON files from the agents directory:
{
"name": "test-agent",
"description": "sub-agent: Validation and testing specialist",
"allowedTools": [
"fs_read",
"fs_write"
]
}
Key requirements:
namefield (required) - determines the agent name passed to kiro-clidescriptionstarting with "sub-agent:" (required) - for filtering and registration- Tool name is normalized:
"test-agent"→"kiro-subagents.test-agent" - Must include
fs_readandfs_writeinallowedTools- Required for agents to create response files, which decouples contexts between orchestrator and sub-agents
Agent Prompt Files (~/.kiro/sub-agents/prompts/)
Each agent can have a corresponding prompt file: {agent-name}.md
Example: ~/.kiro/sub-agents/prompts/test-agent.md
---
name: test-agent
description: Validation and testing specialist for MCP server functionality
capabilities:
- Tool validation
- Session management testing
- Integration testing
use_when:
- Need to validate MCP tools
- Testing session persistence
avoid_when:
- Writing production code
- Deployment tasks
tools:
- fs_read
- fs_write
- execute_bash
model: claude-3-5-sonnet-20241022
tags:
- testing
- validation
- mcp
---
# Test Agent
You are a specialized testing agent...
Frontmatter Structure:
- YAML frontmatter between
---delimiters - Required fields:
name,description - Optional fields:
capabilities,use_when,avoid_when,tools,model,tags - Used to generate enhanced tool descriptions for MCP
- Does NOT modify the agent's system prompt (defined by kiro-cli)
System Prompt Template (~/.kiro/sub-agents/prompts/_system.md)
A special system prompt template that gets appended to every agent call:
Write your response to: {{RESPONSE_FILE}}
Working directory: {{WORKING_DIRECTORY}}
Requirements:
- Plain text only
- No markdown formatting
- Concise output
Placeholder substitution:
{{RESPONSE_FILE}}→response-{uuid}.txt{{WORKING_DIRECTORY}}→ The target working directory
This ensures agents know where to do their actual work and where to write their response files.
Note: Both _system.md and _context-summary.md are loaded on every use, allowing on-the-fly fine-tuning without server restart.
Context Summary Prompt Template (~/.kiro/sub-agents/prompts/_context-summary.md)
A fallback prompt template used when the agent doesn't write to the response file:
Write your previous response to the file: {{RESPONSE_FILE}}
Requirements:
- Plain text format only
- No emojis, icons, or ANSI color codes
- No markdown formatting
- Concise and direct
- Suitable for programmatic consumption by the orchestrator LLM
Placeholder substitution:
{{RESPONSE_FILE}}→response-{uuid}.txt
This fallback ensures the orchestrator can always retrieve the agent's response even if the system prompt is ignored.
Orchestrator Configuration
For the orchestrator agent, configure it to use the budgie MCP server:
{
"name": "orchestrator",
"description": "Master orchestrator agent",
"mcpServers": {
"kiro-subagents": {
"command": "/path/to/budgie",
"args": [],
"type": "stdio"
}
},
"tools": ["@kiro-subagents"]
}
The orchestrator prompt should be in ~/.kiro/sub-agents/prompts/orchestrator.md.
Architecture
Orchestrator → MCP Client → Budgie MCP Server → kiro-cli → Sub-Agent
↓
Health Monitor
(timeout, retry, metrics)
Directory Isolation
The system uses two separate directories:
-
Working Directory (
input.Directory)- MANDATORY - Must be explicitly provided in every tool call
- Passed to agent via prompt:
"In directory {input.Directory}, ..." - Where the agent reads/writes user files
- Security: No default fallback to prevent accidental operations
-
Session Directory (
sessionDir)~/.kiro/sub-agents/sessions/{sessionID}/- Isolated workspace for each session
- Where kiro-cli actually runs (
cmd.Dir = sessionDir) - Where response files are written:
{sessionDir}/response-{uuid}.txt - Response files are NEVER written to the working directory
Sub-Agent Call Flow
This diagram shows the complete flow when a sub-agent is called through the MCP server.
sequenceDiagram
participant Client as MCP Client
participant Server as MCP Server<br/>(main.go)
participant Handler as Tool Handler<br/>(createHandler)
participant Sessions as sessions.GetWorkspaceDir
participant Kiro as kiro.Execute
participant KiroCLI as kiro-cli binary
participant Health as health.Monitor
Client->>Server: CallToolRequest<br/>{tool: "kiro-subagents.agent-name",<br/>input: {prompt, sessionId, directory}}
Server->>Handler: Invoke handler(ctx, req, ToolInput)
Note over Handler: Validate prompt != ""
Note over Handler: Validate directory != ""
Handler->>Sessions: GetWorkspaceDir(sessionId)
alt sessionId is empty
Sessions->>Sessions: Generate new UUID
end
Sessions->>Sessions: Create directory:<br/>~/.kiro/sub-agents/sessions/{sessionId}
Sessions-->>Handler: sessionDir = ~/.kiro/sub-agents/sessions/{sessionId}
Note over Handler: Generate unique response file:<br/>response-{uuid}.txt<br/><br/>Full path: {sessionDir}/response-{uuid}.txt<br/>NOT in working directory!
Note over Handler: Enhance prompt:<br/>"In directory {input.Directory}, {prompt}"
alt systemPromptTemplate exists
Note over Handler: Inject system prompt with:<br/>{{RESPONSE_FILE}} → response-{uuid}.txt<br/>{{WORKING_DIRECTORY}} → input.Directory
end
Handler->>Kiro: Execute(ctx, agentName, enhancedPrompt,<br/>sessionDir, sessionID)
Note over Kiro: Start timer
Kiro->>Kiro: executeOnce(ctx, agentName, prompt,<br/>sessionDir, sessionID)
Note over Kiro: Create timeout context<br/>(default: 10 minutes)
Note over Kiro: Build args:<br/>["chat", "--agent", agentName,<br/>"--no-interactive"]
alt sessionID != ""
Note over Kiro: Add "--resume" flag
end
Note over Kiro: Append prompt to args
Kiro->>KiroCLI: exec.CommandContext(ctx, "kiro-cli", args)<br/>cmd.Dir = sessionDir
Note over KiroCLI: Execute agent in session directory<br/>May write to response file
KiroCLI-->>Kiro: stdout, stderr, error
alt error occurred
alt shouldRetry(error)
Note over Kiro: Wait 2 seconds
Kiro->>Kiro: executeOnce (retry)
Kiro->>KiroCLI: exec.CommandContext (retry)
KiroCLI-->>Kiro: stdout, stderr, error
end
end
Note over Kiro: Calculate duration
alt error != nil
Kiro->>Health: RecordFailure(agentName, duration,<br/>errorMsg, isTimeout)
else success
Kiro->>Health: RecordSuccess(agentName, duration)
end
Kiro-->>Handler: Result{Output, SessionID, Error,<br/>Duration, Retried}
alt error != nil
Handler->>Health: GetMetrics(agentName)
Health-->>Handler: Metrics{SuccessRate, FailedCalls}
Handler-->>Server: error with health stats
Server-->>Client: Error response
end
Handler->>Handler: Read response file:<br/>{sessionDir}/response-{uuid}.txt<br/>(~/.kiro/sub-agents/sessions/{sessionId}/response-{uuid}.txt)
alt file read successful
Note over Handler: Use file content as response
else file not found
Note over Handler: Fallback: Request file creation
Handler->>Kiro: Execute(ctx, agentName,<br/>"Write response to file...",<br/>sessionDir, sessionID)
Kiro->>KiroCLI: exec.CommandContext
KiroCLI-->>Kiro: result
Kiro-->>Handler: Result
Handler->>Handler: Try reading file again
alt still no file
Note over Handler: Use original stdout
end
end
Handler-->>Server: ToolOutput{Response, SessionID}
Server-->>Client: CallToolResult with output
Implementation Details
1. Tool Registration (Startup)
agents.Load(agentsDir)- Loads agent JSON files from~/.kiro/agents/frontmatter.LoadFromPrompt(promptsDir, agentName)- Loads agent metadata from~/.kiro/sub-agents/prompts/{agent}.mdagents.NormalizeToolName(agentName)- Converts agent name to tool name (e.g., "test-agent" → "kiro-subagents.test-agent")mcp.AddTool(server, tool, handler)- Registers tool with MCP server
2. Request Flow
- Input:
ToolInput{Prompt, SessionID, Directory}Prompt(required): The task description for the agentSessionID(optional): UUID to continue existing sessionDirectory(required): Working directory for the agent to operate in
- Output:
ToolOutput{Response, SessionID}
3. Session Management
sessions.GetWorkspaceDir(sessionID)- Creates/retrieves session directory- Each session gets isolated directory:
~/.kiro/sub-agents/sessions/{uuid}/ - Sessions persist across calls when sessionID is reused
- Response files are written to session directory, NOT the working directory
4. Prompt Enhancement
- Prepends directory context:
"In directory {input.Directory}, {prompt}" - Injects system prompt template with placeholders replaced
- Ensures agent knows working directory and response file location
5. Execution
kiro.Execute()- Main execution with retry logicexec.CommandContext()- Spawns kiro-cli process with timeout- Command runs in session directory with
--agentand--no-interactiveflags --resumeflag added if continuing existing session
6. Response Handling
- Primary: Read from
response-{uuid}.txtfile in session directory - Fallback: Use stdout from kiro-cli
- Secondary fallback: Request explicit file write and retry
7. Health Monitoring
health.Monitortracks success/failure rates per agent- Records duration, error messages, timeout status
- Metrics included in error responses to help debugging
Kiro-CLI Context Management
Session Persistence with --resume Flag
The system leverages kiro-cli's built-in context management:
-
Session Directory Structure
- Each session gets:
~/.kiro/sub-agents/sessions/{sessionID}/ - kiro-cli runs with
cmd.Dir = sessionDir - kiro-cli internally binds conversation history (context) to this directory
- Each sub-agent uses this directory to write response-{uuid}.txt files
- The budgie instances keep track of their own session directories and remove them on exit
- Each session gets:
-
Context Resumption
- First call:
kiro-cli chat --agent {name} --no-interactive "{prompt}" - Subsequent calls:
kiro-cli chat --agent {name} --no-interactive --resume "{prompt}" - The
--resumeflag tells kiro-cli to load conversation history from current directory - kiro-cli manages context files internally within the session directory
- First call:
-
Non-Interactive Mode
--no-interactiveflag ensures kiro-cli exits after single response- No user prompts or interactive input required
- Suitable for programmatic/automated execution
Complete Flow Summary
- Startup: Load agents from
~/.kiro/agents/*.json, filter for"sub-agent:"prefix - Tool Registration: Load frontmatter from
~/.kiro/sub-agents/prompts/{agent}.mdfor enhanced descriptions - Tool Call: Client invokes
kiro-subagents.{agent-name}with prompt, directory, and optional sessionID - Session Setup: Create/retrieve
~/.kiro/sub-agents/sessions/{sessionID}/ - Prompt Enhancement: Prepend directory context + append system prompt template
- Execution: Run
kiro-cli chat --agent {name} --no-interactive [--resume] "{prompt}"in session directory - Context Persistence: kiro-cli stores conversation history in session directory automatically
- Response: Read from
{sessionDir}/response-{uuid}.txtor fallback to stdout
TODO
Security
- Prompt Sanitizer
- Implement prompt sanitization to prevent execution of malicious prompts
- Protect against prompt injection attacks from:
fs_read- malicious content in filesweb_fetch- malicious content from web pagesweb_search- malicious content in search results- Other external data sources
- Consider:
- Input validation and filtering
- Content escaping strategies
- Sandboxing untrusted content
- Rate limiting and abuse detection
Architecture & Design
-
Agent Organization Strategy
- Evaluate and decide: Should sub-agents be role-based or task-based?
- Role-based (current approach):
- Examples: architect, developer, qa-engineer, security
- Pros: Clear responsibilities, mimics team structure
- Cons: May be too broad, harder to optimize per task
- Task-based alternative:
- Examples: code-analyzer, test-runner, vulnerability-scanner
- Pros: More focused, easier to optimize, composable
- Cons: More agents to manage, potential overlap
- Consider hybrid approach or migration strategy
-
Response Sharing Without File System Access
- Find alternative method to share sub-agent responses with orchestrator
- Current limitation: Every sub-agent requires
fs_readandfs_writeinallowedToolsto write response files - Desired: Context separation without mandatory file system tool allowance
- Potential approaches:
- Direct stdout capture (current fallback, but less reliable)
- Structured output format in stdout (JSON, YAML)
- MCP-level response interception
- Custom protocol between budgie and kiro-cli
- Environment variables or pipes for response data
- Benefits: Better security, more flexible agent permissions
License
See LICENSE file for details.