Letta OpenCode 插件
MCP服务器,它使Letta代理能够将任务委托给OpenCode执行。
架构概述
这个插件实现了“将OpenCode作为附加组件”的模式,在该模式中,OpenCode充当Letta代理的临时执行层:
- 莱塔特(Letta)特工 保持上下文、规划和协调
- OpenCode(奥普恩代码) 负责具体执行开发任务
- 交流 通过Letta内存块双向发生
- 交通 使用基于HTTP的MCP(JSON-RPC)
关键组件
- MCP服务器 - 可流式传输的HTTP JSON-RPC服务器,提供OpenCode功能(MCP协议2025-06-18)
- Letta客户端适配器 带重试逻辑的Letta API类型包装器
- 执行经理 - 带资源限制的Docker容器编排
- 工作区内存块 - Letta与OpenCode之间的共享状态
- HTTP传输 - 基于会话的HTTP流传输,具备源验证和DNS重绑定保护
- 代理ID头部支持 - 自动从(数据中)提取代理ID
x-agent-idHTTP头部
安装
npm install
npm run build配置
复制 .env.example 到;向;朝 .env 并配置:
所需变量
LETTA_API_URL- Letta API 端点(例如,https://letta.oculair.ca)LETTA_API_TOKEN- Letta API的身份验证令牌
运行器配置
RUNNER_IMAGE- OpenCode 执行的 Docker 镜像(默认:ghcr.io/anthropics/claude-code:latest)RUNNER_CPU_LIMIT- 每个容器的CPU限制(默认:2.0)RUNNER_MEMORY_LIMIT- 每个容器的内存限制(默认:2g)RUNNER_TIMEOUT_MS- 任务执行超时时间(以毫秒为单位)(默认:300000)
任务队列
MAX_CONCURRENT_TASKS- 最大并发任务执行数(默认:3)
服务器配置
MCP_PORT- 服务器端口(默认:3456)MCP_HOST- 服务器主机(默认:0.0.0.0)DEBUG- 启用调试日志记录(默认:false)
特性标志(或功能开关)
ENABLE_ASYNC_EXECUTE- 允许异步任务执行(默认:true)ENFORCE_IDEMPOTENCY- 强制使用幂等性密钥(默认:true)
用法
开发模式
npm run dev生产模式
npm run build
npm start提供的工具
ping
简单的连接测试。
health
返回服务器状态和环境配置。
opencode_execute_task
将开发任务委托给OpenCode,在隔离的Docker容器中执行。
参数:
agent_id(字符串,必填):请求任务的 Letta 代理的 IDtask_description(字符串,必填):要执行的任务的自然语言描述idempotency_key(字符串,可选):用于防止在24小时窗口内重复执行的键timeout_ms(数字,可选):任务执行超时时间(以毫秒为单位)(覆盖默认值)sync(布尔值,可选):如果true,等待完成;如果false,立即返回(默认:false)
返回值:
task_id任务的唯一标识符status当前任务状态(queued,running,completed,failed,timeout)workspace_block_id用于双向通信的工作区内存块的ID- 当……时的额外字段
sync=true:exit_code,duration_ms,output
示例(异步):
{
"agent_id": "agent-123",
"task_description": "Create a new React component for user profile",
"idempotency_key": "profile-component-v1",
"sync": false
}示例(同步):
{
"agent_id": "agent-123",
"task_description": "Run unit tests and return results",
"sync": true,
"timeout_ms": 60000
}开发状态
- \[x\] LETTA-9:引导HTTP MCP服务器框架
- \[x\] LETTA-10:实现带有重试和409错误处理的Letta客户端适配器
- \[x\] LETTA-11:为Docker容器编排创建执行管理器
- \[x\] LETTA-12:实现具有幂等性和队列功能的任务执行工具
- \[x\] LETTA-13:定义带版本控制的工作区模块架构
- \[x\] LETTA-14:添加指标、日志和文档
项目结构
letta-opencode-plugin/
├── src/
│ ├── server.ts # Main MCP server with tool handlers
│ ├── letta-client.ts # Letta API wrapper with retry logic
│ ├── workspace-manager.ts # Workspace memory block management
│ ├── execution-manager.ts # Docker container orchestration
│ ├── task-registry.ts # Task queue and idempotency tracking
│ ├── tools/
│ │ └── execute-task.ts # opencode_execute_task implementation
│ └── types/
│ ├── letta.ts # Letta API types
│ ├── workspace.ts # Workspace block schema
│ ├── execution.ts # Execution manager types
│ └── task.ts # Task registry types
├── dist/ # Compiled output
├── package.json
├── tsconfig.json
├── .env.example
└── README.mdOpenCode 集成
这个插件与OpenCode服务器集成,以提供AI辅助的开发任务执行功能。参见 OPENCODE_INTEGRATION.md 翻译为中文是:“OPENCODE 集成说明.md” 或者 “OPENCODE 集成文档.md”(具体翻译可能根据上下文调整,这里提供了较为通用的译法) 对于:
- OpenCode服务器配置与身份验证
- Claude Sonnet 4.5模型配置
- 代理间通信模式
- 主机凭据挂载策略
- 故障排除指南
主要特点:
- 使用主机系统的OpenCode凭据(无重复API密钥)
- 配置为通过Anthropic使用Claude Sonnet 4.5
- OpenCode代理通过MCP工具与调用的Letta代理进行通信
- 完全访问主机配置的MCP服务器
深入探索建筑学
工作区内存块
工作区块是Letta内存块,具有结构化的JSON模式,支持Letta代理与OpenCode之间的双向通信:
{
version: "1.0.0",
task_id: "task-abc123",
agent_id: "agent-456",
status: "running",
created_at: 1234567890000,
updated_at: 1234567890123,
events: [
{
timestamp: 1234567890100,
type: "task_started",
message: "Task execution started",
data: { /* optional metadata */ }
}
],
artifacts: [
{
timestamp: 1234567890120,
type: "output",
name: "execution_output",
content: "Task completed successfully"
}
],
metadata: { /* custom task metadata */ }
}任务生命周期
- 队列代理来电
opencode_execute_task→ 已注册任务,附带幂等性检查 - 创建工作区工作区内存块已创建并附加到代理
- 执行使用资源限制和超时设置启动的Docker容器
- 显示器捕获了容器日志,事件已写入工作区块
- 完成最终状态和工件已写入工作区块
- 清理任务在24小时幂等性窗口期后从注册表中移除
错误处理
- 409 冲突对于乐观并发,采用指数退避的自动重试机制
- 5xx 错误最多重试3次,每次重试间隔递增
- 超时在宽限期后发送SIGTERM,随后发送SIGKILL
- 队列已满当并发任务数超过最大限制时返回429错误
部署
与HTTP传输一起使用
服务器作为一个独立的HTTP服务运行。通过环境变量对其进行配置:
export LETTA_API_URL=https://letta.oculair.ca
export LETTA_API_TOKEN=your-token-here
export MCP_PORT=3500
npm start然后将客户端连接到 http://localhost:3500/mcp
健康检查: curl http://localhost:3500/health
Docker 部署(兼容 Dockge)
快速入门
# Clone/navigate to the project
cd /opt/stacks/letta-opencode-plugin
# Configure environment
cp .env.example .env
# Edit .env with your Letta API credentials
# Start with Docker Compose
docker compose up -d
# Check health
curl http://localhost:3500/health
# View logs
docker compose logs -fDockge 集成
这个堆栈与Dockge完全兼容。只需:
- 将堆栈目录添加到 Dockge 的堆栈路径中
- 配置
.envDockge 用户界面中的变量 - 从Dockge界面进行部署
重要:Docker 套接字访问
该容器需要访问Docker套接字以启动OpenCode执行容器:
volumes:
- /var/run/docker.sock:/var/run/docker.sock确保 letta 容器中的用户具有适当的 Docker 组权限。
健康监测
该 health 该工具返回用于监控的有用指标:
{
"status": "healthy",
"version": "0.1.0",
"environment": {
"letta_api_url": "https://letta.oculair.ca",
"runner_image": "ghcr.io/anthropics/claude-code:latest"
},
"metrics": {
"active_tasks": 2,
"can_accept_task": true
}
}许可证
麻省理工学院(MIT)
代理ID头部支持
服务器自动从(数据中)提取代理ID x-agent-id 当存在时的HTTP头部。这允许Letta代理在不显式传递的情况下调用MCP服务器 agent_id 在工具参数中。
它是如何运作的
- 头部提取HTTP传输层读取
x-agent-id来自传入请求的头部信息 - 参数注入如果
agent_id如果工具参数中未提供,则会自动从头部注入 - 记录(日志)当DEBUG=true时,会记录代理ID的提取和注入情况,以便进行故障排除
示例用法
# Initialize session
curl -X POST http://localhost:3500/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-protocol-version: 2025-06-18" \
-H "x-agent-id: agent-597b5756-2915-4560-ba6b-91005f085166" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"letta-agent","version":"1.0"}}}'
# Call tool with header (agent_id automatically injected)
curl -X POST http://localhost:3500/mcp \
-H "Content-Type: application/json" \
-H "mcp-session-id: " \
-H "x-agent-id: agent-597b5756-2915-4560-ba6b-91005f085166" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"opencode_execute_task","arguments":{"task_description":"Create a new React component"}}}'调试模式
启用调试日志以查看代理ID头部处理情况:
# In .env
DEBUG=true
# In logs you'll see:
# [http-transport] POST /mcp - 172.17.86.1 (agent: agent-597b5756-2915-4560-ba6b-91005f085166)
# [http-transport] Injected agent_id from x-agent-id header: agent-597b5756-2915-4560-ba6b-91005f085166优先规则
- 显式参数 具有优先权:如果
agent_id如果在工具参数中提供了(相应内容),则忽略头部信息 - 头部备用选项如果
agent_id在参数中缺失了,该x-agent-id使用头部值 - 验证来自任一来源的代理ID必须有效(匹配模式:
^[a-zA-Z0-9\-_]+$)
