currency-exchange-mcp 1.0.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 +68 -0
- package/build/currency-api.d.ts +7 -0
- package/build/currency-api.d.ts.map +1 -0
- package/build/currency-api.js +55 -0
- package/build/currency-api.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +19 -0
- package/build/index.js.map +1 -0
- package/build/programs/exchange.d.ts +24 -0
- package/build/programs/exchange.d.ts.map +1 -0
- package/build/programs/exchange.js +70 -0
- package/build/programs/exchange.js.map +1 -0
- package/build/programs/index.d.ts +2 -0
- package/build/programs/index.d.ts.map +1 -0
- package/build/programs/index.js +2 -0
- package/build/programs/index.js.map +1 -0
- package/build/programs/types.d.ts +49 -0
- package/build/programs/types.d.ts.map +1 -0
- package/build/programs/types.js +14 -0
- package/build/programs/types.js.map +1 -0
- package/build/tools/currency-exchange-tool.d.ts +10 -0
- package/build/tools/currency-exchange-tool.d.ts.map +1 -0
- package/build/tools/currency-exchange-tool.js +103 -0
- package/build/tools/currency-exchange-tool.js.map +1 -0
- package/build/tools/exchange.d.ts +3 -0
- package/build/tools/exchange.d.ts.map +1 -0
- package/build/tools/exchange.js +79 -0
- package/build/tools/exchange.js.map +1 -0
- package/build/types.d.ts +22 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +14 -0
- package/build/types.js.map +1 -0
- package/package.json +31 -0
- package/src/index.ts +23 -0
- package/src/programs/exchange.ts +99 -0
- package/src/programs/index.ts +1 -0
- package/src/programs/types.ts +37 -0
- package/src/tools/exchange.ts +91 -0
- package/tsconfig.json +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Currency Exchange MCP
|
|
2
|
+
|
|
3
|
+
A Model Context Protocol (MCP) server that provides currency exchange rate conversion tools.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Convert amounts between currencies using real-time exchange rates
|
|
8
|
+
- Get exchange rates between any two currencies
|
|
9
|
+
- Support for historical exchange rates by date
|
|
10
|
+
- Uses the reliable fawazahmed0/currency-api for exchange rate data
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pnpm install
|
|
16
|
+
pnpm run build
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## Available Tools
|
|
21
|
+
|
|
22
|
+
#### 1. `convert_currency`
|
|
23
|
+
|
|
24
|
+
Converts an amount from one currency to another using current or historical exchange rates.
|
|
25
|
+
|
|
26
|
+
**Example prompts:**
|
|
27
|
+
- *"How much is 10 NOK in USD?"*
|
|
28
|
+
- *"Convert 20000 yen to USD"*
|
|
29
|
+
- *"How much was 100 USD worth in EUR on 2024-03-15?"*
|
|
30
|
+
- *"Convert 500 CAD to JPY"*
|
|
31
|
+
|
|
32
|
+
#### 2. `get_exchange_rate`
|
|
33
|
+
|
|
34
|
+
Gets the exchange rate between two currencies.
|
|
35
|
+
|
|
36
|
+
**Example prompts:**
|
|
37
|
+
- *"What's the current exchange rate from EUR to GBP?"*
|
|
38
|
+
- *"What's the USD to CHF rate?"*
|
|
39
|
+
- *"What was the EUR to USD rate on 2024-01-01?"*
|
|
40
|
+
|
|
41
|
+
### Using with Claude
|
|
42
|
+
|
|
43
|
+
To use this MCP server with Claude, add it to your MCP configuration:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"mcpServers": {
|
|
48
|
+
"currency-exchange": {
|
|
49
|
+
"command": "node",
|
|
50
|
+
"args": ["/path/to/currency-exchange-mcp/build/index.js"]
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Once configured, Claude will automatically use the appropriate tools when you ask currency-related questions.
|
|
57
|
+
|
|
58
|
+
## Data Source
|
|
59
|
+
|
|
60
|
+
This MCP server uses the [fawazahmed0/currency-api](https://github.com/fawazahmed0/exchange-api) which provides:
|
|
61
|
+
- Real-time exchange rates
|
|
62
|
+
- Historical exchange rates
|
|
63
|
+
- Support for 150+ currencies
|
|
64
|
+
- Free usage with no API key required
|
|
65
|
+
|
|
66
|
+
## License
|
|
67
|
+
|
|
68
|
+
MIT
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare class CurrencyApiClient {
|
|
2
|
+
private readonly baseUrl;
|
|
3
|
+
getExchangeRate(fromCurrency: string, toCurrency: string, date?: string): Promise<number>;
|
|
4
|
+
convertCurrency(amount: number, fromCurrency: string, toCurrency: string, date?: string): Promise<number>;
|
|
5
|
+
getSupportedCurrencies(baseCurrency?: string): Promise<string[]>;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=currency-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"currency-api.d.ts","sourceRoot":"","sources":["../src/currency-api.ts"],"names":[],"mappings":"AAEA,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4D;IAE9E,eAAe,CACjB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,IAAI,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC;IAiCZ,eAAe,CACjB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,IAAI,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC;IAKZ,sBAAsB,CAAC,YAAY,GAAE,MAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAoBhF"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export class CurrencyApiClient {
|
|
2
|
+
baseUrl = 'https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api';
|
|
3
|
+
async getExchangeRate(fromCurrency, toCurrency, date) {
|
|
4
|
+
const normalizedFrom = fromCurrency.toLowerCase();
|
|
5
|
+
const normalizedTo = toCurrency.toLowerCase();
|
|
6
|
+
let url;
|
|
7
|
+
if (date) {
|
|
8
|
+
url = `${this.baseUrl}@${date}/v1/currencies/${normalizedFrom}.json`;
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
url = `${this.baseUrl}@latest/v1/currencies/${normalizedFrom}.json`;
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const response = await fetch(url);
|
|
15
|
+
if (!response.ok) {
|
|
16
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
17
|
+
}
|
|
18
|
+
const data = await response.json();
|
|
19
|
+
const rates = data[normalizedFrom];
|
|
20
|
+
if (!rates || !(normalizedTo in rates)) {
|
|
21
|
+
throw new Error(`Exchange rate not available for ${fromCurrency} to ${toCurrency}`);
|
|
22
|
+
}
|
|
23
|
+
return rates[normalizedTo];
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (error instanceof Error) {
|
|
27
|
+
throw new Error(`Failed to fetch exchange rate: ${error.message}`);
|
|
28
|
+
}
|
|
29
|
+
throw new Error('Unknown error occurred while fetching exchange rate');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async convertCurrency(amount, fromCurrency, toCurrency, date) {
|
|
33
|
+
const rate = await this.getExchangeRate(fromCurrency, toCurrency, date);
|
|
34
|
+
return amount * rate;
|
|
35
|
+
}
|
|
36
|
+
async getSupportedCurrencies(baseCurrency = 'eur') {
|
|
37
|
+
const url = `${this.baseUrl}@latest/v1/currencies/${baseCurrency.toLowerCase()}.json`;
|
|
38
|
+
try {
|
|
39
|
+
const response = await fetch(url);
|
|
40
|
+
if (!response.ok) {
|
|
41
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
42
|
+
}
|
|
43
|
+
const data = await response.json();
|
|
44
|
+
const rates = data[baseCurrency.toLowerCase()];
|
|
45
|
+
return Object.keys(rates).map(code => code.toUpperCase());
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (error instanceof Error) {
|
|
49
|
+
throw new Error(`Failed to fetch supported currencies: ${error.message}`);
|
|
50
|
+
}
|
|
51
|
+
throw new Error('Unknown error occurred while fetching supported currencies');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=currency-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"currency-api.js","sourceRoot":"","sources":["../src/currency-api.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,iBAAiB;IACT,OAAO,GAAG,wDAAwD,CAAC;IAEpF,KAAK,CAAC,eAAe,CACjB,YAAoB,EACpB,UAAkB,EAClB,IAAa;QAEb,MAAM,cAAc,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC;QAClD,MAAM,YAAY,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;QAE9C,IAAI,GAAW,CAAC;QAChB,IAAI,IAAI,EAAE,CAAC;YACP,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,kBAAkB,cAAc,OAAO,CAAC;QACzE,CAAC;aAAM,CAAC;YACJ,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,yBAAyB,cAAc,OAAO,CAAC;QACxE,CAAC;QAED,IAAI,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACf,MAAM,IAAI,KAAK,CAAC,uBAAuB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;YAC9D,CAAC;YAED,MAAM,IAAI,GAAwB,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxD,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC;YAEnC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,YAAY,IAAI,KAAK,CAAC,EAAE,CAAC;gBACrC,MAAM,IAAI,KAAK,CAAC,mCAAmC,YAAY,OAAO,UAAU,EAAE,CAAC,CAAC;YACxF,CAAC;YAED,OAAO,KAAK,CAAC,YAAY,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,kCAAkC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACvE,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QAC3E,CAAC;IACL,CAAC;IAED,KAAK,CAAC,eAAe,CACjB,MAAc,EACd,YAAoB,EACpB,UAAkB,EAClB,IAAa;QAEb,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;QACxE,OAAO,MAAM,GAAG,IAAI,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,sBAAsB,CAAC,eAAuB,KAAK;QACrD,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,yBAAyB,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC;QAEtF,IAAI,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACf,MAAM,IAAI,KAAK,CAAC,uBAAuB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;YAC9D,CAAC;YAED,MAAM,IAAI,GAAwB,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxD,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC;YAE/C,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,yCAAyC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAC9E,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;QAClF,CAAC;IACL,CAAC;CACJ"}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/build/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { registerCurrencyExchangeTools } from './tools/exchange.js';
|
|
5
|
+
const server = new McpServer({
|
|
6
|
+
name: 'currency-exchange-mcp',
|
|
7
|
+
version: '1.0.0',
|
|
8
|
+
});
|
|
9
|
+
registerCurrencyExchangeTools(server);
|
|
10
|
+
async function main() {
|
|
11
|
+
const transport = new StdioServerTransport();
|
|
12
|
+
await server.connect(transport);
|
|
13
|
+
console.error('Currency Exchange MCP server running on stdio');
|
|
14
|
+
}
|
|
15
|
+
main().catch((error) => {
|
|
16
|
+
console.error('Fatal error:', error);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAC;AAEpE,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IACzB,IAAI,EAAE,uBAAuB;IAC7B,OAAO,EAAE,OAAO;CACnB,CAAC,CAAC;AAEH,6BAA6B,CAAC,MAAM,CAAC,CAAC;AAEtC,KAAK,UAAU,IAAI;IACf,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;AACnE,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
interface ExchangeOptions {
|
|
2
|
+
fromCurrency: string;
|
|
3
|
+
toCurrency: string;
|
|
4
|
+
amount?: number;
|
|
5
|
+
date?: string;
|
|
6
|
+
}
|
|
7
|
+
interface ExchangeRateResult {
|
|
8
|
+
rate: number;
|
|
9
|
+
fromCurrency: string;
|
|
10
|
+
toCurrency: string;
|
|
11
|
+
date: string;
|
|
12
|
+
}
|
|
13
|
+
interface ConversionResult extends ExchangeRateResult {
|
|
14
|
+
amount: number;
|
|
15
|
+
convertedAmount: number;
|
|
16
|
+
}
|
|
17
|
+
export declare class Exchange {
|
|
18
|
+
private static readonly baseUrl;
|
|
19
|
+
static getExchangeRate(options: ExchangeOptions): Promise<ExchangeRateResult>;
|
|
20
|
+
static convertCurrency(options: ExchangeOptions): Promise<ConversionResult>;
|
|
21
|
+
static getSupportedCurrencies(baseCurrency?: string): Promise<string[]>;
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=exchange.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exchange.d.ts","sourceRoot":"","sources":["../../src/programs/exchange.ts"],"names":[],"mappings":"AAAA,UAAU,eAAe;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,kBAAkB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,gBAAiB,SAAQ,kBAAkB;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,QAAQ;IACjB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAA4D;WAE9E,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,kBAAkB,CAAC;WAuCtE,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;WAiBpE,sBAAsB,CAAC,YAAY,GAAE,MAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAoBvF"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export class Exchange {
|
|
2
|
+
static baseUrl = 'https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api';
|
|
3
|
+
static async getExchangeRate(options) {
|
|
4
|
+
const { fromCurrency, toCurrency, date } = options;
|
|
5
|
+
const normalizedFrom = fromCurrency.toLowerCase();
|
|
6
|
+
const normalizedTo = toCurrency.toLowerCase();
|
|
7
|
+
let url;
|
|
8
|
+
if (date) {
|
|
9
|
+
url = `${this.baseUrl}@${date}/v1/currencies/${normalizedFrom}.json`;
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
url = `${this.baseUrl}@latest/v1/currencies/${normalizedFrom}.json`;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const response = await fetch(url);
|
|
16
|
+
if (!response.ok) {
|
|
17
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
18
|
+
}
|
|
19
|
+
const data = await response.json();
|
|
20
|
+
const rates = data[normalizedFrom];
|
|
21
|
+
if (!rates || !(normalizedTo in rates)) {
|
|
22
|
+
throw new Error(`Exchange rate not available for ${fromCurrency} to ${toCurrency}`);
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
rate: rates[normalizedTo],
|
|
26
|
+
fromCurrency: fromCurrency.toUpperCase(),
|
|
27
|
+
toCurrency: toCurrency.toUpperCase(),
|
|
28
|
+
date: date || new Date().toISOString().split('T')[0]
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
if (error instanceof Error) {
|
|
33
|
+
throw new Error(`Failed to fetch exchange rate: ${error.message}`);
|
|
34
|
+
}
|
|
35
|
+
throw new Error('Unknown error occurred while fetching exchange rate');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
static async convertCurrency(options) {
|
|
39
|
+
const { amount } = options;
|
|
40
|
+
if (!amount || amount <= 0) {
|
|
41
|
+
throw new Error('Amount must be provided and positive for currency conversion');
|
|
42
|
+
}
|
|
43
|
+
const rateResult = await this.getExchangeRate(options);
|
|
44
|
+
const convertedAmount = amount * rateResult.rate;
|
|
45
|
+
return {
|
|
46
|
+
...rateResult,
|
|
47
|
+
amount,
|
|
48
|
+
convertedAmount: Math.round(convertedAmount * 100) / 100
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
static async getSupportedCurrencies(baseCurrency = 'eur') {
|
|
52
|
+
const url = `${this.baseUrl}@latest/v1/currencies/${baseCurrency.toLowerCase()}.json`;
|
|
53
|
+
try {
|
|
54
|
+
const response = await fetch(url);
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
57
|
+
}
|
|
58
|
+
const data = await response.json();
|
|
59
|
+
const rates = data[baseCurrency.toLowerCase()];
|
|
60
|
+
return Object.keys(rates).map(code => code.toUpperCase()).sort();
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
if (error instanceof Error) {
|
|
64
|
+
throw new Error(`Failed to fetch supported currencies: ${error.message}`);
|
|
65
|
+
}
|
|
66
|
+
throw new Error('Unknown error occurred while fetching supported currencies');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=exchange.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exchange.js","sourceRoot":"","sources":["../../src/programs/exchange.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/programs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/programs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const CurrencyCodeSchema: z.ZodString;
|
|
3
|
+
export declare const ConvertCurrencyArgsSchema: z.ZodObject<{
|
|
4
|
+
amount: z.ZodNumber;
|
|
5
|
+
from_currency: z.ZodString;
|
|
6
|
+
to_currency: z.ZodString;
|
|
7
|
+
date: z.ZodOptional<z.ZodString>;
|
|
8
|
+
}, "strip", z.ZodTypeAny, {
|
|
9
|
+
amount: number;
|
|
10
|
+
from_currency: string;
|
|
11
|
+
to_currency: string;
|
|
12
|
+
date?: string | undefined;
|
|
13
|
+
}, {
|
|
14
|
+
amount: number;
|
|
15
|
+
from_currency: string;
|
|
16
|
+
to_currency: string;
|
|
17
|
+
date?: string | undefined;
|
|
18
|
+
}>;
|
|
19
|
+
export declare const GetExchangeRateArgsSchema: z.ZodObject<{
|
|
20
|
+
from_currency: z.ZodString;
|
|
21
|
+
to_currency: z.ZodString;
|
|
22
|
+
date: z.ZodOptional<z.ZodString>;
|
|
23
|
+
}, "strip", z.ZodTypeAny, {
|
|
24
|
+
from_currency: string;
|
|
25
|
+
to_currency: string;
|
|
26
|
+
date?: string | undefined;
|
|
27
|
+
}, {
|
|
28
|
+
from_currency: string;
|
|
29
|
+
to_currency: string;
|
|
30
|
+
date?: string | undefined;
|
|
31
|
+
}>;
|
|
32
|
+
export type ConvertCurrencyArgs = z.infer<typeof ConvertCurrencyArgsSchema>;
|
|
33
|
+
export type GetExchangeRateArgs = z.infer<typeof GetExchangeRateArgsSchema>;
|
|
34
|
+
export interface CurrencyApiResponse {
|
|
35
|
+
[key: string]: {
|
|
36
|
+
[currencyCode: string]: number;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export interface ExchangeRateResult {
|
|
40
|
+
rate: number;
|
|
41
|
+
from_currency: string;
|
|
42
|
+
to_currency: string;
|
|
43
|
+
date: string;
|
|
44
|
+
}
|
|
45
|
+
export interface ConversionResult extends ExchangeRateResult {
|
|
46
|
+
amount: number;
|
|
47
|
+
converted_amount: number;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/programs/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,kBAAkB,aAA2C,CAAC;AAE3E,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;EAKpC,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;EAIpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAC5E,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,MAAM,WAAW,mBAAmB;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG;QACX,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC;KAClC,CAAC;CACL;AAED,MAAM,WAAW,kBAAkB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAiB,SAAQ,kBAAkB;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;CAC5B"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const CurrencyCodeSchema = z.string().length(3).regex(/^[A-Z]{3}$/);
|
|
3
|
+
export const ConvertCurrencyArgsSchema = z.object({
|
|
4
|
+
amount: z.number().positive(),
|
|
5
|
+
from_currency: CurrencyCodeSchema,
|
|
6
|
+
to_currency: CurrencyCodeSchema,
|
|
7
|
+
date: z.string().optional().describe('Date in YYYY-MM-DD format. If not provided, uses latest rates')
|
|
8
|
+
});
|
|
9
|
+
export const GetExchangeRateArgsSchema = z.object({
|
|
10
|
+
from_currency: CurrencyCodeSchema,
|
|
11
|
+
to_currency: CurrencyCodeSchema,
|
|
12
|
+
date: z.string().optional().describe('Date in YYYY-MM-DD format. If not provided, uses latest rates')
|
|
13
|
+
});
|
|
14
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/programs/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;AAE3E,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,aAAa,EAAE,kBAAkB;IACjC,WAAW,EAAE,kBAAkB;IAC/B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+DAA+D,CAAC;CACxG,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,aAAa,EAAE,kBAAkB;IACjC,WAAW,EAAE,kBAAkB;IAC/B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+DAA+D,CAAC;CACxG,CAAC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { ConversionResult, ExchangeRateResult } from '../types.js';
|
|
3
|
+
export declare class CurrencyExchangeTool {
|
|
4
|
+
private apiClient;
|
|
5
|
+
constructor();
|
|
6
|
+
getToolDefinitions(): Tool[];
|
|
7
|
+
convertCurrency(args: unknown): Promise<ConversionResult>;
|
|
8
|
+
getExchangeRate(args: unknown): Promise<ExchangeRateResult>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=currency-exchange-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"currency-exchange-tool.d.ts","sourceRoot":"","sources":["../../src/tools/currency-exchange-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAE1D,OAAO,EAKH,gBAAgB,EAChB,kBAAkB,EACrB,MAAM,aAAa,CAAC;AAErB,qBAAa,oBAAoB;IAC7B,OAAO,CAAC,SAAS,CAAoB;;IAMrC,kBAAkB,IAAI,IAAI,EAAE;IA4DtB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAqBzD,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAiBpE"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { CurrencyApiClient } from '../currency-api.js';
|
|
2
|
+
import { ConvertCurrencyArgsSchema, GetExchangeRateArgsSchema } from '../types.js';
|
|
3
|
+
export class CurrencyExchangeTool {
|
|
4
|
+
apiClient;
|
|
5
|
+
constructor() {
|
|
6
|
+
this.apiClient = new CurrencyApiClient();
|
|
7
|
+
}
|
|
8
|
+
getToolDefinitions() {
|
|
9
|
+
return [
|
|
10
|
+
{
|
|
11
|
+
name: 'convert_currency',
|
|
12
|
+
description: 'Convert an amount from one currency to another using current or historical exchange rates',
|
|
13
|
+
inputSchema: {
|
|
14
|
+
type: 'object',
|
|
15
|
+
properties: {
|
|
16
|
+
amount: {
|
|
17
|
+
type: 'number',
|
|
18
|
+
description: 'The amount to convert (must be positive)',
|
|
19
|
+
minimum: 0
|
|
20
|
+
},
|
|
21
|
+
from_currency: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'Source currency code (3 letters, e.g., USD, EUR, NOK)',
|
|
24
|
+
pattern: '^[A-Z]{3}$'
|
|
25
|
+
},
|
|
26
|
+
to_currency: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
description: 'Target currency code (3 letters, e.g., USD, EUR, NOK)',
|
|
29
|
+
pattern: '^[A-Z]{3}$'
|
|
30
|
+
},
|
|
31
|
+
date: {
|
|
32
|
+
type: 'string',
|
|
33
|
+
description: 'Optional date in YYYY-MM-DD format for historical rates. If not provided, uses latest rates',
|
|
34
|
+
pattern: '^\\d{4}-\\d{2}-\\d{2}$'
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
required: ['amount', 'from_currency', 'to_currency']
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'get_exchange_rate',
|
|
42
|
+
description: 'Get the exchange rate between two currencies',
|
|
43
|
+
inputSchema: {
|
|
44
|
+
type: 'object',
|
|
45
|
+
properties: {
|
|
46
|
+
from_currency: {
|
|
47
|
+
type: 'string',
|
|
48
|
+
description: 'Source currency code (3 letters, e.g., USD, EUR, NOK)',
|
|
49
|
+
pattern: '^[A-Z]{3}$'
|
|
50
|
+
},
|
|
51
|
+
to_currency: {
|
|
52
|
+
type: 'string',
|
|
53
|
+
description: 'Target currency code (3 letters, e.g., USD, EUR, NOK)',
|
|
54
|
+
pattern: '^[A-Z]{3}$'
|
|
55
|
+
},
|
|
56
|
+
date: {
|
|
57
|
+
type: 'string',
|
|
58
|
+
description: 'Optional date in YYYY-MM-DD format for historical rates. If not provided, uses latest rates',
|
|
59
|
+
pattern: '^\\d{4}-\\d{2}-\\d{2}$'
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
required: ['from_currency', 'to_currency']
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
async convertCurrency(args) {
|
|
68
|
+
const validatedArgs = ConvertCurrencyArgsSchema.parse(args);
|
|
69
|
+
const { amount, from_currency, to_currency, date } = validatedArgs;
|
|
70
|
+
try {
|
|
71
|
+
const rate = await this.apiClient.getExchangeRate(from_currency, to_currency, date);
|
|
72
|
+
const convertedAmount = amount * rate;
|
|
73
|
+
return {
|
|
74
|
+
amount,
|
|
75
|
+
converted_amount: Math.round(convertedAmount * 100) / 100, // Round to 2 decimal places
|
|
76
|
+
rate,
|
|
77
|
+
from_currency,
|
|
78
|
+
to_currency,
|
|
79
|
+
date: date || new Date().toISOString().split('T')[0]
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
throw new Error(`Currency conversion failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async getExchangeRate(args) {
|
|
87
|
+
const validatedArgs = GetExchangeRateArgsSchema.parse(args);
|
|
88
|
+
const { from_currency, to_currency, date } = validatedArgs;
|
|
89
|
+
try {
|
|
90
|
+
const rate = await this.apiClient.getExchangeRate(from_currency, to_currency, date);
|
|
91
|
+
return {
|
|
92
|
+
rate,
|
|
93
|
+
from_currency,
|
|
94
|
+
to_currency,
|
|
95
|
+
date: date || new Date().toISOString().split('T')[0]
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
throw new Error(`Failed to get exchange rate: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=currency-exchange-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"currency-exchange-tool.js","sourceRoot":"","sources":["../../src/tools/currency-exchange-tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exchange.d.ts","sourceRoot":"","sources":["../../src/tools/exchange.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAiBpE,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,SAAS,QAyE9D"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { Exchange } from '../programs/index.js';
|
|
3
|
+
const convertCurrencySchema = z.object({
|
|
4
|
+
amount: z.number().positive().describe('The amount to convert (must be positive)'),
|
|
5
|
+
from_currency: z.string().length(3).regex(/^[A-Z]{3}$/).describe('Source currency code (3 letters, e.g., USD, EUR, NOK)'),
|
|
6
|
+
to_currency: z.string().length(3).regex(/^[A-Z]{3}$/).describe('Target currency code (3 letters, e.g., USD, EUR, NOK)'),
|
|
7
|
+
date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().describe('Optional date in YYYY-MM-DD format for historical rates. If not provided, uses latest rates')
|
|
8
|
+
});
|
|
9
|
+
const getExchangeRateSchema = z.object({
|
|
10
|
+
from_currency: z.string().length(3).regex(/^[A-Z]{3}$/).describe('Source currency code (3 letters, e.g., USD, EUR, NOK)'),
|
|
11
|
+
to_currency: z.string().length(3).regex(/^[A-Z]{3}$/).describe('Target currency code (3 letters, e.g., USD, EUR, NOK)'),
|
|
12
|
+
date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().describe('Optional date in YYYY-MM-DD format for historical rates. If not provided, uses latest rates')
|
|
13
|
+
});
|
|
14
|
+
export function registerCurrencyExchangeTools(server) {
|
|
15
|
+
server.registerTool('convert_currency', {
|
|
16
|
+
description: 'Convert an amount from one currency to another using current or historical exchange rates',
|
|
17
|
+
inputSchema: convertCurrencySchema,
|
|
18
|
+
}, async ({ amount, from_currency, to_currency, date }) => {
|
|
19
|
+
try {
|
|
20
|
+
const result = await Exchange.convertCurrency({
|
|
21
|
+
amount,
|
|
22
|
+
fromCurrency: from_currency,
|
|
23
|
+
toCurrency: to_currency,
|
|
24
|
+
date
|
|
25
|
+
});
|
|
26
|
+
return {
|
|
27
|
+
content: [
|
|
28
|
+
{
|
|
29
|
+
type: 'text',
|
|
30
|
+
text: JSON.stringify(result, null, 4),
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
return {
|
|
37
|
+
content: [
|
|
38
|
+
{
|
|
39
|
+
type: 'text',
|
|
40
|
+
text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
isError: true,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
server.registerTool('get_exchange_rate', {
|
|
48
|
+
description: 'Get the exchange rate between two currencies',
|
|
49
|
+
inputSchema: getExchangeRateSchema,
|
|
50
|
+
}, async ({ from_currency, to_currency, date }) => {
|
|
51
|
+
try {
|
|
52
|
+
const result = await Exchange.getExchangeRate({
|
|
53
|
+
fromCurrency: from_currency,
|
|
54
|
+
toCurrency: to_currency,
|
|
55
|
+
date
|
|
56
|
+
});
|
|
57
|
+
return {
|
|
58
|
+
content: [
|
|
59
|
+
{
|
|
60
|
+
type: 'text',
|
|
61
|
+
text: JSON.stringify(result, null, 4),
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
return {
|
|
68
|
+
content: [
|
|
69
|
+
{
|
|
70
|
+
type: 'text',
|
|
71
|
+
text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
isError: true,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=exchange.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exchange.js","sourceRoot":"","sources":["../../src/tools/exchange.ts"],"names":[],"mappings":"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"}
|
package/build/types.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const CurrencyCodeSchema: any;
|
|
3
|
+
export declare const ConvertCurrencyArgsSchema: any;
|
|
4
|
+
export declare const GetExchangeRateArgsSchema: any;
|
|
5
|
+
export type ConvertCurrencyArgs = z.infer<typeof ConvertCurrencyArgsSchema>;
|
|
6
|
+
export type GetExchangeRateArgs = z.infer<typeof GetExchangeRateArgsSchema>;
|
|
7
|
+
export interface CurrencyApiResponse {
|
|
8
|
+
[key: string]: {
|
|
9
|
+
[currencyCode: string]: number;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export interface ExchangeRateResult {
|
|
13
|
+
rate: number;
|
|
14
|
+
from_currency: string;
|
|
15
|
+
to_currency: string;
|
|
16
|
+
date: string;
|
|
17
|
+
}
|
|
18
|
+
export interface ConversionResult extends ExchangeRateResult {
|
|
19
|
+
amount: number;
|
|
20
|
+
converted_amount: number;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,kBAAkB,KAA2C,CAAC;AAE3E,eAAO,MAAM,yBAAyB,KAKpC,CAAC;AAEH,eAAO,MAAM,yBAAyB,KAIpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAC5E,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,MAAM,WAAW,mBAAmB;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG;QACX,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC;KAClC,CAAC;CACL;AAED,MAAM,WAAW,kBAAkB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAiB,SAAQ,kBAAkB;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;CAC5B"}
|
package/build/types.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const CurrencyCodeSchema = z.string().length(3).regex(/^[A-Z]{3}$/);
|
|
3
|
+
export const ConvertCurrencyArgsSchema = z.object({
|
|
4
|
+
amount: z.number().positive(),
|
|
5
|
+
from_currency: CurrencyCodeSchema,
|
|
6
|
+
to_currency: CurrencyCodeSchema,
|
|
7
|
+
date: z.string().optional().describe('Date in YYYY-MM-DD format. If not provided, uses latest rates')
|
|
8
|
+
});
|
|
9
|
+
export const GetExchangeRateArgsSchema = z.object({
|
|
10
|
+
from_currency: CurrencyCodeSchema,
|
|
11
|
+
to_currency: CurrencyCodeSchema,
|
|
12
|
+
date: z.string().optional().describe('Date in YYYY-MM-DD format. If not provided, uses latest rates')
|
|
13
|
+
});
|
|
14
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;AAE3E,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,aAAa,EAAE,kBAAkB;IACjC,WAAW,EAAE,kBAAkB;IAC/B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+DAA+D,CAAC;CACxG,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,aAAa,EAAE,kBAAkB;IACjC,WAAW,EAAE,kBAAkB;IAC/B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+DAA+D,CAAC;CACxG,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "currency-exchange-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for currency exchange rate conversion",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "build/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"start": "node build/index.js",
|
|
10
|
+
"dev": "tsx src/index.ts",
|
|
11
|
+
"inspect": "pnpm dlx @modelcontextprotocol/inspector tsx src/index.ts",
|
|
12
|
+
"clean": "rm -rf build"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"mcp",
|
|
16
|
+
"currency",
|
|
17
|
+
"exchange",
|
|
18
|
+
"rates"
|
|
19
|
+
],
|
|
20
|
+
"author": "",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
24
|
+
"zod": "^3.25.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^22.10.2",
|
|
28
|
+
"tsx": "^4.19.2",
|
|
29
|
+
"typescript": "^5.7.2"
|
|
30
|
+
}
|
|
31
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
|
+
import { registerCurrencyExchangeTools } from './tools/exchange.js';
|
|
6
|
+
|
|
7
|
+
const server = new McpServer({
|
|
8
|
+
name: 'currency-exchange-mcp',
|
|
9
|
+
version: '1.0.0',
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
registerCurrencyExchangeTools(server);
|
|
13
|
+
|
|
14
|
+
async function main() {
|
|
15
|
+
const transport = new StdioServerTransport();
|
|
16
|
+
await server.connect(transport);
|
|
17
|
+
console.error('Currency Exchange MCP server running on stdio');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
main().catch((error) => {
|
|
21
|
+
console.error('Fatal error:', error);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
interface ExchangeOptions {
|
|
2
|
+
fromCurrency: string;
|
|
3
|
+
toCurrency: string;
|
|
4
|
+
amount?: number;
|
|
5
|
+
date?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface ExchangeRateResult {
|
|
9
|
+
rate: number;
|
|
10
|
+
fromCurrency: string;
|
|
11
|
+
toCurrency: string;
|
|
12
|
+
date: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface ConversionResult extends ExchangeRateResult {
|
|
16
|
+
amount: number;
|
|
17
|
+
convertedAmount: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class Exchange {
|
|
21
|
+
private static readonly baseUrl = 'https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api';
|
|
22
|
+
|
|
23
|
+
static async getExchangeRate(options: ExchangeOptions): Promise<ExchangeRateResult> {
|
|
24
|
+
const { fromCurrency, toCurrency, date } = options;
|
|
25
|
+
const normalizedFrom = fromCurrency.toLowerCase();
|
|
26
|
+
const normalizedTo = toCurrency.toLowerCase();
|
|
27
|
+
|
|
28
|
+
let url: string;
|
|
29
|
+
if (date) {
|
|
30
|
+
url = `${this.baseUrl}@${date}/v1/currencies/${normalizedFrom}.json`;
|
|
31
|
+
} else {
|
|
32
|
+
url = `${this.baseUrl}@latest/v1/currencies/${normalizedFrom}.json`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const response = await fetch(url);
|
|
37
|
+
if (!response.ok) {
|
|
38
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const data: any = await response.json();
|
|
42
|
+
const rates = data[normalizedFrom];
|
|
43
|
+
|
|
44
|
+
if (!rates || !(normalizedTo in rates)) {
|
|
45
|
+
throw new Error(`Exchange rate not available for ${fromCurrency} to ${toCurrency}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
rate: rates[normalizedTo],
|
|
50
|
+
fromCurrency: fromCurrency.toUpperCase(),
|
|
51
|
+
toCurrency: toCurrency.toUpperCase(),
|
|
52
|
+
date: date || new Date().toISOString().split('T')[0]
|
|
53
|
+
};
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (error instanceof Error) {
|
|
56
|
+
throw new Error(`Failed to fetch exchange rate: ${error.message}`);
|
|
57
|
+
}
|
|
58
|
+
throw new Error('Unknown error occurred while fetching exchange rate');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
static async convertCurrency(options: ExchangeOptions): Promise<ConversionResult> {
|
|
63
|
+
const { amount } = options;
|
|
64
|
+
|
|
65
|
+
if (!amount || amount <= 0) {
|
|
66
|
+
throw new Error('Amount must be provided and positive for currency conversion');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const rateResult = await this.getExchangeRate(options);
|
|
70
|
+
const convertedAmount = amount * rateResult.rate;
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
...rateResult,
|
|
74
|
+
amount,
|
|
75
|
+
convertedAmount: Math.round(convertedAmount * 100) / 100
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
static async getSupportedCurrencies(baseCurrency: string = 'eur'): Promise<string[]> {
|
|
80
|
+
const url = `${this.baseUrl}@latest/v1/currencies/${baseCurrency.toLowerCase()}.json`;
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
const response = await fetch(url);
|
|
84
|
+
if (!response.ok) {
|
|
85
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const data: any = await response.json();
|
|
89
|
+
const rates = data[baseCurrency.toLowerCase()];
|
|
90
|
+
|
|
91
|
+
return Object.keys(rates).map(code => code.toUpperCase()).sort();
|
|
92
|
+
} catch (error) {
|
|
93
|
+
if (error instanceof Error) {
|
|
94
|
+
throw new Error(`Failed to fetch supported currencies: ${error.message}`);
|
|
95
|
+
}
|
|
96
|
+
throw new Error('Unknown error occurred while fetching supported currencies');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Exchange } from './exchange.js';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const CurrencyCodeSchema = z.string().length(3).regex(/^[A-Z]{3}$/);
|
|
4
|
+
|
|
5
|
+
export const ConvertCurrencyArgsSchema = z.object({
|
|
6
|
+
amount: z.number().positive(),
|
|
7
|
+
from_currency: CurrencyCodeSchema,
|
|
8
|
+
to_currency: CurrencyCodeSchema,
|
|
9
|
+
date: z.string().optional().describe('Date in YYYY-MM-DD format. If not provided, uses latest rates')
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export const GetExchangeRateArgsSchema = z.object({
|
|
13
|
+
from_currency: CurrencyCodeSchema,
|
|
14
|
+
to_currency: CurrencyCodeSchema,
|
|
15
|
+
date: z.string().optional().describe('Date in YYYY-MM-DD format. If not provided, uses latest rates')
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export type ConvertCurrencyArgs = z.infer<typeof ConvertCurrencyArgsSchema>;
|
|
19
|
+
export type GetExchangeRateArgs = z.infer<typeof GetExchangeRateArgsSchema>;
|
|
20
|
+
|
|
21
|
+
export interface CurrencyApiResponse {
|
|
22
|
+
[key: string]: {
|
|
23
|
+
[currencyCode: string]: number;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ExchangeRateResult {
|
|
28
|
+
rate: number;
|
|
29
|
+
from_currency: string;
|
|
30
|
+
to_currency: string;
|
|
31
|
+
date: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ConversionResult extends ExchangeRateResult {
|
|
35
|
+
amount: number;
|
|
36
|
+
converted_amount: number;
|
|
37
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { Exchange } from '../programs/index.js';
|
|
4
|
+
|
|
5
|
+
const convertCurrencySchema = z.object({
|
|
6
|
+
amount: z.number().positive().describe('The amount to convert (must be positive)'),
|
|
7
|
+
from_currency: z.string().length(3).regex(/^[A-Z]{3}$/).describe('Source currency code (3 letters, e.g., USD, EUR, NOK)'),
|
|
8
|
+
to_currency: z.string().length(3).regex(/^[A-Z]{3}$/).describe('Target currency code (3 letters, e.g., USD, EUR, NOK)'),
|
|
9
|
+
date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().describe('Optional date in YYYY-MM-DD format for historical rates. If not provided, uses latest rates')
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const getExchangeRateSchema = z.object({
|
|
13
|
+
from_currency: z.string().length(3).regex(/^[A-Z]{3}$/).describe('Source currency code (3 letters, e.g., USD, EUR, NOK)'),
|
|
14
|
+
to_currency: z.string().length(3).regex(/^[A-Z]{3}$/).describe('Target currency code (3 letters, e.g., USD, EUR, NOK)'),
|
|
15
|
+
date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().describe('Optional date in YYYY-MM-DD format for historical rates. If not provided, uses latest rates')
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export function registerCurrencyExchangeTools(server: McpServer) {
|
|
19
|
+
server.registerTool(
|
|
20
|
+
'convert_currency',
|
|
21
|
+
{
|
|
22
|
+
description: 'Convert an amount from one currency to another using current or historical exchange rates',
|
|
23
|
+
inputSchema: convertCurrencySchema,
|
|
24
|
+
},
|
|
25
|
+
async ({ amount, from_currency, to_currency, date }) => {
|
|
26
|
+
try {
|
|
27
|
+
const result = await Exchange.convertCurrency({
|
|
28
|
+
amount,
|
|
29
|
+
fromCurrency: from_currency,
|
|
30
|
+
toCurrency: to_currency,
|
|
31
|
+
date
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
content: [
|
|
36
|
+
{
|
|
37
|
+
type: 'text' as const,
|
|
38
|
+
text: JSON.stringify(result, null, 4),
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
} catch (error) {
|
|
43
|
+
return {
|
|
44
|
+
content: [
|
|
45
|
+
{
|
|
46
|
+
type: 'text' as const,
|
|
47
|
+
text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
isError: true,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
server.registerTool(
|
|
57
|
+
'get_exchange_rate',
|
|
58
|
+
{
|
|
59
|
+
description: 'Get the exchange rate between two currencies',
|
|
60
|
+
inputSchema: getExchangeRateSchema,
|
|
61
|
+
},
|
|
62
|
+
async ({ from_currency, to_currency, date }) => {
|
|
63
|
+
try {
|
|
64
|
+
const result = await Exchange.getExchangeRate({
|
|
65
|
+
fromCurrency: from_currency,
|
|
66
|
+
toCurrency: to_currency,
|
|
67
|
+
date
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
content: [
|
|
72
|
+
{
|
|
73
|
+
type: 'text' as const,
|
|
74
|
+
text: JSON.stringify(result, null, 4),
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
} catch (error) {
|
|
79
|
+
return {
|
|
80
|
+
content: [
|
|
81
|
+
{
|
|
82
|
+
type: 'text' as const,
|
|
83
|
+
text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
isError: true,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"allowSyntheticDefaultImports": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"allowJs": true,
|
|
9
|
+
"outDir": "./build",
|
|
10
|
+
"rootDir": "./src",
|
|
11
|
+
"strict": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"forceConsistentCasingInFileNames": true,
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"declaration": true,
|
|
16
|
+
"declarationMap": true,
|
|
17
|
+
"sourceMap": true
|
|
18
|
+
},
|
|
19
|
+
"include": [
|
|
20
|
+
"src/**/*"
|
|
21
|
+
],
|
|
22
|
+
"exclude": [
|
|
23
|
+
"node_modules",
|
|
24
|
+
"build"
|
|
25
|
+
]
|
|
26
|
+
}
|