API + MCP / SCHEMA 0.1

给 Agent 一份
有依据的数据。

先查看公开 mock 演示,再用获邀签发的 API Key 接入真实数据。示例不会在本页执行,也不会收集你的密钥。

文档配置的服务地址:https://api.o2o.dev。地址配置不代表服务已上线,接入前请由团队确认。

试用与鉴权

当前采用邀请制,由项目团队人工签发和撤销应用密钥。请通过与你对接的团队成员申请;暂无在线注册或支付流程。

在服务端使用 Authorization: Bearer <API_KEY>。不要把密钥放进浏览器代码、公开仓库、查询参数或 NEXT_PUBLIC_* 环境变量。

默认每应用每天 1,000 次、每分钟 30 次调用;REST 与 MCP 共享 UTC 固定窗口配额。MCP 的工具调用计入配额,初始化和工具列表不计入。试用阶段不收取在线支付。

REST API

GET/v1/places

按名称、地区、类别、距离及设施查询

GET/v1/places/{id}

门店详情、依据、时效与模块覆盖

GET/v1/places/{id}/menu

菜单规格、观测价格及价格条件

GET/v1/places/{id}/offers

套餐内容、售卖方案及使用规则

GET/v1/coverage

已发布覆盖、模块完整率与更新时间

POST/mcp

与 REST 共用数据、权限和配额的工具调用

下载 OpenAPI 契约 →

结构化筛选

q 按名称匹配;country 为 CN 或 SG 等国家代码;city、category 按已发布值筛选。parking、private_room、children_facilities、pets 接受 available、unavailable、conditional,仅匹配有效且无冲突的依据。

距离查询同时提供 lat、lon、radius_km(最多 50 公里),只匹配已确认 WGS84 坐标。默认每页 20 条,per_page 最大 100;page 从 1 开始。fields 为逗号分隔字段名,稳定 ID、来源和模块状态始终保留。

首版没有任意自然语言查询、套餐资格判断、预订、库存或交易接口。

从一次查询开始

Python · 在服务端运行

import json, os
from urllib.request import Request, urlopen

base = os.environ.get("O2O_API_BASE_URL", "https://api.o2o.dev")
request = Request(
    base + "/v1/places?country=CN&category=restaurant&per_page=5",
    headers={"Authorization": "Bearer " + os.environ["O2O_API_KEY"]},
)
with urlopen(request, timeout=15) as response:
    print(json.load(response))

JavaScript · Node.js

const base = process.env.O2O_API_BASE_URL || "https://api.o2o.dev";
const response = await fetch(base + "/v1/places?country=SG", {
  headers: { Authorization: `Bearer ${process.env.O2O_API_KEY}` },
  signal: AbortSignal.timeout(15_000),
});
if (!response.ok) throw new Error(`o2o: ${response.status}`);
const { data, meta } = await response.json();
console.log(data, meta);

MCP 工具

将远程 HTTP MCP 地址配置为 https://api.o2o.dev/mcp,并通过客户端支持的安全密钥配置传入 Bearer 请求头。不同客户端的配置格式不同,下方是协议请求示例,不是通用客户端配置文件。

POST https://api.o2o.dev/mcp
Authorization: Bearer <API_KEY>
Content-Type: application/json
Accept: application/json, text/event-stream

{"jsonrpc":"2.0","id":1,"method":"initialize",
 "params":{"protocolVersion":"2025-06-18",
 "capabilities":{},"clientInfo":{"name":"your-agent","version":"1.0"}}}

初始化后发送 notifications/initialized,再调用 tools/list 或 tools/call。支持 2025-03-26 和 2025-06-18;采用无状态 HTTP JSON 响应,不提供 SSE 流或会话。

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "search_places",
    "arguments": {
      "country": "CN",
      "private_room": "available",
      "per_page": 5
    }
  }
}

工具:search_places、get_place、get_menu、get_offers、get_coverage。详情工具使用 id 参数;搜索参数与 REST 一致。

读懂数据,而不只读到数据

稳定身份
门店 ID 不随名称变化;品牌、门店和平台外部 ID 分开记录。
来源与依据
evidence 记录字段依据、observed_at、valid_until、verification 和 conflict;sources 提供可公开的来源归属。原始私有材料不会公开。
未知与缺失
unknown 不等于 false。门店存在但没有菜单返回 200、data: []、meta.status: missing;不存在的门店返回 404。
价格语义
金额为十进制字符串,附币种、单位和适用条件。优惠价格不代表所有用户可购买;未提供的费用不能默认为零。
时间与冲突
采用门店当地时区,区分观测时间与有效期。默认复核周期:地址和联系方式 90 天,营业时间与设施 30 天,菜单价格 7 天。来源明确期限可缩短周期。
深度档案
菜单、有效且已确认的营业时间,加至少两项有效且已确认的设施信息。不代表所有字段齐全。
授权范围
只分发已核准许可的数据。对来源撤销授权、过期和冲突持续做显式标记;不从菜单或店名推断过敏原安全。

错误与安全重试

400参数不合法

检查字段名、分页和参数类型。

401鉴权失败

检查密钥是否有效或已撤销。

403来源请求被拒绝

浏览器 Origin 需显式允许;优先服务端调用。

404门店不存在

不要将它等同于某个模块缺失。

429配额已用完

等待下一配额窗口,避免立即循环重试。

遇到 5xx 或网络超时采用有上限的指数退避。集成日志不要记录 API Key、完整搜索正文或精确用户坐标。