@cyanheads/exchange-rates-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.
- package/AGENTS.md +392 -0
- package/CLAUDE.md +392 -0
- package/Dockerfile +105 -0
- package/LICENSE +201 -0
- package/README.md +340 -0
- package/changelog/0.1.x/0.1.1.md +32 -0
- package/changelog/template.md +127 -0
- package/dist/config/server-config.d.ts +13 -0
- package/dist/config/server-config.d.ts.map +1 -0
- package/dist/config/server-config.js +27 -0
- package/dist/config/server-config.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server/prompts/definitions/index.d.ts +6 -0
- package/dist/mcp-server/prompts/definitions/index.d.ts.map +1 -0
- package/dist/mcp-server/prompts/definitions/index.js +6 -0
- package/dist/mcp-server/prompts/definitions/index.js.map +1 -0
- package/dist/mcp-server/resources/definitions/fx-currencies.resource.d.ts +14 -0
- package/dist/mcp-server/resources/definitions/fx-currencies.resource.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/fx-currencies.resource.js +43 -0
- package/dist/mcp-server/resources/definitions/fx-currencies.resource.js.map +1 -0
- package/dist/mcp-server/resources/definitions/fx-rates-latest.resource.d.ts +15 -0
- package/dist/mcp-server/resources/definitions/fx-rates-latest.resource.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/fx-rates-latest.resource.js +61 -0
- package/dist/mcp-server/resources/definitions/fx-rates-latest.resource.js.map +1 -0
- package/dist/mcp-server/resources/definitions/index.d.ts +7 -0
- package/dist/mcp-server/resources/definitions/index.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/index.js +7 -0
- package/dist/mcp-server/resources/definitions/index.js.map +1 -0
- package/dist/mcp-server/tools/definitions/fx-convert-currency.tool.d.ts +33 -0
- package/dist/mcp-server/tools/definitions/fx-convert-currency.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/fx-convert-currency.tool.js +133 -0
- package/dist/mcp-server/tools/definitions/fx-convert-currency.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/fx-dataframe-describe.tool.d.ts +28 -0
- package/dist/mcp-server/tools/definitions/fx-dataframe-describe.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/fx-dataframe-describe.tool.js +105 -0
- package/dist/mcp-server/tools/definitions/fx-dataframe-describe.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/fx-dataframe-query.tool.d.ts +25 -0
- package/dist/mcp-server/tools/definitions/fx-dataframe-query.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/fx-dataframe-query.tool.js +125 -0
- package/dist/mcp-server/tools/definitions/fx-dataframe-query.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/fx-get-rate.tool.d.ts +30 -0
- package/dist/mcp-server/tools/definitions/fx-get-rate.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/fx-get-rate.tool.js +121 -0
- package/dist/mcp-server/tools/definitions/fx-get-rate.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/fx-get-rates.tool.d.ts +28 -0
- package/dist/mcp-server/tools/definitions/fx-get-rates.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/fx-get-rates.tool.js +115 -0
- package/dist/mcp-server/tools/definitions/fx-get-rates.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/fx-get-timeseries.tool.d.ts +41 -0
- package/dist/mcp-server/tools/definitions/fx-get-timeseries.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/fx-get-timeseries.tool.js +229 -0
- package/dist/mcp-server/tools/definitions/fx-get-timeseries.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/fx-list-currencies.tool.d.ts +14 -0
- package/dist/mcp-server/tools/definitions/fx-list-currencies.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/fx-list-currencies.tool.js +47 -0
- package/dist/mcp-server/tools/definitions/fx-list-currencies.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/index.d.ts +12 -0
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/index.js +12 -0
- package/dist/mcp-server/tools/definitions/index.js.map +1 -0
- package/dist/services/canvas/canvas-accessor.d.ts +10 -0
- package/dist/services/canvas/canvas-accessor.d.ts.map +1 -0
- package/dist/services/canvas/canvas-accessor.js +12 -0
- package/dist/services/canvas/canvas-accessor.js.map +1 -0
- package/dist/services/frankfurter/frankfurter-service.d.ts +46 -0
- package/dist/services/frankfurter/frankfurter-service.d.ts.map +1 -0
- package/dist/services/frankfurter/frankfurter-service.js +181 -0
- package/dist/services/frankfurter/frankfurter-service.js.map +1 -0
- package/dist/services/frankfurter/types.d.ts +59 -0
- package/dist/services/frankfurter/types.d.ts.map +1 -0
- package/dist/services/frankfurter/types.js +6 -0
- package/dist/services/frankfurter/types.js.map +1 -0
- package/package.json +104 -0
- package/server.json +127 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Type definitions for the Frankfurter API service.
|
|
3
|
+
* @module services/frankfurter/types
|
|
4
|
+
*/
|
|
5
|
+
/** Map of ISO 4217 currency code → full name. */
|
|
6
|
+
export interface CurrencyMap {
|
|
7
|
+
[code: string]: string;
|
|
8
|
+
}
|
|
9
|
+
/** A single currency with code and name. */
|
|
10
|
+
export interface Currency {
|
|
11
|
+
code: string;
|
|
12
|
+
name: string;
|
|
13
|
+
}
|
|
14
|
+
/** Raw API response from GET /latest or GET /{date}. */
|
|
15
|
+
export interface FrankfurterRateResponse {
|
|
16
|
+
amount: number;
|
|
17
|
+
base: string;
|
|
18
|
+
date: string;
|
|
19
|
+
rates: {
|
|
20
|
+
[code: string]: number;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/** Raw API response from GET /{start}..{end} (time series). */
|
|
24
|
+
export interface FrankfurterSeriesResponse {
|
|
25
|
+
amount: number;
|
|
26
|
+
base: string;
|
|
27
|
+
end_date: string;
|
|
28
|
+
rates: {
|
|
29
|
+
[date: string]: {
|
|
30
|
+
[code: string]: number;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
start_date: string;
|
|
34
|
+
}
|
|
35
|
+
/** A resolved exchange rate with provenance. */
|
|
36
|
+
export interface ResolvedRate {
|
|
37
|
+
/** The base currency code. */
|
|
38
|
+
baseCurrency: string;
|
|
39
|
+
/** True when the API snapped the requested date to a prior business day. */
|
|
40
|
+
dateSnapped: boolean;
|
|
41
|
+
/** The quote currency code. */
|
|
42
|
+
quoteCurrency: string;
|
|
43
|
+
/** The exchange rate (how many quote units per 1 base). */
|
|
44
|
+
rate: number;
|
|
45
|
+
/** The actual date of the rate (may differ from requested on weekends/holidays). */
|
|
46
|
+
rateDate: string;
|
|
47
|
+
/** Human-readable rate type caveat. */
|
|
48
|
+
rateType: 'ECB reference (mid-market)';
|
|
49
|
+
/** Data source attribution. */
|
|
50
|
+
source: 'ECB via Frankfurter';
|
|
51
|
+
}
|
|
52
|
+
/** A time-series row for canvas registration. Must satisfy `Record<string, unknown>` for spillover. */
|
|
53
|
+
export interface SeriesRow extends Record<string, unknown> {
|
|
54
|
+
base_currency: string;
|
|
55
|
+
date: string;
|
|
56
|
+
quote_currency: string;
|
|
57
|
+
rate: number;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/services/frankfurter/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,iDAAiD;AACjD,MAAM,WAAW,WAAW;IAC1B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CACxB;AAED,4CAA4C;AAC5C,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wDAAwD;AACxD,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;CACnC;AAED,+DAA+D;AAC/D,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG;YAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IACtD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,gDAAgD;AAChD,MAAM,WAAW,YAAY;IAC3B,8BAA8B;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,WAAW,EAAE,OAAO,CAAC;IACrB,+BAA+B;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,oFAAoF;IACpF,QAAQ,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,QAAQ,EAAE,4BAA4B,CAAC;IACvC,+BAA+B;IAC/B,MAAM,EAAE,qBAAqB,CAAC;CAC/B;AAED,uGAAuG;AACvG,MAAM,WAAW,SAAU,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACxD,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/services/frankfurter/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cyanheads/exchange-rates-mcp-server",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"mcpName": "io.github.cyanheads/exchange-rates-mcp-server",
|
|
5
|
+
"description": "Convert currencies, get FX rates, and query historical ECB exchange rate data via MCP. STDIO or Streamable HTTP.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"exchange-rates-mcp-server": "dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"changelog/",
|
|
14
|
+
"dist/",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE",
|
|
17
|
+
"CLAUDE.md",
|
|
18
|
+
"AGENTS.md",
|
|
19
|
+
"Dockerfile",
|
|
20
|
+
"server.json"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "bun run scripts/build.ts",
|
|
24
|
+
"rebuild": "bun run scripts/clean.ts && bun run scripts/build.ts",
|
|
25
|
+
"clean": "bun run scripts/clean.ts",
|
|
26
|
+
"devcheck": "bun run scripts/devcheck.ts",
|
|
27
|
+
"audit:refresh": "rm -f bun.lock && bun install && bun audit",
|
|
28
|
+
"tree": "bun run scripts/tree.ts",
|
|
29
|
+
"list-skills": "bun run scripts/list-skills.ts",
|
|
30
|
+
"format": "biome check --write .",
|
|
31
|
+
"format:unsafe": "biome check --write --unsafe .",
|
|
32
|
+
"lint:mcp": "bun run scripts/lint-mcp.ts",
|
|
33
|
+
"lint:packaging": "bun run scripts/lint-packaging.ts",
|
|
34
|
+
"bundle": "npm run build && npx -y @anthropic-ai/mcpb pack . dist/exchange-rates-mcp-server.mcpb",
|
|
35
|
+
"changelog:build": "bun run scripts/build-changelog.ts",
|
|
36
|
+
"changelog:check": "bun run scripts/build-changelog.ts --check",
|
|
37
|
+
"release:github": "bun run scripts/release-github.ts",
|
|
38
|
+
"publish-mcp": "mcp-publisher login github -token \"$(security find-generic-password -a \"$USER\" -s mcp-publisher-github-pat -w)\" && mcp-publisher publish",
|
|
39
|
+
"test": "vitest run",
|
|
40
|
+
"start": "node dist/index.js",
|
|
41
|
+
"start:stdio": "MCP_TRANSPORT_TYPE=stdio node dist/index.js",
|
|
42
|
+
"start:http": "MCP_TRANSPORT_TYPE=http node dist/index.js"
|
|
43
|
+
},
|
|
44
|
+
"keywords": [
|
|
45
|
+
"exchange-rates",
|
|
46
|
+
"currency-conversion",
|
|
47
|
+
"fx",
|
|
48
|
+
"forex",
|
|
49
|
+
"ecb",
|
|
50
|
+
"frankfurter",
|
|
51
|
+
"fiat",
|
|
52
|
+
"mcp",
|
|
53
|
+
"mcp-server",
|
|
54
|
+
"model-context-protocol",
|
|
55
|
+
"typescript",
|
|
56
|
+
"bun",
|
|
57
|
+
"stdio",
|
|
58
|
+
"streamable-http",
|
|
59
|
+
"ai-agent"
|
|
60
|
+
],
|
|
61
|
+
"repository": {
|
|
62
|
+
"type": "git",
|
|
63
|
+
"url": "git+https://github.com/cyanheads/exchange-rates-mcp-server.git"
|
|
64
|
+
},
|
|
65
|
+
"bugs": {
|
|
66
|
+
"url": "https://github.com/cyanheads/exchange-rates-mcp-server/issues"
|
|
67
|
+
},
|
|
68
|
+
"homepage": "https://github.com/cyanheads/exchange-rates-mcp-server#readme",
|
|
69
|
+
"author": "cyanheads <casey@caseyjhand.com> (https://github.com/cyanheads/exchange-rates-mcp-server#readme)",
|
|
70
|
+
"funding": [
|
|
71
|
+
{
|
|
72
|
+
"type": "github",
|
|
73
|
+
"url": "https://github.com/sponsors/cyanheads"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"type": "buy_me_a_coffee",
|
|
77
|
+
"url": "https://www.buymeacoffee.com/cyanheads"
|
|
78
|
+
}
|
|
79
|
+
],
|
|
80
|
+
"license": "Apache-2.0",
|
|
81
|
+
"packageManager": "bun@1.3.11",
|
|
82
|
+
"engines": {
|
|
83
|
+
"bun": ">=1.3.0",
|
|
84
|
+
"node": ">=24.0.0"
|
|
85
|
+
},
|
|
86
|
+
"publishConfig": {
|
|
87
|
+
"access": "public"
|
|
88
|
+
},
|
|
89
|
+
"dependencies": {
|
|
90
|
+
"@cyanheads/mcp-ts-core": "^0.9.21",
|
|
91
|
+
"@duckdb/node-api": "^1.5.3-r.3",
|
|
92
|
+
"pino-pretty": "^13.1.3",
|
|
93
|
+
"zod": "^4.4.3"
|
|
94
|
+
},
|
|
95
|
+
"devDependencies": {
|
|
96
|
+
"@biomejs/biome": "^2.4.16",
|
|
97
|
+
"@types/node": "^25.9.1",
|
|
98
|
+
"depcheck": "^1.4.7",
|
|
99
|
+
"ignore": "^7.0.5",
|
|
100
|
+
"tsc-alias": "^1.8.17",
|
|
101
|
+
"typescript": "^6.0.3",
|
|
102
|
+
"vitest": "^4.1.8"
|
|
103
|
+
}
|
|
104
|
+
}
|
package/server.json
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
+
"name": "io.github.cyanheads/exchange-rates-mcp-server",
|
|
4
|
+
"description": "Convert currencies, get FX rates, and query historical ECB exchange rate data.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"url": "https://github.com/cyanheads/exchange-rates-mcp-server",
|
|
7
|
+
"source": "github"
|
|
8
|
+
},
|
|
9
|
+
"version": "0.1.1",
|
|
10
|
+
"packages": [
|
|
11
|
+
{
|
|
12
|
+
"registryType": "npm",
|
|
13
|
+
"registryBaseUrl": "https://registry.npmjs.org",
|
|
14
|
+
"identifier": "@cyanheads/exchange-rates-mcp-server",
|
|
15
|
+
"runtimeHint": "bun",
|
|
16
|
+
"version": "0.1.1",
|
|
17
|
+
"packageArguments": [
|
|
18
|
+
{
|
|
19
|
+
"type": "positional",
|
|
20
|
+
"value": "run"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"type": "positional",
|
|
24
|
+
"value": "start:stdio"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"environmentVariables": [
|
|
28
|
+
{
|
|
29
|
+
"name": "FRANKFURTER_BASE_URL",
|
|
30
|
+
"description": "Frankfurter API base URL. Override for local testing or self-hosted instances.",
|
|
31
|
+
"format": "string",
|
|
32
|
+
"isRequired": false,
|
|
33
|
+
"default": "https://api.frankfurter.dev/v1"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "FX_TIMESERIES_CANVAS_THRESHOLD_DAYS",
|
|
37
|
+
"description": "Day range above which fx_get_timeseries spills results to DataCanvas for SQL analytics.",
|
|
38
|
+
"format": "string",
|
|
39
|
+
"isRequired": false,
|
|
40
|
+
"default": "90"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"name": "MCP_LOG_LEVEL",
|
|
44
|
+
"description": "Sets the minimum log level for output (e.g., 'debug', 'info', 'warn').",
|
|
45
|
+
"format": "string",
|
|
46
|
+
"isRequired": false,
|
|
47
|
+
"default": "info"
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"transport": {
|
|
51
|
+
"type": "stdio"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"registryType": "npm",
|
|
56
|
+
"registryBaseUrl": "https://registry.npmjs.org",
|
|
57
|
+
"identifier": "@cyanheads/exchange-rates-mcp-server",
|
|
58
|
+
"runtimeHint": "bun",
|
|
59
|
+
"version": "0.1.1",
|
|
60
|
+
"packageArguments": [
|
|
61
|
+
{
|
|
62
|
+
"type": "positional",
|
|
63
|
+
"value": "run"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"type": "positional",
|
|
67
|
+
"value": "start:http"
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"environmentVariables": [
|
|
71
|
+
{
|
|
72
|
+
"name": "FRANKFURTER_BASE_URL",
|
|
73
|
+
"description": "Frankfurter API base URL. Override for local testing or self-hosted instances.",
|
|
74
|
+
"format": "string",
|
|
75
|
+
"isRequired": false,
|
|
76
|
+
"default": "https://api.frankfurter.dev/v1"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"name": "FX_TIMESERIES_CANVAS_THRESHOLD_DAYS",
|
|
80
|
+
"description": "Day range above which fx_get_timeseries spills results to DataCanvas for SQL analytics.",
|
|
81
|
+
"format": "string",
|
|
82
|
+
"isRequired": false,
|
|
83
|
+
"default": "90"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name": "MCP_HTTP_HOST",
|
|
87
|
+
"description": "The hostname for the HTTP server.",
|
|
88
|
+
"format": "string",
|
|
89
|
+
"isRequired": false,
|
|
90
|
+
"default": "127.0.0.1"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"name": "MCP_HTTP_PORT",
|
|
94
|
+
"description": "The port to run the HTTP server on.",
|
|
95
|
+
"format": "string",
|
|
96
|
+
"isRequired": false,
|
|
97
|
+
"default": "3010"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"name": "MCP_HTTP_ENDPOINT_PATH",
|
|
101
|
+
"description": "The endpoint path for the MCP server.",
|
|
102
|
+
"format": "string",
|
|
103
|
+
"isRequired": false,
|
|
104
|
+
"default": "/mcp"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"name": "MCP_AUTH_MODE",
|
|
108
|
+
"description": "Authentication mode to use: 'none', 'jwt', or 'oauth'.",
|
|
109
|
+
"format": "string",
|
|
110
|
+
"isRequired": false,
|
|
111
|
+
"default": "none"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"name": "MCP_LOG_LEVEL",
|
|
115
|
+
"description": "Sets the minimum log level for output (e.g., 'debug', 'info', 'warn').",
|
|
116
|
+
"format": "string",
|
|
117
|
+
"isRequired": false,
|
|
118
|
+
"default": "info"
|
|
119
|
+
}
|
|
120
|
+
],
|
|
121
|
+
"transport": {
|
|
122
|
+
"type": "streamable-http",
|
|
123
|
+
"url": "http://localhost:3010/mcp"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
}
|