mcpField
E
exchange-rates-mcp-server

exchange-rates-mcp-server

远程服务
github.com/cyanheads金融数据15 天前更新
代码仓库

关于 exchange-rates-mcp-server

exchange-rates-mcp-server 提供 Frankfurter v1 每日汇率数据,可用于货币换算、汇率查询和历史序列分析。DataCanvas 可暂存较长序列,供只读 SQL 查询。

主要功能

  1. 01发现支持的货币
  2. 02获取当前和历史汇率
  3. 03换算货币金额
  4. 04查询每日汇率时间序列
  5. 05暂存序列供 SQL 分析

适用场景

  1. 01按最新或历史汇率换算金额
  2. 02查询特定日期的货币对汇率
  3. 03查看一段时间内的汇率变化
  4. 04使用 SQL 汇总暂存的汇率数据

MCP 相关

通过 STDIO 或 Streamable HTTP 向 MCP 客户端提供货币与时间序列工具及资源。DataCanvas 可提供可选暂存和 SQL 工具,也提供公共托管端点。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://exchange-rates.caseyjhand.com/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

安装包
npm@cyanheads/exchange-rates-mcp-server0.5.1

工具

7

此工具无需参数。

详细介绍

@cyanheads/exchange-rates-mcp-server

通过 MCP 转换货币、获取外汇汇率,并查询 Frankfurter v1 历史汇率数据。支持 STDIO 或 Streamable HTTP。

7 个工具 • 1 个选择启用的工具 • 2 个资源

版本 许可证 Docker MCP SDK npm TypeScript Bun

在 Claude Desktop 中安装 在 Cursor 中安装 在 VS Code 中安装

框架


概述

获取 Frankfurter v1 每日汇率、当前货币信息,以及从 1999-01-04 起的历史数据。转换金额、查询特定时点或历史汇率、汇总完整日期范围的数据,并对暂存的时间序列运行 SQL。历史数据涵盖已停用货币,并会根据请求的数据进行检查。响应中包含 source: "Frankfurter v1" 和 rate_type: "Daily rate (Frankfurter v1)";v1 返回的数据不会标明具体的数据提供方。无需 API 密钥。

工具
工具描述
fx_list_currencies发现当前支持的货币,提供完整名称和最新提供汇率的日期
fx_get_rates指定基础货币在最新日期或历史日期的所有汇率快照
fx_get_rate指定货币对在最新日期或历史日期的汇率
fx_convert_currency按最新汇率或历史汇率转换两种货币之间的金额
fx_get_timeseries指定货币对在日期范围内的历史每日汇率
fx_dataframe_describe列出先前调用 fx_get_timeseries 暂存的 DataCanvas 表和列
fx_dataframe_query对暂存的 DataCanvas 表运行只读 SQL SELECT 查询
fx_dataframe_drop移除一个暂存的 DataCanvas 表或视图(需主动启用,且具有破坏性)

DataCanvas(DuckDB)默认开启。设置 CANVAS_PROVIDER_TYPE=none 可将其关闭:此时,三个 fx_dataframe_* 工具会从 tools/list 中移除;若省略 canvas_id,fx_get_timeseries 会直接返回范围内的数据;显式暂存则会失败并返回 canvas_unavailable。Claude Desktop bundle(.mcpb)不包含 DuckDB 的原生绑定,因此运行时会关闭 DataCanvas。fx_dataframe_drop 还需要设置 FX_ENABLE_CANVAS_DROP=true。

四个汇率和货币转换工具都接受 base 作为 base_currency 的别名;货币对工具还接受 quote 作为 quote_currency 的别名。同一字段只能发送其中一种写法,不能同时发送。公布的架构使用规范名称。

货币值(包括 symbols)会先去除首尾空格,再转换为大写。指定日期接受 YYYY-MM-DD 或字面值 latest(也是默认值);范围日期必须使用 YYYY-MM-DD。公布的日期模式会保留处理程序级别的 invalid_date_format 错误,用于处理格式错误、空白或日历上不存在的日期。对于未来日期范围错误,建议将 end_date 设为今天或更早的日期;end_date 仍为必填项。

资源
资源描述
fx://currencies所有受支持货币的稳定参考文档
fx://rates/latest/{base}基础货币最新汇率快照的稳定 URI

所有资源数据也可通过工具访问——程序化访问时可使用 fx_list_currencies 或 fx_get_rates。

取消工具调用或资源读取会停止其上游获取、响应正文读取和重试退避。未取消的请求仍会重试两次,且每次尝试的超时时间为 10 秒。

功能参考

fx_list_currencies 工具
  • 无输入参数
  • 返回 currencies: [{ code, name }]、count、source 和 as_of(最新提供每日汇率的日期),并按代码字母顺序排序
  • 此工具用于发现当前支持的货币。历史请求会根据未经筛选的 EUR 快照或原始提供范围进行验证,因此已停用的代码在有观测数据的日期仍可使用。未知代码会返回 unsupported_currency,并提供已接受和已拒绝代码的排序列表以及输入字段;当前货币若没有历史观测数据,则会返回 upstream_no_data。

fx_get_rates 工具
  • base_currency 为必填项;date 为可选项(默认为最新日期,历史数据始于 1999-01-04,不接受未来日期);可选的 symbols 数组可缩小响应范围,且至少须包含一个代码
  • 返回 rates 映射(报价货币代码 → 汇率)、实际的 rate_date,以及当周末或节假日的请求日期回退到前一个工作日时返回的 date_snapped: true
  • 在 symbols 中指定基础货币是有效的——工具会在本地以汇率 1 作答,而不会将请求发送到上游
  • 类型化错误:invalid_date_format、unsupported_currency、date_out_of_range、upstream_no_data

fx_get_rate 工具
  • 必须提供 base_currency、quote_currency;date 可选(默认最新日期,历史数据自 1999-01-04 起,不支持未来日期)
  • 返回 rate、rate_date;如果请求的日期是周末或节假日并回退到前一个工作日,则还会返回 date_snapped: true
  • 每个货币对都使用同一份未经筛选的 EUR 快照中的报价货币 EUR 腿 / 基础货币 EUR 腿计算,不进行中间舍入;EUR 的腿为 1。同种货币的货币对仅在实际观测日期返回 1。
  • 类型化错误:invalid_date_format、unsupported_currency、date_out_of_range、upstream_no_data

fx_convert_currency 工具
  • 必须提供 base_currency、quote_currency、amount(必须大于 0);date 可选(默认最新日期,历史数据自 1999-01-04 起,不支持未来日期)
  • 通过一次上游调用处理 EUR↔任意货币、任意货币↔EUR 以及交叉汇率货币对(例如 USD→JPY)
  • 返回 quote_amount(舍入至小数点后 6 位)、rate、rate_date、date_snapped,以及用于溯源的 rate_type 和 source
  • 类型化错误:invalid_date_format、unsupported_currency、date_out_of_range、upstream_no_data

fx_get_timeseries 工具
  • 必须提供 base_currency、quote_currency、start_date、end_date(历史数据自 1999-01-04 起,不支持未来日期,且 start ≤ end);canvas_id 为可选项,可追加到现有画布
  • 内联结果每页最多包含 500 个发布日;rate_count 始终表示整个范围的总数;若返回 truncated: true,可使用 next_start_date 继续获取
  • 超过 FX_TIMESERIES_CANVAS_THRESHOLD_DAYS(默认 90 天)的范围会被考虑用于 DataCanvas 暂存。超过 40,000 个字符预览预算的时间序列会返回 spilled: true、canvas_id 和 table_name;较小的时间序列以及设置了 CANVAS_PROVIDER_TYPE=none 的部署会以内联方式分页
  • 同种货币的货币对在实际观测日期返回 1。每条非恒等关系记录都必须在同一日期具有两条 EUR 腿;缺少的腿绝不会用于伪造观测值。成员资格使用所有提供的原始日期,再进行包含边界的截取,从而保留仅包含周末的空窗口。
  • 空范围(仅包含周末或节假日)会返回 rate_count: 0 和说明性 notice,可与错误区分
  • 能放入内联预览的长范围会释放其新获取的画布;暂存失败或取消时也会释放。提供的画布会保持可用。
  • 明确指定 canvas_id 时,始终会暂存完整结果,包括较短范围和空范围,并使用 rate DOUBLE。每个表名都会附加一个新的标识符后缀;重复和并发调用都会保留所有先前的表。未知 ID 会报错 canvas_not_found;DataCanvas 已禁用时会报错 canvas_unavailable。预览包含所有观测值时,truncated 为 false。
  • 非空结果会包含 summary: { mean, min: { rate, date }, max: { rate, date }, first: { rate, date }, last: { rate, date }, change_pct }。该摘要涵盖请求区间内分页或暂存前的所有观测值;续页调用则汇总其较短的请求区间。极值相同时选择最早日期;单个观测值和恒等关系的变动均为 0。空序列不包含 summary。Mean 是每日观测值的非加权算术平均值,并非税务机关或会计政策的规定。

fx_dataframe_describe 工具
  • 必须提供 canvas_id(来自先前的 fx_get_timeseries 调用)
  • 返回每个已暂存表的 kind、row_count 和列架构(name、type、nullable),以及 expires_at
  • 在调用 fx_dataframe_query 前必须先执行;当 CANVAS_PROVIDER_TYPE=none 时不注册
  • ID 不存在或已过期时返回 canvas_not_found

fx_dataframe_query 工具
  • 必须提供 canvas_id 和只读 SQL query;row_limit 必须是正整数(默认值为 150)。超过 10,000 的值会被限制为 10,000,并在通知中列出请求值和生效值;限制和截断通知会同时出现,分页指引使用生效值。
  • 支持聚合、GROUP BY、窗口函数,以及跨多个 fx_get_timeseries 调用所创建表的 JOIN
  • 返回的行数不超过 row_limit;truncated: true 和 notice 会提供下一页的 ORDER BY <column> LIMIT <n> OFFSET <m> 格式;稳定分页必须使用 ORDER BY
  • Markdown 表格单元格中的管道符、尖括号和换行符会经过转义,以确保它们留在各自的单元格内;structuredContent 保留原始值
  • 当 CANVAS_PROVIDER_TYPE=none 时不注册;失败时返回类型化错误:canvas_not_found、missing_table、invalid_query

fx_dataframe_drop 工具
  • 必须提供 canvas_id 和准确的 table_name(来自 fx_dataframe_describe)
  • 移除一个暂存表或视图;上游汇率数据不受影响,可通过 fx_get_timeseries 重新暂存该序列
  • 根据表是否存在,返回 dropped: true/false
  • 除非设置 FX_ENABLE_CANVAS_DROP=true,否则此工具处于禁用状态——此时它不会出现在 tools/list 中,仅在启动日志和 HTTP 入口页中以名称和启用提示的形式显示;当 CANVAS_PROVIDER_TYPE=none 时也不注册

fx://currencies 资源
  • 无参数;以 application/json 格式返回当前发现结果,其中包含 currencies、count、source、as_of——与 fx_list_currencies 返回的负载相同
  • 作为单个静态资源列出

fx://rates/latest/{base} 资源
  • base 是 URI 中的 ISO 4217 货币代码
  • 返回最新已提供的每日快照中的 base_currency、rate_date、rates 映射、rate_type 和 source
  • 列出四个示例 URI(EUR、USD、GBP、JPY)作为发现提示

功能

基于 @cyanheads/mcp-ts-core 构建:支持 stdio 和 Streamable HTTP 传输、可插拔身份验证(none / jwt / oauth)、可切换存储(in-memory、filesystem、Supabase、Cloudflare KV/R2/D1),并提供结构化日志记录和可选的 OpenTelemetry 跟踪。

汇率数据:

  • 通过 Frankfurter v1 获取无需密钥的每日数据
  • 每个快照或日期范围仅请求一次未筛选的 EUR 数据,并在本地计算交叉汇率;同一响应也会提供历史成员信息
  • 周末/节假日日期语义:当 API 返回的日期与请求日期不同时,会显示 date_snapped
  • 在货币有观测到的发布数据的日期,本地计算该货币的身份汇率为 1
  • 超出内联预览预算的长时间序列会暂存到 DataCanvas(默认启用 DuckDB),以便对完整日期范围进行 SQL 聚合

便于 Agent 使用的输出:

  • 每个响应都包含汇率来源信息——rate_type、source、rate_date 和 date_snapped,便于 Agent 判断可信度和时效性
  • 结构化错误契约——类型化的 reason 字段(unsupported_currency、date_out_of_range、invalid_query 等)让调用方能够根据失败类型分支处理,无需解析字符串
  • 有界响应——内联时间序列分页通过 next_start_date 继续,SQL 结果限制为 row_limit,因此没有任何调用会返回无界负载
  • 成功路径的 notice 补充信息——说明序列为空、分页序列的后续位置,或哪些工具可以读取已暂存的序列,避免将合法的零结果误认为失败

开始使用

公共托管实例

公共实例位于 https://exchange-rates.caseyjhand.com/mcp,无需安装。通过 Streamable HTTP 将任意 MCP 客户端连接到该实例:

{
  "mcpServers": {
    "exchange-rates-mcp-server": {
      "type": "streamable-http",
      "url": "https://exchange-rates.caseyjhand.com/mcp"
    }
  }
}
自托管 / 本地

无需 API 密钥——Frankfurter 无需密钥。在 MCP 客户端配置文件中添加以下内容:

{
  "mcpServers": {
    "exchange-rates-mcp-server": {
      "type": "stdio",
      "command": "bunx",
      "args": ["@cyanheads/exchange-rates-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info"
      }
    }
  }
}

或使用 npx(无需 Bun):

{
  "mcpServers": {
    "exchange-rates-mcp-server": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@cyanheads/exchange-rates-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info"
      }
    }
  }
}

或使用 Docker:

{
  "mcpServers": {
    "exchange-rates-mcp-server": {
      "type": "stdio",
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "MCP_TRANSPORT_TYPE=stdio",
        "ghcr.io/cyanheads/exchange-rates-mcp-server:latest"
      ]
    }
  }
}

DataCanvas(DuckDB)默认启用,适用于长时间序列的 SQL 分析。若要关闭,请添加 CANVAS_PROVIDER_TYPE=none:数据框工具会从 tools/list 中移除;省略 canvas_id 时,fx_get_timeseries 会以内联方式分页。显式请求暂存时会失败,并返回 canvas_unavailable。

{
  "mcpServers": {
    "exchange-rates-mcp-server": {
      "type": "stdio",
      "command": "bunx",
      "args": ["@cyanheads/exchange-rates-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "CANVAS_PROVIDER_TYPE": "none"
      }
    }
  }
}

若要使用 Streamable HTTP,请设置传输方式并启动服务:

MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
先决条件
  • Bun v1.4.0 或更高版本(或 Node.js v24+)。
  • 无需 API 密钥——Frankfurter 免费且无需密钥。
安装
  1. 克隆仓库:
git clone https://github.com/cyanheads/exchange-rates-mcp-server.git
  1. 进入目录:
cd exchange-rates-mcp-server
  1. 安装依赖:
bun install
  1. 配置环境:
cp .env.example .env
# edit .env as needed (all vars are optional — no keys required)

配置

所有配置都会在启动时通过 Zod 架构验证。环境变量:

变量描述默认值
FRANKFURTER_BASE_URLFrankfurter API 基础 URL。可覆盖此值以进行本地测试或使用自托管实例。https://api.frankfurter.dev/v1
FX_TIMESERIES_CANVAS_THRESHOLD_DAYS超过此天数范围时,fx_get_timeseries 会考虑自动暂存到 DataCanvas;若未提供 canvas_id,适合预览的序列仍以内联方式返回。显式提供 canvas_id 始终会请求暂存。90
FX_ENABLE_CANVAS_DROP启用具有破坏性的 fx_dataframe_drop 工具。默认关闭:不会注册该工具,也不会将其列入 tools/list。false
CANVAS_PROVIDER_TYPECanvas 引擎。duckdb 会为 fx_get_timeseries 启用长范围数据溢出所用的 DataCanvas,并注册三个 fx_dataframe_* 工具;none 会禁用它们,并将其从 tools/list 中移除。空值会采用默认值。.mcpb 包设置为 none。duckdb
MCP_TRANSPORT_TYPE传输方式:stdio 或 http。stdio
MCP_HTTP_PORTHTTP 服务端口。3010
MCP_SESSION_MODEHTTP 会话模式:auto、stateful 或 stateless。代码中将服务声明为 stateless——这里没有处理器会在调用过程中向客户端请求输入,因此无需会话即可恢复;设置此变量会覆盖该声明。stateless
MCP_AUTH_MODE认证模式:none、jwt 或 oauth。none
MCP_REQUEST_STATE_KEY可选密钥(≥ 32 字节,所有实例必须相同),用于在多轮交互间封装处理器返回的 requestState。这里没有任何工具会返回此值。—
MCP_LOG_LEVEL日志级别(RFC 5424:debug、info、notice、warning、error)。同时也是镜像到客户端的日志最低级别。info
LOG_TOOL_FAILURE_PAYLOADS记录每次失败的工具调用参数和结果(仅按键名进行脱敏)。false
LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTESLOG_TOOL_FAILURE_PAYLOADS 的单个负载上限,单位为 UTF-8 字节。16384
OTEL_ENABLED启用 OpenTelemetry 插桩。false
OTEL_EXPORTER_OTLP_ENDPOINTOTLP 基础 URL;追踪数据发送到 /v1/traces,指标发送到 /v1/metrics。—
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT可选的 OTLP 日志导出端点(例如 http://localhost:4318/v1/logs);基础端点不会启用日志导出。—

完整的可选覆盖项(包括存储、会话和遥测变量)请参阅 .env.example。


运行服务

本地开发
  • 构建并运行:

    bun run rebuild
    bun run start:stdio
    # or
    bun run start:http
    
  • 运行检查和测试:

    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 exchange-rates-mcp-server .
docker run --rm -p 3010:3010 exchange-rates-mcp-server

Dockerfile 默认使用 HTTP 传输、无状态会话模式,并将日志写入 /var/log/exchange-rates-mcp-server。默认会安装 OpenTelemetry 对等依赖;如需省略这些依赖,请使用 --build-arg OTEL_ENABLED=false 构建。生产依赖(包括 DuckDB 的原生绑定)会在单独的 deps 阶段针对目标平台交叉安装,因此多架构构建无需在仿真环境下运行 Bun,运行时映像仅包含 node_modules 和 dist/。


项目结构

目录用途
src/index.tscreateApp() 入口点 — 注册工具、资源和画布访问器。
src/config/使用 Zod 解析并验证服务器专属环境变量。
src/mcp-server/tools/工具定义(*.tool.ts)— fx_* 工具。
src/mcp-server/resources/资源定义 — fx://currencies 和 fx://rates/latest/{base}。
src/services/frankfurter/Frankfurter HTTP 客户端、重试逻辑和领域类型。
src/services/canvas/模块级 DataCanvas 访问器,用于 fx_get_timeseries 溢出处理。
src/utils/输出辅助工具 — 为 fx_dataframe_query 转义 Markdown 表格单元格。
tests/与 src/ 结构对应的单元测试和集成测试。
docs/设计文档和想法笔记。

开发指南

开发指南和架构规则请参阅 CLAUDE.md。简要来说:

  • 处理程序抛出异常,框架负责捕获 — 工具逻辑中不要使用 try/catch
  • 使用 ctx.log 进行请求级日志记录,使用 ctx.state 进行租户级存储
  • 通过 src/mcp-server/*/definitions/index.ts 中的聚合导出注册新工具和资源
  • 封装外部 API 调用:验证原始数据 → 规范化为领域类型 → 返回输出架构;绝不伪造缺失字段
  • 在每个响应中保留 rate_type: "Daily rate (Frankfurter v1)" 和 source: "Frankfurter v1" 来源信息

贡献

欢迎提交问题。提交前请运行检查和测试:

bun run devcheck
bun run test

许可证

Apache-2.0 — 详情请参阅 LICENSE。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。