@fre4x/fred 1.1.2 → 1.1.3
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 +8 -8
- package/dist/index.js +187 -127
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -10,14 +10,14 @@ The Federal Reserve publishes the data that governments and institutions use to
|
|
|
10
10
|
|
|
11
11
|
| Tool | What it reaches |
|
|
12
12
|
|------|----------------|
|
|
13
|
-
| `
|
|
14
|
-
| `
|
|
15
|
-
| `
|
|
16
|
-
| `
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
20
|
-
| `
|
|
13
|
+
| `search_series` | Full-text search across all FRED series |
|
|
14
|
+
| `get_series_info` | Metadata for a series — units, frequency, range, last update |
|
|
15
|
+
| `get_series_data` | Observation time-series for any series (e.g. `GDP`, `UNRATE`, `CPIAUCSL`) |
|
|
16
|
+
| `get_category_series` | All series under a given FRED category |
|
|
17
|
+
| `get_releases` | Index of all FRED data releases |
|
|
18
|
+
| `get_release_series` | Series belonging to a specific release |
|
|
19
|
+
| `get_sources` | All primary data sources in FRED |
|
|
20
|
+
| `get_source` | Details for one source |
|
|
21
21
|
|
|
22
22
|
All list tools support pagination via `limit` / `offset`.
|
|
23
23
|
|
package/dist/index.js
CHANGED
|
@@ -7065,9 +7065,9 @@ var require_combined_stream = __commonJS({
|
|
|
7065
7065
|
}
|
|
7066
7066
|
});
|
|
7067
7067
|
|
|
7068
|
-
// ../node_modules/form-data/node_modules/mime-db/db.json
|
|
7068
|
+
// ../node_modules/form-data/node_modules/mime-types/node_modules/mime-db/db.json
|
|
7069
7069
|
var require_db = __commonJS({
|
|
7070
|
-
"../node_modules/form-data/node_modules/mime-db/db.json"(exports, module) {
|
|
7070
|
+
"../node_modules/form-data/node_modules/mime-types/node_modules/mime-db/db.json"(exports, module) {
|
|
7071
7071
|
module.exports = {
|
|
7072
7072
|
"application/1d-interleaved-parityfec": {
|
|
7073
7073
|
source: "iana"
|
|
@@ -15590,9 +15590,9 @@ var require_db = __commonJS({
|
|
|
15590
15590
|
}
|
|
15591
15591
|
});
|
|
15592
15592
|
|
|
15593
|
-
// ../node_modules/form-data/node_modules/mime-db/index.js
|
|
15593
|
+
// ../node_modules/form-data/node_modules/mime-types/node_modules/mime-db/index.js
|
|
15594
15594
|
var require_mime_db = __commonJS({
|
|
15595
|
-
"../node_modules/form-data/node_modules/mime-db/index.js"(exports, module) {
|
|
15595
|
+
"../node_modules/form-data/node_modules/mime-types/node_modules/mime-db/index.js"(exports, module) {
|
|
15596
15596
|
module.exports = require_db();
|
|
15597
15597
|
}
|
|
15598
15598
|
});
|
|
@@ -16764,7 +16764,7 @@ var require_form_data = __commonJS({
|
|
|
16764
16764
|
var path = __require("path");
|
|
16765
16765
|
var http3 = __require("http");
|
|
16766
16766
|
var https3 = __require("https");
|
|
16767
|
-
var
|
|
16767
|
+
var parseUrl = __require("url").parse;
|
|
16768
16768
|
var fs = __require("fs");
|
|
16769
16769
|
var Stream = __require("stream").Stream;
|
|
16770
16770
|
var crypto2 = __require("crypto");
|
|
@@ -17017,7 +17017,7 @@ var require_form_data = __commonJS({
|
|
|
17017
17017
|
var options;
|
|
17018
17018
|
var defaults2 = { method: "post" };
|
|
17019
17019
|
if (typeof params === "string") {
|
|
17020
|
-
params =
|
|
17020
|
+
params = parseUrl(params);
|
|
17021
17021
|
options = populate({
|
|
17022
17022
|
port: params.port,
|
|
17023
17023
|
path: params.pathname,
|
|
@@ -17074,6 +17074,76 @@ var require_form_data = __commonJS({
|
|
|
17074
17074
|
}
|
|
17075
17075
|
});
|
|
17076
17076
|
|
|
17077
|
+
// ../node_modules/proxy-from-env/index.js
|
|
17078
|
+
var require_proxy_from_env = __commonJS({
|
|
17079
|
+
"../node_modules/proxy-from-env/index.js"(exports) {
|
|
17080
|
+
"use strict";
|
|
17081
|
+
var parseUrl = __require("url").parse;
|
|
17082
|
+
var DEFAULT_PORTS = {
|
|
17083
|
+
ftp: 21,
|
|
17084
|
+
gopher: 70,
|
|
17085
|
+
http: 80,
|
|
17086
|
+
https: 443,
|
|
17087
|
+
ws: 80,
|
|
17088
|
+
wss: 443
|
|
17089
|
+
};
|
|
17090
|
+
var stringEndsWith = String.prototype.endsWith || function(s) {
|
|
17091
|
+
return s.length <= this.length && this.indexOf(s, this.length - s.length) !== -1;
|
|
17092
|
+
};
|
|
17093
|
+
function getProxyForUrl(url3) {
|
|
17094
|
+
var parsedUrl = typeof url3 === "string" ? parseUrl(url3) : url3 || {};
|
|
17095
|
+
var proto = parsedUrl.protocol;
|
|
17096
|
+
var hostname3 = parsedUrl.host;
|
|
17097
|
+
var port = parsedUrl.port;
|
|
17098
|
+
if (typeof hostname3 !== "string" || !hostname3 || typeof proto !== "string") {
|
|
17099
|
+
return "";
|
|
17100
|
+
}
|
|
17101
|
+
proto = proto.split(":", 1)[0];
|
|
17102
|
+
hostname3 = hostname3.replace(/:\d*$/, "");
|
|
17103
|
+
port = parseInt(port) || DEFAULT_PORTS[proto] || 0;
|
|
17104
|
+
if (!shouldProxy(hostname3, port)) {
|
|
17105
|
+
return "";
|
|
17106
|
+
}
|
|
17107
|
+
var proxy = getEnv("npm_config_" + proto + "_proxy") || getEnv(proto + "_proxy") || getEnv("npm_config_proxy") || getEnv("all_proxy");
|
|
17108
|
+
if (proxy && proxy.indexOf("://") === -1) {
|
|
17109
|
+
proxy = proto + "://" + proxy;
|
|
17110
|
+
}
|
|
17111
|
+
return proxy;
|
|
17112
|
+
}
|
|
17113
|
+
function shouldProxy(hostname3, port) {
|
|
17114
|
+
var NO_PROXY = (getEnv("npm_config_no_proxy") || getEnv("no_proxy")).toLowerCase();
|
|
17115
|
+
if (!NO_PROXY) {
|
|
17116
|
+
return true;
|
|
17117
|
+
}
|
|
17118
|
+
if (NO_PROXY === "*") {
|
|
17119
|
+
return false;
|
|
17120
|
+
}
|
|
17121
|
+
return NO_PROXY.split(/[,\s]/).every(function(proxy) {
|
|
17122
|
+
if (!proxy) {
|
|
17123
|
+
return true;
|
|
17124
|
+
}
|
|
17125
|
+
var parsedProxy = proxy.match(/^(.+):(\d+)$/);
|
|
17126
|
+
var parsedProxyHostname = parsedProxy ? parsedProxy[1] : proxy;
|
|
17127
|
+
var parsedProxyPort = parsedProxy ? parseInt(parsedProxy[2]) : 0;
|
|
17128
|
+
if (parsedProxyPort && parsedProxyPort !== port) {
|
|
17129
|
+
return true;
|
|
17130
|
+
}
|
|
17131
|
+
if (!/^[.*]/.test(parsedProxyHostname)) {
|
|
17132
|
+
return hostname3 !== parsedProxyHostname;
|
|
17133
|
+
}
|
|
17134
|
+
if (parsedProxyHostname.charAt(0) === "*") {
|
|
17135
|
+
parsedProxyHostname = parsedProxyHostname.slice(1);
|
|
17136
|
+
}
|
|
17137
|
+
return !stringEndsWith.call(hostname3, parsedProxyHostname);
|
|
17138
|
+
});
|
|
17139
|
+
}
|
|
17140
|
+
function getEnv(key) {
|
|
17141
|
+
return process.env[key.toLowerCase()] || process.env[key.toUpperCase()] || "";
|
|
17142
|
+
}
|
|
17143
|
+
exports.getProxyForUrl = getProxyForUrl;
|
|
17144
|
+
}
|
|
17145
|
+
});
|
|
17146
|
+
|
|
17077
17147
|
// ../node_modules/ms/index.js
|
|
17078
17148
|
var require_ms = __commonJS({
|
|
17079
17149
|
"../node_modules/ms/index.js"(exports, module) {
|
|
@@ -18191,7 +18261,7 @@ var require_follow_redirects = __commonJS({
|
|
|
18191
18261
|
removeMatchingHeaders(/^content-/i, this._options.headers);
|
|
18192
18262
|
}
|
|
18193
18263
|
var currentHostHeader = removeMatchingHeaders(/^host$/i, this._options.headers);
|
|
18194
|
-
var currentUrlParts =
|
|
18264
|
+
var currentUrlParts = parseUrl(this._currentUrl);
|
|
18195
18265
|
var currentHost = currentHostHeader || currentUrlParts.host;
|
|
18196
18266
|
var currentUrl = /^\w+:/.test(location) ? this._currentUrl : url3.format(Object.assign(currentUrlParts, { host: currentHost }));
|
|
18197
18267
|
var redirectUrl = resolveUrl(location, currentUrl);
|
|
@@ -18230,7 +18300,7 @@ var require_follow_redirects = __commonJS({
|
|
|
18230
18300
|
if (isURL(input)) {
|
|
18231
18301
|
input = spreadUrlObject(input);
|
|
18232
18302
|
} else if (isString2(input)) {
|
|
18233
|
-
input = spreadUrlObject(
|
|
18303
|
+
input = spreadUrlObject(parseUrl(input));
|
|
18234
18304
|
} else {
|
|
18235
18305
|
callback = options;
|
|
18236
18306
|
options = validateUrl(input);
|
|
@@ -18266,7 +18336,7 @@ var require_follow_redirects = __commonJS({
|
|
|
18266
18336
|
}
|
|
18267
18337
|
function noop2() {
|
|
18268
18338
|
}
|
|
18269
|
-
function
|
|
18339
|
+
function parseUrl(input) {
|
|
18270
18340
|
var parsed;
|
|
18271
18341
|
if (useNativeURL) {
|
|
18272
18342
|
parsed = new URL2(input);
|
|
@@ -18279,7 +18349,7 @@ var require_follow_redirects = __commonJS({
|
|
|
18279
18349
|
return parsed;
|
|
18280
18350
|
}
|
|
18281
18351
|
function resolveUrl(relative, base) {
|
|
18282
|
-
return useNativeURL ? new URL2(relative, base) :
|
|
18352
|
+
return useNativeURL ? new URL2(relative, base) : parseUrl(url3.resolve(base, relative));
|
|
18283
18353
|
}
|
|
18284
18354
|
function validateUrl(input) {
|
|
18285
18355
|
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
|
|
@@ -18368,22 +18438,26 @@ var require_follow_redirects = __commonJS({
|
|
|
18368
18438
|
// ../packages/shared/dist/errors.js
|
|
18369
18439
|
function createApiError(message, statusCode) {
|
|
18370
18440
|
let hint = "Check your network connection and retry.";
|
|
18441
|
+
let type = "Service Error";
|
|
18371
18442
|
if (statusCode === 429) {
|
|
18372
|
-
|
|
18443
|
+
type = "Rate Limit";
|
|
18444
|
+
hint = "Request volume is too high. Suggestion: Wait briefly before retrying or reduce concurrent calls.";
|
|
18373
18445
|
} else if (statusCode === 401 || statusCode === 403) {
|
|
18374
|
-
|
|
18446
|
+
type = "Authentication Error";
|
|
18447
|
+
hint = "The request could not be authorized. Suggestion: Verify your API key or token in the environment configuration.";
|
|
18375
18448
|
} else if (statusCode && statusCode >= 500) {
|
|
18376
|
-
|
|
18449
|
+
type = "Upstream Error";
|
|
18450
|
+
hint = "The remote service is experiencing temporary issues. Suggestion: Try again in a few minutes.";
|
|
18377
18451
|
} else if (statusCode === 404) {
|
|
18378
|
-
|
|
18452
|
+
type = "Not Found";
|
|
18453
|
+
hint = "The requested information could not be found. Suggestion: Check if the ID, Ticker, or query parameters are correct.";
|
|
18379
18454
|
}
|
|
18380
|
-
const detail = statusCode ? ` (HTTP ${statusCode})` : "";
|
|
18381
18455
|
return {
|
|
18382
18456
|
isError: true,
|
|
18383
18457
|
content: [
|
|
18384
18458
|
{
|
|
18385
18459
|
type: "text",
|
|
18386
|
-
text:
|
|
18460
|
+
text: `${type}: ${message}
|
|
18387
18461
|
|
|
18388
18462
|
**Next Action**: ${hint}`
|
|
18389
18463
|
}
|
|
@@ -32447,7 +32521,8 @@ config(en_default());
|
|
|
32447
32521
|
var zod_default = external_exports;
|
|
32448
32522
|
|
|
32449
32523
|
// ../packages/shared/dist/pagination.js
|
|
32450
|
-
var
|
|
32524
|
+
var zodCompat = zod_exports;
|
|
32525
|
+
var z2 = zodCompat.z ?? zodCompat.default?.z ?? zodCompat.default ?? zodCompat;
|
|
32451
32526
|
var paginationSchema = z2.object({
|
|
32452
32527
|
limit: z2.number().int().min(1).max(100).default(20).describe("Maximum results to return (1\u2013100, default 20)"),
|
|
32453
32528
|
offset: z2.number().int().min(0).default(0).describe("Number of results to skip for pagination (default 0)")
|
|
@@ -32465,6 +32540,14 @@ function applyPagination(items, params) {
|
|
|
32465
32540
|
};
|
|
32466
32541
|
}
|
|
32467
32542
|
|
|
32543
|
+
// ../packages/shared/dist/package.js
|
|
32544
|
+
import { createRequire as createJsonRequire } from "node:module";
|
|
32545
|
+
function getPackageVersion(moduleUrl) {
|
|
32546
|
+
const require2 = createJsonRequire(moduleUrl);
|
|
32547
|
+
const packageJson = require2("../package.json");
|
|
32548
|
+
return packageJson.version ?? "0.0.0";
|
|
32549
|
+
}
|
|
32550
|
+
|
|
32468
32551
|
// ../node_modules/zod/v3/helpers/util.js
|
|
32469
32552
|
var util;
|
|
32470
32553
|
(function(util4) {
|
|
@@ -43051,7 +43134,7 @@ function normalizeValue(value) {
|
|
|
43051
43134
|
if (value === false || value == null) {
|
|
43052
43135
|
return value;
|
|
43053
43136
|
}
|
|
43054
|
-
return utils_default.isArray(value) ? value.map(normalizeValue) : String(value)
|
|
43137
|
+
return utils_default.isArray(value) ? value.map(normalizeValue) : String(value);
|
|
43055
43138
|
}
|
|
43056
43139
|
function parseTokens(str) {
|
|
43057
43140
|
const tokens = /* @__PURE__ */ Object.create(null);
|
|
@@ -43355,74 +43438,8 @@ function buildFullPath(baseURL, requestedURL, allowAbsoluteUrls) {
|
|
|
43355
43438
|
return requestedURL;
|
|
43356
43439
|
}
|
|
43357
43440
|
|
|
43358
|
-
// ../node_modules/proxy-from-env/index.js
|
|
43359
|
-
var DEFAULT_PORTS = {
|
|
43360
|
-
ftp: 21,
|
|
43361
|
-
gopher: 70,
|
|
43362
|
-
http: 80,
|
|
43363
|
-
https: 443,
|
|
43364
|
-
ws: 80,
|
|
43365
|
-
wss: 443
|
|
43366
|
-
};
|
|
43367
|
-
function parseUrl(urlString) {
|
|
43368
|
-
try {
|
|
43369
|
-
return new URL(urlString);
|
|
43370
|
-
} catch {
|
|
43371
|
-
return null;
|
|
43372
|
-
}
|
|
43373
|
-
}
|
|
43374
|
-
function getProxyForUrl(url3) {
|
|
43375
|
-
var parsedUrl = (typeof url3 === "string" ? parseUrl(url3) : url3) || {};
|
|
43376
|
-
var proto = parsedUrl.protocol;
|
|
43377
|
-
var hostname3 = parsedUrl.host;
|
|
43378
|
-
var port = parsedUrl.port;
|
|
43379
|
-
if (typeof hostname3 !== "string" || !hostname3 || typeof proto !== "string") {
|
|
43380
|
-
return "";
|
|
43381
|
-
}
|
|
43382
|
-
proto = proto.split(":", 1)[0];
|
|
43383
|
-
hostname3 = hostname3.replace(/:\d*$/, "");
|
|
43384
|
-
port = parseInt(port) || DEFAULT_PORTS[proto] || 0;
|
|
43385
|
-
if (!shouldProxy(hostname3, port)) {
|
|
43386
|
-
return "";
|
|
43387
|
-
}
|
|
43388
|
-
var proxy = getEnv(proto + "_proxy") || getEnv("all_proxy");
|
|
43389
|
-
if (proxy && proxy.indexOf("://") === -1) {
|
|
43390
|
-
proxy = proto + "://" + proxy;
|
|
43391
|
-
}
|
|
43392
|
-
return proxy;
|
|
43393
|
-
}
|
|
43394
|
-
function shouldProxy(hostname3, port) {
|
|
43395
|
-
var NO_PROXY = getEnv("no_proxy").toLowerCase();
|
|
43396
|
-
if (!NO_PROXY) {
|
|
43397
|
-
return true;
|
|
43398
|
-
}
|
|
43399
|
-
if (NO_PROXY === "*") {
|
|
43400
|
-
return false;
|
|
43401
|
-
}
|
|
43402
|
-
return NO_PROXY.split(/[,\s]/).every(function(proxy) {
|
|
43403
|
-
if (!proxy) {
|
|
43404
|
-
return true;
|
|
43405
|
-
}
|
|
43406
|
-
var parsedProxy = proxy.match(/^(.+):(\d+)$/);
|
|
43407
|
-
var parsedProxyHostname = parsedProxy ? parsedProxy[1] : proxy;
|
|
43408
|
-
var parsedProxyPort = parsedProxy ? parseInt(parsedProxy[2]) : 0;
|
|
43409
|
-
if (parsedProxyPort && parsedProxyPort !== port) {
|
|
43410
|
-
return true;
|
|
43411
|
-
}
|
|
43412
|
-
if (!/^[.*]/.test(parsedProxyHostname)) {
|
|
43413
|
-
return hostname3 !== parsedProxyHostname;
|
|
43414
|
-
}
|
|
43415
|
-
if (parsedProxyHostname.charAt(0) === "*") {
|
|
43416
|
-
parsedProxyHostname = parsedProxyHostname.slice(1);
|
|
43417
|
-
}
|
|
43418
|
-
return !hostname3.endsWith(parsedProxyHostname);
|
|
43419
|
-
});
|
|
43420
|
-
}
|
|
43421
|
-
function getEnv(key) {
|
|
43422
|
-
return process.env[key.toLowerCase()] || process.env[key.toUpperCase()] || "";
|
|
43423
|
-
}
|
|
43424
|
-
|
|
43425
43441
|
// ../node_modules/axios/lib/adapters/http.js
|
|
43442
|
+
var import_proxy_from_env = __toESM(require_proxy_from_env(), 1);
|
|
43426
43443
|
var import_follow_redirects = __toESM(require_follow_redirects(), 1);
|
|
43427
43444
|
import http from "http";
|
|
43428
43445
|
import https from "https";
|
|
@@ -43431,7 +43448,7 @@ import util3 from "util";
|
|
|
43431
43448
|
import zlib from "zlib";
|
|
43432
43449
|
|
|
43433
43450
|
// ../node_modules/axios/lib/env/data.js
|
|
43434
|
-
var VERSION = "1.
|
|
43451
|
+
var VERSION = "1.13.6";
|
|
43435
43452
|
|
|
43436
43453
|
// ../node_modules/axios/lib/helpers/parseProtocol.js
|
|
43437
43454
|
function parseProtocol(url3) {
|
|
@@ -43952,9 +43969,6 @@ var Http2Sessions = class {
|
|
|
43952
43969
|
} else {
|
|
43953
43970
|
entries.splice(i, 1);
|
|
43954
43971
|
}
|
|
43955
|
-
if (!session.closed) {
|
|
43956
|
-
session.close();
|
|
43957
|
-
}
|
|
43958
43972
|
return;
|
|
43959
43973
|
}
|
|
43960
43974
|
}
|
|
@@ -44000,7 +44014,7 @@ function dispatchBeforeRedirect(options, responseDetails) {
|
|
|
44000
44014
|
function setProxy(options, configProxy, location) {
|
|
44001
44015
|
let proxy = configProxy;
|
|
44002
44016
|
if (!proxy && proxy !== false) {
|
|
44003
|
-
const proxyUrl = getProxyForUrl(location);
|
|
44017
|
+
const proxyUrl = import_proxy_from_env.default.getProxyForUrl(location);
|
|
44004
44018
|
if (proxyUrl) {
|
|
44005
44019
|
proxy = new URL(proxyUrl);
|
|
44006
44020
|
}
|
|
@@ -45046,16 +45060,14 @@ var factory = (env) => {
|
|
|
45046
45060
|
const encodeText = isFetchSupported && (typeof TextEncoder2 === "function" ? /* @__PURE__ */ ((encoder) => (str) => encoder.encode(str))(new TextEncoder2()) : async (str) => new Uint8Array(await new Request(str).arrayBuffer()));
|
|
45047
45061
|
const supportsRequestStream = isRequestSupported && isReadableStreamSupported && test(() => {
|
|
45048
45062
|
let duplexAccessed = false;
|
|
45049
|
-
const body = new ReadableStream2();
|
|
45050
45063
|
const hasContentType = new Request(platform_default.origin, {
|
|
45051
|
-
body,
|
|
45064
|
+
body: new ReadableStream2(),
|
|
45052
45065
|
method: "POST",
|
|
45053
45066
|
get duplex() {
|
|
45054
45067
|
duplexAccessed = true;
|
|
45055
45068
|
return "half";
|
|
45056
45069
|
}
|
|
45057
45070
|
}).headers.has("Content-Type");
|
|
45058
|
-
body.cancel();
|
|
45059
45071
|
return duplexAccessed && !hasContentType;
|
|
45060
45072
|
});
|
|
45061
45073
|
const supportsResponseStream = isResponseSupported && isReadableStreamSupported && test(() => utils_default.isReadableStream(new Response("").body));
|
|
@@ -45841,20 +45853,30 @@ var {
|
|
|
45841
45853
|
// src/api.ts
|
|
45842
45854
|
var FRED_BASE_URL = "https://api.stlouisfed.org/fred";
|
|
45843
45855
|
var httpsAgent = new https2.Agent({ keepAlive: true });
|
|
45856
|
+
function getApiKey() {
|
|
45857
|
+
const key = process.env.FRED_API_KEY;
|
|
45858
|
+
if (!key) {
|
|
45859
|
+
throw new Error(
|
|
45860
|
+
"FRED_API_KEY environment variable not set. Please set it to use this server."
|
|
45861
|
+
);
|
|
45862
|
+
}
|
|
45863
|
+
return key;
|
|
45864
|
+
}
|
|
45865
|
+
function buildRequestParams(params) {
|
|
45866
|
+
const filteredEntries = Object.entries(params).filter(
|
|
45867
|
+
([, value]) => value !== void 0
|
|
45868
|
+
);
|
|
45869
|
+
return Object.fromEntries([
|
|
45870
|
+
...filteredEntries,
|
|
45871
|
+
["api_key", getApiKey()],
|
|
45872
|
+
["file_type", "json"]
|
|
45873
|
+
]);
|
|
45874
|
+
}
|
|
45844
45875
|
var FredApiClient = class {
|
|
45845
45876
|
client;
|
|
45846
|
-
apiKey;
|
|
45847
45877
|
constructor() {
|
|
45848
|
-
const key = process.env.FRED_API_KEY;
|
|
45849
|
-
if (!key) {
|
|
45850
|
-
throw new Error(
|
|
45851
|
-
"FRED_API_KEY environment variable not set. Please set it to use this server."
|
|
45852
|
-
);
|
|
45853
|
-
}
|
|
45854
|
-
this.apiKey = key;
|
|
45855
45878
|
this.client = axios_default.create({
|
|
45856
45879
|
baseURL: FRED_BASE_URL,
|
|
45857
|
-
params: { api_key: this.apiKey, file_type: "json" },
|
|
45858
45880
|
httpsAgent
|
|
45859
45881
|
});
|
|
45860
45882
|
}
|
|
@@ -45862,13 +45884,13 @@ var FredApiClient = class {
|
|
|
45862
45884
|
const { data } = await this.client.get(
|
|
45863
45885
|
"/series/search",
|
|
45864
45886
|
{
|
|
45865
|
-
params: {
|
|
45887
|
+
params: buildRequestParams({
|
|
45866
45888
|
search_text: query,
|
|
45867
45889
|
limit,
|
|
45868
45890
|
offset,
|
|
45869
45891
|
order_by: "popularity",
|
|
45870
45892
|
sort_order: "desc"
|
|
45871
|
-
}
|
|
45893
|
+
})
|
|
45872
45894
|
}
|
|
45873
45895
|
);
|
|
45874
45896
|
return data;
|
|
@@ -45877,7 +45899,7 @@ var FredApiClient = class {
|
|
|
45877
45899
|
const { data } = await this.client.get(
|
|
45878
45900
|
"/series",
|
|
45879
45901
|
{
|
|
45880
|
-
params: { series_id: seriesId }
|
|
45902
|
+
params: buildRequestParams({ series_id: seriesId })
|
|
45881
45903
|
}
|
|
45882
45904
|
);
|
|
45883
45905
|
return data;
|
|
@@ -45886,12 +45908,12 @@ var FredApiClient = class {
|
|
|
45886
45908
|
const { data } = await this.client.get(
|
|
45887
45909
|
"/series/observations",
|
|
45888
45910
|
{
|
|
45889
|
-
params: {
|
|
45911
|
+
params: buildRequestParams({
|
|
45890
45912
|
series_id: seriesId,
|
|
45891
45913
|
limit,
|
|
45892
45914
|
offset,
|
|
45893
45915
|
sort_order: "desc"
|
|
45894
|
-
}
|
|
45916
|
+
})
|
|
45895
45917
|
}
|
|
45896
45918
|
);
|
|
45897
45919
|
return data;
|
|
@@ -45900,13 +45922,13 @@ var FredApiClient = class {
|
|
|
45900
45922
|
const { data } = await this.client.get(
|
|
45901
45923
|
"/category/series",
|
|
45902
45924
|
{
|
|
45903
|
-
params: {
|
|
45925
|
+
params: buildRequestParams({
|
|
45904
45926
|
category_id: categoryId,
|
|
45905
45927
|
limit,
|
|
45906
45928
|
offset,
|
|
45907
45929
|
order_by: "popularity",
|
|
45908
45930
|
sort_order: "desc"
|
|
45909
|
-
}
|
|
45931
|
+
})
|
|
45910
45932
|
}
|
|
45911
45933
|
);
|
|
45912
45934
|
return data;
|
|
@@ -45915,7 +45937,12 @@ var FredApiClient = class {
|
|
|
45915
45937
|
const { data } = await this.client.get(
|
|
45916
45938
|
"/releases",
|
|
45917
45939
|
{
|
|
45918
|
-
params: {
|
|
45940
|
+
params: buildRequestParams({
|
|
45941
|
+
limit,
|
|
45942
|
+
offset,
|
|
45943
|
+
order_by: "release_id",
|
|
45944
|
+
sort_order: "desc"
|
|
45945
|
+
})
|
|
45919
45946
|
}
|
|
45920
45947
|
);
|
|
45921
45948
|
return data;
|
|
@@ -45924,20 +45951,31 @@ var FredApiClient = class {
|
|
|
45924
45951
|
const { data } = await this.client.get(
|
|
45925
45952
|
"/release/series",
|
|
45926
45953
|
{
|
|
45927
|
-
params: {
|
|
45954
|
+
params: buildRequestParams({
|
|
45955
|
+
release_id: releaseId,
|
|
45956
|
+
limit,
|
|
45957
|
+
offset,
|
|
45958
|
+
order_by: "popularity",
|
|
45959
|
+
sort_order: "desc"
|
|
45960
|
+
})
|
|
45928
45961
|
}
|
|
45929
45962
|
);
|
|
45930
45963
|
return data;
|
|
45931
45964
|
}
|
|
45932
45965
|
async getSources() {
|
|
45933
|
-
const { data } = await this.client.get(
|
|
45966
|
+
const { data } = await this.client.get(
|
|
45967
|
+
"/sources",
|
|
45968
|
+
{
|
|
45969
|
+
params: buildRequestParams({})
|
|
45970
|
+
}
|
|
45971
|
+
);
|
|
45934
45972
|
return data;
|
|
45935
45973
|
}
|
|
45936
45974
|
async getSource(sourceId) {
|
|
45937
45975
|
const { data } = await this.client.get(
|
|
45938
45976
|
"/source",
|
|
45939
45977
|
{
|
|
45940
|
-
params: { source_id: sourceId }
|
|
45978
|
+
params: buildRequestParams({ source_id: sourceId })
|
|
45941
45979
|
}
|
|
45942
45980
|
);
|
|
45943
45981
|
return data;
|
|
@@ -46138,9 +46176,10 @@ var MOCK_FIXTURES = {
|
|
|
46138
46176
|
};
|
|
46139
46177
|
|
|
46140
46178
|
// src/index.ts
|
|
46179
|
+
var PACKAGE_VERSION = getPackageVersion(import.meta.url);
|
|
46141
46180
|
var server = new McpServer({
|
|
46142
46181
|
name: "fred-mcp-server",
|
|
46143
|
-
version:
|
|
46182
|
+
version: PACKAGE_VERSION
|
|
46144
46183
|
});
|
|
46145
46184
|
var clientInstance = null;
|
|
46146
46185
|
function getClient() {
|
|
@@ -46150,25 +46189,36 @@ function getClient() {
|
|
|
46150
46189
|
return clientInstance;
|
|
46151
46190
|
}
|
|
46152
46191
|
function extractErrorMessage(err) {
|
|
46192
|
+
const sanitize = (value) => {
|
|
46193
|
+
const apiKey = process.env.FRED_API_KEY;
|
|
46194
|
+
let sanitized = value.replace(
|
|
46195
|
+
/([?&]api_key=)[^&\s]+/gi,
|
|
46196
|
+
"$1[REDACTED]"
|
|
46197
|
+
);
|
|
46198
|
+
if (apiKey) {
|
|
46199
|
+
sanitized = sanitized.split(apiKey).join("[REDACTED]");
|
|
46200
|
+
}
|
|
46201
|
+
return sanitized;
|
|
46202
|
+
};
|
|
46153
46203
|
if (typeof err !== "object" || err === null) {
|
|
46154
|
-
return String(err);
|
|
46204
|
+
return sanitize(String(err));
|
|
46155
46205
|
}
|
|
46156
46206
|
const error48 = err;
|
|
46157
46207
|
const responseData = error48.response?.data;
|
|
46158
46208
|
if (typeof responseData === "string" && responseData.trim()) {
|
|
46159
|
-
return responseData.trim();
|
|
46209
|
+
return sanitize(responseData.trim());
|
|
46160
46210
|
}
|
|
46161
46211
|
if (responseData && typeof responseData === "object") {
|
|
46162
46212
|
const data = responseData;
|
|
46163
46213
|
const nestedMessage = data.error_message ?? data.message ?? data.error ?? data.detail;
|
|
46164
46214
|
if (nestedMessage !== void 0 && nestedMessage !== null) {
|
|
46165
|
-
return String(nestedMessage);
|
|
46215
|
+
return sanitize(String(nestedMessage));
|
|
46166
46216
|
}
|
|
46167
46217
|
}
|
|
46168
46218
|
if (error48.message !== void 0 && error48.message !== null) {
|
|
46169
|
-
return String(error48.message);
|
|
46219
|
+
return sanitize(String(error48.message));
|
|
46170
46220
|
}
|
|
46171
|
-
return "Request failed.";
|
|
46221
|
+
return sanitize("Request failed.");
|
|
46172
46222
|
}
|
|
46173
46223
|
function handleFredError(err) {
|
|
46174
46224
|
if (typeof err === "object" && err !== null) {
|
|
@@ -46245,7 +46295,7 @@ function formatSources(sources, total, offset, limit) {
|
|
|
46245
46295
|
` + rows.join("\n") + formatPaginationFooter(offset, limit, total);
|
|
46246
46296
|
}
|
|
46247
46297
|
server.registerTool(
|
|
46248
|
-
"
|
|
46298
|
+
"search_series",
|
|
46249
46299
|
{
|
|
46250
46300
|
title: "Search FRED Series",
|
|
46251
46301
|
description: "Search FRED economic data series by text query.",
|
|
@@ -46278,7 +46328,7 @@ server.registerTool(
|
|
|
46278
46328
|
}
|
|
46279
46329
|
);
|
|
46280
46330
|
server.registerTool(
|
|
46281
|
-
"
|
|
46331
|
+
"get_series_info",
|
|
46282
46332
|
{
|
|
46283
46333
|
title: "Get FRED Series Info",
|
|
46284
46334
|
description: "Get metadata for a specific FRED series.",
|
|
@@ -46316,7 +46366,7 @@ server.registerTool(
|
|
|
46316
46366
|
}
|
|
46317
46367
|
);
|
|
46318
46368
|
server.registerTool(
|
|
46319
|
-
"
|
|
46369
|
+
"get_series_data",
|
|
46320
46370
|
{
|
|
46321
46371
|
title: "Get FRED Series Data",
|
|
46322
46372
|
description: "Get observation data points for a specific FRED series.",
|
|
@@ -46371,7 +46421,7 @@ server.registerTool(
|
|
|
46371
46421
|
}
|
|
46372
46422
|
);
|
|
46373
46423
|
server.registerTool(
|
|
46374
|
-
"
|
|
46424
|
+
"get_category_series",
|
|
46375
46425
|
{
|
|
46376
46426
|
title: "Get FRED Category Series",
|
|
46377
46427
|
description: "Get series belonging to a specific FRED category.",
|
|
@@ -46405,6 +46455,11 @@ server.registerTool(
|
|
|
46405
46455
|
limit,
|
|
46406
46456
|
offset
|
|
46407
46457
|
);
|
|
46458
|
+
if (!res.seriess || res.seriess.length === 0) {
|
|
46459
|
+
return createNotFoundError(
|
|
46460
|
+
`Category '${category_id}' not found.`
|
|
46461
|
+
);
|
|
46462
|
+
}
|
|
46408
46463
|
const text = formatSeriesList(res.seriess, res.count, offset);
|
|
46409
46464
|
return { content: [{ type: "text", text: truncateToLimit(text) }] };
|
|
46410
46465
|
} catch (err) {
|
|
@@ -46413,7 +46468,7 @@ server.registerTool(
|
|
|
46413
46468
|
}
|
|
46414
46469
|
);
|
|
46415
46470
|
server.registerTool(
|
|
46416
|
-
"
|
|
46471
|
+
"get_releases",
|
|
46417
46472
|
{
|
|
46418
46473
|
title: "Get FRED Releases",
|
|
46419
46474
|
description: "Get all economic data releases from FRED.",
|
|
@@ -46443,7 +46498,7 @@ server.registerTool(
|
|
|
46443
46498
|
}
|
|
46444
46499
|
);
|
|
46445
46500
|
server.registerTool(
|
|
46446
|
-
"
|
|
46501
|
+
"get_release_series",
|
|
46447
46502
|
{
|
|
46448
46503
|
title: "Get FRED Release Series",
|
|
46449
46504
|
description: "Get series belonging to a specific FRED release.",
|
|
@@ -46477,6 +46532,11 @@ server.registerTool(
|
|
|
46477
46532
|
limit,
|
|
46478
46533
|
offset
|
|
46479
46534
|
);
|
|
46535
|
+
if (!res.seriess || res.seriess.length === 0) {
|
|
46536
|
+
return createNotFoundError(
|
|
46537
|
+
`Release '${release_id}' not found.`
|
|
46538
|
+
);
|
|
46539
|
+
}
|
|
46480
46540
|
const text = formatSeriesList(res.seriess, res.count, offset);
|
|
46481
46541
|
return { content: [{ type: "text", text: truncateToLimit(text) }] };
|
|
46482
46542
|
} catch (err) {
|
|
@@ -46485,7 +46545,7 @@ server.registerTool(
|
|
|
46485
46545
|
}
|
|
46486
46546
|
);
|
|
46487
46547
|
server.registerTool(
|
|
46488
|
-
"
|
|
46548
|
+
"get_sources",
|
|
46489
46549
|
{
|
|
46490
46550
|
title: "Get FRED Sources",
|
|
46491
46551
|
description: "Get all data sources available in FRED.",
|
|
@@ -46532,7 +46592,7 @@ server.registerTool(
|
|
|
46532
46592
|
}
|
|
46533
46593
|
);
|
|
46534
46594
|
server.registerTool(
|
|
46535
|
-
"
|
|
46595
|
+
"get_source",
|
|
46536
46596
|
{
|
|
46537
46597
|
title: "Get FRED Source",
|
|
46538
46598
|
description: "Get details for a specific FRED data source.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fre4x/fred",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "A FRED economic data MCP server for LLMs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
"dist"
|
|
12
12
|
],
|
|
13
13
|
"scripts": {
|
|
14
|
-
"build": "node
|
|
14
|
+
"build": "node ../scripts/build-package.mjs",
|
|
15
15
|
"typecheck": "cross-env NODE_OPTIONS=--max-old-space-size=4096 tsc --noEmit",
|
|
16
16
|
"start": "node dist/index.js",
|
|
17
17
|
"dev": "tsx src/index.ts",
|
|
18
18
|
"watch": "tsc -w",
|
|
19
|
-
"inspector": "node ../scripts/run-official-inspector.mjs node dist/index.js",
|
|
20
|
-
"test": "vitest run --passWithNoTests --exclude dist"
|
|
19
|
+
"inspector": "npm run build && node ../scripts/run-official-inspector.mjs node dist/index.js",
|
|
20
|
+
"test": "node ../scripts/run-vitest.mjs run --passWithNoTests --exclude dist"
|
|
21
21
|
},
|
|
22
22
|
"keywords": [
|
|
23
23
|
"mcp",
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
"author": "fritzprix",
|
|
30
30
|
"license": "MIT",
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
32
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
33
33
|
"axios": "^1.13.5",
|
|
34
|
-
"zod": "^4.
|
|
34
|
+
"zod": "^4.3.6"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@types/node": "^25.3.
|
|
37
|
+
"@types/node": "^25.3.5",
|
|
38
38
|
"tsx": "^4.21.0",
|
|
39
39
|
"typescript": "^5.9.3",
|
|
40
40
|
"vitest": "^4.0.18"
|