expert-booking-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@expert-booking-mcpFind available expert slots for a data science consultation this Friday."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Expert Booking MCP Server
一个面向 AI Agent、支持渐进式工具发现的专家预约 MCP Server。默认端点采用 Streamable HTTP 和 MCP 2026-07-28 modern era 的 server/discover;为保证终态响应时间可验证,旧版 stateless/SSE fallback 会被明确拒绝,不做静默降级。
一条命令验证
npm install && npm test测试会真实启动 Streamable HTTP MCP 端点,用官方 Client 完成能力发现、工具发现与工具调用,并覆盖预约状态机。完整可重复 Demo:
npm run demo启动持久化服务:
cp .env.example .env
set -a; source .env; set +a
npm run dev
# MCP endpoint: http://127.0.0.1:3000/mcp生产构建使用 npm run build && npm start。服务默认仅绑定 localhost,并启用 Host/Origin 校验;远程暴露前必须另加认证。
设计动机、现实风险和未覆盖范围见 NOTES.md。
给本地 Agent 的安装提示词
把下面内容复制给需要安装 MCP 的编码 Agent:
请在当前仓库安装并接入 expert-booking-mcp:
1. 确认 Node.js >= 22,运行 npm ci。
2. 运行 cp .env.example .env && npm run dev,MCP 地址是 http://127.0.0.1:3000/mcp。
3. 按当前 MCP Host 的配置方式添加这个 Streamable HTTP Server,不要改成 stdio。客户端请求需复用 src/temporal-http.ts 的 createTemporalClientFetch,以附带服务要求的动态时间字段。
4. 连接后确认 tools/list 能发现 tool_catalog.search、tool_catalog.read、tool_catalog.call,并通过目录工具搜索、读取和调用 booking 工具。
5. 运行 npm test 验证安装;需要查看完整预约流程时运行 npm run demo。付款由用户在 Agent 外完成,不要实现或代替付款。
如果失败,请保留原始错误并定位原因,不要通过关闭参数校验、时间校验或 Host/Origin 校验来绕过问题。最后告诉我 MCP 配置位置、实际运行的命令和验证结果。Agent 使用流程
默认 tools/list 只返回三个稳定、低上下文成本的 MCP Tool:
MCP Tool | 用途 |
| 检索式预筛选;返回标题、 |
| 通过 |
| 以未经转换的 |
目录中的四个固定逻辑工具是:
逻辑工具 | 关键输入 | 结果 |
|
| 结构化时段候选、总数、下一页游标 |
|
| 五分钟独占预约、支付页、完整快照和 Server 签发的 |
|
| intent 与支付双重校验后的完整确认快照 |
|
| 当前完整预约快照 |
推荐 Host 轨迹:
server/discover:发现 MCP 能力与协议版本。tools/list:仅加载上述三个目录工具。tool_catalog.search:搜索相关逻辑工具;状态栏只保留返回的工具名。tool_catalog.read:按需读 schema;读完整后将 schema 一次追加到上下文尾部,此后留在原历史位置以命中前缀缓存。tool_catalog.call:把用户/Agent 给出的业务参数原样送入严格校验和执行。
第 3–5 步是服务提供的协议能力;“把 schema 放到对话历史的哪个位置”最终由 MCP Host 控制,Server 通过 instructions、固定 schema 和分页元数据给出可执行约定。
状态机与事务
AVAILABLE SLOT
│ hold (SQLite IMMEDIATE transaction)
▼
HELD / payment=PENDING ───── expiresAt reached ────▶ EXPIRED
│
├── queryPayment=PENDING ─────────────────────▶ HELD
├── queryPayment=FAILED ─────────────────────▶ PAYMENT_FAILED
├── queryPayment=CLOSED ─────────────────────▶ PAYMENT_CLOSED
└── fresh human approval + exact PAID match ──▶ CONFIRMEDone_active_booking_per_slot部分唯一索引从存储层保证每个时段最多一个HELD/CONFIRMED预约。临时预约的
expiresAt = heldAt + 5 分钟。每次相关读写前在同一事务中清理过期预约,因此进程重启后也不会丢失释放动作。本地状态变更全部位于 SQLite 事务内;异常会回滚整个本地变更。只读支付查询在事务外执行,返回后重新读取版本并在一个事务中提交最终状态,避免持锁等待外部网络。
支付初始状态只能是
PENDING,确认只允许本地PENDING → PAID。bookingId同时是不可变、唯一的payment.queryId,重复确认查询同一个支付对象。expectedVersion提供乐观并发控制。Hold 与 Confirm 各自要求 UUID 幂等键;同键同参返回原结果,同键异参返回IDEMPOTENCY_CONFLICT。FAILED/CLOSED会事务性释放时段。支付已经成功但预约在外部查询完成前过期时,服务拒绝确认;退款/人工对账按题目范围留给外围系统。
参数保真与错误契约
逻辑工具由 AJV 严格校验:coerceTypes=false、useDefaults=false、removeAdditional=false、所有对象 additionalProperties=false。例如邮箱不会转小写,数字字符串不会转换为数字,未知字段不会被丢弃。业务参数与调用上下文分开传递,日志上下文不会注入业务参数。
所有执行结果都是机器可读 envelope。写操作返回完整的变更后预约,而非空 200 OK:
{
"ok": false,
"error": {
"code": "PAYMENT_PENDING",
"message": "Payment has not completed; the booking remains held until expiresAt.",
"retryable": true,
"details": { "bookingId": "booking-..." },
"recovery": { "action": "Ask the user to finish payment, then retry confirmation before expiry." }
},
"meta": {
"traceId": "32 lowercase hex characters",
"spanId": "16 lowercase hex characters",
"operationId": "UUID",
"clientSentAt": "RFC 3339",
"serverReceivedAt": "RFC 3339",
"serverResultCreatedAt": "RFC 3339",
"cache": "BYPASS"
}
}输入 schema 错误由 MCP SDK 或 INVALID_ARGUMENTS 返回;可预期业务错误不会泄露堆栈。主要错误包括 SLOT_UNAVAILABLE、BOOKING_EXPIRED、VERSION_CONFLICT、PAYMENT_PENDING、PAYMENT_MISMATCH、HUMAN_APPROVAL_EXPIRED、APPROVAL_INTENT_HASH_MISMATCH、APPROVAL_INTENT_MISMATCH 和 IDEMPOTENCY_CONFLICT。
Human in the loop
临时预约是可自动重试、会自动释放的动作。最终确认必须携带:
{
"humanApproval": {
"approvalId": "UUID",
"decision": "APPROVE",
"approvedAt": "2026-08-26T09:30:00.000Z",
"intent": {
"bookingId": "booking-...",
"slotId": "slot-ai-001",
"startsAt": "2030-09-02T02:00:00.000Z",
"amount": "500.00",
"currency": "CNY",
"version": 1
},
"intentHash": "sha256:<64 lowercase hex>"
}
}hold_slot 和处于 HELD/PENDING 的 get_booking 会返回 confirmationIntent。Host 必须向用户展示对应的 booking、专家、时段、金额、币种和版本,并把其中的 intent、intentHash 原样复制到批准对象;不要由 Agent 重建或修改。Server 先重新计算 hash,再把六个字段与当前 booking 精确比较,任一不一致都不会查询支付。
v1 canonical intent 是按 key 升序排列的无空白 UTF-8 JSON:amount, bookingId, currency, slotId, startsAt, version。intentHash 是 sha256: 加该字节串的 64 位小写十六进制 SHA-256。Server 返回 hash,因此一般 Client 只需原样传递。这个无密钥 hash 绑定内容完整性,但不是对批准者身份的数字签名;需要抵御不可信 Host 时,应把 v1 binding 升级为 Server HMAC 或签名 challenge。
批准有效期为 120 秒,允许 5 秒时钟偏差;缺失、过期、未来时间、缺少 binding 或 binding 不匹配的默认行为都是 不查询支付、不确认预约。确认成功后 confirmationIntent 变为 null,避免把旧 intent 当成可再次批准的 challenge。
支付依赖 seam
预约模块只依赖下面的只读 port:
interface PaymentQueryPort {
queryPayment(bookingId: string, trace: TraceContext): Promise<PaymentResult>;
}生产 adapter 对 PAYMENT_QUERY_BASE_URL/payments/{bookingId} 发 GET,请求超时 3 秒并传递 traceparent。测试和 Demo 注入 Stub;仓库没有实现支付服务或支付动作。支付结果必须精确匹配 bookingId、金额字符串和币种,PAID 还必须有 paidAt。
按需加载、分页与缓存
Tool 搜索和时段搜索都返回结构化候选,不拼接全文。
游标是与原查询绑定的不透明 token;跨查询复用会返回
INVALID_CURSOR。tool_catalog.read以 0-basedoffset和显式limit读取,返回totalLines、truncated、omittedLines、next和人类可读继续方式。固定 Tool 目录的 search/read 结果可永久安全复用;可预约时段查询缓存 5 秒,任何预约写入或过期释放都会使其失效。
SQLite WAL 允许多个只读感知调用安全并发;写入由数据库事务和唯一索引串行化。
可观测性
每个目录动作和逻辑工具动作都向 stderr 输出 JSON Lines,包含 source、RFC 3339 timestamp、caller、动作、耗时、trace_id、span_id、operation_id。支付查询创建子 span 并通过 W3C traceparent 传播。
调用方显式传入 UUID requestSpanId;服务用它确定性派生 128-bit trace_id,每次动作生成新的 64-bit span_id。OpenTelemetry 标准要求 span_id 是 16 个十六进制字符而不是 UUID,因此另行生成 UUID operation_id,没有伪造不兼容的 trace context。代码同时调用 OpenTelemetry API;部署方可注册 exporter。
所有 MCP HTTP 请求必须由显式 client adapter 在真正发送边界加入 x-mcp-client-sent-at,并在 params._meta 写入同值;Server 不会替 Client 猜测或注入该时间。Server 在入口和响应边界分别加入 x-mcp-server-received-at、x-mcp-server-responded-at,JSON-RPC result._meta 同样携带三段时间;Tool envelope 另以 serverResultCreatedAt 标识业务结果生成时刻。因此 Agent 可验证:
clientSentAt ≤ serverReceivedAt ≤ serverResultCreatedAt ≤ serverRespondedAt ≤ clientReceivedAt缺失或非法 RFC 3339 客户端时间会得到 HTTP 400 / MISSING_CLIENT_TIMESTAMP,响应不会伪造客户端时间,并回显 JSON-RPC request id。支付查询这个 Server 发出的外部 GET 也携带 x-mcp-server-request-sent-at;依赖响应的发送时间(若对方提供)及本地接收时间进入结构化日志。当前工具响应均为 JSON;未来启用 SSE 进度/Server-initiated MCP request 前,需要为每个事件补独立发送时间,而不能只沿用建流 Header。
最重要的测试场景
竞争与过期释放:先验证第二位用户无法占用,再推进时钟超过五分钟并验证其可预约。这直接覆盖“同一时段仅一人”和“过期后重新开放”两个核心不变量。
先查后做的支付确认:
PENDING保持预约不变,随后同一支付查询 ID 返回PAID,只发生一次本地PENDING → PAID/CONFIRMED。这是外部付款与本地事务交界处风险最高的路径。金额/身份不匹配回滚:支付返回
PAID但金额错误,本地仍保持HELD/PENDING/version=1,证明外部查询无法造成部分提交。幂等重放与参数漂移:同键同参得到同一预约;同键异参明确冲突,防止 Agent 重试制造重复副作用。
Human approval 超时:过期批准不会调用支付依赖,验证默认拒绝行为。
真实 MCP modern discovery:官方 Client 通过 Streamable HTTP 协商到
modern,发现三项稳定工具,再检索和调用逻辑工具。独立进程时序黑盒:测试先构建,再
spawn生产入口,用官方 Client 验证每次 wire request/response、Tool envelope 与日志的时间顺序,并确保子进程和临时数据库被清理。
假设与范围
预置三位专家和六个 2030 年 UTC 时段;不实现专家管理。
所有时间通过 RFC 3339 传输,存储为 UTC ISO 字符串;服务不静默转换调用参数。
跨机器时序比较假设 Client、预约服务和支付服务通过 NTP 保持时钟同步;生产告警应配置允许偏差。Server 不根据偏差静默改写调用方时间。
金额用两位小数字符串,币种用三位大写代码,避免浮点误差。
最小实现没有账户认证;localhost 运行且 booking ID 不可猜。生产环境必须在 MCP handler 前验证身份,并按 caller 限制预约读取。
付款页 URL 仅由配置基址和 booking ID 组成;本仓库不提供页面。
退款、通知、后台、已付款但过期后的自动对账,以及云部署不在范围内。
项目结构
src/
booking-service.ts 深预约模块:状态机、幂等、事务、缓存
database.ts SQLite schema、约束与预置数据
tool-catalog.ts 固定逻辑 schema、检索、分片读取、严格分发
mcp-server.ts 三个稳定 MCP Tool 与 Streamable HTTP handler
payment.ts 只读支付 HTTP adapter
observability.ts OTel hooks 与结构化日志
temporal-http.ts MCP Client/Server wire 时间契约
test/ 状态机与真实 HTTP MCP 集成测试
scripts/demo.ts 可重复端到端演示
NOTES.md 设计动机、现实风险、取舍与明确未覆盖范围实现对齐官方 MCP TypeScript SDK HTTP Guide、MCP Tools Guide、Streamable HTTP 2026-07-28 规范 与 MCP Pagination 规范。
This server cannot be deployed
Maintenance
Related MCP Connectors
Pay-per-use tool marketplace for AI agents. Search, price-check, and call APIs via MCP.
Search and compare flight offers through a cache-aware Streamable HTTP MCP server for AI agents.
AI Reasoning Cache & Consensus Layer with 11 MCP tools via Streamable HTTP.
MCP layer for local businesses: discover, query, book, and transact with verified SMB AI agents.