关于 openaq-mcp-server
openaq-mcp-server 通过 OpenAQ v3 提供全球监测站的实测空气质量数据,面向环境研究和空气质量分析。它可查找站点、读取最新传感器值并获取污染物历史序列,同时保留单位和观测时间信息。
主要功能
- 01按坐标、区域或国家查找监测站
- 02读取站点传感器的最新数值
- 03获取污染物历史序列及小时或日汇总
- 04查询污染物目录和国家覆盖范围
- 05将大型序列暂存并用只读 SQL 查询
适用场景
- 01查找某地附近测量特定污染物的站点
- 02查看站点最新读数及其单位和时间
- 03分析一段时期的污染物历史变化
MCP 相关
该 MCP 服务向客户端提供站点搜索、读数和历史测量等工具,以及站点和污染物目录资源。支持 STDIO 与 Streamable HTTP;调用 OpenAQ v3 需要 API 密钥。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://openaq.caseyjhand.com/mcpclaude mcp add --transport http cyanheads-openaq https://openaq.caseyjhand.com/mcp{"mcpServers":{"cyanheads-openaq":{"type":"http","url":"https://openaq.caseyjhand.com/mcp"}}}在 Cursor 中打开{"servers":{"cyanheads-openaq":{"type":"http","url":"https://openaq.caseyjhand.com/mcp"}}}在 VS Code 中打开{"mcpServers":{"cyanheads-openaq":{"type":"http","url":"https://openaq.caseyjhand.com/mcp"}}}{"mcpServers":{"cyanheads-openaq":{"serverUrl":"https://openaq.caseyjhand.com/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
工具
详细介绍
@cyanheads/openaq-mcp-server
通过 MCP 查找空气质量监测站、读取最新传感器数值,并获取污染物历史序列。支持 STDIO 或 Streamable HTTP。
概述
通过 OpenAQ v3 API 获取实测空气质量数据:来自全球政府参考监测仪和研究级传感器的物理传感器观测数据。查找监测站、读取当前数值,并通过任意 MCP 客户端获取污染物历史序列。可作为 stdio 进程、本地 Streamable HTTP 服务或上述公开托管端点运行。
工具
| 工具 | 描述 |
|---|---|
openaq_find_locations | 按地点附近、边界框或国家查找监测站;返回其他工具所需的地点 ID |
openaq_get_readings | 获取监测站每个传感器的最新数值,并标注污染物和单位 |
openaq_get_measurements | 获取监测站某种污染物的历史序列,支持原始数据或按小时/天汇总 |
openaq_list_parameters | 污染物目录及其标准单位;将污染物和单位映射到其参数 ID |
openaq_list_countries | 国家覆盖情况:数据时间跨度及各国测量的参数 |
openaq_dataframe_describe | 列出已暂存到 DataCanvas 的表和列 |
openaq_dataframe_query | 对已暂存的测量序列运行只读 SQL SELECT |
openaq_dataframe_drop | 删除完整的暂存画布;需通过 OPENAQ_ENABLE_CANVAS_DROP=true 选择启用 |
资源
| 资源 | 描述 |
|---|---|
openaq://location/{locationId} | 单个监测站的元数据:坐标、提供方、带单位的传感器、数据时间跨度 |
openaq://parameters | 完整的污染物和单位目录 |
两个资源均与工具输出一致,因此仅支持工具的客户端也不会缺少任何内容。
能力参考
openaq_find_locations 工具
- 使用
coordinates和radius(单位为米,1–25000,默认值为 12000)、bbox和/或iso(来自openaq_list_countries的代码)限定范围;至少需要其中一项,且coordinates与bbox不能同时使用。还可用parametersId、monitor、mobile和providersId进一步筛选;每页最多 100 个站点(limit,默认值为 20),page从 1 开始 - 每个站点包含
id、distanceMeters(仅适用于坐标搜索)、provider/providerId、isMonitor/isMobile、包含单位信息的parameters,以及datetimeFirst/datetimeLast时间范围;OpenAQ 未提供时,coordinates、country和provider为 null totalCount统计截至当前页的站点数;设置totalCountIsLowerBound时,该值为下限。未找到匹配项时返回no_locations_found,页码超出末页时返回page_exhausted
openaq_get_readings 工具
- 提供
locationId,或提供coordinates和parametersId,以解析出 25 km 内测量该参数的最近站点(最多比较 1,000 个匹配站点;达到 1,000 个时会附加notice);提供locationId时,可选用parametersId筛选单个参数 - 每个传感器返回一条读数,包含
value、unit、sensorId和datetimeUtc/datetimeLocal;另返回站点的provider、providerId、timezone和datetimeLast - 未找到时会返回对应错误类型:
location_not_found、parameter_not_at_location(附带站点的availableid)和no_station_near_coordinates、no_recent_values
openaq_get_measurements 工具
- 必须提供
locationId和parametersId;datetimeFrom/datetimeTo接受 UTC 时间戳或站点当地时间的YYYY-MM-DD日期(站点没有时区时使用 UTC 日期)。aggregation可设为raw(默认值)、hourly或daily;每次调用最多返回 5,000 行 - 返回
series、sensorId、pulledCount、pullComplete、effectiveRange,以及站点的provider、providerId和timezone。设置totalCountIsLowerBound时,totalCount为下限;汇总结果还会包含统计摘要、gapCount、前 20 个缺失时间间隔(作为gaps),以及边界时间桶被截断时的提示 - 超过 100 行时,
series会以预览形式返回(truncated),且拉取的行会暂存到 DataCanvas,表名为measurements_<sensorId>(canvasId、tableName),条件是CANVAS_PROVIDER_TYPE=duckdb;提供canvas_id时,无论数据量大小,都会暂存到该画布。每个传感器对应一张表:第二个传感器会新增一张可供联接的表;对同一传感器再次暂存时,会覆盖之前的序列
openaq_list_parameters 工具
- 可选使用
query(不区分大小写)搜索代码、显示名称和描述;pollutantsOnly会排除气象和粒子计数通道 - 每行包含
id、name、displayName、unit和description;一种污染物可能因单位不同而对应多个 id(CO 在 µg/m³ 中为 4,在 ppm 中为 8,在 ppb 中为 102)
openaq_list_countries 工具
- 可选使用
query(两字母值会优先匹配 ISO 3166-1 alpha-2 代码;否则匹配代码或名称中包含的子串)和parametersId;每页最多 100 个(limit,默认值为 20),page从 1 开始 - 每行包含
code(openaq_find_locations的iso值)、name、datetimeFirst/datetimeLast时间范围,以及该国任何地点测量的parameters;totalCount为筛选后的完整计数
openaq_dataframe_describe 工具
- 接受来自
openaq_get_measurements的canvas_id,并返回每个暂存表的name、rowCount和columns。调用openaq_dataframe_query前请先调用此工具:暂存表为扁平结构(min、sd),而内联的series会将这些字段嵌套在summary下 - 除非设置了
CANVAS_PROVIDER_TYPE=duckdb,否则会返回canvas_unavailable;id 未知或已过期时会返回canvas_not_found
openaq_dataframe_query 工具
- 接受
canvas_id和一条只读SELECT语句;写入、DDL 以及文件/网络表函数都会被拒绝 - 每次响应最多返回 200 行;如果结果因达到上限而被截断,则会将
truncated设为 true;可通过ORDER BY加LIMIT/OFFSET翻页 - 失败时会返回
canvas_unavailable、canvas_not_found或missing_table
openaq_dataframe_drop 工具
- 仅当设置了
OPENAQ_ENABLE_CANVAS_DROP=true时才会注册;除非CANVAS_PROVIDER_TYPE=duckdb,否则调用会以canvas_unavailable失败。禁用时,HTTP 首页会显示启用提示,且tools/list中不会包含该工具 - 接受
canvas_id并删除整个 canvas,包括所有暂存表。共享该 ID 的其他 Agent 将失去访问权限;OpenAQ 的源数据不受影响 - 返回请求中的
canvasId和dropped:删除成功时为 true,不存在可访问的 canvas 时为 false。关闭身份验证时,调用方共用一个租户:启用该功能后,任何持有 ID 的人都可以删除对应的 canvas
openaq://location/{locationId} 资源
application/json:名称、地区、时区、国家、提供方、isMonitor/isMobile、坐标、sensors(每项都包含parameterId和unit),以及datetimeFirst/datetimeLast时间范围locationId来自openaq_find_locations;缓存 5 分钟
openaq://parameters 资源
application/json目录,行内容与未筛选的openaq_list_parameters相同- 缓存 1 小时
功能
基于 @cyanheads/mcp-ts-core 构建:支持 stdio 和 Streamable HTTP 传输、可插拔身份验证(none/jwt/oauth)、可切换存储(in-memory、filesystem、Supabase、Cloudflare KV/R2/D1),以及支持可选 OpenTelemetry 跟踪的结构化日志。
OpenAQ 专属功能:
- 基于 OpenAQ v3 REST API 的类型化客户端:使用
X-API-Key身份验证、带退避的重试,并为每次 OpenAQ 调用提供类型化上游错误(invalid_api_key、rate_limited、upstream_timeout、upstream_error) - 隐藏 v3 的站点 → 传感器 → 测量值层级结构:读数会与最新数据流及站点的传感器映射关联;测量值则通过站点和参数解析到对应传感器
- 在请求发送到 OpenAQ 之前,对坐标和边界框角点进行范围检查,并拒绝相互矛盾的搜索范围
- 较大的测量序列会暂存到 DataCanvas 中,以便使用 DuckDB SQL 进行只读查询;每个传感器对应一张表,因此可以联接同一
canvas_id上的两个序列
便于 Agent 使用的输出:
- 数据来自实际测量,而非模型估算:搜索不到站点时会返回
no_locations_found或no_station_near_coordinates,并说明这是无覆盖数据,而非空气质量良好 - 每个数值都会附带单位,且绝不进行单位换算;
parametersId会同时选择污染物和单位 - 明确标示数据新鲜度和截断情况:提供每个数值的时间戳和
datetimeLast,以及达到结果上限时的totalCount/truncated/notice
开始使用
公共托管实例
公共实例位于 https://openaq.caseyjhand.com/mcp,无需安装。通过 Streamable HTTP 将任意 MCP 客户端连接到该实例:
{
"mcpServers": {
"openaq-mcp-server": {
"type": "streamable-http",
"url": "https://openaq.caseyjhand.com/mcp"
}
}
}
自托管/本地部署
将以下内容添加到 MCP 客户端配置文件中。
{
"mcpServers": {
"openaq-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/openaq-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"OPENAQ_API_KEY": "your-api-key"
}
}
}
}
或者使用 npx(无需 Bun):
{
"mcpServers": {
"openaq-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/openaq-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"OPENAQ_API_KEY": "your-api-key"
}
}
}
}
或者使用 Docker:
{
"mcpServers": {
"openaq-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"-e", "OPENAQ_API_KEY=your-api-key",
"ghcr.io/cyanheads/openaq-mcp-server:latest"
]
}
}
}
将 "CANVAS_PROVIDER_TYPE": "duckdb" 添加到 env,即可为大型测量序列启用 DataCanvas SQL。
使用 Streamable HTTP 时,设置传输方式并启动服务:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 OPENAQ_API_KEY=your-api-key bun run start:http
# Server listens at http://localhost:3010/mcp
先决条件
- Bun v1.4.0 或更高版本(或 Node.js v24+)。
- 从 OpenAQ Explorer 账户获取免费的 OpenAQ v3 API 密钥。
安装
- 克隆代码仓库:
git clone https://github.com/cyanheads/openaq-mcp-server.git
- 进入目录:
cd openaq-mcp-server
- 安装依赖:
bun install
- 配置环境:
cp .env.example .env
# edit .env and set OPENAQ_API_KEY
配置
| 变量 | 说明 | 默认值 |
|---|---|---|
OPENAQ_API_KEY | 必填。 OpenAQ v3 API 密钥,通过 X-API-Key 标头发送。 | — |
OPENAQ_API_BASE_URL | OpenAQ v3 API 基础 URL,可用于代理或测试镜像。 | https://api.openaq.org/v3 |
CANVAS_PROVIDER_TYPE | duckdb 会将大型测量序列暂存,以便通过 dataframe 工具执行 SQL;未设置时,大型序列会返回预览和提示。.mcpb 捆绑包不包含 DuckDB,因此进行 canvas 操作时请使用 npm、npx 或 Docker。 | none |
OPENAQ_ENABLE_CANVAS_DROP | 启用 openaq_dataframe_drop,以删除整个画布并释放其资源。需要 DuckDB;如果某个 ID 与同一租户中的其他 Agent 共享,则该 Agent 也有权删除。 | false |
MCP_TRANSPORT_TYPE | 传输方式:stdio 或 http。 | stdio |
MCP_HTTP_PORT | HTTP 服务端口。 | 3010 |
MCP_SESSION_MODE | HTTP 会话模式:stateless、stateful 或 auto。会覆盖服务端明确设置的无状态模式;auto 会解析为有状态模式。 | stateless |
MCP_AUTH_MODE | 身份验证:none、jwt 或 oauth。 | none |
MCP_LOG_LEVEL | 日志级别(debug、info、warning、error 等)。 | info |
OTEL_ENABLED | 启用 OpenTelemetry。 | false |
OTEL_EXPORTER_OTLP_ENDPOINT | OTLP 基础 URL;跟踪数据使用 /v1/traces,指标使用 /v1/metrics。信号专用端点会覆盖此项。 | — |
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT | 设置完整端点 URL,以启用 OTLP 日志导出。基础端点不会启用日志。 | — |
LOG_TOOL_FAILURE_PAYLOADS | 记录调用失败时的参数和结果。仅按键名脱敏;自由格式值中的机密信息仍会保留。 | false |
LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES | 每个失败负载的 UTF-8 字节数上限。 | 16384 |
完整的可选覆盖项列表请参见 .env.example。
运行服务端
本地开发
-
构建并运行:
bun run rebuild bun run start:http # or start:stdio -
运行检查和测试:
bun run devcheck # Lint, format, typecheck, security, changelog sync bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker build -t openaq-mcp-server .
docker run --rm -e OPENAQ_API_KEY=your-api-key -p 3010:3010 openaq-mcp-server
此镜像默认使用 HTTP 传输、无状态会话模式,并将日志写入 /var/log/openaq-mcp-server。镜像中包含 DuckDB,因此设置 CANVAS_PROVIDER_TYPE=duckdb 后即可使用 DataCanvas。默认会安装 OpenTelemetry 对等依赖;构建时使用 --build-arg OTEL_ENABLED=false 可省略这些依赖。
项目结构
| 目录 | 用途 |
|---|---|
src/index.ts | createApp() 入口:注册工具和资源,并连接服务与画布。 |
src/config | 使用 Zod 解析并验证服务端专用环境变量。 |
src/mcp-server/tools | 工具定义(definitions/*.tool.ts)以及共享的输入、错误和格式辅助工具(shared/)。 |
src/mcp-server/resources | 资源定义(definitions/*.resource.ts)。 |
src/services | OpenAQ v3 客户端和领域类型(openaq/),以及 DataCanvas 访问器。 |
tests/ | 与 src/ 结构对应的单元测试和集成测试。 |
开发指南
开发指南和架构规则请参见 CLAUDE.md / AGENTS.md。简要说明如下:
- 处理程序抛出异常,框架负责捕获——仅在将失败映射到已声明的错误原因或保留部分结果时捕获异常
- 使用
ctx.log记录请求范围内的日志,使用ctx.state存储租户范围内的数据 - 在
createApp()数组中注册新工具和资源 - 封装 OpenAQ API:验证原始数据 → 规范化为领域类型 → 返回输出架构;原样呈现单位,绝不编造缺失字段
贡献
欢迎提交问题。提交前请运行检查和测试:
bun run devcheck
bun run test
许可证
Apache-2.0 — 详情请参阅 LICENSE。
数据来自 OpenAQ 平台,使用此服务的输出时必须注明 OpenAQ (使用条款)。OpenAQ 汇总了政府机构、研究机构和其他网络的测量数据,其中每个来源都可能制定自己的署名或许可条款。openaq_find_locations、openaq_get_readings 和 openaq_get_measurements 结果中的 provider 字段,以及 openaq://location/{locationId} 资源名称,会标明数据的来源网络;使用任何提供方的数据前,请查阅并遵守其条款。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。