关于 opentable-mcp
opentable-mcp 是面向 OpenTable 用户的 MCP 服务,可通过自然语言查询餐厅、查看预订并管理订位与收藏。它借助已登录的 Chrome 会话发送请求,并为预订等写入操作设置确认步骤。
主要功能
- 01搜索餐厅并查询空位
- 02查看餐厅详情与菜单
- 03查看和管理预订
- 04添加或移除收藏
- 05写入操作需确认
适用场景
- 01查找指定日期和人数的空位
- 02查看个人预订与餐厅菜单
- 03预订、修改或取消餐位
- 04维护 OpenTable 收藏列表
MCP 相关
向 MCP 客户端提供 OpenTable 查询和账户管理工具。默认通过本机 WebSocket 中继至已登录的 Chrome 标签页;写入操作需确认。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y opentable-mcpOT_BRIDGEWhich browser transport to use: "websocket" (default, the fetchproxy bridge) or "mcp-chrome".OT_MCP_CHROME_URLURL of the mcp-chrome bridge (default http://127.0.0.1:12306/mcp). Only used when OT_BRIDGE=mcp-chrome.OT_WS_PORTOverrides the fetchproxy WebSocket port (default 37149, the fleet-shared port).FETCHPROXY_WS_HOSTBridge bind interface, a literal IP only (anything else is ignored); default 127.0.0.1. Keep on loopback — it exists for a hosted child in its own network namespace.FETCHPROXY_IDENTITY_DIRWhere to store the long-term bridge identity keypair, an absolute path only (anything else is ignored); default ~/.fetchproxy/identity/. Exists for a host that runs a separate child per caller.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
15收录的工具列表 · 更新于 1 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| view | enum | 否 | 响应格式:“compact”(默认)会省略响应中其他位置已有的字段;“full”会返回此服务端支持的所有字段。compact 会从响应中移除图片/头像 URL;“full”会原样返回 OpenTable 的负载。不支持字段投影:此服务端没有经过验证的 OpenTable 重要字段记录,擅自编造可能会删掉调用方需要的字段。compact | full |
| scope | enum | 否 | upcoming | past | all |
详细介绍
opentable-mcp
面向 Claude 的 OpenTable 预订管理 MCP 服务——通过自然语言查找空位、预订、取消、管理收藏,并查看你的控制面板。
v0.3.0-alpha 状态:Chrome 扩展桥接、10 个工具,支持读取和写入。 每个 OpenTable 请求都会通过本地 WebSocket 中继,由你已登录的 Chrome 标签页发出——每个请求都使用你现有的会话,并像由你亲自点击一样到达 OpenTable。
工作原理
OpenTable 的边缘防护(Akamai Bot Manager)会在 /、/s、/r/…、/dapi/… 和 /booking/… 上实施行为挑战。自行构建 HTTP 客户端的工具——cycletls、伪装 curl、无头 Chrome——会创建独立身份,并收到 403 或 JS 验证页面。opentable-mcp 则反其道而行:直接使用你自己的浏览器会话,包括已有的 Cookie 和 TLS 上下文。
因此,这个 MCP 服务不会冒充浏览器,而是:
- 通过
@fetchproxy/server在127.0.0.1:37149上启动 WebSocket 监听器。 - ContextMint Bridge 浏览器扩展(只需安装一次,所有基于 fetchproxy 的 MCP 服务都可共用)会从已登录的浏览器连接,并通过 opentable.com 标签页中继每个请求,使用
fetch(..., { credentials: 'include' })——使用你的 TLS、你的 Cookie,以及已通过验证的_abck。 - 将 JSON 响应(公开的 GraphQL / JSON 端点)和 SSR HTML(
/user/*)解析为符合工具格式的输出。
无需粘贴 Cookie。无需 cycletls。无需 Playwright。只需由你自己的浏览器自行操作——MCP 服务只负责选择请求内容。
工具
| 工具 | 类型 | 来源 |
|---|---|---|
opentable_list_reservations | 读取 | /user/dining-dashboard SSR |
opentable_get_profile | 读取 | /user/dining-dashboard SSR |
opentable_list_favorites | 读取 | /user/favorites SSR |
opentable_search_restaurants | 读取 | /dapi/fe/gql?opname=Autocomplete |
opentable_get_restaurant | 读取 | /r/{slug} SSR(__INITIAL_STATE__) |
opentable_get_menu | 读取 | 餐厅资料 SSR(restaurantProfile.menus) |
opentable_find_slots | 读取 | /dapi/fe/gql?opname=RestaurantsAvailability |
opentable_book_preview | 读取 | /booking/details SSR + SlotLock |
opentable_book | 写入 | SlotLock → /dapi/booking/make-reservation |
opentable_cancel | 写入 | /dapi/fe/gql?opname=CancelReservation |
opentable_modify_preview | 读取 | /booking/details SSR(isModify=true)+ SlotLock |
opentable_modify | 写入 | /dapi/booking/make-reservation(isModify: true) |
opentable_add_favorite | 写入 | /dapi/wishlist/add |
opentable_remove_favorite | 写入 | /dapi/wishlist/remove |
opentable_healthcheck | 读取 | /robots.txt(桥接探测) |
已发布菜单
opentable_get_menu 接受与 opentable_get_restaurant 相同的餐厅 ID、slug、路径或精确 URL。省略 menu_name 可返回所有已发布菜单;也可以传入 "Dinner" 之类的精确标题(不区分大小写)来选择一个菜单:
{"restaurant_id":"https://www.opentable.com/r/social-san-juan","menu_name":"Dinner"}
响应包含餐厅身份信息、源 url、available_menus、menus,以及可选的外部 menu_url。每个已发布菜单都会保留 OpenTable 的分区/菜品、价格字符串、variationGroups、货币、提供方和 updated 时间戳。view 默认为 compact(移除媒体 URL);full 还会保留媒体 URL。已发布的价格可能与餐厅当前菜单不同,因此引用价格时请保留来源和更新时间戳。
大型菜单会按完整菜品分页返回,因此回复不会在菜品内容中途停止。不带分页参数时,能够完整放入响应的菜单会原样返回;较大的菜单则返回第一页。每页都包含 available_sections 和 pagination:
{"offset":0,"returned_items":20,"total_items":57,"next_offset":20}
要继续获取菜单,请再次调用,并将 offset 设为 next_offset,同时使用相同的 menu_name/section_name;最后一页的 next_offset 为 null。可选的分页输入:
section_name—— 精确的分区标题(不区分大小写);回复会添加section_found。offset—— 起始菜品位置(默认为0)。limit—— 每页最多返回的菜品数(1–50,默认为 20)。为控制在响应预算内,页面可能返回较少的菜品。
对于没有输出限制的客户端,设置 view: "full" 且不提供分页参数时,会返回未设上限的完整菜单。单个菜品若大到无法放入一页,会报错,不会截断描述。
status 用于区分 available、menu_not_found(请检查 available_menus)、external_only 和 not_available。菜单缺失不属于 HTTP/bridge 或解析错误;这些故障仍会作为错误返回。外部链接会直接返回,不会抓取其他主机的内容,也不会解析 PDF。此工具只会通过现有的浏览器桥接读取同一餐厅页面;它不会预订餐桌。
条款确认
使用此 MCP 服务,即表示您确认并同意以下内容:
1. 此服务访问的是您自己的 OpenTable 账户。 每个请求都会通过 ContextMint Bridge 浏览器扩展(或 hangwin/mcp-chrome),经由您已登录的浏览器标签页发送。它不会,也无法访问其他人的预订。
2. OpenTable 的使用条款适用于您对本服务的使用,就像这些条款也适用于您直接使用 opentable.com 一样。以下条款与此处内容最相关:
除非 OpenTable 明确授权,否则您不得使用任何深层链接、机器人、网络爬虫、抓取工具、生成式 AI 或其他 AI 技术,包括但不限于通过与您的浏览器交互或以其他方式使用浏览器来运行的技术,例如自动化助手或其他自动或手动的设备、流程或手段,来访问、复制、搜索或监控服务或 OpenTable 内容的任何部分。
还有一条至关重要:“AI Agent 的行为被视为使用这些 Agent 的用户的行为,用户有责任检查并核实相关操作……”
每次您调用此服务中的工具,即表示您同意这些条款——维护者于 2026-05-23 阅读了这些条款。OpenTable 的使用条款明确将 AI/自动化助手访问列为未经授权的行为;也明确规定,AI Agent 的行为归于您本人。
3. 仅限个人非商业用途。 本项目与 OpenTable, Inc. 无关联,也未获其认可、赞助或与其合作。这是一款个人自动化工具,调用 opentable.com 所使用的相同 /dapi/... 和 /booking/... 端点。请勿将其用于批量预订、抢占需要信用卡担保的餐位、转售预订或任何商业用途。预订/取消/修改工具的存在,是为了让您像坐在浏览器前一样管理一项预订。
4. 不保证稳定性。 此服务依赖 OpenTable 内部持久化的 GraphQL 查询哈希,而 OpenTable 会在不同部署版本之间轮换这些哈希。哈希轮换后,工具就会失效,我们会重新捕获它们。您能否正常使用,取决于 OpenTable 的发布节奏。
5. 您须对使用此服务及您的 OpenTable 账户所产生的任何后果承担全部责任——包括速率限制、时段锁定拒绝、失控预订导致的未到店罚金、账户警告、暂停或任何执法措施。根据 OpenTable 的使用条款,AI Agent 的行为就是您的行为——请在确认前检查每项预订/取消操作。如果 OpenTable 对您的使用提出异议,请停止使用此服务。
本节是维护者本着诚信对条款所作的概述,不构成法律建议,也不会修改或取代 OpenTable 的实际使用条款。
安装
npm install
npm run build
安装 ContextMint Bridge
opentable-mcp 与所有其他基于 fetchproxy 的 MCP 共用一个浏览器扩展:ContextMint Bridge。请从 https://github.com/nullnet-app/contextmint-bridge/releases 安装一次:
ContextMint Bridge 是更名后的 fetchproxy 浏览器扩展,由同一位维护者开发;fetchproxy 自己的 README(https://github.com/chrischall/fetchproxy#extension)也指向它。其源代码公开在 https://github.com/nullnet-app/contextmint-bridge:你可以自行构建,也可以使用随发布版一同提供的 .sha256 文件校验发布版 zip(shasum -a 256 -c contextmint-bridge-chrome-<version>.zip.sha256)。
- **Chrome:**从最新发布版下载 Chrome zip,解压,然后以未打包扩展的方式加载(
chrome://extensions→ 开发者模式 → 加载未打包的扩展程序)。Safari 尚不可用——它将内置于 ContextMint 应用中,而该应用目前没有公开下载地址——所以请暂时使用 Chrome。 - 在同一个浏览器配置文件中登录
https://www.opentable.com/。 - 检测到 WebSocket、标签页和身份验证 Cookie 后,扩展徽章会显示绿点。
完成后,任何启动 node dist/bundle.js 的 MCP 客户端都可以通过你已登录的标签页访问 OpenTable。
**完整的设置和故障排除指南:**请参阅 ContextMint Bridge 仓库,了解状态点参考、WS 协议和请求生命周期。有关 OpenTable 重新部署时捕获持久化查询哈希的信息,请参阅此处的 CLAUDE.md。
配置(Claude Desktop / Claude Code)
{
"mcpServers": {
"opentable": {
"command": "node",
"args": ["/absolute/path/to/opentable-mcp/dist/bundle.js"]
}
}
}
默认情况下无需设置环境变量——身份验证信息保存在浏览器中,而非 MCP 进程中。
可选:改用 hangwin/mcp-chrome 作为桥接
如果你已安装用于浏览器自动化的 hangwin/mcp-chrome,opentable-mcp 可以通过它路由 OpenTable 请求,而不使用 ContextMint Bridge:
{
"mcpServers": {
"opentable": {
"command": "node",
"args": ["/absolute/path/to/opentable-mcp/dist/bundle.js"],
"env": { "OT_BRIDGE": "mcp-chrome" }
}
}
}
在这种模式下,你无需使用 ContextMint Bridge。每个 OpenTable 请求都会针对你现有的 mcp-chrome 安装调用一次 chrome_network_request,并通过 tabUrl 固定到一个 opentable.com 标签页。
**此模式为只读模式。**预订、修改、取消和收藏操作都会被拒绝,并返回明确的错误信息——OpenTable 的写入端点需要来自餐厅、预订或账户页面的 CSRF 令牌,而此传输方式无法提供该令牌——并且 opentable_find_slots 不可用。对于这些操作,请使用默认的 ContextMint Bridge 传输方式。
**注意:**此路径要求使用包含 PR #348 的版本或更新版本的 mcp-chrome(该 PR 为 chrome_network_request 增加了 tabUrl 参数)。早于 #348 的 mcp-chrome 版本只能使用活动标签页,跨源 fetch 时会出现异常。此路径的实时验证需等待上游合并后进行。
其他环境变量:OT_WS_PORT(默认值为 37149)可覆盖 fetchproxy WebSocket 端口;OT_MCP_CHROME_URL(默认值为 http://127.0.0.1:12306/mcp)可覆盖 mcp-chrome 端点。
确认
opentable_book、opentable_modify 和 opentable_cancel 会在执行前征求确认。能够显示确认提示词的客户端(Claude Code)会显示提示。对于无法显示提示的客户端(claude.ai、Claude Desktop),首次调用不会预订、更改或取消任何内容:它会返回将要执行操作的预览,以及一个 confirmToken。无论哪种情况,提示都会列出餐厅、日期、时间和人数;对于预订或更改,还会列出将被扣款的卡片和取消政策(这些信息由预览工具返回的 booking_token / modify_token 携带;取消操作会在你的用餐仪表板中查找预订,如果找不到,则会发出警告)。只有使用相同参数和该令牌再次调用时,操作才会执行一次;如果期间更改了任何参数,操作就会被拒绝(DRAFT_CHANGED),并返回新的预览。
| variable | default | |
|---|---|---|
MCP_CONFIRM_MODE | ask-user | 对于无法显示确认提示的客户端(claude.ai、Claude Desktop),写入操作的执行方式。ask-user:分两步执行——首次调用不执行任何操作,只返回预览和令牌;模型必须先在聊天中征得你的批准,才能携带令牌再次调用。auto:同样分两步执行,但模型审阅预览后可自行使用令牌。refuse:此类客户端上的写入操作会被拒绝。能够显示提示的客户端(Claude Code)始终会收到真实提示,除非 MCP_CONFIRM_ELICITATION=off。无法识别的值会按 refuse 处理。 |
MCP_CONFIRM_ELICITATION | on | off 表示永不显示确认提示,因此所有客户端都会采用 MCP_CONFIRM_MODE 的行为。对于声称能够显示提示、但实际上从不显示的客户端,请设置此项(写入操作会挂起——opencode 2.0.x)。任何其他值都会按 on 处理,并在 stderr 上显示警告。 |
MCP_CONFIRM_TTL_SECONDS | 600 | 令牌的有效时长。 |
MCP_CONFIRM_SECRET | random per process | 签名密钥;只有在令牌必须跨服务重启继续有效时才设置。使用 mcp-host 时,主机会提供稳定的子进程专用密钥(MCP_HOST_CONFIRM_SECRET),已使用的令牌会记录在 MCP_DATA_DIR 下,因此批准信息在空闲重启后仍然有效。 |
运行(本地 stdio)
node dist/bundle.js
测试
npm test # vitest, 72 unit tests, mocked fetch
npm run build # tsc + esbuild bundle
npx tsx scripts/probe-find-slots.ts # live GET round-trip via extension
npx tsx scripts/probe-list-res.ts # live dashboard SSR
scripts/probe-*.ts 文件会启动 MCP 服务,通过扩展桥接调用一两个工具,并打印响应。使用这些文件需要加载扩展并打开一个 opentable 标签页。
故障排查
- 弹出窗口中出现红点 / “extension offline” 错误。 请参阅 ContextMint Bridge 的故障排查指南——大多数“extension offline”问题都是上游生命周期错误(服务工作线程休眠、内容脚本失效),而非 opentable-mcp 的问题。
- Chrome 中出现行为验证页面。 Akamai 有时会在标签页长时间空闲后中断页面,并显示“验证你是人类”的插页。完成验证后,标签页即可恢复使用。
- “OpenTable returned an incomplete page”。 OpenTable 有时会在真实页面加载完成前返回一个简短的占位页面(只有几 KB,没有页面状态),或者要求进行人工验证。健康检查会将此情况记录为
incomplete_page,以区别于parse_error(页面大小正常,但格式已更改)。在已登录的桥接浏览器中刷新餐厅页面,等待加载完成,然后重试一次。 find_slots返回 HTTP 409。 浏览器中的 OpenTable 会话需要刷新。在已登录的桥接标签页中打开餐厅页面,等待可订状态加载,然后重试一次。错误提示表明可订状态尚未验证,而非没有空位;通过桥接健康检查并不代表可订状态正常。list_favorites未反映刚执行的add_favorite。/user/favoritesSSR 页面会缓存几秒钟。约 10 s 后重新列出,或通过opentable_get_profile的计数进行确认。
目录结构
src/transport-fetchproxy.ts—FetchproxyTransport:对@fetchproxy/server的FetchproxyServer进行轻量封装;后者是与 ContextMint Bridge 浏览器扩展通信的共享 WebSocket 桥接层。src/client.ts—OpenTableClient:封装传输层,并提供fetchJson/fetchHtml和错误映射。src/tools/*.ts— 每个功能各一个文件(预订 / 餐厅 / 收藏 / 用户 / 搜索)。每个文件都会导出registerXxxTools(server, client)。src/parse-*.ts— 纯 HTML/JSON 解析器,均已通过单元测试。tests/— 与src/一一对应的目录,使用 vitest。WebSocket 协议级别的测试位于上游的 fetchproxy 仓库。scripts/probe-*.ts— 实时往返探测脚本(需要 ContextMint Bridge 和已登录账号)。
已知问题
- Apollo 持久化查询。 时段搜索、时段锁定、取消和自动补全都使用从 opentable.com 捕获的
extensions.persistedQuery.sha256Hash哈希值。如果 OpenTable 重新部署,服务会返回PersistedQueryNotFound;重新捕获哈希的步骤见CLAUDE.md→“Hot spots”。 dining_area_id是必填的预订参数。 我们无法自动解析餐厅区域,因此请将餐厅的 slug 或数字 ID 传给opentable_get_restaurant(slug 会路由至/r/{slug},数字 ID 会路由至/restaurant/profile/{id}),读取diningAreas[],再将 ID 传给opentable_book。- Service Worker 休眠。 MV3 SW 在空闲约 30 秒后会休眠。ContextMint Bridge 会保持自身活跃;冷启动时,第一个请求可能需要等待最多约 5 秒以重新连接 WebSocket。
本项目由 AI(Claude Opus 4.7)开发并维护。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。