fred-mcp-server
Version:
Federal Reserve Economic Data (FRED) MCP Server - Access all 800,000+ economic time series with search, browse, and data retrieval capabilities
235 lines (234 loc) • 7.91 kB
JavaScript
/**
* FRED Browse API Client
*
* Provides comprehensive browsing of FRED categories, releases, and sources
*/
import { makeRequest } from "../common/request.js";
import { z } from "zod";
/**
* Category schema
*/
const CategorySchema = z.object({
id: z.number(),
name: z.string(),
parent_id: z.number(),
});
/**
* Release schema
*/
const ReleaseSchema = z.object({
id: z.number(),
realtime_start: z.string(),
realtime_end: z.string(),
name: z.string(),
press_release: z.boolean(),
link: z.string().optional(),
notes: z.string().optional(),
});
/**
* Source schema
*/
const SourceSchema = z.object({
id: z.number(),
realtime_start: z.string(),
realtime_end: z.string(),
name: z.string(),
link: z.string().optional(),
notes: z.string().optional(),
});
/**
* Browse all FRED categories
*/
export async function browseCategories(categoryId) {
try {
const endpoint = categoryId ? `category/children` : "category";
const queryParams = {};
if (categoryId) {
queryParams.category_id = categoryId;
}
const response = await makeRequest(endpoint, queryParams);
return {
content: [{
type: "text",
text: JSON.stringify({
categories: response.categories.map(cat => ({
id: cat.id,
name: cat.name,
parent_id: cat.parent_id
}))
}, null, 2)
}]
};
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Failed to browse categories: ${error.message}`);
}
throw error;
}
}
/**
* Get series in a specific category
*/
export async function getCategorySeries(categoryId, options = {}) {
try {
const queryParams = {
category_id: categoryId
};
if (options.limit !== undefined)
queryParams.limit = options.limit;
if (options.offset !== undefined)
queryParams.offset = options.offset;
if (options.order_by)
queryParams.order_by = options.order_by;
if (options.sort_order)
queryParams.sort_order = options.sort_order;
if (options.filter_variable)
queryParams.filter_variable = options.filter_variable;
if (options.filter_value)
queryParams.filter_value = options.filter_value;
const response = await makeRequest("category/series", queryParams);
return {
content: [{
type: "text",
text: JSON.stringify({
category_id: categoryId,
total_series: response.count,
showing: `${response.offset + 1}-${Math.min(response.offset + response.limit, response.count)}`,
series: response.seriess.map((s) => ({
id: s.id,
title: s.title,
units: s.units,
frequency: s.frequency,
observation_range: `${s.observation_start} to ${s.observation_end}`,
last_updated: s.last_updated
}))
}, null, 2)
}]
};
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Failed to get category series: ${error.message}`);
}
throw error;
}
}
/**
* Browse all FRED releases
*/
export async function browseReleases(options = {}) {
try {
const queryParams = {};
if (options.limit !== undefined)
queryParams.limit = options.limit;
if (options.offset !== undefined)
queryParams.offset = options.offset;
if (options.order_by)
queryParams.order_by = options.order_by;
if (options.sort_order)
queryParams.sort_order = options.sort_order;
const response = await makeRequest("releases", queryParams);
return {
content: [{
type: "text",
text: JSON.stringify({
total_releases: response.count,
showing: `${response.offset + 1}-${Math.min(response.offset + response.limit, response.count)}`,
releases: response.releases.map(rel => ({
id: rel.id,
name: rel.name,
press_release: rel.press_release,
link: rel.link
}))
}, null, 2)
}]
};
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Failed to browse releases: ${error.message}`);
}
throw error;
}
}
/**
* Get series in a specific release
*/
export async function getReleaseSeries(releaseId, options = {}) {
try {
const queryParams = {
release_id: releaseId
};
if (options.limit !== undefined)
queryParams.limit = options.limit;
if (options.offset !== undefined)
queryParams.offset = options.offset;
if (options.order_by)
queryParams.order_by = options.order_by;
if (options.sort_order)
queryParams.sort_order = options.sort_order;
const response = await makeRequest("release/series", queryParams);
return {
content: [{
type: "text",
text: JSON.stringify({
release_id: releaseId,
total_series: response.count,
showing: `${response.offset + 1}-${Math.min(response.offset + response.limit, response.count)}`,
series: response.seriess.map((s) => ({
id: s.id,
title: s.title,
units: s.units,
frequency: s.frequency,
observation_range: `${s.observation_start} to ${s.observation_end}`,
last_updated: s.last_updated
}))
}, null, 2)
}]
};
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Failed to get release series: ${error.message}`);
}
throw error;
}
}
/**
* Browse all FRED sources
*/
export async function browseSources(options = {}) {
try {
const queryParams = {};
if (options.limit !== undefined)
queryParams.limit = options.limit;
if (options.offset !== undefined)
queryParams.offset = options.offset;
if (options.order_by)
queryParams.order_by = options.order_by;
if (options.sort_order)
queryParams.sort_order = options.sort_order;
const response = await makeRequest("sources", queryParams);
return {
content: [{
type: "text",
text: JSON.stringify({
total_sources: response.count,
showing: `${response.offset + 1}-${Math.min(response.offset + response.limit, response.count)}`,
sources: response.sources.map(src => ({
id: src.id,
name: src.name,
link: src.link
}))
}, null, 2)
}]
};
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Failed to browse sources: ${error.message}`);
}
throw error;
}
}