@cyanheads/exchange-rates-mcp-server 0.1.4 → 0.2.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/AGENTS.md +53 -33
- package/CLAUDE.md +53 -33
- package/Dockerfile +9 -6
- package/LICENSE +1 -1
- package/README.md +24 -15
- package/changelog/0.1.x/0.1.5.md +29 -0
- package/changelog/0.2.x/0.2.0.md +41 -0
- package/changelog/template.md +5 -3
- package/dist/index.js +18 -4
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/resources/definitions/fx-rates-latest.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/fx-rates-latest.resource.js +4 -3
- package/dist/mcp-server/resources/definitions/fx-rates-latest.resource.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-convert-currency.tool.d.ts +10 -0
- package/dist/mcp-server/tools/definitions/fx-convert-currency.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-convert-currency.tool.js +29 -5
- package/dist/mcp-server/tools/definitions/fx-convert-currency.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-dataframe-describe.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-dataframe-describe.tool.js +7 -4
- package/dist/mcp-server/tools/definitions/fx-dataframe-describe.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-dataframe-query.tool.d.ts +6 -1
- package/dist/mcp-server/tools/definitions/fx-dataframe-query.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-dataframe-query.tool.js +30 -10
- package/dist/mcp-server/tools/definitions/fx-dataframe-query.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-get-rate.tool.d.ts +10 -0
- package/dist/mcp-server/tools/definitions/fx-get-rate.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-get-rate.tool.js +29 -5
- package/dist/mcp-server/tools/definitions/fx-get-rate.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-get-rates.tool.d.ts +11 -1
- package/dist/mcp-server/tools/definitions/fx-get-rates.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-get-rates.tool.js +33 -7
- package/dist/mcp-server/tools/definitions/fx-get-rates.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-get-timeseries.tool.d.ts +13 -1
- package/dist/mcp-server/tools/definitions/fx-get-timeseries.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-get-timeseries.tool.js +93 -44
- package/dist/mcp-server/tools/definitions/fx-get-timeseries.tool.js.map +1 -1
- package/dist/services/canvas/canvas-accessor.d.ts.map +1 -1
- package/dist/services/frankfurter/errors.d.ts +42 -0
- package/dist/services/frankfurter/errors.d.ts.map +1 -0
- package/dist/services/frankfurter/errors.js +64 -0
- package/dist/services/frankfurter/errors.js.map +1 -0
- package/dist/services/frankfurter/frankfurter-service.d.ts +42 -8
- package/dist/services/frankfurter/frankfurter-service.d.ts.map +1 -1
- package/dist/services/frankfurter/frankfurter-service.js +146 -67
- package/dist/services/frankfurter/frankfurter-service.js.map +1 -1
- package/dist/services/frankfurter/types.d.ts +14 -0
- package/dist/services/frankfurter/types.d.ts.map +1 -1
- package/package.json +12 -11
- package/server.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fx-get-rate.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-get-rate.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EACL,cAAc,EACd,qBAAqB,
|
|
1
|
+
{"version":3,"file":"fx-get-rate.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-get-rate.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,14 +15,24 @@ export declare const fxGetRates: import("@cyanheads/mcp-ts-core").ToolDefinition
|
|
|
15
15
|
rate_type: z.ZodString;
|
|
16
16
|
source: z.ZodString;
|
|
17
17
|
}, z.core.$strip>, readonly [{
|
|
18
|
+
readonly reason: "invalid_date_format";
|
|
19
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
20
|
+
readonly when: "date is not a real calendar date written as YYYY-MM-DD.";
|
|
21
|
+
readonly recovery: "Pass an ISO 8601 calendar date in YYYY-MM-DD form, for example 2024-06-01.";
|
|
22
|
+
}, {
|
|
18
23
|
readonly reason: "unsupported_currency";
|
|
19
24
|
readonly code: JsonRpcErrorCode.ValidationError;
|
|
20
|
-
readonly when: "base_currency is not in the ECB currency set.";
|
|
25
|
+
readonly when: "base_currency or an entry in symbols is not in the ECB currency set.";
|
|
21
26
|
readonly recovery: "Call fx_list_currencies to get the list of valid currency codes.";
|
|
22
27
|
}, {
|
|
23
28
|
readonly reason: "date_out_of_range";
|
|
24
29
|
readonly code: JsonRpcErrorCode.ValidationError;
|
|
25
30
|
readonly when: "date is before 1999-01-04 or in the future.";
|
|
26
31
|
readonly recovery: "ECB data starts 1999-01-04; omit date for the latest available rate.";
|
|
32
|
+
}, {
|
|
33
|
+
readonly reason: "upstream_no_data";
|
|
34
|
+
readonly code: JsonRpcErrorCode.NotFound;
|
|
35
|
+
readonly when: "Every requested currency is supported but the ECB published no rates for this date.";
|
|
36
|
+
readonly recovery: "Try a more recent date — ECB history starts later for some currencies.";
|
|
27
37
|
}], undefined>;
|
|
28
38
|
//# sourceMappingURL=fx-get-rates.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fx-get-rates.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-get-rates.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"fx-get-rates.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-get-rates.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AASjE,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAmKrB,CAAC"}
|
|
@@ -4,12 +4,14 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
-
import {
|
|
7
|
+
import { failureOf } from '../../../services/frankfurter/errors.js';
|
|
8
|
+
import { ECB_START_DATE, getFrankfurterService, isIsoDate, } from '../../../services/frankfurter/frankfurter-service.js';
|
|
8
9
|
export const fxGetRates = tool('fx_get_rates', {
|
|
9
10
|
description: 'Get all available exchange rates for one base currency in a single snapshot. ' +
|
|
10
11
|
'Useful for bulk comparison and seeding downstream tools. ' +
|
|
11
12
|
'Returns a map of quote currency → rate plus the snapshot date. ' +
|
|
12
|
-
'Optionally filter to a subset of quote currencies via symbols.'
|
|
13
|
+
'Optionally filter to a subset of quote currencies via symbols. ' +
|
|
14
|
+
'Listing the base currency itself in symbols is accepted and returns a rate of 1 for it.',
|
|
13
15
|
annotations: {
|
|
14
16
|
readOnlyHint: true,
|
|
15
17
|
idempotentHint: true,
|
|
@@ -28,7 +30,8 @@ export const fxGetRates = tool('fx_get_rates', {
|
|
|
28
30
|
.array(z.string().describe('ISO 4217 currency code to include in the response.'))
|
|
29
31
|
.optional()
|
|
30
32
|
.describe('Optional list of quote currency codes to filter the response. ' +
|
|
31
|
-
'Omit to return all ~30 supported currencies.'
|
|
33
|
+
'Omit to return all ~30 supported currencies (the base is not among them). ' +
|
|
34
|
+
'Including base_currency here is valid — it comes back with a rate of 1.'),
|
|
32
35
|
}),
|
|
33
36
|
output: z.object({
|
|
34
37
|
base_currency: z.string().describe('The base currency code.'),
|
|
@@ -45,10 +48,16 @@ export const fxGetRates = tool('fx_get_rates', {
|
|
|
45
48
|
source: z.string().describe('Always "ECB via Frankfurter" — the upstream data provider.'),
|
|
46
49
|
}),
|
|
47
50
|
errors: [
|
|
51
|
+
{
|
|
52
|
+
reason: 'invalid_date_format',
|
|
53
|
+
code: JsonRpcErrorCode.ValidationError,
|
|
54
|
+
when: 'date is not a real calendar date written as YYYY-MM-DD.',
|
|
55
|
+
recovery: 'Pass an ISO 8601 calendar date in YYYY-MM-DD form, for example 2024-06-01.',
|
|
56
|
+
},
|
|
48
57
|
{
|
|
49
58
|
reason: 'unsupported_currency',
|
|
50
59
|
code: JsonRpcErrorCode.ValidationError,
|
|
51
|
-
when: 'base_currency is not in the ECB currency set.',
|
|
60
|
+
when: 'base_currency or an entry in symbols is not in the ECB currency set.',
|
|
52
61
|
recovery: 'Call fx_list_currencies to get the list of valid currency codes.',
|
|
53
62
|
},
|
|
54
63
|
{
|
|
@@ -57,11 +66,21 @@ export const fxGetRates = tool('fx_get_rates', {
|
|
|
57
66
|
when: 'date is before 1999-01-04 or in the future.',
|
|
58
67
|
recovery: 'ECB data starts 1999-01-04; omit date for the latest available rate.',
|
|
59
68
|
},
|
|
69
|
+
{
|
|
70
|
+
reason: 'upstream_no_data',
|
|
71
|
+
code: JsonRpcErrorCode.NotFound,
|
|
72
|
+
when: 'Every requested currency is supported but the ECB published no rates for this date.',
|
|
73
|
+
recovery: 'Try a more recent date — ECB history starts later for some currencies.',
|
|
74
|
+
},
|
|
60
75
|
],
|
|
61
76
|
async handler(input, ctx) {
|
|
62
77
|
const service = getFrankfurterService();
|
|
63
78
|
const date = input.date ?? 'latest';
|
|
64
79
|
if (date !== 'latest') {
|
|
80
|
+
/** Format first — the range comparisons below are lexicographic and would misread a malformed date. */
|
|
81
|
+
if (!isIsoDate(date)) {
|
|
82
|
+
throw ctx.fail('invalid_date_format', `date "${date}" is not a valid YYYY-MM-DD calendar date.`, { ...ctx.recoveryFor('invalid_date_format'), field: 'date' });
|
|
83
|
+
}
|
|
65
84
|
if (date < ECB_START_DATE) {
|
|
66
85
|
throw ctx.fail('date_out_of_range', `Date ${date} is before ECB data start ${ECB_START_DATE}.`, {
|
|
67
86
|
...ctx.recoveryFor('date_out_of_range'),
|
|
@@ -79,9 +98,16 @@ export const fxGetRates = tool('fx_get_rates', {
|
|
|
79
98
|
raw = await service.getRates(input.base_currency, date, input.symbols);
|
|
80
99
|
}
|
|
81
100
|
catch (err) {
|
|
82
|
-
const
|
|
83
|
-
if (
|
|
84
|
-
|
|
101
|
+
const failure = failureOf(err);
|
|
102
|
+
if (failure?.reason === 'unsupported_currency') {
|
|
103
|
+
/** The service names the offending field and codes — base_currency and symbols are both reachable here. */
|
|
104
|
+
throw ctx.fail('unsupported_currency', err.message, {
|
|
105
|
+
...ctx.recoveryFor('unsupported_currency'),
|
|
106
|
+
field: failure.field,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
if (failure?.reason === 'upstream_no_data') {
|
|
110
|
+
throw ctx.fail('upstream_no_data', `The ECB published no ${input.base_currency} rates for ${date === 'latest' ? 'the latest business day' : date}.`, { ...ctx.recoveryFor('upstream_no_data') });
|
|
85
111
|
}
|
|
86
112
|
throw err;
|
|
87
113
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fx-get-rates.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-get-rates.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EACL,cAAc,EACd,qBAAqB,
|
|
1
|
+
{"version":3,"file":"fx-get-rates.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-get-rates.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,6 +23,11 @@ export declare const fxGetTimeseries: import("@cyanheads/mcp-ts-core").ToolDefin
|
|
|
23
23
|
canvas_id: z.ZodOptional<z.ZodString>;
|
|
24
24
|
table_name: z.ZodOptional<z.ZodString>;
|
|
25
25
|
}, z.core.$strip>, readonly [{
|
|
26
|
+
readonly reason: "invalid_date_format";
|
|
27
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
28
|
+
readonly when: "start_date or end_date is not a real calendar date written as YYYY-MM-DD.";
|
|
29
|
+
readonly recovery: "Pass ISO 8601 calendar dates in YYYY-MM-DD form, for example 2024-06-01.";
|
|
30
|
+
}, {
|
|
26
31
|
readonly reason: "unsupported_currency";
|
|
27
32
|
readonly code: JsonRpcErrorCode.ValidationError;
|
|
28
33
|
readonly when: "base_currency or quote_currency is not in the ECB currency set.";
|
|
@@ -37,5 +42,12 @@ export declare const fxGetTimeseries: import("@cyanheads/mcp-ts-core").ToolDefin
|
|
|
37
42
|
readonly code: JsonRpcErrorCode.ValidationError;
|
|
38
43
|
readonly when: "start_date is after end_date.";
|
|
39
44
|
readonly recovery: "Ensure start_date is before or equal to end_date.";
|
|
40
|
-
}
|
|
45
|
+
}, {
|
|
46
|
+
readonly reason: "upstream_no_data";
|
|
47
|
+
readonly code: JsonRpcErrorCode.NotFound;
|
|
48
|
+
readonly when: "Both currencies are supported but the ECB published no rates across this range.";
|
|
49
|
+
readonly recovery: "Try a more recent range — ECB history starts later for some currencies.";
|
|
50
|
+
}], {
|
|
51
|
+
readonly notice: z.ZodOptional<z.ZodString>;
|
|
52
|
+
}>;
|
|
41
53
|
//# sourceMappingURL=fx-get-timeseries.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fx-get-timeseries.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-get-timeseries.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"fx-get-timeseries.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-get-timeseries.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAWjE,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmV1B,CAAC"}
|
|
@@ -7,13 +7,19 @@ import { spillover } from '@cyanheads/mcp-ts-core/canvas';
|
|
|
7
7
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
8
8
|
import { getServerConfig } from '../../../config/server-config.js';
|
|
9
9
|
import { getCanvas } from '../../../services/canvas/canvas-accessor.js';
|
|
10
|
-
import {
|
|
10
|
+
import { failureOf } from '../../../services/frankfurter/errors.js';
|
|
11
|
+
import { ECB_START_DATE, getFrankfurterService, isIsoDate, } from '../../../services/frankfurter/frankfurter-service.js';
|
|
11
12
|
export const fxGetTimeseries = tool('fx_get_timeseries', {
|
|
12
13
|
description: 'Get historical daily exchange rates for a currency pair over a date range. ' +
|
|
13
|
-
'ECB publishes on business days only — weekends and holidays produce no entry
|
|
14
|
+
'ECB publishes on business days only — weekends and holidays produce no entry, and no date ' +
|
|
15
|
+
'outside the requested range is ever returned, so a range covering only non-publication days ' +
|
|
16
|
+
'comes back with an empty rates map and a notice explaining why. ' +
|
|
17
|
+
'A same-currency pair returns a rate of 1 on each publication day in the range. ' +
|
|
14
18
|
'Short ranges (≤90 days by default) are returned inline as a date→rate map. ' +
|
|
15
|
-
'
|
|
16
|
-
'
|
|
19
|
+
'When DataCanvas is enabled (CANVAS_PROVIDER_TYPE=duckdb) long ranges spill to it: the response ' +
|
|
20
|
+
'carries spilled=true, a canvas_id, and a table_name — call fx_dataframe_describe to inspect the ' +
|
|
21
|
+
'staged table, then fx_dataframe_query to run SQL against it. ' +
|
|
22
|
+
'Without DataCanvas long ranges stay inline (spilled=false) and the notice says so.',
|
|
17
23
|
annotations: {
|
|
18
24
|
readOnlyHint: true,
|
|
19
25
|
idempotentHint: true,
|
|
@@ -44,15 +50,20 @@ export const fxGetTimeseries = tool('fx_get_timeseries', {
|
|
|
44
50
|
quote_currency: z.string().describe('Quote currency code.'),
|
|
45
51
|
start_date: z
|
|
46
52
|
.string()
|
|
47
|
-
.describe('
|
|
53
|
+
.describe('First date in the returned series. Always inside the requested range — later than the ' +
|
|
54
|
+
'requested start when that day had no ECB fix, and equal to it when the series is empty.'),
|
|
48
55
|
end_date: z
|
|
49
56
|
.string()
|
|
50
|
-
.describe('
|
|
57
|
+
.describe('Last date in the returned series. Always inside the requested range — earlier than the ' +
|
|
58
|
+
'requested end when that day had no ECB fix, and equal to it when the series is empty.'),
|
|
51
59
|
rates: z
|
|
52
60
|
.record(z.string(), z.number())
|
|
53
|
-
.describe('Date → rate map for the inline result.
|
|
54
|
-
'
|
|
55
|
-
|
|
61
|
+
.describe('Date → rate map for the inline result. Publication days inside the requested range only. ' +
|
|
62
|
+
'Truncated to a preview when the result was spilled to canvas; empty when the range ' +
|
|
63
|
+
'contains no publication day at all.'),
|
|
64
|
+
rate_count: z
|
|
65
|
+
.number()
|
|
66
|
+
.describe('Total number of data points (publication days) inside the requested range.'),
|
|
56
67
|
rate_type: z
|
|
57
68
|
.string()
|
|
58
69
|
.describe('Always "ECB reference (mid-market)" — these are reference rates, not tradeable bid/ask.'),
|
|
@@ -69,7 +80,20 @@ export const fxGetTimeseries = tool('fx_get_timeseries', {
|
|
|
69
80
|
.optional()
|
|
70
81
|
.describe('Canvas table name — present when spilled is true. Use in fx_dataframe_query SQL.'),
|
|
71
82
|
}),
|
|
83
|
+
enrichment: {
|
|
84
|
+
notice: z
|
|
85
|
+
.string()
|
|
86
|
+
.optional()
|
|
87
|
+
.describe('Explains a result that would otherwise look broken — an empty series, or a long range ' +
|
|
88
|
+
'that stayed inline because DataCanvas is not configured.'),
|
|
89
|
+
},
|
|
72
90
|
errors: [
|
|
91
|
+
{
|
|
92
|
+
reason: 'invalid_date_format',
|
|
93
|
+
code: JsonRpcErrorCode.ValidationError,
|
|
94
|
+
when: 'start_date or end_date is not a real calendar date written as YYYY-MM-DD.',
|
|
95
|
+
recovery: 'Pass ISO 8601 calendar dates in YYYY-MM-DD form, for example 2024-06-01.',
|
|
96
|
+
},
|
|
73
97
|
{
|
|
74
98
|
reason: 'unsupported_currency',
|
|
75
99
|
code: JsonRpcErrorCode.ValidationError,
|
|
@@ -88,12 +112,28 @@ export const fxGetTimeseries = tool('fx_get_timeseries', {
|
|
|
88
112
|
when: 'start_date is after end_date.',
|
|
89
113
|
recovery: 'Ensure start_date is before or equal to end_date.',
|
|
90
114
|
},
|
|
115
|
+
{
|
|
116
|
+
reason: 'upstream_no_data',
|
|
117
|
+
code: JsonRpcErrorCode.NotFound,
|
|
118
|
+
when: 'Both currencies are supported but the ECB published no rates across this range.',
|
|
119
|
+
recovery: 'Try a more recent range — ECB history starts later for some currencies.',
|
|
120
|
+
},
|
|
91
121
|
],
|
|
92
122
|
async handler(input, ctx) {
|
|
93
123
|
const service = getFrankfurterService();
|
|
94
124
|
const config = getServerConfig();
|
|
95
125
|
const today = new Date().toISOString().slice(0, 10);
|
|
96
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Format first. Every check below — the ECB epoch bound, the future bound, and
|
|
128
|
+
* the start/end ordering — is a lexicographic string comparison, so a malformed
|
|
129
|
+
* date silently reads as an out-of-range or reversed range instead of a bad date.
|
|
130
|
+
*/
|
|
131
|
+
for (const field of ['start_date', 'end_date']) {
|
|
132
|
+
const value = input[field];
|
|
133
|
+
if (!isIsoDate(value)) {
|
|
134
|
+
throw ctx.fail('invalid_date_format', `${field} "${value}" is not a valid YYYY-MM-DD calendar date.`, { ...ctx.recoveryFor('invalid_date_format'), field });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
97
137
|
if (input.start_date < ECB_START_DATE) {
|
|
98
138
|
throw ctx.fail('date_out_of_range', `start_date ${input.start_date} is before ECB data start ${ECB_START_DATE}.`, {
|
|
99
139
|
...ctx.recoveryFor('date_out_of_range'),
|
|
@@ -112,20 +152,24 @@ export const fxGetTimeseries = tool('fx_get_timeseries', {
|
|
|
112
152
|
// Compute calendar days to decide inline vs spillover
|
|
113
153
|
const msPerDay = 86_400_000;
|
|
114
154
|
const dayCount = (new Date(input.end_date).getTime() - new Date(input.start_date).getTime()) / msPerDay + 1;
|
|
115
|
-
let
|
|
116
|
-
let rows;
|
|
155
|
+
let series;
|
|
117
156
|
try {
|
|
118
|
-
|
|
157
|
+
series = await service.getTimeSeries(input.base_currency, input.quote_currency, input.start_date, input.end_date);
|
|
119
158
|
}
|
|
120
159
|
catch (err) {
|
|
121
|
-
const
|
|
122
|
-
if (
|
|
123
|
-
throw ctx.fail('unsupported_currency',
|
|
160
|
+
const failure = failureOf(err);
|
|
161
|
+
if (failure?.reason === 'unsupported_currency') {
|
|
162
|
+
throw ctx.fail('unsupported_currency', err.message, {
|
|
163
|
+
...ctx.recoveryFor('unsupported_currency'),
|
|
164
|
+
field: failure.field,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
if (failure?.reason === 'upstream_no_data') {
|
|
168
|
+
throw ctx.fail('upstream_no_data', `The ECB published no ${input.base_currency}/${input.quote_currency} rates between ${input.start_date} and ${input.end_date}.`, { ...ctx.recoveryFor('upstream_no_data') });
|
|
124
169
|
}
|
|
125
170
|
throw err;
|
|
126
171
|
}
|
|
127
|
-
const actualStart =
|
|
128
|
-
const actualEnd = raw.end_date;
|
|
172
|
+
const { rows, startDate: actualStart, endDate: actualEnd } = series;
|
|
129
173
|
ctx.log.info('Fetched timeseries', {
|
|
130
174
|
base: input.base_currency,
|
|
131
175
|
quote: input.quote_currency,
|
|
@@ -134,24 +178,39 @@ export const fxGetTimeseries = tool('fx_get_timeseries', {
|
|
|
134
178
|
points: rows.length,
|
|
135
179
|
dayCount,
|
|
136
180
|
});
|
|
137
|
-
// Inline path — short range
|
|
138
181
|
const canvas = getCanvas();
|
|
139
|
-
const
|
|
182
|
+
const exceedsThreshold = dayCount > config.timeseriesCanvasThresholdDays;
|
|
183
|
+
const shouldSpill = canvas != null && exceedsThreshold;
|
|
184
|
+
/**
|
|
185
|
+
* An empty series and a long range that never spilled both look like failures
|
|
186
|
+
* from the outside. Say which one happened and why, on both client surfaces.
|
|
187
|
+
*/
|
|
188
|
+
if (rows.length === 0) {
|
|
189
|
+
ctx.enrich.notice(`The ECB published no ${input.base_currency.toUpperCase()}/${input.quote_currency.toUpperCase()} rate between ` +
|
|
190
|
+
`${input.start_date} and ${input.end_date}. Reference rates are published on TARGET business days ` +
|
|
191
|
+
'only, so a range covering just a weekend or a bank holiday is legitimately empty rather than ' +
|
|
192
|
+
'broken. Widen the range — a window spanning several weekdays will contain a publication day.');
|
|
193
|
+
}
|
|
194
|
+
else if (exceedsThreshold && canvas == null) {
|
|
195
|
+
ctx.enrich.notice(`This ${dayCount}-day range is past the ${config.timeseriesCanvasThresholdDays}-day spill threshold, but ` +
|
|
196
|
+
'DataCanvas is not configured on this server, so the full series is inline and spilled is false. ' +
|
|
197
|
+
'Set CANVAS_PROVIDER_TYPE=duckdb to stage long ranges for SQL instead.');
|
|
198
|
+
}
|
|
199
|
+
/** Fields every branch below returns identically — only rates/count/spill differ. */
|
|
200
|
+
const envelope = {
|
|
201
|
+
base_currency: input.base_currency.toUpperCase(),
|
|
202
|
+
quote_currency: input.quote_currency.toUpperCase(),
|
|
203
|
+
start_date: actualStart,
|
|
204
|
+
end_date: actualEnd,
|
|
205
|
+
rate_type: 'ECB reference (mid-market)',
|
|
206
|
+
source: 'ECB via Frankfurter',
|
|
207
|
+
};
|
|
208
|
+
// Inline path — short range, or long range with no canvas to spill to
|
|
140
209
|
if (!shouldSpill) {
|
|
141
210
|
const rateMap = {};
|
|
142
211
|
for (const row of rows)
|
|
143
212
|
rateMap[row.date] = row.rate;
|
|
144
|
-
return {
|
|
145
|
-
base_currency: input.base_currency.toUpperCase(),
|
|
146
|
-
quote_currency: input.quote_currency.toUpperCase(),
|
|
147
|
-
start_date: actualStart,
|
|
148
|
-
end_date: actualEnd,
|
|
149
|
-
rates: rateMap,
|
|
150
|
-
rate_count: rows.length,
|
|
151
|
-
rate_type: 'ECB reference (mid-market)',
|
|
152
|
-
source: 'ECB via Frankfurter',
|
|
153
|
-
spilled: false,
|
|
154
|
-
};
|
|
213
|
+
return { ...envelope, rates: rateMap, rate_count: rows.length, spilled: false };
|
|
155
214
|
}
|
|
156
215
|
// Canvas spillover path
|
|
157
216
|
const instance = await canvas.acquire(input.canvas_id, ctx);
|
|
@@ -177,14 +236,9 @@ export const fxGetTimeseries = tool('fx_get_timeseries', {
|
|
|
177
236
|
}
|
|
178
237
|
if (spillResult.spilled) {
|
|
179
238
|
return {
|
|
180
|
-
|
|
181
|
-
quote_currency: input.quote_currency.toUpperCase(),
|
|
182
|
-
start_date: actualStart,
|
|
183
|
-
end_date: actualEnd,
|
|
239
|
+
...envelope,
|
|
184
240
|
rates: previewRates,
|
|
185
241
|
rate_count: spillResult.handle.rowCount,
|
|
186
|
-
rate_type: 'ECB reference (mid-market)',
|
|
187
|
-
source: 'ECB via Frankfurter',
|
|
188
242
|
spilled: true,
|
|
189
243
|
canvas_id: instance.canvasId,
|
|
190
244
|
table_name: spillResult.handle.tableName,
|
|
@@ -192,21 +246,16 @@ export const fxGetTimeseries = tool('fx_get_timeseries', {
|
|
|
192
246
|
}
|
|
193
247
|
// Fell under budget even at canvas threshold — return inline
|
|
194
248
|
return {
|
|
195
|
-
|
|
196
|
-
quote_currency: input.quote_currency.toUpperCase(),
|
|
197
|
-
start_date: actualStart,
|
|
198
|
-
end_date: actualEnd,
|
|
249
|
+
...envelope,
|
|
199
250
|
rates: previewRates,
|
|
200
251
|
rate_count: spillResult.previewRows.length,
|
|
201
|
-
rate_type: 'ECB reference (mid-market)',
|
|
202
|
-
source: 'ECB via Frankfurter',
|
|
203
252
|
spilled: false,
|
|
204
253
|
};
|
|
205
254
|
},
|
|
206
255
|
format: (result) => {
|
|
207
256
|
const lines = [
|
|
208
257
|
`**${result.base_currency}/${result.quote_currency} time series** — ${result.start_date} to ${result.end_date}`,
|
|
209
|
-
`*${result.rate_count}
|
|
258
|
+
`*${result.rate_count} publication-day data points · ${result.rate_type} · ${result.source} · spilled: ${result.spilled}*`,
|
|
210
259
|
];
|
|
211
260
|
if (result.spilled) {
|
|
212
261
|
lines.push(`\n📊 **Result staged on DataCanvas** (large range)`, `Canvas ID: \`${result.canvas_id}\``, `Table: \`${result.table_name}\``, `Use \`fx_dataframe_query\` with this canvas_id to run SQL. Preview (first entries below):`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fx-get-timeseries.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-get-timeseries.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAC;AACjE,OAAO,EACL,cAAc,EACd,qBAAqB,
|
|
1
|
+
{"version":3,"file":"fx-get-timeseries.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-get-timeseries.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canvas-accessor.d.ts","sourceRoot":"","sources":["../../../src/services/canvas/canvas-accessor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAIhE,sEAAsE;AACtE,eAAO,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"canvas-accessor.d.ts","sourceRoot":"","sources":["../../../src/services/canvas/canvas-accessor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAIhE,sEAAsE;AACtE,eAAO,MAAM,SAAS,MAAO,UAAU,GAAG,SAAS,KAAG,IAErD,CAAC;AAEF,sEAAsE;AACtE,eAAO,MAAM,SAAS,QAAO,UAAU,GAAG,SAAoB,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Structured failures for the Frankfurter service. Each constructor
|
|
3
|
+
* stamps a contract `reason` (and the offending input field) onto `McpError.data`
|
|
4
|
+
* so tool handlers classify failures by reading `failureOf()` instead of matching
|
|
5
|
+
* on message prose.
|
|
6
|
+
* @module services/frankfurter/errors
|
|
7
|
+
*/
|
|
8
|
+
import { McpError } from '@cyanheads/mcp-ts-core/errors';
|
|
9
|
+
/**
|
|
10
|
+
* Contract reasons the Frankfurter service attaches to the errors it throws.
|
|
11
|
+
* Every calling tool declares the subset it can surface in its `errors[]`.
|
|
12
|
+
*/
|
|
13
|
+
declare const FAILURE_REASONS: readonly ['invalid_date_format', 'unsupported_currency', 'upstream_no_data'];
|
|
14
|
+
export type FrankfurterFailureReason = (typeof FAILURE_REASONS)[number];
|
|
15
|
+
/** Structured failure payload carried on `McpError.data`. */
|
|
16
|
+
export interface FrankfurterFailure {
|
|
17
|
+
/** The input at fault, named as the calling tool exposes it (e.g. `start_date`, `symbols`). */
|
|
18
|
+
field?: string;
|
|
19
|
+
/** Contract reason — mirrors the `errors[]` entry the calling tool declares. */
|
|
20
|
+
reason: FrankfurterFailureReason;
|
|
21
|
+
}
|
|
22
|
+
/** A date input that is not a real YYYY-MM-DD calendar date. */
|
|
23
|
+
export declare function invalidDateFormat(field: string, value: string): McpError;
|
|
24
|
+
/**
|
|
25
|
+
* One or more currency codes outside the ECB reference set. Codes are checked
|
|
26
|
+
* against the live currency list before the request, because Frankfurter's 404
|
|
27
|
+
* body carries no field attribution.
|
|
28
|
+
*/
|
|
29
|
+
export declare function unsupportedCurrency(field: string, codes: string[]): McpError;
|
|
30
|
+
/**
|
|
31
|
+
* The ECB published no rates for an otherwise well-formed request — most often a
|
|
32
|
+
* date that predates the requested currency's series (ILS and BRL start well after
|
|
33
|
+
* the 1999-01-04 ECB epoch).
|
|
34
|
+
*/
|
|
35
|
+
export declare function upstreamNoData(url: string): McpError;
|
|
36
|
+
/**
|
|
37
|
+
* Read the structured failure off a service-thrown error.
|
|
38
|
+
* Returns `undefined` for anything the service did not classify.
|
|
39
|
+
*/
|
|
40
|
+
export declare function failureOf(error: unknown): FrankfurterFailure | undefined;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/services/frankfurter/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAA6B,MAAM,+BAA+B,CAAC;AAEpF;;;GAGG;AACH,QAAA,MAAM,eAAe,YACnB,qBAAqB,EACrB,sBAAsB,EACtB,kBAAkB,CACV,CAAC;AAEX,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE,6DAA6D;AAC7D,MAAM,WAAW,kBAAkB;IACjC,+FAA+F;IAC/F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,MAAM,EAAE,wBAAwB,CAAC;CAClC;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,CAMxE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,QAAQ,CAM5E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAKpD;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,GAAG,SAAS,CASxE"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Structured failures for the Frankfurter service. Each constructor
|
|
3
|
+
* stamps a contract `reason` (and the offending input field) onto `McpError.data`
|
|
4
|
+
* so tool handlers classify failures by reading `failureOf()` instead of matching
|
|
5
|
+
* on message prose.
|
|
6
|
+
* @module services/frankfurter/errors
|
|
7
|
+
*/
|
|
8
|
+
import { McpError, notFound, validationError } from '@cyanheads/mcp-ts-core/errors';
|
|
9
|
+
/**
|
|
10
|
+
* Contract reasons the Frankfurter service attaches to the errors it throws.
|
|
11
|
+
* Every calling tool declares the subset it can surface in its `errors[]`.
|
|
12
|
+
*/
|
|
13
|
+
const FAILURE_REASONS = [
|
|
14
|
+
'invalid_date_format',
|
|
15
|
+
'unsupported_currency',
|
|
16
|
+
'upstream_no_data',
|
|
17
|
+
];
|
|
18
|
+
/** A date input that is not a real YYYY-MM-DD calendar date. */
|
|
19
|
+
export function invalidDateFormat(field, value) {
|
|
20
|
+
return validationError(`${field} "${value}" is not a valid YYYY-MM-DD calendar date.`, {
|
|
21
|
+
field,
|
|
22
|
+
reason: 'invalid_date_format',
|
|
23
|
+
value,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* One or more currency codes outside the ECB reference set. Codes are checked
|
|
28
|
+
* against the live currency list before the request, because Frankfurter's 404
|
|
29
|
+
* body carries no field attribution.
|
|
30
|
+
*/
|
|
31
|
+
export function unsupportedCurrency(field, codes) {
|
|
32
|
+
const message = codes.length === 1
|
|
33
|
+
? `${field} "${codes[0]}" is not supported by the ECB.`
|
|
34
|
+
: `${field} contains codes not supported by the ECB: ${codes.join(', ')}.`;
|
|
35
|
+
return validationError(message, { codes, field, reason: 'unsupported_currency' });
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The ECB published no rates for an otherwise well-formed request — most often a
|
|
39
|
+
* date that predates the requested currency's series (ILS and BRL start well after
|
|
40
|
+
* the 1999-01-04 ECB epoch).
|
|
41
|
+
*/
|
|
42
|
+
export function upstreamNoData(url) {
|
|
43
|
+
return notFound('The ECB published no rates for this request.', {
|
|
44
|
+
reason: 'upstream_no_data',
|
|
45
|
+
url,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Read the structured failure off a service-thrown error.
|
|
50
|
+
* Returns `undefined` for anything the service did not classify.
|
|
51
|
+
*/
|
|
52
|
+
export function failureOf(error) {
|
|
53
|
+
if (!(error instanceof McpError))
|
|
54
|
+
return;
|
|
55
|
+
const data = error.data;
|
|
56
|
+
const reason = FAILURE_REASONS.find((known) => known === data?.reason);
|
|
57
|
+
if (reason === undefined)
|
|
58
|
+
return;
|
|
59
|
+
return {
|
|
60
|
+
...(typeof data?.field === 'string' ? { field: data.field } : {}),
|
|
61
|
+
reason,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/services/frankfurter/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEpF;;;GAGG;AACH,MAAM,eAAe,GAAG;IACtB,qBAAqB;IACrB,sBAAsB;IACtB,kBAAkB;CACV,CAAC;AAYX,gEAAgE;AAChE,MAAM,UAAU,iBAAiB,CAAC,KAAa,EAAE,KAAa;IAC5D,OAAO,eAAe,CAAC,GAAG,KAAK,KAAK,KAAK,4CAA4C,EAAE;QACrF,KAAK;QACL,MAAM,EAAE,qBAAqB;QAC7B,KAAK;KACN,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAa,EAAE,KAAe;IAChE,MAAM,OAAO,GACX,KAAK,CAAC,MAAM,KAAK,CAAC;QAChB,CAAC,CAAC,GAAG,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,gCAAgC;QACvD,CAAC,CAAC,GAAG,KAAK,6CAA6C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;IAC/E,OAAO,eAAe,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC,CAAC;AACpF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,OAAO,QAAQ,CAAC,8CAA8C,EAAE;QAC9D,MAAM,EAAE,kBAAkB;QAC1B,GAAG;KACJ,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,IAAI,CAAC,CAAC,KAAK,YAAY,QAAQ,CAAC;QAAE,OAAO;IACzC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAyD,CAAC;IAC7E,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,IAAI,EAAE,MAAM,CAAC,CAAC;IACvE,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO;IACjC,OAAO;QACL,GAAG,CAAC,OAAO,IAAI,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,MAAM;KACP,CAAC;AACJ,CAAC"}
|