@cyanheads/exchange-rates-mcp-server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@cyanheads/exchange-rates-mcp-serverconvert 100 USD to EUR"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Public Hosted Server: https://exchange-rates.caseyjhand.com/mcp
Tools
Seven tools for working with ECB FX rate data — currency lookup and disambiguation, point-in-time rates and conversions, historical time-series retrieval, and SQL analytics over the DataCanvas workspace that long time-series calls produce:
Tool | Description |
| List all ~30 ECB-supported ISO 4217 currencies with full names. Use before converting to disambiguate "dollars" (USD vs AUD vs CAD vs HKD vs SGD). |
| Snapshot of all available rates for a base currency at latest or a historical date. Optional |
| Exchange rate for a single currency pair at latest or a historical date. Surfaces |
| Convert an amount between any two currencies at latest or a historical rate. Cross-rates are triangulated through EUR. Returns converted amount, rate used, rate date, and whether the date was snapped. |
| Historical daily rates for a currency pair over a date range. Short ranges (≤90 days) are returned inline; long ranges spill to DataCanvas with a |
| List DataCanvas tables and their columns from a prior |
| Run a read-only SQL SELECT against a DataCanvas table produced by |
fx_list_currencies
Enumerate all supported currencies before converting or querying.
Returns
[{ code, name }]for all ~30 ECB-scoped currenciesECB coverage fluctuates as currencies enter/exit scope — always call this tool to validate user-supplied codes rather than hard-coding a list
fx_get_rates
Full rates snapshot for a base currency in one call.
Returns all available quote currencies at a given date (default: latest)
Optional
symbolsparameter narrows the response to specific quote currenciesUseful for seeding bulk comparison workflows or discovering what's available
fx_get_rate
Point-in-time exchange rate for a single pair.
Returns the rate, the actual rate date, and
date_snapped: truewhen the API silently moved a weekend/holiday request to the prior business dayCross-rates (neither side EUR) are triangulated in a single API call — no extra round trip
Use
fx_convert_currencywhen you need the converted amount; use this tool when you only need the rate number
fx_convert_currency
Convert an amount between any two currencies.
Handles EUR ↔ any, any ↔ EUR, and cross-rate (USD → JPY via EUR) in one upstream call
Returns
converted_amount,rate,rate_date,date_snapped, plusrate_typeandsourceprovenance on every responseHistorical conversions supported back to 1999-01-04 (ECB launch date)
fx_get_timeseries + fx_dataframe_describe / fx_dataframe_query
Historical rate series and DataCanvas SQL analytics.
fx_get_timeseries returns a date-keyed series (business days only — ECB publishes once per business day):
Short ranges (≤
FX_TIMESERIES_CANVAS_THRESHOLD_DAYS, default 90 days) → inlineratesmap + metadataLong ranges → first N rows inline +
canvas_id,table_name, andtruncated: true— the full series is registered as a DuckDB-backed table
Once a canvas_id is in hand:
fx_dataframe_describe— list the tables and columns on the canvas (required beforefx_dataframe_query)fx_dataframe_query— run arbitrary SQL SELECT against the registered table; supports aggregations, GROUP BY, window functions, JOINs across tables from multiplefx_get_timeseriescalls
The canvas uses a session-scoped TTL. To continue working with a prior series, call fx_get_timeseries again with the same parameters to obtain a fresh canvas_id.
Related MCP server: currency-exchange-mcp
Resources and prompts
Type | Name | Description |
Resource |
| All supported currencies as a stable reference document. Injectable context for clients that support resources. |
Resource |
| Latest rates snapshot for a base currency as a stable URI. |
All resource data is also reachable via tools. Use fx_list_currencies or fx_get_rates for programmatic access.
Features
Built on @cyanheads/mcp-ts-core:
Declarative tool and resource definitions — single file per primitive, framework handles registration and validation
Unified error handling — handlers throw, framework catches, classifies, and formats
Typed error contracts with recovery hints —
unsupported_currency,date_out_of_range,canvas_not_found,invalid_queryPluggable auth:
none,jwt,oauthStructured logging with optional OpenTelemetry tracing
STDIO and Streamable HTTP transports
ECB FX–specific:
Keyless access via Frankfurter — a Cloudflare-fronted ECB proxy; no API keys required
Cross-rate triangulation: any pair works (USD → JPY fetches EUR/USD and EUR/JPY in one call, computes JPY/USD ratio)
Weekend/holiday date semantics:
date_snappedflag surfaces when the API returns a different date than requestedECB data covers ~30 major currencies from 1999-01-04 to present;
fx_list_currenciesalways reflects the live setDataCanvas integration:
fx_get_timeseriesspills long ranges to DuckDB for aggregations and trend analysisRate provenance on every response:
rate_type: "ECB reference (mid-market)"andsource: "ECB via Frankfurter"— explicitly mid-market, not tradeable bid/ask
Agent-friendly output:
Rate provenance on every response —
rate_type,source,rate_date, anddate_snappedso agents can reason about trust and freshnessStructured error contracts — typed
reasonfields (unsupported_currency,date_out_of_range,invalid_query, …) let callers branch on failure type, not string parsingDiscriminated DataCanvas output —
canvas_idandtruncated: truesignal when a time-series exceeds the inline limit and SQL follow-up is needed
Getting started
Public Hosted Instance
A public instance is available at https://exchange-rates.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"exchange-rates-mcp-server": {
"type": "streamable-http",
"url": "https://exchange-rates.caseyjhand.com/mcp"
}
}
}Self-Hosted / Local
No API key required — Frankfurter is keyless. Add the following to your MCP client configuration file:
{
"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"
}
}
}
}Or with npx (no Bun required):
{
"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"
}
}
}
}Or with 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"
]
}
}
}To enable DataCanvas for long time-series SQL analytics, add CANVAS_PROVIDER_TYPE=duckdb:
{
"mcpServers": {
"exchange-rates-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/exchange-rates-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"CANVAS_PROVIDER_TYPE": "duckdb"
}
}
}
}For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcpPrerequisites
Bun v1.3.0 or higher (or Node.js v24+).
No API key — Frankfurter is free and keyless.
Installation
Clone the repository:
git clone https://github.com/cyanheads/exchange-rates-mcp-server.gitNavigate into the directory:
cd exchange-rates-mcp-serverInstall dependencies:
bun installConfigure environment:
cp .env.example .env
# edit .env as needed (all vars are optional — no keys required)Configuration
All configuration is validated at startup via Zod schemas. Environment variables:
Variable | Description | Default |
| Frankfurter API base URL. Override for local testing or a self-hosted instance. |
|
| Day range above which |
|
| Canvas engine. Set to |
|
| Transport: |
|
| Port for HTTP server. |
|
| Auth mode: |
|
| Log level (RFC 5424: |
|
| Enable OpenTelemetry instrumentation. |
|
See .env.example for the full list of optional overrides including storage, session, and telemetry vars.
Running the server
Local development
Build and run:
bun run rebuild bun run start:stdio # or bun run start:httpRun checks and tests:
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-serverThe Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/exchange-rates-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them. DuckDB native binaries are pre-built in the build stage and copied to production, keeping the production image free of build tools.
Project structure
Directory | Purpose |
|
|
| Server-specific environment variable parsing and validation with Zod. |
| Tool definitions ( |
| Resource definitions — |
| Frankfurter HTTP client, retry logic, and domain types. |
| Module-level DataCanvas accessor for |
| Unit and integration tests mirroring |
| Design document and idea notes. |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
Handlers throw, framework catches — no
try/catchin tool logicUse
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storageRegister new tools and resources via the barrels in
src/mcp-server/*/definitions/index.tsWrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
ECB rates are mid-market reference rates — preserve the
rate_typeprovenance in every response
Contributing
Issues and pull requests are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testLicense
Apache-2.0 — see LICENSE for details.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/cyanheads/exchange-rates-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server