hitl mcp
仅询问代理工作流的HITL MCP服务器。
  
______________________________________________________________________
目录
______________________________________________________________________
背景
在许多Agent系统中,Agent最终会达到无法自主继续的地步:
- 一个人必须批准或拒绝一个决定
- 一个人必须从几个候选人中选择一个
- 人类必须提供缺失的业务输入
- 工作流必须暂停,直到手动确认到达
在没有专用HITL层的情况下,这些工作流通常使用特别提示、侧通道UI或自定义回调协议来实现。这造成了三个反复出现的问题:
- Agent和应用程序不共享“待定人工输入”的稳定模型。
- 人工答案很难与请求它们的确切代理运行和会话相关联。
- 等待、部分提交、取消和恢复语义在客户端之间变得不一致。
hitl-mcp 通过为人类问题暴露一个狭窄、明确的契约来解决这个问题:
- 代理创建问题
- 客户或运营商用户界面阅读未决问题
- 人类回答、跳过或取消它们
- 代理在调用者作用域的状态机上等待,直到工作完成
______________________________________________________________________
什么是hitl mcp
hitl-mcp 是一个 面向问题的人在环服务器 基于MCP和HTTP构建。
它在相同的底层状态上提供两个访问表面:
- MCP工具 用于代理和代理平台
- HTTP API 用于操作员控制台、后端或自定义审批UI
公共抽象是有意的小:
- 公共单位是
question - 问题属于a 呼叫者范围
- 答案可以逐步提交
- 等待被建模为范围级操作,而不是问题级长轮询
该服务器专为代理作为发起者,但由人类完成部分决策循环的工作流而设计。
______________________________________________________________________
目标
- 为Agent工作流提供稳定、最小的HITL合同。
- 通过以下方式明确呼叫者隔离
agent_identity和agent_session_id. - 支持同一调用者范围内的多个未决问题。
- 支持部分进度,而不是强制一次性提交最终结果。
- 允许MCP和HTTP客户端在相同的基础问题状态上操作。
- 保持存储可插拔,以便本地开发可以使用内存,生产可以使用Redis。
- 通过健康状况、准备状态、指标和结构化日志来观察操作行为。
______________________________________________________________________
非目标
- 不是通用的工作流引擎。
- 不是用于审批控制台的UI框架。
- 不是任务队列或事件总线。
- 不是通用的表单生成器。
- 不是用于访问控制和审阅者分配的策略引擎。
- 不是用于任意业务流程的持久编排平台。
hitl-mcp 仅管理问题状态、调用者范围、等待语义和答案提交。
______________________________________________________________________
核心模型
公共单位:问题
从外部来看,系统只暴露 question.
一个问题是:
- 服务器生成
question_id - 一
type - 提示元数据,例如
title,description,tags,以及extra - 一种状态,例如
pending,answered,skipped,或cancelled
支持的问题类型:
single_choicemulti_choicetextbooleanrange
呼叫者范围
每个操作的范围如下:
agent_identityagent_session_id
该范围是以下内容的隔离边界:
- 提出问题
- 列出未决问题
- 等待进展
- 提交答案
- 取消提问
只要两个代理的调用者范围不同,它们就可以提出相同的问题而不会发生冲突。
内部团体与公共API
存储层可能仍然在内部使用分组,但分组是一个实现细节。
公众API有意质疑第一:
- 创建问题
- 获取未决问题
- 提交答案
question_id - 取消由
question_id - 在示波器上等待
部分提交
答案不需要一批到达。
服务器接受增量进度:
- 现在回答一个问题
- 稍后回答另一个问题
- 明确跳过可选问题
- 继续等待,直到范围完成
等待模式
hitl_wait 等效作用域级等待行为支持两种模式:
terminal_only:仅当作用域没有未决问题时返回progressive:每次状态更改后返回,然后让调用者再次等待
terminal_only 对于线性工作流来说更简单。 progressive 当调用者需要对每个中间更新做出反应时,效果更好。
______________________________________________________________________
快速开始
安装
git clone
cd hitl-mcp
npm install在开发中运行
npm run dev默认本地绑定:
- HTTP基本URL:
http://0.0.0.0:3000 - MCP基本URL:
http://0.0.0.0:3000/mcp - HTTP API前缀:
/api/v1
使用Docker运行
塑造形象:
docker build -t hitl-mcp .使用内存存储运行:
docker run --rm -p 3000:3000 \
-e MCP_URL=http://localhost:3000 \
hitl-mcp使用Redis运行:
docker run --rm -p 3000:3000 \
-e MCP_URL=http://localhost:3000 \
-e HITL_STORAGE=redis \
-e HITL_REDIS_URL=redis://host.docker.internal:6379 \
hitl-mcp使用环境变量从源代码运行
export MCP_URL=http://localhost:3000
npm run dev最小创建请求
curl -X POST "http://localhost:3000/api/v1/questions" \
-H "Content-Type: application/json" \
-H "x-agent-identity: agent/example" \
-H "x-agent-session-id: session-123" \
-d '{
"title": "Release decision",
"questions": [
{
"type": "single_choice",
"title": "Deploy to production?",
"options": [
{ "value": "yes", "label": "Yes" },
{ "value": "no", "label": "No" }
]
}
]
}'______________________________________________________________________
互动是如何运作的
本节描述了预期的运行时流,无论调用者是使用MCP工具还是HTTP API。
顺序1:标准提问->等待->回答->完成
- Agent在其调用者范围内创建一个或多个问题。
- 代理人立即致电
hitl_wait. - UI或后端获取同一调用者范围的未决问题。
- 人类回答一个或多个悬而未决的问题。
- 代理在作用域上等待。
- 当作用域中没有未决问题时,wait将返回最终结果。
序列2:部分提交
- 代理创建多个问题。
- 人类只回答了一个子集。
- 服务器会保留这些答案,并保留剩余的问题。
- 代理人可以继续等待。
- 其他提交将继续,直到范围完成。
序列3:渐进式等待
HITL_WAIT_MODE=progressive- 代理人打电话来
hitl_wait. - 范围内的任何回答、跳过或取消都会唤醒服务员。
- 等待结果报告了
question_ids变了。 - 代理决定是继续等待还是对中间更新采取行动。
序列4:取消
- 呼叫者取消范围内的一个问题或所有未决问题。
- 服务器更新作用域状态并通知服务员。
- 如果没有悬而未决的问题,范围就变成了终点。
范围语义
等待总是 范围级别 操作。
这是故意的:
- 一次代理运行可能有多个未决问题
- 代理通常关心工作流是否可以继续
- 作用域级等待避免了按问题分段的同步逻辑
操作规则:
- 之后每
hitl_ask,下一个HITL工具调用必须是hitl_wait - 不要治疗
hitl_ask作为完成 - 不要替代
hitl_get_pending_questions对于第一篇帖子,请稍候
______________________________________________________________________
MCP工具
hitl-mcp 公开以下MCP工具:
hitl_ask
为当前调用者范围创建一个或多个问题。
输入形状:
{
"title": "Release decision",
"description": "Human approval required before deploy",
"ttl_seconds": 3600,
"questions": [
{
"type": "boolean",
"title": "Approve deployment?"
}
]
}笔记:
question_id不得由呼叫者提供- 服务器生成
question_id - 一个请求可以创建多个问题
hitl_wait
在当前调用者作用域上等待。
典型响应字段:
statusis_terminalchanged_question_idspending_questionsresolved_questionsanswered_question_idsskipped_question_idscancelled_question_idsis_complete
resolved_questions 包含完整的已解决问题对象及其最终状态和任何存储的答案。
hitl_get_pending_questions
返回当前调用者作用域中的所有未决问题。
hitl_submit_answers
提交新答案和可选跳过。
输入形状:
{
"answers": {
"q_01JXYZ...": { "value": true }
},
"skipped_question_ids": ["q_01JABC..."],
"idempotency_key": "idem-1"
}笔记:
answers可能包含未决问题的任何子集- 可选问题可以明确跳过
- 必填问题不能跳过
- 提交在服务器端累积
hitl_cancel_questions
取消范围内选定的未决问题或所有未决问题。
输入形状:
{
"question_ids": ["q_01JXYZ..."],
"reason": "no longer needed"
}或者:
{
"cancel_all": true
}hitl_get_question
通过以下方式获取一个问题 question_id.
______________________________________________________________________
HTTP API
HTTP控制平面主要用于操作员UI、后端服务和故障排除。
响应信封
所有HTTP响应都使用相同的信封:
{
"request_id": "http-request-id",
"success": true,
"data": {},
"error": null
}失败时:
{
"request_id": "http-request-id",
"success": false,
"data": {},
"error": {
"code": "QUESTION_NOT_FOUND",
"message": "question not found",
"details": null
}
}标题和标识规则
对于问题API,服务器要求在每个调用者范围的请求上都有一个会话头:
- 默认会话标头:
x-agent-session-id
身份规则:
- 发送
x-agent-identity在每个调用者范围的请求上
操作上:
- 服务器读取
agent_identity直接x-agent-identity
GET /api/v1/healthz
返回活动状态。
GET /api/v1/readyz
返回准备状态。
这是对Redis支持的生产部署的正确探测。
GET /api/v1/metrics
返回进程内指标快照。
POST /api/v1/questions
为当前调用者范围创建一个或多个问题。
请求正文:
{
"title": "Release decision",
"description": "Human approval required before deploy",
"ttl_seconds": 3600,
"questions": [
{
"type": "single_choice",
"title": "Deploy to production?",
"options": [
{ "value": "yes", "label": "Yes" },
{ "value": "no", "label": "No" }
]
},
{
"type": "text",
"title": "Anything to note?",
"required": false
}
]
}支持的问题有效载荷:
single_choice随着optionsmulti_choice随着optionstext可选text_constraintsbooleanrange随着range_constraints
GET /api/v1/questions/pending
返回当前调用者作用域的所有未决问题。
POST /api/v1/questions/answers
提交已回答和跳过的问题。
请求正文:
{
"answers": {
"q_01JXYZ...": { "value": "yes" }
},
"skipped_question_ids": ["q_01JABC..."],
"idempotency_key": "idem-1"
}行为:
- 接受部分进展
- 保持累积作用域状态
- 成功提交后唤醒范围服务员
典型错误代码:
QUESTION_NOT_FOUNDANSWER_VALIDATION_FAILED
POST /api/v1/questions/cancel
取消当前呼叫者范围内的未决问题。
请求正文:
{
"question_ids": ["q_01JXYZ..."],
"reason": "no longer needed"
}或者:
{
"cancel_all": true
}GET /api/v1/questions/:question_id
通过以下方式获取一个问题 question_id.
如果问题不存在,服务器将返回 404 随着 QUESTION_NOT_FOUND.
______________________________________________________________________
运行时配置
配置源和优先级
配置按以下顺序加载:
- 内置默认值
config/hitl-mcp.yaml.env- 过程环境变量
后来的来源会取代以前的来源。
环境变量
代码库当前支持以下环境变量。
| 变量 | 默认值 | 目的 | 何时更改 |
|---|---|---|---|
PORT | 3000 | 回退HTTP端口。相当于 HITL_HTTP_PORT 当设置时。 | 仅在运行时注入时更改 PORT 或者当平台需要固定端口环境时。 |
MCP_URL | http://0.0.0.0:3000 | MCP服务器元数据使用的公共基URL。 | 更改任何非本地部署,以便MCP客户端接收可访问的外部URL |
HITL_SERVER_NAME | hitl-mcp | MCP服务器名称元数据。 | 将此服务器嵌入到其他产品标识下时进行更改。 |
HITL_SERVER_VERSION | 0.1.0 | MCP服务器版本元数据。 | 发布具有显式运行时版本的打包版本时进行更改。 |
HITL_HTTP_HOST | 0.0.0.0 | HTTP绑定主机。 | 仅当您有意只进行环回绑定或使用其他接口时才进行更改。 |
HITL_HTTP_PORT | 3000 | 显式HTTP端口。覆盖默认端口。 | 使用自定义端口映射更改本地多服务设置或生产平台。 |
HITL_HTTP_API_PREFIX | /api/v1 | HTTP控制平面路由的前缀。 | 仅当您需要将API装载到不同的路径段之后时才更改。 |
HITL_STORAGE | memory | 存储后端选择: memory 或 redis。 | 设置为 redis 用于多进程或持久部署。 |
HITL_REDIS_URL | redis://127.0.0.1:6379 | Redis连接URL。 | 需要时 HITL_STORAGE=redis 外部本地违约。 |
HITL_REDIS_PREFIX | hitl | Redis密钥前缀。 | 当多个环境共享一个Redis实例时更改。 |
HITL_TTL_SECONDS | 604800 | 新创建的问题集的默认TTL。 | 更改以使未决问题保留与您的业务SLA保持一致。 |
HITL_ANSWERED_RETENTION_SECONDS | 2592000 | 应答状态的保留窗口。 | 当可审计性或存储压力需要不同的保留期时,请进行更改。 |
HITL_PENDING_MAX_WAIT_SECONDS | 0 | 一次等待呼叫的最长持续时间。 0 意味着没有超时限制。 | 更改何时需要有界等待以进行工作进程调度或请求生命周期控制。 |
HITL_WAIT_MODE | terminal_only | 作用域等待行为: terminal_only 或 progressive。 | 设置为 progressive 当调用者必须对每个中间更新做出反应时。 |
HITL_AGENT_SESSION_HEADER | x-agent-session-id | 用于读取的标头名称 agent_session_id. | 与使用其他会话标头的现有网关或客户端集成时进行更改。 |
HITL_CREATE_CONFLICT_POLICY | error | 在配置界面中创建冲突策略。 | 保持默认值。当前代码验证并加载它,但它当前未被请求处理程序应用。 |
HITL_LOG_LEVEL | info | 结构化日志记录级别: debug, info, warn, error | 提高或降低详细程度,以满足调试和生产噪音要求。 |
HITL_ENABLE_METRICS | true | 在配置中启用指标收集。 | 保持启用状态,除非您有意将可观测性开销降至最低。 |
YAML示例
http:
host: 0.0.0.0
port: 3000
apiPrefix: /api/v1
storage:
kind: redis
redis:
url: redis://127.0.0.1:6379
keyPrefix: hitl
ttl:
defaultSeconds: 604800
answeredRetentionSeconds: 2592000
pending:
maxWaitSeconds: 0
waitMode: terminal_only
agentIdentity:
sessionHeader: x-agent-session-id
createConflictPolicy: error
observability:
logLevel: info
enableMetrics: true配置建议
本地开发
HITL_STORAGE=memory- 发送
x-agent-identity来自您的客户或测试工具 - 保持
HITL_WAIT_MODE=terminal_only
共享开发或暂存
HITL_STORAGE=redis- 设置一个真实
MCP_URL - 使用独特的
HITL_REDIS_PREFIX - 确保上游呼叫者始终提供
x-agent-identity
生产
HITL_STORAGE=redis- 集
MCP_URL指向外部可访问的URL - 电线准备就绪
/api/v1/readyz - 明确审查TTL和保留值
- 确保上游呼叫者始终提供
x-agent-identity
______________________________________________________________________
它在内部是如何工作的
作用域状态机
hitl-mcp 在调用者范围级别保持问题进度。
每个状态更改操作都会更新一个范围快照,其中包含:
- 未决问题
- 已解决的问题,包含完整的问题有效载荷和答案(如果可用)
- 已回答的问题ID
- 跳过的问题ID
- 已取消的问题ID
- 更改了问题ID
- 完成状态
此快照是等待结果的真实来源。
服务员通知模型
服务器保存一个由调用者作用域键入的进程内服务员注册表。
当收到回复或取消时:
- 存储已更新
- 计算新的作用域快照
- 通知了那个炉灶的服务员
hitl_wait根据配置的等待模式进行解析
存储选择
存在两种存储模式:
- 记忆:简单,流程本地化,适合测试和本地开发
- 瑞迪斯:跨流程耐用,适合实际部署
如果在运行时初始化期间选择了Redis但不可用,服务器将回退到内存存储并记录警告。
这种回退在本地开发中很有用,但生产环境应将其视为配置错误的信号。
身份处理
对于HTTP问题API:
- 会话标识来自
HITL_AGENT_SESSION_HEADER - 呼叫者身份来自
x-agent-identity
对于MCP工具调用:
- 服务器从请求上下文将调用者作用域注入MCP工具状态
- 工具层读取
agent_identity和agent_session_id从注射状态
______________________________________________________________________
建筑
运行时有五个主要层。
1.配置层
从默认值、YAML加载并验证配置, .env,以及运行时环境变量。
2.服务器层
构建MCP服务器和HTTP应用程序,连接中间件,并注册路由和工具。
3.服务层
HitlService 定义以下操作行为:
- 创造
- 列表待定
- 等待
- 提交答案
- 取消
- 获取问题
这是主要的应用边界。
4.存储层
提供以下存储库实现:
- 内存开发和测试
- Redis支持的持久性
5.观测层
提供:
- 结构化日志
- 请求ID
- 准备就绪检查
- 度量快照
请求流摘要
对于HTTP:
- 调用者上下文中间件解析身份和会话
- 路由处理程序验证输入和调用
HitlService - 存储库更新状态
- 回复被包裹在标准信封中
对于MCP:
- 检查MCP请求上下文
- 调用者作用域被注入到工具状态中
- 工具处理程序委托给
HitlService - 工具输出反映了最新的作用域状态
______________________________________________________________________
运营
健康和准备
- 生活:
GET /api/v1/healthz - 准备就绪:
GET /api/v1/readyz - 韵律学:
GET /api/v1/metrics
使用就绪性而非活性来保护Redis支持的生产流量。
日志记录
服务器发出结构化的请求和错误日志。
集 HITL_LOG_LEVEL=debug 在对请求流或存储库行为进行故障排除时。
指标
指标通过以下方式以JSON快照的形式公开 /api/v1/metrics.
当前的实现跟踪操作信号,如等待时间和待处理计数。
常见部署检查
在声明部署正常之前,请验证:
MCP_URL匹配外部可访问的URL。- 暴露的HTTP端口与您的运行时或入口映射匹配。
HITL_STORAGE=redis与可访问的Redis实例配对。- 上游呼叫者发送
x-agent-identity以及所配置的会话报头。 /api/v1/healthz,/api/v1/readyz,以及/api/v1/metrics所有人都按照预期做出了回应。
______________________________________________________________________
项目结构
.
├── config/ # YAML configuration examples
├── docs/
│ ├── api/ # MCP tool and HTTP API reference docs
│ └── runbooks/ # Operational runbooks
├── src/
│ ├── config/ # Config schema, defaults, loaders
│ ├── core/ # HitlService application logic
│ ├── domain/ # Domain types, schemas, validators
│ ├── http/ # Hono routes, middleware, response helpers
│ ├── mcp/ # MCP tool registration and caller-scope helpers
│ ├── observability/ # Logging and metrics
│ ├── state/ # Waiter and state-machine helpers
│ └── storage/ # In-memory and Redis repositories
├── tests/ # Unit and integration coverage
├── Dockerfile # Production-oriented container build
└── index.ts # Runtime entrypoint