@allratestoday/mcp-server 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # AllRatesToday MCP Server — @allratestoday/mcp-server
2
2
 
3
+ Website: https://allratestoday.com · Hosted endpoint (no install): https://allratestoday.com/api/mcp · Docs: https://allratestoday.com/mcp/
4
+
3
5
  [![npm version](https://img.shields.io/npm/v/@allratestoday/mcp-server.svg)](https://www.npmjs.com/package/@allratestoday/mcp-server)
4
6
  [![npm downloads](https://img.shields.io/npm/dm/@allratestoday/mcp-server.svg)](https://www.npmjs.com/package/@allratestoday/mcp-server)
5
7
  [![license](https://img.shields.io/npm/l/@allratestoday/mcp-server.svg)](./LICENSE)
@@ -21,7 +23,7 @@ After installation, your assistant can answer questions like:
21
23
 
22
24
  - 📡 **Live mid-market rates** — 150+ ISO 4217 currencies, refreshed every ~60 seconds
23
25
  - 📈 **Historical series built in** — `1d` / `7d` / `30d` / `1y` windows with sensible granularity per period
24
- - 🧰 **Six focused tools** — `get_exchange_rate`, `get_historical_rates`, `get_rates_authenticated`, `list_currencies`, `list_central_banks`, `get_official_rates`; small surface, easy for the model to use correctly
26
+ - 🧰 **Eight focused tools** — `get_exchange_rate`, `get_historical_rates`, `get_rates_authenticated`, `list_currencies`, `list_central_banks`, `get_official_rates`, `get_reference_rate`, `request_trial_key`; small surface, easy for the model to use correctly
25
27
  - 🔌 **Works everywhere MCP does** — stdio transport, MCP 1.x; Claude Code, Cursor, Claude Desktop, Windsurf, or any generic host
26
28
  - 🔓 **Works with no API key** — installs and answers out of the box from the open ECB reference table; a free key unlocks real-time rates for 160+ currencies
27
29
  - 🛡️ **Honest about what it returned** — every keyless answer says which rate it is and when it was published; API errors map to clear, actionable messages
@@ -41,6 +43,8 @@ Install it with no configuration at all and it starts, connects, and answers:
41
43
  | `list_currencies` | ✅ | All 160+ supported ISO 4217 codes. |
42
44
  | `list_central_banks` | ✅ | Codes, names and latest publication date of all 121 central banks + 3 tax authorities. |
43
45
  | `get_official_rates` | ✅ | Latest **official table** (or one pair) published by any of them. A dated table needs the key. |
46
+ | `get_reference_rate` | ✅ | The **Daily Reference Rate**: one never-revised table per business day, fixed at 16:00 London. A past date needs the key. |
47
+ | `request_trial_key` | ✅ | Self-issues a 100-call, 7-day key with no account and adopts it for the session. |
44
48
  | `get_historical_rates` | 🔑 | Returns one sentence explaining how to get a free key. |
45
49
  | `get_rates_authenticated` | 🔑 | Same. |
46
50
 
@@ -198,8 +202,10 @@ After configuring your client, test in this order:
198
202
  - [`list_currencies`](#list_currencies) — all supported currency codes, names, symbols
199
203
  - [`list_central_banks`](#list_central_banks) — every covered central bank / tax authority with its code and latest publication date
200
204
  - [`get_official_rates`](#get_official_rates) — the official table (or one pair) a named institution published
205
+ - [`get_reference_rate`](#get_reference_rate) — the Daily Reference Rate, one fixed mid-market table per business day (16:00 London)
206
+ - [`request_trial_key`](#request_trial_key) — self-issue a 100-call, 7-day trial key, no account needed
201
207
 
202
- `get_historical_rates` and `get_rates_authenticated` require `ALLRATES_API_KEY`; the other four work keyless.
208
+ `get_historical_rates` and `get_rates_authenticated` require `ALLRATES_API_KEY`; the other six work keyless.
203
209
 
204
210
  ---
205
211
 
@@ -374,6 +380,32 @@ Omit `source`/`target` for the whole table as `rates: [{ base, quote, type, valu
374
380
 
375
381
  ---
376
382
 
383
+ ### `get_reference_rate`
384
+
385
+ AllRatesToday's **Daily Reference Rate**: the per-currency median of samples taken in a five-minute window centred on 16:00 London, published once per business day and never revised. Use it when a report, index or research series needs *one* reproducible rate per day. It is not the WM/Refinitiv fix and not a registered benchmark; every response carries a disclaimer and the `rate_date`.
386
+
387
+ **Input**
388
+
389
+ | Field | Type | Required | Description |
390
+ |---|---|---|---|
391
+ | `source` | string | no | With `target`, narrows to one pair (crossed via USD, flagged `derived`) |
392
+ | `target` | string | no | See above |
393
+ | `date` | string | no | Past business day `YYYY-MM-DD` (API key). Omit for the latest table |
394
+
395
+ **Output** — `{ rate_date, base, time, rates }` for the table, or `{ rate_date, source, target, rate, derived }` for a pair, plus `method` and `disclaimer`. Keyless for the latest table. Docs: https://allratestoday.com/reference-rate/
396
+
397
+ ---
398
+
399
+ ### `request_trial_key`
400
+
401
+ Self-issues an API key with 100 lifetime calls, valid 7 days, with no account and no email, and switches this server to it for the rest of the session. The reply tells the user to copy the key into the MCP config as `ALLRATES_API_KEY` to keep it across restarts. Capped at 3 keys per IP per day.
402
+
403
+ **Input** — `agent` (string, optional), `purpose` (string, optional).
404
+
405
+ **Output** — `{ key, calls, expires_at, adopted, note }`.
406
+
407
+ ---
408
+
377
409
  ## ⚙️ Environment variables
378
410
 
379
411
  | Variable | Default | Required | Purpose |
@@ -474,6 +506,8 @@ server.json # MCP registry manifest
474
506
 
475
507
  See [GitHub Releases](https://github.com/cahthuranag/mcp-server/releases) for the full list. Recent highlights:
476
508
 
509
+ - **0.7.0** — `get_reference_rate` (Daily Reference Rate, 16:00 London, keyless latest table) and `request_trial_key` (self-issued 100-call trial key adopted for the session)
510
+ - **0.6.1** — README: Claude Code plugin and hosted `/api/mcp` endpoint cross-links; coverage wording refreshed
477
511
  - **0.6.0** — Official rates: new keyless `list_central_banks` and `get_official_rates` tools expose the latest table from 121 central banks + 3 tax authorities (dated tables need the key)
478
512
  - **0.5.0** — Keyless mode: the server starts and answers without an API key (`get_exchange_rate` via the open ECB reference table, `list_currencies` unchanged); metered tools return actionable sign-up guidance instead of the process exiting
479
513
  - **0.4.x** — README overhaul; registry metadata updates
package/dist/client.d.ts CHANGED
@@ -17,13 +17,34 @@ export declare class NeedsKeyError extends AllRatesTodayError {
17
17
  constructor(what: string);
18
18
  }
19
19
  export declare class AllRatesTodayClient {
20
- private readonly apiKey?;
20
+ private apiKey?;
21
21
  private readonly baseUrl;
22
22
  private readonly fetchImpl;
23
23
  constructor(options?: ClientOptions);
24
24
  private request;
25
25
  /** True when no API key is configured: only the open endpoints are reachable. */
26
26
  get keyless(): boolean;
27
+ /** Adopt a key at runtime (used after request_trial_key) so the rest of the session is keyed. */
28
+ setApiKey(key: string | undefined): void;
29
+ /**
30
+ * Daily Reference Rate: one never-revised mid-market table per business day,
31
+ * fixed at 16:00 London (median of samples in a 5-minute window). Latest
32
+ * table and single pairs are keyless; a dated table needs the key.
33
+ */
34
+ getReferenceRate(params?: {
35
+ source?: string;
36
+ target?: string;
37
+ date?: string;
38
+ }): Promise<Record<string, unknown>>;
39
+ /**
40
+ * Self-issue a trial key (100 calls, 7 days, no account) and adopt it for the
41
+ * rest of this process. POST with a JSON body: the site rejects bodiless
42
+ * POSTs as cross-site form submissions.
43
+ */
44
+ requestTrialKey(params?: {
45
+ agent?: string;
46
+ purpose?: string;
47
+ }): Promise<any>;
27
48
  getRate(source: string, target: string): Promise<{
28
49
  rate: number;
29
50
  source: string;
package/dist/client.js CHANGED
@@ -81,6 +81,65 @@ export class AllRatesTodayClient {
81
81
  get keyless() {
82
82
  return !this.apiKey;
83
83
  }
84
+ /** Adopt a key at runtime (used after request_trial_key) so the rest of the session is keyed. */
85
+ setApiKey(key) {
86
+ this.apiKey = key || undefined;
87
+ }
88
+ /**
89
+ * Daily Reference Rate: one never-revised mid-market table per business day,
90
+ * fixed at 16:00 London (median of samples in a 5-minute window). Latest
91
+ * table and single pairs are keyless; a dated table needs the key.
92
+ */
93
+ getReferenceRate(params = {}) {
94
+ if (Boolean(params.source) !== Boolean(params.target)) {
95
+ return Promise.reject(new AllRatesTodayError('Provide both source and target, or neither.'));
96
+ }
97
+ const pair = { source: params.source?.toUpperCase(), target: params.target?.toUpperCase() };
98
+ if (params.date) {
99
+ if (this.keyless)
100
+ return Promise.reject(new NeedsKeyError(`The reference-rate table for ${params.date}`));
101
+ return this.request(`/v1/reference-rate/${encodeURIComponent(params.date)}`, pair);
102
+ }
103
+ return this.request('/open/reference-rate', pair);
104
+ }
105
+ /**
106
+ * Self-issue a trial key (100 calls, 7 days, no account) and adopt it for the
107
+ * rest of this process. POST with a JSON body: the site rejects bodiless
108
+ * POSTs as cross-site form submissions.
109
+ */
110
+ async requestTrialKey(params = {}) {
111
+ const res = await this.fetchImpl(`${this.baseUrl}/agent/keys`, {
112
+ method: 'POST',
113
+ headers: {
114
+ 'Accept': 'application/json',
115
+ 'Content-Type': 'application/json',
116
+ 'User-Agent': `allratestoday-mcp/${VERSION}`,
117
+ },
118
+ body: JSON.stringify({ agent: params.agent, purpose: params.purpose }),
119
+ });
120
+ const text = await res.text();
121
+ let body;
122
+ try {
123
+ body = text ? JSON.parse(text) : null;
124
+ }
125
+ catch {
126
+ body = text;
127
+ }
128
+ if (!res.ok) {
129
+ const upstream = body && typeof body === 'object' && typeof body.error === 'string' ? body.error : undefined;
130
+ throw new AllRatesTodayError(upstream ?? `HTTP ${res.status}`, res.status, body);
131
+ }
132
+ const key = body && typeof body === 'object' && typeof body.key === 'string' ? body.key : undefined;
133
+ if (key)
134
+ this.setApiKey(key);
135
+ return {
136
+ ...(body ?? {}),
137
+ adopted: Boolean(key),
138
+ note: 'This server now uses the trial key for the rest of this session. To keep it after a restart, ' +
139
+ 'put it in the MCP config: "env": { "ALLRATES_API_KEY": "<key>" }. For a lasting key register free ' +
140
+ 'at https://allratestoday.com/register (300 calls) or see https://allratestoday.com/pricing.',
141
+ };
142
+ }
84
143
  getRate(source, target) {
85
144
  // Keyless: fall back to the open, edge-cached ECB reference table. It is
86
145
  // the official daily fixing rather than a live mid-market quote and covers
package/dist/index.js CHANGED
@@ -45,6 +45,8 @@ async function main() {
45
45
  ' • list_currencies — all supported currency codes',
46
46
  ' • list_central_banks — 121 central banks + 3 tax authorities we carry',
47
47
  ' • get_official_rates — latest official table (or one pair) from any of them',
48
+ ' • get_reference_rate — Daily Reference Rate, one fixed table per business day (16:00 London)',
49
+ ' • request_trial_key — self-issue a 100-call, 7-day key without an account',
48
50
  '',
49
51
  ' Needs a free API key (real-time mid-market rates for 160+ currencies,',
50
52
  ' historical series, multi-target and point-in-time lookups):',
@@ -235,6 +237,62 @@ async function main() {
235
237
  return fail(err);
236
238
  }
237
239
  });
240
+ server.registerTool('get_reference_rate', {
241
+ title: 'Get the Daily Reference Rate (16:00 London)',
242
+ description: "AllRatesToday's once-a-day, never-revised mid-market rate: the per-currency median of samples in a five-minute window centred on 16:00 London, published each business day. Use it when the user needs ONE reproducible rate per day — index levels, return series, research datasets, month-end reports — rather than a live quote (get_exchange_rate) or an institution's official rate (get_official_rates). Omit source/target for the whole table; give both for one pair (crossed via USD, flagged `derived`). Omit `date` for the latest table (no key needed); give `date` (API key) for a past business day. Not the WM/Refinitiv fix and not a registered benchmark — relay the disclaimer and the `rate_date`.",
243
+ inputSchema: {
244
+ source: ccy.optional().describe('Optional. With target, narrows to one pair.'),
245
+ target: ccy.optional().describe('Optional. With source, narrows to one pair.'),
246
+ date: z
247
+ .string()
248
+ .regex(/^\d{4}-\d{2}-\d{2}$/)
249
+ .optional()
250
+ .describe('Optional past business day, YYYY-MM-DD (API key). Omit for the latest table.'),
251
+ },
252
+ outputSchema: {
253
+ rate_date: z.string().describe('Business day the table was fixed on — cite this'),
254
+ base: z.string().optional(),
255
+ time: z.string().optional().describe('Fixing time, e.g. 16:00 Europe/London'),
256
+ rates: z.record(z.string(), z.unknown()).optional().describe('Full table keyed by currency code'),
257
+ source: z.string().optional(),
258
+ target: z.string().optional(),
259
+ rate: z.number().optional(),
260
+ derived: z.boolean().optional(),
261
+ method: z.string().optional(),
262
+ disclaimer: z.string().optional(),
263
+ },
264
+ annotations: READ_ONLY,
265
+ }, async ({ source, target, date }) => {
266
+ try {
267
+ return ok(await client.getReferenceRate({ source, target, date }));
268
+ }
269
+ catch (err) {
270
+ return fail(err);
271
+ }
272
+ });
273
+ server.registerTool('request_trial_key', {
274
+ title: 'Request a trial API key',
275
+ description: 'Self-issue an AllRatesToday API key with 100 lifetime calls, valid 7 days, with no account and no email. Use it when another tool answered "needs an API key" and the user wants real-time rates, history or dated tables right now. The key is adopted by this server for the rest of the session and returned once — tell the user to put it in the MCP config as ALLRATES_API_KEY to keep it. Capped at 3 keys per IP per day. For a lasting key, register at https://allratestoday.com/register (free, 300 calls) or see https://allratestoday.com/pricing.',
276
+ inputSchema: {
277
+ agent: z.string().max(80).optional().describe('Optional: the agent or product requesting the key.'),
278
+ purpose: z.string().max(200).optional().describe('Optional: one line on what the rates are for.'),
279
+ },
280
+ outputSchema: {
281
+ key: z.string().optional(),
282
+ calls: z.number().optional(),
283
+ expires_at: z.string().optional(),
284
+ adopted: z.boolean().describe('True when this server switched to the new key'),
285
+ note: z.string(),
286
+ },
287
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
288
+ }, async ({ agent, purpose }) => {
289
+ try {
290
+ return ok(await client.requestTrialKey({ agent, purpose }));
291
+ }
292
+ catch (err) {
293
+ return fail(err);
294
+ }
295
+ });
238
296
  const transport = new StdioServerTransport();
239
297
  await server.connect(transport);
240
298
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allratestoday/mcp-server",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "mcpName": "io.github.cahthuranag/mcp-server",
5
5
  "description": "MCP server for AllRatesToday — let AI coding tools (Claude Code, Cursor, Claude Desktop) fetch real-time and historical currency exchange rates.",
6
6
  "keywords": [