Skip to main content
Glama
Dante-dan

expert-booking-mcp

by Dante-dan

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

用途

tool_catalog.search

检索式预筛选;返回标题、tool:// 位置、摘要、总数和 nextCursor

tool_catalog.read

通过 offset/limit 分片读取固定的完整 schema,明确报告截断与下一段位置

tool_catalog.call

以未经转换的 arguments 调用已加载的逻辑工具

目录中的四个固定逻辑工具是:

逻辑工具

关键输入

结果

booking.search_available_slots

query、显式 limit、可选时间/专业过滤和 cursor

结构化时段候选、总数、下一页游标

booking.hold_slot

slotId、原样保存的客户信息、UUID idempotencyKey

五分钟独占预约、支付页、完整快照和 Server 签发的 confirmationIntent

booking.confirm_booking

bookingIdexpectedVersion、UUID 幂等键、两分钟内且绑定 intent 的人工批准

intent 与支付双重校验后的完整确认快照

booking.get_booking

bookingId

当前完整预约快照

推荐 Host 轨迹:

  1. server/discover:发现 MCP 能力与协议版本。

  2. tools/list:仅加载上述三个目录工具。

  3. tool_catalog.search:搜索相关逻辑工具;状态栏只保留返回的工具名。

  4. tool_catalog.read:按需读 schema;读完整后将 schema 一次追加到上下文尾部,此后留在原历史位置以命中前缀缓存。

  5. 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 ──▶ CONFIRMED
  • one_active_booking_per_slot 部分唯一索引从存储层保证每个时段最多一个 HELD/CONFIRMED 预约。

  • 临时预约的 expiresAt = heldAt + 5 分钟。每次相关读写前在同一事务中清理过期预约,因此进程重启后也不会丢失释放动作。

  • 本地状态变更全部位于 SQLite 事务内;异常会回滚整个本地变更。只读支付查询在事务外执行,返回后重新读取版本并在一个事务中提交最终状态,避免持锁等待外部网络。

  • 支付初始状态只能是 PENDING,确认只允许本地 PENDING → PAIDbookingId 同时是不可变、唯一的 payment.queryId,重复确认查询同一个支付对象。

  • expectedVersion 提供乐观并发控制。Hold 与 Confirm 各自要求 UUID 幂等键;同键同参返回原结果,同键异参返回 IDEMPOTENCY_CONFLICT

  • FAILED/CLOSED 会事务性释放时段。支付已经成功但预约在外部查询完成前过期时,服务拒绝确认;退款/人工对账按题目范围留给外围系统。

参数保真与错误契约

逻辑工具由 AJV 严格校验:coerceTypes=falseuseDefaults=falseremoveAdditional=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_UNAVAILABLEBOOKING_EXPIREDVERSION_CONFLICTPAYMENT_PENDINGPAYMENT_MISMATCHHUMAN_APPROVAL_EXPIREDAPPROVAL_INTENT_HASH_MISMATCHAPPROVAL_INTENT_MISMATCHIDEMPOTENCY_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/PENDINGget_booking 会返回 confirmationIntent。Host 必须向用户展示对应的 booking、专家、时段、金额、币种和版本,并把其中的 intentintentHash 原样复制到批准对象;不要由 Agent 重建或修改。Server 先重新计算 hash,再把六个字段与当前 booking 精确比较,任一不一致都不会查询支付。

v1 canonical intent 是按 key 升序排列的无空白 UTF-8 JSON:amount, bookingId, currency, slotId, startsAt, versionintentHashsha256: 加该字节串的 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-based offset 和显式 limit 读取,返回 totalLinestruncatedomittedLinesnext 和人类可读继续方式。

  • 固定 Tool 目录的 search/read 结果可永久安全复用;可预约时段查询缓存 5 秒,任何预约写入或过期释放都会使其失效。

  • SQLite WAL 允许多个只读感知调用安全并发;写入由数据库事务和唯一索引串行化。

可观测性

每个目录动作和逻辑工具动作都向 stderr 输出 JSON Lines,包含 source、RFC 3339 timestampcaller、动作、耗时、trace_idspan_idoperation_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-atx-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。

最重要的测试场景

  1. 竞争与过期释放:先验证第二位用户无法占用,再推进时钟超过五分钟并验证其可预约。这直接覆盖“同一时段仅一人”和“过期后重新开放”两个核心不变量。

  2. 先查后做的支付确认PENDING 保持预约不变,随后同一支付查询 ID 返回 PAID,只发生一次本地 PENDING → PAID/CONFIRMED。这是外部付款与本地事务交界处风险最高的路径。

  3. 金额/身份不匹配回滚:支付返回 PAID 但金额错误,本地仍保持 HELD/PENDING/version=1,证明外部查询无法造成部分提交。

  4. 幂等重放与参数漂移:同键同参得到同一预约;同键异参明确冲突,防止 Agent 重试制造重复副作用。

  5. Human approval 超时:过期批准不会调用支付依赖,验证默认拒绝行为。

  6. 真实 MCP modern discovery:官方 Client 通过 Streamable HTTP 协商到 modern,发现三项稳定工具,再检索和调用逻辑工具。

  7. 独立进程时序黑盒:测试先构建,再 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 GuideMCP Tools GuideStreamable HTTP 2026-07-28 规范MCP Pagination 规范

-
license - not tested
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • AI Reasoning Cache & Consensus Layer with 11 MCP tools via Streamable HTTP.

  • MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.

  • MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Dante-dan/expert-booking-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server