@cyanheads/eurostat-mcp-server 0.1.1

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.
Files changed (57) hide show
  1. package/CLAUDE.md +391 -0
  2. package/Dockerfile +98 -0
  3. package/LICENSE +201 -0
  4. package/README.md +303 -0
  5. package/changelog/0.1.x/0.1.0.md +20 -0
  6. package/changelog/0.1.x/0.1.1.md +21 -0
  7. package/changelog/template.md +119 -0
  8. package/dist/config/server-config.d.ts +12 -0
  9. package/dist/config/server-config.d.ts.map +1 -0
  10. package/dist/config/server-config.js +28 -0
  11. package/dist/config/server-config.js.map +1 -0
  12. package/dist/index.d.ts +7 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +36 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/mcp-server/resources/definitions/eurostat-dataset.resource.d.ts +28 -0
  17. package/dist/mcp-server/resources/definitions/eurostat-dataset.resource.d.ts.map +1 -0
  18. package/dist/mcp-server/resources/definitions/eurostat-dataset.resource.js +49 -0
  19. package/dist/mcp-server/resources/definitions/eurostat-dataset.resource.js.map +1 -0
  20. package/dist/mcp-server/tools/definitions/eurostat-browse-themes.tool.d.ts +30 -0
  21. package/dist/mcp-server/tools/definitions/eurostat-browse-themes.tool.d.ts.map +1 -0
  22. package/dist/mcp-server/tools/definitions/eurostat-browse-themes.tool.js +85 -0
  23. package/dist/mcp-server/tools/definitions/eurostat-browse-themes.tool.js.map +1 -0
  24. package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.d.ts +40 -0
  25. package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.d.ts.map +1 -0
  26. package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.js +106 -0
  27. package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.js.map +1 -0
  28. package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.d.ts +31 -0
  29. package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.d.ts.map +1 -0
  30. package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.js +68 -0
  31. package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.js.map +1 -0
  32. package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.d.ts +70 -0
  33. package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.d.ts.map +1 -0
  34. package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.js +152 -0
  35. package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.js.map +1 -0
  36. package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.d.ts +31 -0
  37. package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.d.ts.map +1 -0
  38. package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.js +107 -0
  39. package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.js.map +1 -0
  40. package/dist/services/eurostat-catalogue/eurostat-catalogue-service.d.ts +53 -0
  41. package/dist/services/eurostat-catalogue/eurostat-catalogue-service.d.ts.map +1 -0
  42. package/dist/services/eurostat-catalogue/eurostat-catalogue-service.js +254 -0
  43. package/dist/services/eurostat-catalogue/eurostat-catalogue-service.js.map +1 -0
  44. package/dist/services/eurostat-catalogue/types.d.ts +48 -0
  45. package/dist/services/eurostat-catalogue/types.d.ts.map +1 -0
  46. package/dist/services/eurostat-catalogue/types.js +6 -0
  47. package/dist/services/eurostat-catalogue/types.js.map +1 -0
  48. package/dist/services/eurostat-data/eurostat-data-service.d.ts +36 -0
  49. package/dist/services/eurostat-data/eurostat-data-service.d.ts.map +1 -0
  50. package/dist/services/eurostat-data/eurostat-data-service.js +278 -0
  51. package/dist/services/eurostat-data/eurostat-data-service.js.map +1 -0
  52. package/dist/services/eurostat-data/types.d.ts +109 -0
  53. package/dist/services/eurostat-data/types.d.ts.map +1 -0
  54. package/dist/services/eurostat-data/types.js +13 -0
  55. package/dist/services/eurostat-data/types.js.map +1 -0
  56. package/package.json +81 -0
  57. package/server.json +127 -0
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @fileoverview Tool for querying statistical data from a Eurostat dataset.
3
+ * @module mcp-server/tools/definitions/eurostat-query-dataset.tool
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ export declare const eurostatQueryDataset: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
8
+ dataset_code: z.ZodString;
9
+ filters: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
10
+ geo_level: z.ZodOptional<z.ZodEnum<{
11
+ aggregate: "aggregate";
12
+ country: "country";
13
+ nuts1: "nuts1";
14
+ nuts2: "nuts2";
15
+ nuts3: "nuts3";
16
+ }>>;
17
+ since_period: z.ZodOptional<z.ZodString>;
18
+ until_period: z.ZodOptional<z.ZodString>;
19
+ last_n_periods: z.ZodOptional<z.ZodNumber>;
20
+ lang: z.ZodDefault<z.ZodEnum<{
21
+ EN: "EN";
22
+ FR: "FR";
23
+ DE: "DE";
24
+ }>>;
25
+ }, z.core.$strip>, z.ZodObject<{
26
+ datasetCode: z.ZodString;
27
+ datasetLabel: z.ZodString;
28
+ dimensionsUsed: z.ZodArray<z.ZodString>;
29
+ observations: z.ZodArray<z.ZodObject<{
30
+ dimensions: z.ZodObject<{}, z.core.$loose>;
31
+ value: z.ZodNullable<z.ZodNumber>;
32
+ status: z.ZodOptional<z.ZodObject<{
33
+ code: z.ZodString;
34
+ label: z.ZodString;
35
+ }, z.core.$strip>>;
36
+ }, z.core.$strip>>;
37
+ obsCount: z.ZodNumber;
38
+ timeRange: z.ZodObject<{
39
+ start: z.ZodString;
40
+ end: z.ZodString;
41
+ }, z.core.$strip>;
42
+ missingObsCount: z.ZodNumber;
43
+ }, z.core.$strip>, readonly [{
44
+ readonly reason: "not_found";
45
+ readonly code: JsonRpcErrorCode.NotFound;
46
+ readonly when: "The dataset code does not exist (HTTP 404, Eurostat error id 100).";
47
+ readonly recovery: "Use eurostat_search_datasets or eurostat_browse_themes to find a valid dataset code.";
48
+ }, {
49
+ readonly reason: "no_results";
50
+ readonly code: JsonRpcErrorCode.NotFound;
51
+ readonly when: "The query returned no observations — valid dataset but the filter combination matched no data.";
52
+ readonly recovery: "Verify dimension values with eurostat_get_dimension_values; invalid dimension values silently return no data.";
53
+ }, {
54
+ readonly reason: "async_response";
55
+ readonly code: JsonRpcErrorCode.ServiceUnavailable;
56
+ readonly when: "Eurostat returned an async warning — the query matched too many observations.";
57
+ readonly retryable: false;
58
+ readonly recovery: "Add dimension filters (geo, unit, na_item) to reduce the result size, then retry.";
59
+ }, {
60
+ readonly reason: "invalid_dimension";
61
+ readonly code: JsonRpcErrorCode.InvalidParams;
62
+ readonly when: "A dimension code in filters does not exist in this dataset (HTTP 400, Eurostat error id 150).";
63
+ readonly recovery: "Use eurostat_get_dataset_info to see valid dimension codes for this dataset.";
64
+ }, {
65
+ readonly reason: "conflicting_params";
66
+ readonly code: JsonRpcErrorCode.InvalidParams;
67
+ readonly when: "Both \"geo\" filter and geo_level were provided simultaneously.";
68
+ readonly recovery: "Use either a \"geo\" key in filters or the geo_level parameter — not both.";
69
+ }]>;
70
+ //# sourceMappingURL=eurostat-query-dataset.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eurostat-query-dataset.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurostat-query-dataset.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAIjE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4L/B,CAAC"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * @fileoverview Tool for querying statistical data from a Eurostat dataset.
3
+ * @module mcp-server/tools/definitions/eurostat-query-dataset.tool
4
+ */
5
+ import { tool, z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ import { getEurostatDataService } from '../../../services/eurostat-data/eurostat-data-service.js';
8
+ import { GEO_LEVEL_VALUES } from '../../../services/eurostat-data/types.js';
9
+ export const eurostatQueryDataset = tool('eurostat_query_dataset', {
10
+ title: 'Query Eurostat Dataset',
11
+ description: 'Fetch statistical data from a Eurostat dataset with dimension filters. Returns decoded observations with dimension codes and labels, numeric values, and status flags (e.g., "p" = provisional, "e" = estimated). Call eurostat_get_dataset_info first to discover valid dimension codes and values. Apply filters to keep the result set manageable — large unfiltered queries may trigger an async response error. Use filters.geo for specific country/region codes, or geo_level for NUTS hierarchy filtering (mutually exclusive). Use last_n_periods for the N most recent periods without knowing the end date.',
12
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
13
+ input: z.object({
14
+ dataset_code: z.string().min(1).describe('Dataset code (e.g., "nama_10_gdp"). Required.'),
15
+ filters: z
16
+ .record(z.string(), z.array(z.string()))
17
+ .default({})
18
+ .describe('Dimension filters as a map of dimension code → array of valid values. Example: {"unit": ["CP_MEUR"], "na_item": ["B1GQ"], "geo": ["DE", "FR"]}. Do not include "geo" here if using geo_level. Invalid dimension values silently return no data — verify with eurostat_get_dimension_values first.'),
19
+ geo_level: z
20
+ .enum(GEO_LEVEL_VALUES)
21
+ .optional()
22
+ .describe('Filter by NUTS hierarchy level. Mutually exclusive with a "geo" key in filters. Options: "aggregate" (EU/EA totals), "country" (41 member/candidate states), "nuts1" (127 major regions), "nuts2" (309 basic regions), "nuts3" (1,343 small regions).'),
23
+ since_period: z
24
+ .string()
25
+ .optional()
26
+ .describe('Start of time range (e.g., "2020", "2023-Q1", "2024-01"). Mutually exclusive with last_n_periods.'),
27
+ until_period: z
28
+ .string()
29
+ .optional()
30
+ .describe('End of time range (e.g., "2024"). Omit for data through the latest available period. Mutually exclusive with last_n_periods.'),
31
+ last_n_periods: z
32
+ .number()
33
+ .int()
34
+ .min(1)
35
+ .optional()
36
+ .describe('Return only the N most recent periods. Mutually exclusive with since_period and until_period.'),
37
+ lang: z
38
+ .enum(['EN', 'FR', 'DE'])
39
+ .default('EN')
40
+ .describe('Language for labels in the response. Default is "EN". Options: "EN", "FR", "DE".'),
41
+ }),
42
+ output: z.object({
43
+ datasetCode: z.string().describe('Dataset code as provided.'),
44
+ datasetLabel: z.string().describe('Human-readable dataset title.'),
45
+ dimensionsUsed: z
46
+ .array(z.string())
47
+ .describe('Ordered list of dimension codes present in the response (e.g., ["freq", "unit", "na_item", "geo", "time"]).'),
48
+ observations: z
49
+ .array(z
50
+ .object({
51
+ // dimensions is a dynamic map (keys = dimension codes from dimensionsUsed).
52
+ // Using passthrough so the full {code, label} pairs flow to structuredContent
53
+ // even though the keys are not known at schema definition time.
54
+ dimensions: z
55
+ .object({})
56
+ .passthrough()
57
+ .describe('Map of dimension code → {code, label}. One entry per dimension in dimensionsUsed, keyed by dimension code (e.g., {"geo": {"code": "DE", "label": "Germany"}, "time": {"code": "2023", "label": "2023"}}).'),
58
+ value: z
59
+ .number()
60
+ .nullable()
61
+ .describe('Numeric observation value, or null when missing (flagged as unavailable in the source data).'),
62
+ status: z
63
+ .object({
64
+ code: z.string().describe('Status flag code (e.g., "p", "e", "d").'),
65
+ label: z
66
+ .string()
67
+ .describe('Status description (e.g., "provisional", "estimated", "definition differs").'),
68
+ })
69
+ .optional()
70
+ .describe('Status flag for this observation. Omitted for normal observations.'),
71
+ })
72
+ .describe('A single decoded observation with dimension values, numeric value, and optional status.'))
73
+ .describe('Decoded observations. Each entry has one dimension entry per dimension in dimensionsUsed, plus value and optional status.'),
74
+ obsCount: z.number().describe('Number of observations returned.'),
75
+ timeRange: z
76
+ .object({
77
+ start: z.string().describe('Earliest period in this result.'),
78
+ end: z.string().describe('Most recent period in this result.'),
79
+ })
80
+ .describe('Time coverage of the returned observations.'),
81
+ missingObsCount: z
82
+ .number()
83
+ .describe('Number of observations with null value (missing data points in the source).'),
84
+ }),
85
+ errors: [
86
+ {
87
+ reason: 'not_found',
88
+ code: JsonRpcErrorCode.NotFound,
89
+ when: 'The dataset code does not exist (HTTP 404, Eurostat error id 100).',
90
+ recovery: 'Use eurostat_search_datasets or eurostat_browse_themes to find a valid dataset code.',
91
+ },
92
+ {
93
+ reason: 'no_results',
94
+ code: JsonRpcErrorCode.NotFound,
95
+ when: 'The query returned no observations — valid dataset but the filter combination matched no data.',
96
+ recovery: 'Verify dimension values with eurostat_get_dimension_values; invalid dimension values silently return no data.',
97
+ },
98
+ {
99
+ reason: 'async_response',
100
+ code: JsonRpcErrorCode.ServiceUnavailable,
101
+ when: 'Eurostat returned an async warning — the query matched too many observations.',
102
+ retryable: false,
103
+ recovery: 'Add dimension filters (geo, unit, na_item) to reduce the result size, then retry.',
104
+ },
105
+ {
106
+ reason: 'invalid_dimension',
107
+ code: JsonRpcErrorCode.InvalidParams,
108
+ when: 'A dimension code in filters does not exist in this dataset (HTTP 400, Eurostat error id 150).',
109
+ recovery: 'Use eurostat_get_dataset_info to see valid dimension codes for this dataset.',
110
+ },
111
+ {
112
+ reason: 'conflicting_params',
113
+ code: JsonRpcErrorCode.InvalidParams,
114
+ when: 'Both "geo" filter and geo_level were provided simultaneously.',
115
+ recovery: 'Use either a "geo" key in filters or the geo_level parameter — not both.',
116
+ },
117
+ ],
118
+ async handler(input, ctx) {
119
+ const svc = getEurostatDataService();
120
+ const sinceP = input.since_period?.trim() || undefined;
121
+ const untilP = input.until_period?.trim() || undefined;
122
+ const result = await svc.queryDataset(input.dataset_code, input.filters, input.geo_level, sinceP, untilP, input.last_n_periods, input.lang, ctx);
123
+ ctx.log.info('Dataset query complete', {
124
+ datasetCode: input.dataset_code,
125
+ obsCount: result.obsCount,
126
+ missingObsCount: result.missingObsCount,
127
+ });
128
+ return result;
129
+ },
130
+ format: (result) => {
131
+ const lines = [
132
+ `# ${result.datasetLabel} (\`${result.datasetCode}\`)`,
133
+ `**Observations:** ${result.obsCount} (${result.missingObsCount} missing) | **Period:** ${result.timeRange.start} – ${result.timeRange.end}`,
134
+ `**Dimensions:** ${result.dimensionsUsed.join(', ')}\n`,
135
+ ];
136
+ const maxRows = 200;
137
+ const shown = result.observations.slice(0, maxRows);
138
+ for (const obs of shown) {
139
+ // dimensions is typed as {} from passthrough() — cast to the runtime shape for rendering
140
+ const dims = obs.dimensions;
141
+ const dimParts = result.dimensionsUsed.map((dim) => `${dim}=${dims[dim]?.code ?? '?'} (${dims[dim]?.label ?? '?'})`);
142
+ const val = obs.value != null ? String(obs.value) : 'N/A';
143
+ const statusPart = obs.status ? ` [${obs.status.code}: ${obs.status.label}]` : '';
144
+ lines.push(`${dimParts.join(' | ')} → ${val}${statusPart}`);
145
+ }
146
+ if (result.observations.length > maxRows) {
147
+ lines.push(`\n_(${result.observations.length - maxRows} more observations not shown)_`);
148
+ }
149
+ return [{ type: 'text', text: lines.join('\n') }];
150
+ },
151
+ });
152
+ //# sourceMappingURL=eurostat-query-dataset.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eurostat-query-dataset.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurostat-query-dataset.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @fileoverview Tool for searching the Eurostat dataset catalogue by keyword.
3
+ * @module mcp-server/tools/definitions/eurostat-search-datasets.tool
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ export declare const eurostatSearchDatasets: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
8
+ query: z.ZodString;
9
+ limit: z.ZodDefault<z.ZodNumber>;
10
+ }, z.core.$strip>, z.ZodObject<{
11
+ datasets: z.ZodArray<z.ZodObject<{
12
+ code: z.ZodString;
13
+ label: z.ZodString;
14
+ type: z.ZodEnum<{
15
+ dataset: "dataset";
16
+ table: "table";
17
+ }>;
18
+ dataStart: z.ZodOptional<z.ZodString>;
19
+ dataEnd: z.ZodOptional<z.ZodString>;
20
+ lastUpdated: z.ZodOptional<z.ZodString>;
21
+ obsCount: z.ZodOptional<z.ZodNumber>;
22
+ themePath: z.ZodArray<z.ZodString>;
23
+ }, z.core.$strip>>;
24
+ totalMatches: z.ZodNumber;
25
+ }, z.core.$strip>, readonly [{
26
+ readonly reason: "no_match";
27
+ readonly code: JsonRpcErrorCode.NotFound;
28
+ readonly when: "No datasets matched the query string.";
29
+ readonly recovery: "Try a broader or different search term. Use eurostat_browse_themes to explore themes without text search.";
30
+ }]>;
31
+ //# sourceMappingURL=eurostat-search-datasets.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eurostat-search-datasets.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurostat-search-datasets.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;GAqHjC,CAAC"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * @fileoverview Tool for searching the Eurostat dataset catalogue by keyword.
3
+ * @module mcp-server/tools/definitions/eurostat-search-datasets.tool
4
+ */
5
+ import { tool, z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ import { getEurostatCatalogueService } from '../../../services/eurostat-catalogue/eurostat-catalogue-service.js';
8
+ export const eurostatSearchDatasets = tool('eurostat_search_datasets', {
9
+ title: 'Search Eurostat Datasets',
10
+ description: 'Search the Eurostat catalogue (8,933 datasets) by keyword. Returns matching datasets with codes, descriptions, period coverage, and theme breadcrumbs. Use this to discover dataset codes before calling eurostat_get_dataset_info or eurostat_query_dataset. Results are ranked by label match and limited to datasets and predefined tables — folders are excluded. The catalogue is loaded once per session from the Eurostat TOC file.',
11
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
12
+ input: z.object({
13
+ query: z
14
+ .string()
15
+ .min(1)
16
+ .describe('Search terms — case-insensitive substring match against dataset labels.'),
17
+ limit: z
18
+ .number()
19
+ .int()
20
+ .min(1)
21
+ .max(100)
22
+ .default(20)
23
+ .describe('Maximum number of results to return (1–100). Default is 20.'),
24
+ }),
25
+ output: z.object({
26
+ datasets: z
27
+ .array(z
28
+ .object({
29
+ code: z
30
+ .string()
31
+ .describe('Dataset code (e.g., "nama_10_gdp"). Use this in eurostat_get_dataset_info and eurostat_query_dataset.'),
32
+ label: z.string().describe('Human-readable dataset title.'),
33
+ type: z
34
+ .enum(['dataset', 'table'])
35
+ .describe('Entry type: "dataset" for standard datasets, "table" for predefined tables.'),
36
+ dataStart: z
37
+ .string()
38
+ .optional()
39
+ .describe('Earliest data period available (e.g., "1975"). Omitted when not reported by Eurostat.'),
40
+ dataEnd: z
41
+ .string()
42
+ .optional()
43
+ .describe('Most recent data period available (e.g., "2025"). Omitted when not reported by Eurostat.'),
44
+ lastUpdated: z
45
+ .string()
46
+ .optional()
47
+ .describe('Date of last data update (e.g., "22.05.2026"). Omitted when not reported.'),
48
+ obsCount: z
49
+ .number()
50
+ .optional()
51
+ .describe('Approximate number of observations. Omitted when not reported by Eurostat.'),
52
+ themePath: z
53
+ .array(z.string())
54
+ .describe('Breadcrumb path from root theme to this dataset (e.g., ["Economy and finance", "National accounts"]). Empty for top-level entries.'),
55
+ })
56
+ .describe('A matched dataset entry.'))
57
+ .describe('Matching datasets, up to the requested limit.'),
58
+ totalMatches: z
59
+ .number()
60
+ .describe('Total number of datasets matching the query before the limit is applied.'),
61
+ }),
62
+ errors: [
63
+ {
64
+ reason: 'no_match',
65
+ code: JsonRpcErrorCode.NotFound,
66
+ when: 'No datasets matched the query string.',
67
+ recovery: 'Try a broader or different search term. Use eurostat_browse_themes to explore themes without text search.',
68
+ },
69
+ ],
70
+ async handler(input, ctx) {
71
+ const svc = getEurostatCatalogueService();
72
+ const { datasets, totalMatches } = await svc.search(input.query, input.limit, ctx);
73
+ if (datasets.length === 0) {
74
+ throw ctx.fail('no_match', `No datasets matched "${input.query}".`, {
75
+ recovery: {
76
+ hint: `Try a broader term or use eurostat_browse_themes to explore themes without text search.`,
77
+ },
78
+ });
79
+ }
80
+ ctx.log.info('Dataset search complete', {
81
+ query: input.query,
82
+ totalMatches,
83
+ returned: datasets.length,
84
+ });
85
+ return { datasets, totalMatches };
86
+ },
87
+ format: (result) => {
88
+ const lines = [
89
+ `**${result.totalMatches} total match${result.totalMatches !== 1 ? 'es' : ''}** (showing ${result.datasets.length})\n`,
90
+ ];
91
+ for (const d of result.datasets) {
92
+ lines.push(`## ${d.label}`);
93
+ lines.push(`**Code:** ${d.code} | **Type:** ${d.type}`);
94
+ if (d.dataStart || d.dataEnd) {
95
+ lines.push(`**Period:** ${d.dataStart ?? '?'} – ${d.dataEnd ?? '?'}`);
96
+ }
97
+ if (d.obsCount != null)
98
+ lines.push(`**Observations:** ${d.obsCount.toLocaleString()}`);
99
+ if (d.lastUpdated)
100
+ lines.push(`**Last updated:** ${d.lastUpdated}`);
101
+ if (d.themePath.length > 0)
102
+ lines.push(`**Theme:** ${d.themePath.join(' › ')}`);
103
+ }
104
+ return [{ type: 'text', text: lines.join('\n') }];
105
+ },
106
+ });
107
+ //# sourceMappingURL=eurostat-search-datasets.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eurostat-search-datasets.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurostat-search-datasets.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @fileoverview Eurostat Catalogue Service — fetches and caches the TOC TXT file,
3
+ * provides dataset search and theme tree navigation.
4
+ * @module services/eurostat-catalogue/eurostat-catalogue-service
5
+ */
6
+ import type { Context } from '@cyanheads/mcp-ts-core';
7
+ import type { AppConfig } from '@cyanheads/mcp-ts-core/config';
8
+ import type { StorageService } from '@cyanheads/mcp-ts-core/storage';
9
+ import type { BrowseItem, DatasetResult } from './types.js';
10
+ export declare class EurostatCatalogueService {
11
+ private cache;
12
+ constructor(_config: AppConfig, _storage: StorageService);
13
+ /** Ensure the TOC is loaded, fetching if not yet cached. */
14
+ private ensureLoaded;
15
+ private fetchAndParseToc;
16
+ /**
17
+ * Parse the TSV TOC format.
18
+ * Header: title, code, type, last update of data, last table structure change,
19
+ * data start, data end, values (datasets only — 7 vs 8 cols).
20
+ * Title column uses 4 spaces per depth level as indentation.
21
+ */
22
+ private parseToc;
23
+ private unquote;
24
+ private measureDepth;
25
+ private parseType;
26
+ /**
27
+ * Build a breadcrumb path from root to a given entry (exclusive of the entry itself).
28
+ */
29
+ private buildPath;
30
+ /**
31
+ * Find the "root" of the TOC — the 11 second-level theme folders.
32
+ * The TOC has a single depth-0 root ("Database by themes"); we skip it
33
+ * and return its depth-1 children as the practical entry points.
34
+ */
35
+ private findRootChildren;
36
+ /** Get immediate children of a folder code, or root theme folders if code is undefined. */
37
+ browse(themeCode: string | undefined, ctx: Context): Promise<{
38
+ items: BrowseItem[];
39
+ parentPath: string[];
40
+ }>;
41
+ private toBrowseItem;
42
+ /**
43
+ * Search datasets by case-insensitive substring match against labels.
44
+ * Returns datasets only (not folders), up to `limit` results.
45
+ */
46
+ search(query: string, limit: number, ctx: Context): Promise<{
47
+ datasets: DatasetResult[];
48
+ totalMatches: number;
49
+ }>;
50
+ }
51
+ export declare function initEurostatCatalogueService(config: AppConfig, storage: StorageService): void;
52
+ export declare function getEurostatCatalogueService(): EurostatCatalogueService;
53
+ //# sourceMappingURL=eurostat-catalogue-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eurostat-catalogue-service.d.ts","sourceRoot":"","sources":["../../../src/services/eurostat-catalogue/eurostat-catalogue-service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAE/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAGrE,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAY,MAAM,YAAY,CAAC;AActE,qBAAa,wBAAwB;IACnC,OAAO,CAAC,KAAK,CAAuB;gBAKxB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc;IAExD,4DAA4D;YAC9C,YAAY;YAMZ,gBAAgB;IAgC9B;;;;;OAKG;IACH,OAAO,CAAC,QAAQ;IAyEhB,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,SAAS;IAMjB;;OAEG;IACH,OAAO,CAAC,SAAS;IAYjB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAQxB,2FAA2F;IACrF,MAAM,CACV,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,GAAG,EAAE,OAAO,GACX,OAAO,CAAC;QAAE,KAAK,EAAE,UAAU,EAAE,CAAC;QAAC,UAAU,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAwCzD,OAAO,CAAC,YAAY;IAepB;;;OAGG;IACG,MAAM,CACV,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,OAAO,GACX,OAAO,CAAC;QAAE,QAAQ,EAAE,aAAa,EAAE,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;CAwBhE;AAMD,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAE7F;AAED,wBAAgB,2BAA2B,IAAI,wBAAwB,CAOtE"}