oilpriceapi-mcp 1.1.1 → 2.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 +74 -77
- package/build/__tests__/index.test.d.ts +2 -0
- package/build/__tests__/index.test.d.ts.map +1 -0
- package/build/__tests__/index.test.js +362 -0
- package/build/__tests__/index.test.js.map +1 -0
- package/build/index.d.ts +42 -3
- package/build/index.d.ts.map +1 -1
- package/build/index.js +633 -149
- package/build/index.js.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -7,11 +7,12 @@
|
|
|
7
7
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
10
|
+
- **14 Tools** — spot prices, history, futures, marine fuels, rig counts, diesel by state, storage, OPEC production, forecasts
|
|
11
|
+
- **5 Resources** — subscribable price snapshots for Brent, WTI, Natural Gas, Diesel, and all commodities
|
|
12
|
+
- **6 Prompts** — pre-built analyst templates (daily briefing, spread analysis, gas markets, commodity report, diesel costs, supply analysis)
|
|
13
13
|
- **Natural language** — ask for "brent oil" or "natural gas", not codes
|
|
14
|
-
- **
|
|
14
|
+
- **70+ commodities** — oil, gas, coal, refined products, metals, forex, bunker fuels, state diesel
|
|
15
|
+
- **Smart errors** — unrecognized commodities get suggestions, not silent fallbacks
|
|
15
16
|
|
|
16
17
|
## Quick Start
|
|
17
18
|
|
|
@@ -118,45 +119,49 @@ Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
|
118
119
|
npm install -g oilpriceapi-mcp
|
|
119
120
|
```
|
|
120
121
|
|
|
121
|
-
##
|
|
122
|
+
## Environment Variables
|
|
122
123
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
| Variable | Required | Description |
|
|
125
|
+
| ---------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
126
|
+
| `OILPRICEAPI_KEY` | Yes | API key from [oilpriceapi.com/signup](https://www.oilpriceapi.com/signup?utm_source=npm&utm_medium=mcp&utm_campaign=readme). Free tier: 200 requests/month. |
|
|
127
|
+
| `OILPRICEAPI_BASE_URL` | No | Override API base URL (for staging/testing). Default: `https://api.oilpriceapi.com` |
|
|
126
128
|
|
|
127
129
|
## Tools
|
|
128
130
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
131
|
+
All tools are prefixed with `opa_` to avoid name collisions when multiple MCP servers are loaded.
|
|
132
|
+
|
|
133
|
+
| Tool | Description |
|
|
134
|
+
| ------------------------- | ---------------------------------------------------------------- |
|
|
135
|
+
| `opa_get_price` | Current spot price for a single commodity |
|
|
136
|
+
| `opa_market_overview` | All commodity prices in one call, grouped by category |
|
|
137
|
+
| `opa_compare_prices` | Side-by-side comparison of 2-5 commodities with spread |
|
|
138
|
+
| `opa_list_commodities` | Full commodity catalog (fetched live from API) |
|
|
139
|
+
| `opa_get_history` | Historical prices with high/low/avg/change (day/week/month/year) |
|
|
140
|
+
| `opa_get_futures` | Front-month futures price (Brent BZ or WTI CL) |
|
|
141
|
+
| `opa_get_futures_curve` | Full forward curve with contango/backwardation analysis |
|
|
142
|
+
| `opa_get_marine_fuels` | Bunker fuel prices by port and fuel type (VLSFO/MGO/IFO380) |
|
|
143
|
+
| `opa_get_rig_counts` | Baker Hughes US rig count with week-over-week change |
|
|
144
|
+
| `opa_get_drilling` | Drilling intelligence: wells, permits, completions by region |
|
|
145
|
+
| `opa_get_diesel_by_state` | AAA retail diesel price for any US state (50 states + DC) |
|
|
146
|
+
| `opa_get_storage` | Cushing and SPR oil storage/inventory levels |
|
|
147
|
+
| `opa_get_opec_production` | OPEC country-level production data |
|
|
148
|
+
| `opa_get_forecasts` | EIA STEO energy price forecasts |
|
|
149
|
+
|
|
150
|
+
## Example Questions
|
|
132
151
|
|
|
133
152
|
```
|
|
134
153
|
"What's the current Brent oil price?"
|
|
135
|
-
"
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
"
|
|
144
|
-
"Show all oil prices"
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
### `compare_prices`
|
|
148
|
-
|
|
149
|
-
Compare prices between 2-5 commodities.
|
|
150
|
-
|
|
151
|
-
```
|
|
152
|
-
"Compare Brent and WTI prices"
|
|
153
|
-
"What's the spread between US and European gas?"
|
|
154
|
+
"Compare Brent and WTI crude"
|
|
155
|
+
"Show me oil prices for the past month"
|
|
156
|
+
"What's diesel cost in California vs Texas?"
|
|
157
|
+
"Give me a market overview of refined products"
|
|
158
|
+
"What's the Brent futures curve look like?"
|
|
159
|
+
"How many oil rigs are active in the US?"
|
|
160
|
+
"What are OPEC production levels?"
|
|
161
|
+
"What are bunker fuel prices in Singapore?"
|
|
162
|
+
"Show me Cushing storage levels"
|
|
154
163
|
```
|
|
155
164
|
|
|
156
|
-
### `list_commodities`
|
|
157
|
-
|
|
158
|
-
List all available commodities and their codes.
|
|
159
|
-
|
|
160
165
|
## Resources
|
|
161
166
|
|
|
162
167
|
Subscribable price data (JSON):
|
|
@@ -166,72 +171,64 @@ Subscribable price data (JSON):
|
|
|
166
171
|
| Brent Crude | `price://brent` | Global benchmark crude oil price |
|
|
167
172
|
| WTI Crude | `price://wti` | US benchmark crude oil price |
|
|
168
173
|
| Natural Gas | `price://natural-gas` | US Henry Hub natural gas price |
|
|
174
|
+
| Diesel | `price://diesel` | US national average diesel price |
|
|
169
175
|
| All Prices | `price://all` | All tracked commodity prices |
|
|
170
176
|
|
|
171
177
|
## Prompts
|
|
172
178
|
|
|
173
179
|
Pre-built analyst templates:
|
|
174
180
|
|
|
175
|
-
| Prompt
|
|
176
|
-
|
|
|
177
|
-
| `daily-briefing`
|
|
178
|
-
| `brent-wti-spread`
|
|
179
|
-
| `gas-market-analysis`
|
|
180
|
-
| `commodity-report`
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
### Crude Oil
|
|
185
|
-
|
|
186
|
-
- Brent Crude (global benchmark)
|
|
187
|
-
- WTI (US benchmark)
|
|
188
|
-
- Urals (Russian)
|
|
189
|
-
- Dubai (Middle East)
|
|
190
|
-
|
|
191
|
-
### Natural Gas
|
|
192
|
-
|
|
193
|
-
- US Henry Hub ($/MMBtu)
|
|
194
|
-
- UK NBP (pence/therm)
|
|
195
|
-
- European TTF (EUR/MWh)
|
|
196
|
-
|
|
197
|
-
### Coal
|
|
198
|
-
|
|
199
|
-
- Thermal Coal
|
|
200
|
-
- Newcastle Coal (Asia-Pacific)
|
|
201
|
-
|
|
202
|
-
### Refined Products
|
|
203
|
-
|
|
204
|
-
- Diesel, Gasoline, RBOB Gasoline, Jet Fuel, Heating Oil
|
|
205
|
-
|
|
206
|
-
### Other
|
|
207
|
-
|
|
208
|
-
- Gold, EU Carbon Allowances, EUR/USD, GBP/USD
|
|
181
|
+
| Prompt | Description |
|
|
182
|
+
| ---------------------- | --------------------------------------------------------- |
|
|
183
|
+
| `daily-briefing` | Energy market daily briefing with key prices and movers |
|
|
184
|
+
| `brent-wti-spread` | Analyze the Brent-WTI crude oil spread |
|
|
185
|
+
| `gas-market-analysis` | Compare US vs European natural gas markets |
|
|
186
|
+
| `commodity-report` | Detailed report on a specific commodity (parameterized) |
|
|
187
|
+
| `diesel-cost-analysis` | Compare diesel prices across US states for fleet planning |
|
|
188
|
+
| `supply-analysis` | Analyze supply using OPEC production, rig counts, storage |
|
|
209
189
|
|
|
210
190
|
## Natural Language Support
|
|
211
191
|
|
|
212
|
-
| You say
|
|
213
|
-
|
|
|
214
|
-
| "brent oil", "brent crude"
|
|
215
|
-
| "wti", "us oil"
|
|
216
|
-
| "natural gas", "henry hub"
|
|
217
|
-
| "european gas", "ttf"
|
|
218
|
-
| "diesel"
|
|
219
|
-
| "gold"
|
|
192
|
+
| You say | We understand |
|
|
193
|
+
| --------------------------- | --------------- |
|
|
194
|
+
| "brent oil", "brent crude" | BRENT_CRUDE_USD |
|
|
195
|
+
| "wti", "us oil" | WTI_USD |
|
|
196
|
+
| "natural gas", "henry hub" | NATURAL_GAS_USD |
|
|
197
|
+
| "european gas", "ttf" | DUTCH_TTF_EUR |
|
|
198
|
+
| "diesel" | DIESEL_USD |
|
|
199
|
+
| "gold" | GOLD_USD |
|
|
200
|
+
| "jet fuel", "aviation fuel" | JET_FUEL_USD |
|
|
201
|
+
| "carbon", "carbon credits" | EU_CARBON_EUR |
|
|
220
202
|
|
|
221
203
|
## Development
|
|
222
204
|
|
|
223
205
|
```bash
|
|
224
206
|
npm install
|
|
225
207
|
npm run build
|
|
208
|
+
npm test
|
|
226
209
|
OILPRICEAPI_KEY=your-key node build/index.js
|
|
227
210
|
```
|
|
228
211
|
|
|
212
|
+
## Breaking Changes in v2.0.0
|
|
213
|
+
|
|
214
|
+
- All tool names now use `opa_` prefix (e.g., `get_commodity_price` -> `opa_get_price`)
|
|
215
|
+
- Unrecognized commodity names now return an error with suggestions instead of silently defaulting to Brent
|
|
216
|
+
- `list_commodities` now fetches live from the API (falls back to static list if unavailable)
|
|
217
|
+
|
|
229
218
|
## License
|
|
230
219
|
|
|
231
220
|
MIT
|
|
232
221
|
|
|
233
222
|
## Links
|
|
234
223
|
|
|
235
|
-
- [OilPriceAPI](https://oilpriceapi.com)
|
|
224
|
+
- [OilPriceAPI](https://www.oilpriceapi.com)
|
|
236
225
|
- [API Documentation](https://docs.oilpriceapi.com)
|
|
226
|
+
- [Pricing](https://www.oilpriceapi.com/pricing?utm_source=npm&utm_medium=mcp&utm_campaign=pricing)
|
|
237
227
|
- [MCP Protocol](https://modelcontextprotocol.io)
|
|
228
|
+
|
|
229
|
+
## Also Available As
|
|
230
|
+
|
|
231
|
+
- **[Python SDK](https://pypi.org/project/oilpriceapi/)** - Python client with Pandas integration
|
|
232
|
+
- **[Node.js SDK](https://www.npmjs.com/package/oilpriceapi)** - TypeScript/JavaScript SDK
|
|
233
|
+
- **[Go SDK](https://github.com/OilpriceAPI/oilpriceapi-go)** - Idiomatic Go client
|
|
234
|
+
- **[OpenBB Integration](https://pypi.org/project/openbb-oilpriceapi/)** - OpenBB Platform provider
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { resolveCommodityCode, resolveStateCode, formatPrice, makeApiRequest, COMMODITY_ALIASES, COMMODITY_INFO, } from "../index.js";
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// resolveCommodityCode
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
describe("resolveCommodityCode", () => {
|
|
7
|
+
it("resolves 'brent' alias to BRENT_CRUDE_USD", () => {
|
|
8
|
+
expect(resolveCommodityCode("brent")).toBe("BRENT_CRUDE_USD");
|
|
9
|
+
});
|
|
10
|
+
it("resolves 'brent crude' alias to BRENT_CRUDE_USD", () => {
|
|
11
|
+
expect(resolveCommodityCode("brent crude")).toBe("BRENT_CRUDE_USD");
|
|
12
|
+
});
|
|
13
|
+
it("resolves 'natural gas' alias to NATURAL_GAS_USD", () => {
|
|
14
|
+
expect(resolveCommodityCode("natural gas")).toBe("NATURAL_GAS_USD");
|
|
15
|
+
});
|
|
16
|
+
it("resolves 'wti' alias to WTI_USD", () => {
|
|
17
|
+
expect(resolveCommodityCode("wti")).toBe("WTI_USD");
|
|
18
|
+
});
|
|
19
|
+
it("passes through a valid commodity code unchanged (WTI_USD)", () => {
|
|
20
|
+
expect(resolveCommodityCode("WTI_USD")).toBe("WTI_USD");
|
|
21
|
+
});
|
|
22
|
+
it("passes through a valid commodity code regardless of case (wti_usd)", () => {
|
|
23
|
+
expect(resolveCommodityCode("wti_usd")).toBe("WTI_USD");
|
|
24
|
+
});
|
|
25
|
+
it("passes through BRENT_CRUDE_USD unchanged", () => {
|
|
26
|
+
expect(resolveCommodityCode("BRENT_CRUDE_USD")).toBe("BRENT_CRUDE_USD");
|
|
27
|
+
});
|
|
28
|
+
it("returns null for unknown input", () => {
|
|
29
|
+
expect(resolveCommodityCode("unknown_commodity_xyz")).toBeNull();
|
|
30
|
+
});
|
|
31
|
+
it("returns null for garbage input", () => {
|
|
32
|
+
expect(resolveCommodityCode("!!!")).toBeNull();
|
|
33
|
+
});
|
|
34
|
+
it("resolves case-insensitive alias ('BRENT')", () => {
|
|
35
|
+
expect(resolveCommodityCode("BRENT")).toBe("BRENT_CRUDE_USD");
|
|
36
|
+
});
|
|
37
|
+
it("resolves 'ttf' alias to DUTCH_TTF_EUR", () => {
|
|
38
|
+
expect(resolveCommodityCode("ttf")).toBe("DUTCH_TTF_EUR");
|
|
39
|
+
});
|
|
40
|
+
it("resolves 'gold' alias to GOLD_USD", () => {
|
|
41
|
+
expect(resolveCommodityCode("gold")).toBe("GOLD_USD");
|
|
42
|
+
});
|
|
43
|
+
it("resolves 'carbon' alias to EU_CARBON_EUR", () => {
|
|
44
|
+
expect(resolveCommodityCode("carbon")).toBe("EU_CARBON_EUR");
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// resolveStateCode
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
describe("resolveStateCode", () => {
|
|
51
|
+
it("resolves a 2-letter code ('CA')", () => {
|
|
52
|
+
expect(resolveStateCode("CA")).toBe("CA");
|
|
53
|
+
});
|
|
54
|
+
it("resolves lowercase 2-letter code ('tx')", () => {
|
|
55
|
+
expect(resolveStateCode("tx")).toBe("TX");
|
|
56
|
+
});
|
|
57
|
+
it("resolves full state name ('California')", () => {
|
|
58
|
+
expect(resolveStateCode("California")).toBe("CA");
|
|
59
|
+
});
|
|
60
|
+
it("resolves multi-word state name ('New York')", () => {
|
|
61
|
+
expect(resolveStateCode("New York")).toBe("NY");
|
|
62
|
+
});
|
|
63
|
+
it("resolves 'district of columbia' to DC", () => {
|
|
64
|
+
expect(resolveStateCode("district of columbia")).toBe("DC");
|
|
65
|
+
});
|
|
66
|
+
it("returns null for invalid 2-letter code", () => {
|
|
67
|
+
expect(resolveStateCode("ZZ")).toBeNull();
|
|
68
|
+
});
|
|
69
|
+
it("returns null for unrecognized input", () => {
|
|
70
|
+
expect(resolveStateCode("Middle Earth")).toBeNull();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// formatPrice
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
describe("formatPrice", () => {
|
|
77
|
+
it("formats a USD price with all fields", () => {
|
|
78
|
+
const data = {
|
|
79
|
+
code: "BRENT_CRUDE_USD",
|
|
80
|
+
price: 85.42,
|
|
81
|
+
currency: "USD",
|
|
82
|
+
change_24h: 1.23,
|
|
83
|
+
change_24h_percent: 1.46,
|
|
84
|
+
updated_at: "2024-01-15T10:30:00Z",
|
|
85
|
+
};
|
|
86
|
+
const result = formatPrice(data);
|
|
87
|
+
expect(result).toContain("Brent Crude Oil");
|
|
88
|
+
expect(result).toContain("$85.42");
|
|
89
|
+
expect(result).toContain("barrel");
|
|
90
|
+
expect(result).toContain("+$1.23");
|
|
91
|
+
expect(result).toContain("+1.46%");
|
|
92
|
+
expect(result).toContain("Updated:");
|
|
93
|
+
});
|
|
94
|
+
it("formats a price with missing change fields", () => {
|
|
95
|
+
const data = {
|
|
96
|
+
code: "WTI_USD",
|
|
97
|
+
price: 80.0,
|
|
98
|
+
currency: "USD",
|
|
99
|
+
};
|
|
100
|
+
const result = formatPrice(data);
|
|
101
|
+
expect(result).toContain("WTI Crude Oil");
|
|
102
|
+
expect(result).toContain("$80.00");
|
|
103
|
+
expect(result).not.toContain("24h Change");
|
|
104
|
+
expect(result).not.toContain("Updated:");
|
|
105
|
+
});
|
|
106
|
+
it("formats negative 24h change correctly", () => {
|
|
107
|
+
const data = {
|
|
108
|
+
code: "BRENT_CRUDE_USD",
|
|
109
|
+
price: 83.0,
|
|
110
|
+
currency: "USD",
|
|
111
|
+
change_24h: -2.5,
|
|
112
|
+
change_24h_percent: -2.93,
|
|
113
|
+
};
|
|
114
|
+
const result = formatPrice(data);
|
|
115
|
+
expect(result).toContain("-$2.50");
|
|
116
|
+
expect(result).toContain("-2.93%");
|
|
117
|
+
expect(result).not.toMatch(/\+\$-/);
|
|
118
|
+
});
|
|
119
|
+
it("formats EUR currency with euro symbol", () => {
|
|
120
|
+
const data = {
|
|
121
|
+
code: "EU_CARBON_EUR",
|
|
122
|
+
price: 62.5,
|
|
123
|
+
currency: "EUR",
|
|
124
|
+
};
|
|
125
|
+
const result = formatPrice(data);
|
|
126
|
+
expect(result).toContain("€62.50");
|
|
127
|
+
expect(result).not.toContain("$62.50");
|
|
128
|
+
});
|
|
129
|
+
it("formats GBP currency with pound symbol", () => {
|
|
130
|
+
const data = {
|
|
131
|
+
code: "NATURAL_GAS_GBP",
|
|
132
|
+
price: 75.3,
|
|
133
|
+
currency: "GBP",
|
|
134
|
+
};
|
|
135
|
+
const result = formatPrice(data);
|
|
136
|
+
expect(result).toContain("£75.30");
|
|
137
|
+
expect(result).not.toContain("$75.30");
|
|
138
|
+
});
|
|
139
|
+
it("formats GBp (pence) currency with pound symbol", () => {
|
|
140
|
+
const data = {
|
|
141
|
+
code: "NATURAL_GAS_GBP",
|
|
142
|
+
price: 80.0,
|
|
143
|
+
currency: "GBp",
|
|
144
|
+
};
|
|
145
|
+
const result = formatPrice(data);
|
|
146
|
+
expect(result).toContain("£80.00");
|
|
147
|
+
});
|
|
148
|
+
it("uses created_at as fallback timestamp when updated_at is absent", () => {
|
|
149
|
+
const data = {
|
|
150
|
+
code: "BRENT_CRUDE_USD",
|
|
151
|
+
price: 85.0,
|
|
152
|
+
currency: "USD",
|
|
153
|
+
created_at: "2024-03-01T08:00:00Z",
|
|
154
|
+
};
|
|
155
|
+
const result = formatPrice(data);
|
|
156
|
+
expect(result).toContain("Updated:");
|
|
157
|
+
});
|
|
158
|
+
it("handles unknown code gracefully (falls back to code as name)", () => {
|
|
159
|
+
const data = {
|
|
160
|
+
code: "SOME_UNKNOWN_CODE",
|
|
161
|
+
price: 100.0,
|
|
162
|
+
currency: "USD",
|
|
163
|
+
};
|
|
164
|
+
const result = formatPrice(data);
|
|
165
|
+
expect(result).toContain("SOME_UNKNOWN_CODE");
|
|
166
|
+
expect(result).toContain("$100.00");
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
// makeApiRequest — basic success/failure (no retries, no delays)
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
describe("makeApiRequest - basic", () => {
|
|
173
|
+
beforeEach(() => {
|
|
174
|
+
vi.clearAllMocks();
|
|
175
|
+
});
|
|
176
|
+
it("returns parsed data on a successful 200 response", async () => {
|
|
177
|
+
const mockPayload = { status: "success", data: { price: 85.42 } };
|
|
178
|
+
const mockFetch = vi.fn().mockResolvedValue({
|
|
179
|
+
ok: true,
|
|
180
|
+
status: 200,
|
|
181
|
+
json: async () => mockPayload,
|
|
182
|
+
headers: { get: () => null },
|
|
183
|
+
});
|
|
184
|
+
const result = await makeApiRequest("/v1/prices/latest?by_code=BRENT_CRUDE_USD", mockFetch);
|
|
185
|
+
expect(result).toEqual(mockPayload);
|
|
186
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
187
|
+
});
|
|
188
|
+
it("returns null on 401 without retrying", async () => {
|
|
189
|
+
const mockFetch = vi.fn().mockResolvedValue({
|
|
190
|
+
ok: false,
|
|
191
|
+
status: 401,
|
|
192
|
+
statusText: "Unauthorized",
|
|
193
|
+
headers: { get: () => null },
|
|
194
|
+
});
|
|
195
|
+
const result = await makeApiRequest("/v1/prices/latest", mockFetch);
|
|
196
|
+
expect(result).toBeNull();
|
|
197
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
// makeApiRequest — retry behaviour (fake timers to avoid slow waits)
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
describe("makeApiRequest - retry behaviour", () => {
|
|
204
|
+
beforeEach(() => {
|
|
205
|
+
vi.clearAllMocks();
|
|
206
|
+
vi.useFakeTimers();
|
|
207
|
+
});
|
|
208
|
+
afterEach(() => {
|
|
209
|
+
vi.useRealTimers();
|
|
210
|
+
});
|
|
211
|
+
async function runWithFakeTimers(endpoint, mockFetch) {
|
|
212
|
+
const promise = makeApiRequest(endpoint, mockFetch);
|
|
213
|
+
await vi.runAllTimersAsync();
|
|
214
|
+
return promise;
|
|
215
|
+
}
|
|
216
|
+
it("returns null on 429 after exhausting all retries", async () => {
|
|
217
|
+
const mockFetch = vi.fn().mockResolvedValue({
|
|
218
|
+
ok: false,
|
|
219
|
+
status: 429,
|
|
220
|
+
statusText: "Too Many Requests",
|
|
221
|
+
headers: { get: () => null },
|
|
222
|
+
});
|
|
223
|
+
const result = await runWithFakeTimers("/v1/prices/latest", mockFetch);
|
|
224
|
+
expect(result).toBeNull();
|
|
225
|
+
expect(mockFetch).toHaveBeenCalledTimes(4);
|
|
226
|
+
});
|
|
227
|
+
it("returns null on network error after exhausting all retries", async () => {
|
|
228
|
+
const mockFetch = vi
|
|
229
|
+
.fn()
|
|
230
|
+
.mockRejectedValue(new Error("Network connection refused"));
|
|
231
|
+
const result = await runWithFakeTimers("/v1/prices/latest", mockFetch);
|
|
232
|
+
expect(result).toBeNull();
|
|
233
|
+
expect(mockFetch).toHaveBeenCalledTimes(4);
|
|
234
|
+
});
|
|
235
|
+
it("succeeds on second attempt after initial 429", async () => {
|
|
236
|
+
const mockPayload = { status: "success", data: { price: 82.0 } };
|
|
237
|
+
const mockFetch = vi
|
|
238
|
+
.fn()
|
|
239
|
+
.mockResolvedValueOnce({
|
|
240
|
+
ok: false,
|
|
241
|
+
status: 429,
|
|
242
|
+
statusText: "Too Many Requests",
|
|
243
|
+
headers: { get: () => null },
|
|
244
|
+
})
|
|
245
|
+
.mockResolvedValueOnce({
|
|
246
|
+
ok: true,
|
|
247
|
+
status: 200,
|
|
248
|
+
json: async () => mockPayload,
|
|
249
|
+
headers: { get: () => null },
|
|
250
|
+
});
|
|
251
|
+
const result = await runWithFakeTimers("/v1/prices/latest", mockFetch);
|
|
252
|
+
expect(result).toEqual(mockPayload);
|
|
253
|
+
expect(mockFetch).toHaveBeenCalledTimes(2);
|
|
254
|
+
});
|
|
255
|
+
it("succeeds after two 500 errors then a 200", async () => {
|
|
256
|
+
const mockPayload = { status: "success", data: { price: 79.0 } };
|
|
257
|
+
const mockFetch = vi
|
|
258
|
+
.fn()
|
|
259
|
+
.mockResolvedValueOnce({
|
|
260
|
+
ok: false,
|
|
261
|
+
status: 500,
|
|
262
|
+
statusText: "Internal Server Error",
|
|
263
|
+
headers: { get: () => null },
|
|
264
|
+
})
|
|
265
|
+
.mockResolvedValueOnce({
|
|
266
|
+
ok: false,
|
|
267
|
+
status: 500,
|
|
268
|
+
statusText: "Internal Server Error",
|
|
269
|
+
headers: { get: () => null },
|
|
270
|
+
})
|
|
271
|
+
.mockResolvedValueOnce({
|
|
272
|
+
ok: true,
|
|
273
|
+
status: 200,
|
|
274
|
+
json: async () => mockPayload,
|
|
275
|
+
headers: { get: () => null },
|
|
276
|
+
});
|
|
277
|
+
const result = await runWithFakeTimers("/v1/prices/latest", mockFetch);
|
|
278
|
+
expect(result).toEqual(mockPayload);
|
|
279
|
+
expect(mockFetch).toHaveBeenCalledTimes(3);
|
|
280
|
+
});
|
|
281
|
+
it("respects Retry-After header on 429", async () => {
|
|
282
|
+
const mockPayload = { status: "success", data: { price: 80.0 } };
|
|
283
|
+
const mockFetch = vi
|
|
284
|
+
.fn()
|
|
285
|
+
.mockResolvedValueOnce({
|
|
286
|
+
ok: false,
|
|
287
|
+
status: 429,
|
|
288
|
+
statusText: "Too Many Requests",
|
|
289
|
+
headers: {
|
|
290
|
+
get: (name) => (name === "Retry-After" ? "5" : null),
|
|
291
|
+
},
|
|
292
|
+
})
|
|
293
|
+
.mockResolvedValueOnce({
|
|
294
|
+
ok: true,
|
|
295
|
+
status: 200,
|
|
296
|
+
json: async () => mockPayload,
|
|
297
|
+
headers: { get: () => null },
|
|
298
|
+
});
|
|
299
|
+
const result = await runWithFakeTimers("/v1/prices/latest", mockFetch);
|
|
300
|
+
expect(result).toEqual(mockPayload);
|
|
301
|
+
expect(mockFetch).toHaveBeenCalledTimes(2);
|
|
302
|
+
});
|
|
303
|
+
it("returns null when all retries are exhausted on 500", async () => {
|
|
304
|
+
const mockFetch = vi.fn().mockResolvedValue({
|
|
305
|
+
ok: false,
|
|
306
|
+
status: 500,
|
|
307
|
+
statusText: "Internal Server Error",
|
|
308
|
+
headers: { get: () => null },
|
|
309
|
+
});
|
|
310
|
+
const result = await runWithFakeTimers("/v1/prices/latest", mockFetch);
|
|
311
|
+
expect(result).toBeNull();
|
|
312
|
+
expect(mockFetch).toHaveBeenCalledTimes(4);
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
// ---------------------------------------------------------------------------
|
|
316
|
+
// COMMODITY_ALIASES and COMMODITY_INFO shape checks
|
|
317
|
+
// ---------------------------------------------------------------------------
|
|
318
|
+
describe("COMMODITY_ALIASES", () => {
|
|
319
|
+
it("has entries for major crude oil aliases", () => {
|
|
320
|
+
expect(COMMODITY_ALIASES["brent"]).toBe("BRENT_CRUDE_USD");
|
|
321
|
+
expect(COMMODITY_ALIASES["wti"]).toBe("WTI_USD");
|
|
322
|
+
expect(COMMODITY_ALIASES["urals"]).toBe("URALS_CRUDE_USD");
|
|
323
|
+
expect(COMMODITY_ALIASES["dubai"]).toBe("DUBAI_CRUDE_USD");
|
|
324
|
+
});
|
|
325
|
+
it("has entries for gas aliases", () => {
|
|
326
|
+
expect(COMMODITY_ALIASES["natural gas"]).toBe("NATURAL_GAS_USD");
|
|
327
|
+
expect(COMMODITY_ALIASES["ttf"]).toBe("DUTCH_TTF_EUR");
|
|
328
|
+
expect(COMMODITY_ALIASES["uk gas"]).toBe("NATURAL_GAS_GBP");
|
|
329
|
+
});
|
|
330
|
+
it("has entries for refined product aliases", () => {
|
|
331
|
+
expect(COMMODITY_ALIASES["diesel"]).toBe("DIESEL_USD");
|
|
332
|
+
expect(COMMODITY_ALIASES["gasoline"]).toBe("GASOLINE_USD");
|
|
333
|
+
expect(COMMODITY_ALIASES["jet fuel"]).toBe("JET_FUEL_USD");
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
describe("COMMODITY_INFO", () => {
|
|
337
|
+
it("provides name and unit for BRENT_CRUDE_USD", () => {
|
|
338
|
+
const info = COMMODITY_INFO["BRENT_CRUDE_USD"];
|
|
339
|
+
expect(info).toBeDefined();
|
|
340
|
+
expect(info.name).toBe("Brent Crude Oil");
|
|
341
|
+
expect(info.unit).toBe("barrel");
|
|
342
|
+
});
|
|
343
|
+
it("provides name and unit for DUTCH_TTF_EUR", () => {
|
|
344
|
+
const info = COMMODITY_INFO["DUTCH_TTF_EUR"];
|
|
345
|
+
expect(info).toBeDefined();
|
|
346
|
+
expect(info.name).toBe("European Natural Gas (TTF)");
|
|
347
|
+
expect(info.unit).toBe("MWh");
|
|
348
|
+
});
|
|
349
|
+
it("provides name and unit for EU_CARBON_EUR", () => {
|
|
350
|
+
const info = COMMODITY_INFO["EU_CARBON_EUR"];
|
|
351
|
+
expect(info).toBeDefined();
|
|
352
|
+
expect(info.name).toBe("EU Carbon Allowances");
|
|
353
|
+
expect(info.unit).toBe("metric ton CO2");
|
|
354
|
+
});
|
|
355
|
+
it("provides name and unit for GOLD_USD", () => {
|
|
356
|
+
const info = COMMODITY_INFO["GOLD_USD"];
|
|
357
|
+
expect(info).toBeDefined();
|
|
358
|
+
expect(info.name).toBe("Gold");
|
|
359
|
+
expect(info.unit).toBe("troy oz");
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
//# sourceMappingURL=index.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/__tests__/index.test.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
CHANGED
|
@@ -1,12 +1,51 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* OilPriceAPI MCP Server
|
|
3
|
+
* OilPriceAPI MCP Server v2.0.0
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* The energy commodity MCP server. Real-time oil, gas, and commodity prices
|
|
6
|
+
* for Claude, Cursor, VS Code, and any MCP-compatible client.
|
|
7
7
|
*
|
|
8
8
|
* @see https://oilpriceapi.com
|
|
9
9
|
* @see https://modelcontextprotocol.io
|
|
10
10
|
*/
|
|
11
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
12
|
+
export declare const USER_AGENT = "oilpriceapi-mcp/2.0.0";
|
|
13
|
+
export declare const COMMODITY_ALIASES: Record<string, string>;
|
|
14
|
+
export declare const COMMODITY_INFO: Record<string, {
|
|
15
|
+
name: string;
|
|
16
|
+
unit: string;
|
|
17
|
+
}>;
|
|
18
|
+
export declare const COMMODITY_CODES: readonly ["BRENT_CRUDE_USD", "WTI_USD", "URALS_CRUDE_USD", "DUBAI_CRUDE_USD", "NATURAL_GAS_USD", "NATURAL_GAS_GBP", "DUTCH_TTF_EUR", "COAL_USD", "NEWCASTLE_COAL_USD", "DIESEL_USD", "GASOLINE_USD", "GASOLINE_RBOB_USD", "JET_FUEL_USD", "HEATING_OIL_USD", "GOLD_USD", "GOLD_AM_USD", "GOLD_AM_GBP", "GOLD_AM_EUR", "GOLD_PM_USD", "GOLD_PM_GBP", "GOLD_PM_EUR", "SILVER_FIX_USD", "SILVER_FIX_GBP", "SILVER_FIX_EUR", "EU_CARBON_EUR", "EUR_USD", "GBP_USD"];
|
|
19
|
+
interface PriceData {
|
|
20
|
+
code: string;
|
|
21
|
+
price: number;
|
|
22
|
+
currency: string;
|
|
23
|
+
created_at?: string;
|
|
24
|
+
updated_at?: string;
|
|
25
|
+
change_24h?: number;
|
|
26
|
+
change_24h_percent?: number;
|
|
27
|
+
}
|
|
28
|
+
export interface ApiResponse<T> {
|
|
29
|
+
status: string;
|
|
30
|
+
data: T;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Resolve a natural language commodity name to its API code.
|
|
34
|
+
* Returns null if no match found — callers should return an actionable error.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveCommodityCode(input: string): string | null;
|
|
37
|
+
/**
|
|
38
|
+
* Format a price for display
|
|
39
|
+
*/
|
|
40
|
+
export declare function formatPrice(data: PriceData): string;
|
|
41
|
+
/**
|
|
42
|
+
* Make API request to OilPriceAPI with retry and exponential backoff
|
|
43
|
+
*/
|
|
44
|
+
export declare function makeApiRequest<T>(endpoint: string, fetchFn?: typeof fetch): Promise<T | null>;
|
|
45
|
+
/**
|
|
46
|
+
* Resolve a US state name or abbreviation to a 2-letter code.
|
|
47
|
+
*/
|
|
48
|
+
export declare function resolveStateCode(input: string): string | null;
|
|
49
|
+
export declare function createSandboxServer(): McpServer;
|
|
11
50
|
export {};
|
|
12
51
|
//# sourceMappingURL=index.d.ts.map
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;GAQG"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOpE,eAAO,MAAM,UAAU,0BAA0B,CAAC;AASlD,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA6EpD,CAAC;AAMF,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CA4BzE,CAAC;AAGF,eAAO,MAAM,eAAe,icA4BlB,CAAC;AA6DX,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,CAAC,CAAC;CACT;AAuED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA2BjE;AAyED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CA6BnD;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,CAAC,EACpC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CA0DnB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAe7D;AA6+BD,wBAAgB,mBAAmB,cAElC"}
|