使用说明
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/<uuid> - 通过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 <name> --no-interactive <prompt> │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Docker Volumes: │
│ budgie-session-<uuid> ← 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-<uuid>),确保:
- 会话之间完全隔离
- 无SQLite争用
- 虎皮鹦鹉出口的清洁工作
设计决策
每个会话一个Docker卷
每个sessionId都有一个单独的Docker卷,消除了SQLite争用并保持了干净的隔离。清理模式特定:
| 模式 | 清理操作 |
|---|---|
| 正常 | os.RemoveAll(filepath.Join(baseDir, sessionId)) |
| 沙箱 | docker volume rm budgie-session-<sessionId> |
身份验证令牌处理
主机的kiro-cli数据目录以只读方式装载在 /auth.入口点副本 data.sqlite3 在首次运行时同步到会话卷,然后仅同步 auth_kv 后续运行表(保留对话历史)。
容器路径的快速增强
在沙盒模式下,提示中的工作目录从主机路径更改为 /workspace:
- 正常:
"In directory /Users/x/project, <prompt>" - 沙箱:
"In directory /workspace, <prompt>"
跨平台注意事项
- 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-<sessionId>:/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 <name> --no-interactive [--resume] '<prompt>'
边缘案例
- 孤立卷:如果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.<agent-name>:
输入:
{
"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<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
实现细节
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-interactiveflag确保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文件。