Budgie-Kiro(CLI)子代理MCP服务器
一个基于Go的MCP服务器,它将Kiro代理作为编排的MCP工具公开。
引言
此MCP服务器通过模型上下文协议使kiro-cli可以使用子代理。我知道,当kiro-cli将来原生支持子代理时,这可能会过时。是的,其他工具已经支持子代理,但我想使用kiro-cli。
这是一个5-6小时的个人副项目——不要指望有企业级代码。我让它在我的旧MacBook上工作。你可以自由地让它为你工作,并提出改进建议。
特性
- 自动从以下位置发现代理
~/.kiro/agents/*.json - 在描述中使用“sub-agent:”前缀过滤代理
- 创建隔离会话工作区:
~/.kiro/sub-agents/sessions/ - 通过sessionId支持多回合对话
--resume旗帜 - 健康监测 具有自动超时检测和重试逻辑
- 自动重试 超时或进程崩溃(1次重试,2秒回退)
- 健康指标 跟踪每个代理的成功率、持续时间和失败次数
- 强制目录参数 用于安全和显式工作目录控制
- 响应文件解耦 -代理响应写入会话目录,而不是工作目录
- 沙盒模式 -在隔离的Docker容器中运行子代理以确保安全
安装
go build -o budgie ./cmd/server沙盒模式
沙盒模式在隔离的Docker容器内运行每个子代理,提供:
- 文件系统隔离 -代理只能访问已装载的工作目录
- 凭证保护 -无法访问主机凭据(
~/.aws/,~/.ssh/等等) - 受控执行 -限制药剂作用的爆炸半径
建筑
┌─────────────────────────────────────────────────────────────────┐
│ Host (macOS/Linux) │
│ │
│ ┌──────────────┐ │
│ │ Budgie │ │
│ │ MCP Server │ │
│ └──────┬───────┘ │
│ │ │
│ │ docker run │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Docker Container │ │
│ │ │ │
│ │ /workspace ← working directory (RW) │ │
│ │ /root/.local/share/kiro-cli ← session volume (RW) │ │
│ │ /auth ← host kiro auth (RO) │ │
│ │ /root/.kiro/ ← agent configs (RO) │ │
│ │ │ │
│ │ kiro-cli chat --agent --no-interactive
│ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Docker Volumes: │
│ budgie-session- ← one per session, deleted on exit │
└─────────────────────────────────────────────────────────────────┘先决条件
- 码头工人 已安装并正在运行
- 沙盒图像 建造:
docker build -t budgie-sandbox:latest .用法
# Enable sandbox mode
./budgie --sandbox
# With custom image
./budgie --sandbox --sandbox-image my-custom-image:latest集装箱支架
| 源(主机) | 容器路径 | 模式 | 目的 |
|---|---|---|---|
| 工作目录 | /workspace | RW | 用户的项目文件 |
| Docker卷 | /root/.local/share/kiro-cli | RW | 会话状态 |
~/Library/Application Support/kiro-cli/ | /auth | RO | 认证令牌 |
~/.kiro/ | /root/.kiro/ | RO | 代理配置 |
会话隔离
每个会话都有自己的Docker卷(budgie-session-),确保:
- 会话之间完全隔离
- 无SQLite争用
- 虎皮鹦鹉出口的清洁工作
设计决策
每个会话一个Docker卷
每个sessionId都有一个单独的Docker卷,消除了SQLite争用并保持了干净的隔离。清理模式特定:
| 模式 | 清理操作 |
|---|---|
| 正常 | os.RemoveAll(filepath.Join(baseDir, sessionId)) |
| 沙箱 | docker volume rm budgie-session- |
身份验证令牌处理
主机的kiro-cli数据目录以只读方式装载在 /auth.入口点副本 data.sqlite3 在首次运行时同步到会话卷,然后仅同步 auth_kv 后续运行表(保留对话历史)。
容器路径的快速增强
在沙盒模式下,提示中的工作目录从主机路径更改为 /workspace:
- 正常: `"In directory /Users/x/project,
"`
- 沙箱: `"In directory /workspace,
"`
跨平台注意事项
- kiro-cli二进制文件必须是Linux(无法挂载macOS二进制文件)
- 身份验证数据路径不同:macOS
~/Library/Application Support/kiro-cli/vs Linux~/.local/share/kiro-cli/ - Budgie检测主机操作系统并从正确的路径装载
kiro-cli会话管理
了解kiro-cli如何存储上下文对于 --resume 工作。
存储位置:
- macOS:
~/Library/Application Support/kiro-cli/data.sqlite3 - Linux:
~/.local/share/kiro-cli/data.sqlite3
如何 --resume 作品:
- kiro-cli使用
pwd作为钥匙conversations_v2桌子 --resume加载对话历史记录,其中key = $(pwd)- 集装箱内:
key = /root/.local/share/kiro-cli - 每个会话卷都装载在同一路径上→
--resume查找历史
Docker镜像
需要自定义映像,因为kiro-cli必须是Linux二进制文件。
Dockerfile:
FROM buildpack-deps:bookworm
# OpenJDK 21 (Eclipse Temurin)
RUN apt-get update && apt-get install -y --no-install-recommends wget apt-transport-https gpg \
&& wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public | gpg --dearmor -o /usr/share/keyrings/adoptium.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/adoptium.gpg] https://packages.adoptium.net/artifactory/deb bookworm main" > /etc/apt/sources.list.d/adoptium.list \
&& apt-get update && apt-get install -y --no-install-recommends temurin-21-jdk \
&& rm -rf /var/lib/apt/lists/*
# kubectl
RUN curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key | gpg --dearmor -o /usr/share/keyrings/kubernetes.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/kubernetes.gpg] https://pkgs.k8s.io/core:/stable:/v1.31/deb/ /" > /etc/apt/sources.list.d/kubernetes.list \
&& apt-get update && apt-get install -y --no-install-recommends kubectl \
&& rm -rf /var/lib/apt/lists/*
# Additional dev tools
RUN apt-get update && apt-get install -y --no-install-recommends jq tree ripgrep \
&& rm -rf /var/lib/apt/lists/*
# sqlite3 for entrypoint auth sync
RUN apt-get update && apt-get install -y --no-install-recommends sqlite3 \
&& rm -rf /var/lib/apt/lists/*
# kiro-cli
RUN curl -fsSL https://cli.kiro.dev/install | bash
WORKDIR /workspace
COPY docker/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]入口点脚本(docker/entrypoint.sh):
#!/bin/sh
export PATH="$HOME/.local/bin:$PATH"
KIRO_DATA_DIR="/root/.local/share/kiro-cli"
AUTH_SOURCE="/auth/data.sqlite3"
TARGET_DB="$KIRO_DATA_DIR/data.sqlite3"
mkdir -p "$KIRO_DATA_DIR"
if [ ! -f "$TARGET_DB" ]; then
cp "$AUTH_SOURCE" "$TARGET_DB" 2>/dev/null
elif [ -f "$AUTH_SOURCE" ]; then
sqlite3 "$TARGET_DB" "ATTACH '$AUTH_SOURCE' AS auth_src; \
DELETE FROM auth_kv; \
INSERT INTO auth_kv SELECT * FROM auth_src.auth_kv;" 2>/dev/null
fi
exec "$@"完整的Docker运行命令:
docker run --rm \
-v "/host/working/dir:/workspace:rw" \
-v "budgie-session-:/root/.local/share/kiro-cli:rw" \
-v "$HOME/Library/Application Support/kiro-cli:/auth:ro" \
-v "$HOME/.kiro:/root/.kiro:ro" \
budgie-sandbox:latest \
kiro-cli chat --agent --no-interactive [--resume] '
'边缘案例
- 孤立卷:如果budge崩溃,卷将保持不变。恢复:
docker volume ls -q | grep budgie-session- | xargs docker volume rm - Docker不可用:当出现明显错误时,会快速失败
--sandbox不使用Docker - 网络接入:容器需要用于kiro-cli API调用的出站HTTPS(默认网桥网络工作)
- 容器中的MCP服务器:可以引用主机路径;文件作为限制
______________________________________________________________________
用法
作为MCP服务器
添加到您的编排代理 mcpServers 配置:
{
"mcpServers": {
"kiro-subagents": {
"command": "/path/to/budgie",
"args": [],
"type": "stdio"
}
},
"tools": ["@kiro-subagents"]
}命令行选项
# Default usage
./budgie
# Custom timeout (default: 10 minutes)
./budgie --agent-timeout 5m
# Sandbox mode (run agents in Docker containers)
./budgie --sandbox
./budgie --sandbox --sandbox-image custom-image:latest
# 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.
# List registered tools and exit
./budgie --list-tools
# Verbose mode (save chat debug logs to session directories)
./budgie --verbose模型选择
默认模型为 claude-sonnet-4.5。可以通过代理提示文件中的frontmatter为每个代理覆盖模型:
---
name: my-agent
model: claude-opus-4
---工具接口
每个代理都成为一个名为的工具 kiro-subagents.:
输入:
{
"prompt": "Your task description",
"sessionId": "optional-uuid-for-continuation",
"directory": "required-absolute-path-to-working-directory"
}输出:
{
"response": "Agent's response",
"sessionId": "uuid-for-this-session"
}重要提示: 这 directory 参数是 强制性的。没有它的调用将失败并出现错误。
健康监测
Budgie自动监控代理运行状况并提供恢复:
- 超时:10分钟后代理调用超时(可配置为
--agent-timeout) - 重试:超时或崩溃时自动重试(1次重试,2秒回退)
- 健康指标:跟踪每个代理的成功率、持续时间和失败次数
- 增强错误:故障包括运行状况上下文,以便更好地进行调试
健康检查工具
通过以下方式查询健康指标 kiro-subagents.health-check:
答复:
{
"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": ""
}
]
}代理配置
代理JSON文件(~/.kiro/agents/)
通过从Agents目录加载JSON文件来发现代理:
{
"name": "test-agent",
"description": "sub-agent: Validation and testing specialist",
"allowedTools": [
"fs_read",
"fs_write"
]
}关键要求:
name字段(必填)-确定传递给kiro-cli的代理名称description以“sub-agent:”开头(必填)-用于过滤和注册- 工具名称已规范化:
"test-agent"→"kiro-subagents.test-agent" - 必须包括
fs_read和fs_write在allowedTools-代理需要创建响应文件,该文件将编排器和子代理之间的上下文解耦
代理提示文件(~/.kiro/sub-agents/prompts/)
每个代理都可以有一个相应的提示文件: {agent-name}.md
例子: ~/.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-sonnet-4.5
tags:
- testing
- validation
- mcp
---
# Test Agent
You are a specialized testing agent...正面结构:
- YAML frontmatter之间
---分隔符 - 必填字段:
name,description - 可选字段:
capabilities,use_when,avoid_when,tools,model,tags - 用于为MCP生成增强的工具描述
- 不修改代理的系统提示(由kiro-cli定义)
系统提示模板(~/.kiro/sub-agents/prompts/_system.md)
一个特殊的系统提示模板,附加到每个代理调用中:
Write your response to: {{RESPONSE_FILE}}
Working directory: {{WORKING_DIRECTORY}}
Requirements:
- Plain text only
- No markdown formatting
- Concise output占位符替换:
{{RESPONSE_FILE}}→response-{uuid}.txt{{WORKING_DIRECTORY}}→ 目标工作目录
这确保了代理知道在哪里做他们的实际工作,以及在哪里写他们的响应文件。
注: 两者 _system.md 和 _context-summary.md 每次使用时都会加载,允许在不重新启动服务器的情况下进行动态微调。
上下文摘要提示模板(~/.kiro/sub-agents/prompts/_context-summary.md)
代理不写入响应文件时使用的回退提示模板:
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占位符替换:
{{RESPONSE_FILE}}→response-{uuid}.txt
这种回退确保了即使忽略系统提示,编排器也可以始终检索代理的响应。
编排器配置
对于编排器代理,将其配置为使用budgie MCP服务器:
{
"name": "orchestrator",
"description": "Master orchestrator agent",
"mcpServers": {
"kiro-subagents": {
"command": "/path/to/budgie",
"args": [],
"type": "stdio"
}
},
"tools": ["@kiro-subagents"]
}编排器提示应位于 ~/.kiro/sub-agents/prompts/orchestrator.md.
建筑
Orchestrator → MCP Client → Budgie MCP Server → kiro-cli → Sub-Agent
↓
Health Monitor
(timeout, retry, metrics)目录隔离
系统使用 两个单独的目录:
- 工作目录 (
input.Directory)
- 强制性的 -必须在每次工具调用中明确提供 - 通过提示传递给代理: "In directory {input.Directory}, ..." - 代理读取/写入用户文件的位置 - 安全性:无默认回退以防止意外操作
- 会话目录 (
sessionDir)
- ~/.kiro/sub-agents/sessions/{sessionID}/ - 每个会话的独立工作区 - kiro-cli实际运行的地方(cmd.Dir = sessionDir) - 写入响应文件的位置: {sessionDir}/response-{uuid}.txt - 响应文件永远不会写入工作目录
子代理呼叫流
此图显示了通过MCP服务器调用子代理时的完整流程。
sequenceDiagram
participant Client as MCP Client
participant Server as MCP Server
(main.go)
participant Handler as Tool Handler
(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
{tool: "kiro-subagents.agent-name",
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:
~/.kiro/sub-agents/sessions/{sessionId}
Sessions-->>Handler: sessionDir = ~/.kiro/sub-agents/sessions/{sessionId}
Note over Handler: Generate unique response file:
response-{uuid}.txt
Full path: {sessionDir}/response-{uuid}.txt
NOT in working directory!
Note over Handler: Enhance prompt:
"In directory {input.Directory}, {prompt}"
alt systemPromptTemplate exists
Note over Handler: Inject system prompt with:
{{RESPONSE_FILE}} → response-{uuid}.txt
{{WORKING_DIRECTORY}} → input.Directory
end
Handler->>Kiro: Execute(ctx, agentName, enhancedPrompt,
sessionDir, sessionID)
Note over Kiro: Start timer
Kiro->>Kiro: executeOnce(ctx, agentName, prompt,
sessionDir, sessionID)
Note over Kiro: Create timeout context
(default: 10 minutes)
Note over Kiro: Build args:
["chat", "--agent", agentName,
"--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)
cmd.Dir = sessionDir
Note over KiroCLI: Execute agent in session directory
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,
errorMsg, isTimeout)
else success
Kiro->>Health: RecordSuccess(agentName, duration)
end
Kiro-->>Handler: Result{Output, SessionID, Error,
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:
{sessionDir}/response-{uuid}.txt
(~/.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,
"Write response to file...",
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实现细节
1.工具注册(启动)
agents.Load(agentsDir)-从以下位置加载代理JSON文件~/.kiro/agents/frontmatter.LoadFromPrompt(promptsDir, agentName)-从加载代理元数据~/.kiro/sub-agents/prompts/{agent}.mdagents.NormalizeToolName(agentName)-将代理名称转换为工具名称(例如,“测试代理”→ “kiro次级试剂。测试试剂”)mcp.AddTool(server, tool, handler)-在MCP服务器上注册工具
2.请求流
- 输入:
ToolInput{Prompt, SessionID, Directory}
- Prompt (必填):代理的任务描述 - SessionID (可选):UUID以继续现有会话 - Directory (必填):代理人操作的工作目录
- 输出:
ToolOutput{Response, SessionID}
3.会话管理
sessions.GetWorkspaceDir(sessionID)-创建/检索会话目录- 每个会话都得到一个独立的目录:
~/.kiro/sub-agents/sessions/{uuid}/ - 当sessionID被重用时,会话会在调用之间持续存在
- 响应文件被写入会话目录,而不是工作目录
4.快速增强
- 前置目录上下文:
"In directory {input.Directory}, {prompt}" - 注入替换占位符的系统提示模板
- 确保代理知道工作目录和响应文件的位置
5.执行
kiro.Execute()-具有重试逻辑的主执行exec.CommandContext()-生成超时的kiro-cli进程- 命令在会话目录中运行
--agent和--no-interactive旗帜 --resume如果继续现有会话,则添加标记
6.响应处理
- 初级:阅读
response-{uuid}.txt会话目录中的文件 - 回退:使用kiro-cli的stdout
- 次要回退:请求显式文件写入并重试
7.健康监测
health.Monitor跟踪每个代理的成功/失败率- 记录持续时间、错误消息、超时状态
- 错误响应中包含的指标有助于调试
Kiro CLI上下文管理
会话持久性--恢复标志
该系统利用kiro-cli的内置上下文管理:
- 会话目录结构
- 每节课获得: ~/.kiro/sub-agents/sessions/{sessionID}/ - kiro-cli与一起运行 cmd.Dir = sessionDir - kiro-cli将对话历史(上下文)内部绑定到此目录 - 每个子代理都使用此目录写入响应-{uuid}.txt文件 - budgie实例会跟踪自己的会话目录,并在退出时将其删除
- 上下文恢复
- 第一通电话: kiro-cli chat --agent {name} --no-interactive "{prompt}" - 后续通话: kiro-cli chat --agent {name} --no-interactive --resume "{prompt}" - 这 --resume 标志告诉kiro-cli从当前目录加载会话历史记录 - kiro-cli在会话目录内部管理上下文文件
- 非交互模式
- --no-interactive flag确保kiro-cli在单一响应后退出 - 无需用户提示或交互式输入 - 适用于程序化/自动化执行
完整流程摘要
- 初创公司:来自的负载代理
~/.kiro/agents/*.json,过滤器"sub-agent:"前缀 - 工具注册:从以下位置加载前体
~/.kiro/sub-agents/prompts/{agent}.md用于增强描述 - 工具调用:客户端调用
kiro-subagents.{agent-name}带有提示符、目录和可选会话ID - 会话设置:创建/检索
~/.kiro/sub-agents/sessions/{sessionID}/ - 提示增强:前置目录上下文+附加系统提示模板
- 执行:运行
kiro-cli chat --agent {name} --no-interactive [--resume] "{prompt}"会话目录中 - 上下文持久性:kiro-cli会自动将对话历史存储在会话目录中
- 响应:阅读
{sessionDir}/response-{uuid}.txt或回退到stdout
TODO
安全
- 快速消毒剂
- 实施即时清理,防止执行恶意提示 - 防止来自以下方面的快速注射攻击: - fs_read -文件中的恶意内容 - web_fetch -网页中的恶意内容 - web_search -搜索结果中的恶意内容 - 其他外部数据源 - 考虑: - 输入验证和过滤 - 内容逃逸策略 - 对不受信任的内容进行沙盒处理 - 速率限制和滥用检测
建筑与设计
- 代理组织策略
- 评估并决定:子代理是否应该 基于角色的 或 任务型? - 基于角色的 (当前方法): - 示例:架构师、开发人员、质量保证工程师、安全 - 优点:职责明确,模仿团队结构 - 缺点:可能过于宽泛,难以按任务进行优化 - 任务型 备选方案: - 示例:代码分析器、测试运行器、漏洞扫描程序 - 优点:更专注、更容易优化、可组合 - 缺点:需要管理的代理更多,可能存在重叠 - 考虑混合方法或迁移策略
- 无文件系统访问的响应共享
- 找到与编排器共享子代理响应的替代方法 - 当前限制:每个子代理都需要 fs_read 和 fs_write 在 allowedTools 写入响应文件 - 期望:没有强制文件系统工具允许的上下文分离 - 潜在方法: - 直接stdout捕获(当前回退,但可靠性较低) - stdout中的结构化输出格式(JSON、YAML) - MCP级响应拦截 - budgie和kiro-cli之间的自定义协议 - 响应数据的环境变量或管道 - 优点:更好的安全性,更灵活的代理权限
许可证
有关详细信息,请参阅LICENSE文件。
