Skip to main content
Glama
Jaldekoa
by Jaldekoa

get_fred_series_observations

Retrieve economic time series observations from the Federal Reserve Bank of St. Louis (FRED) database to analyze historical data trends and economic indicators.

Instructions

Get series observations from the Fred API.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
series_idYesThe id for a series.
realtime_startNoThe start of the real-time period. Format: YYYY-MM-DD. Defaults to today's date.
realtime_endNoThe end of the real-time period. Format: YYYY-MM-DD. Defaults to today's date.
limitNoMaximum number of observations to return. Defaults to 10.
offsetNoNumber of observations to offset from first. Defaults to 0.
sort_orderNoSort order of observations. Options: 'asc' or 'desc'. Defaults to 'asc'.asc
observation_startNoStart date of observations. Format: YYYY-MM-DD.
observation_endNoEnd date of observations. Format: YYYY-MM-DD.
unitsNoData value transformation. Options: 'lin', 'chg', 'ch1', 'pch', 'pc1', 'pca', 'cch', 'cca', 'log'. Defaults to 'lin'.lin
frequencyNoFrequency of observations. Options: 'd', 'w', 'bw', 'm', 'q', 'sa', 'a', 'wef', 'weth', 'wew', 'wetu', 'wem', 'wesu', 'wesa', 'bwew', 'bwem'. Defaults to no value for no frequency aggregation.
aggregation_methodNoAggregation method for frequency. Options: 'avg', 'sum', 'eop'. Defaults to 'avg'.avg
output_typeNoOutput type of observations. Options: 1, 2, 3, 4. Defaults to 1.
vintage_datesNoComma-separated list of vintage dates.

Implementation Reference

  • server.py:30-93 (handler)
    The @mcp.tool decorated async function implementing the get_fred_series_observations tool. Handles input parameters, constructs API params, calls the make_request helper to fetch data from FRED API endpoint /series/observations, and returns the observations list.
    @mcp.tool(name="get_fred_series_observations", description="""Get series observations from the Fred API.""")
    async def get_fred_series_observations(
        series_id: Annotated[str, Field(description="The id for a series.")],
        realtime_start: Annotated[Optional[str], Field(description="The start of the real-time period. Format: YYYY-MM-DD. Defaults to today's date.")] = None,
        realtime_end: Annotated[Optional[str], Field(description="The end of the real-time period. Format: YYYY-MM-DD. Defaults to today's date.")] = None,
        limit: Annotated[Optional[int | str], Field(description="Maximum number of observations to return. Defaults to 10.")] = 10,
        offset: Annotated[Optional[int | str], Field(description="Number of observations to offset from first. Defaults to 0.")] = 0,
        sort_order: Annotated[Literal['asc', 'desc'], Field(description="Sort order of observations. Options: 'asc' or 'desc'. Defaults to 'asc'.")] = 'asc',
        observation_start: Annotated[Optional[str], Field(description="Start date of observations. Format: YYYY-MM-DD.")] = None,
        observation_end: Annotated[Optional[str], Field(description="End date of observations. Format: YYYY-MM-DD.")] = None,
        units: Annotated[Literal['lin', 'chg', 'ch1', 'pch', 'pc1', 'pca', 'cch', 'cca', 'log'], Field(description="Data value transformation. Options: 'lin', 'chg', 'ch1', 'pch', 'pc1', 'pca', 'cch', 'cca', 'log'. Defaults to 'lin'.")] = 'lin',
        frequency: Annotated[Literal['d', 'w', 'bw', 'm', 'q', 'sa', 'a', 'wef', 'weth', 'wew', 'wetu', 'wem', 'wesu', 'wesa', 'bwew', 'bwem'], Field(description="Frequency of observations. Options: 'd', 'w', 'bw', 'm', 'q', 'sa', 'a', 'wef', 'weth', 'wew', 'wetu', 'wem', 'wesu', 'wesa', 'bwew', 'bwem'. Defaults to no value for no frequency aggregation.")] = None,
        aggregation_method: Annotated[Literal['avg', 'sum', 'eop'], Field(description="Aggregation method for frequency. Options: 'avg', 'sum', 'eop'. Defaults to 'avg'.")] = 'avg',
        output_type: Annotated[Literal[1, 2, 3, 4], Field(description="Output type of observations. Options: 1, 2, 3, 4. Defaults to 1.")] = 1,
        vintage_dates: Annotated[Optional[str], Field(description="Comma-separated list of vintage dates.")] = None,
    ):
        """Get series observations from the Fred API.
        
        Args:
            series_id (str): The id for a series.
            realtime_start (str): The start of the real-time period. YYYY-MM-DD formatted string, optional, default: today's date.
            realtime_end (str): The end of the real-time period. YYYY-MM-DD formatted string, optional, default: today's date.
            limit (int or str): The maximum number of observations to return. Optional, default: 1000.
            offset (int or str): The number of observations to offset from the first observation. Optional, default: 0.
            sort_order (str): The sort order of the observations. Possible values: "asc" or "desc". Optional, default: "asc".
            observation_start (str): The start date of the observations to get. YYYY-MM-DD formatted string. Optional, default: 1776-07-04 (earliest available).
            observation_end (str): The end date of the observations to get. YYYY-MM-DD formatted string. Optional, default: 9999-12-31 (latest available).
            units (str): A key that indicates a data value transformation. Posible values: 'lin', 'chg', 'ch1', 'pch', 'pc1', 'pca', 'cch', 'cca', 'log'. Optional, default: 'lin' (No transformation).
            frequency (str): The frequency of the observations. Posible values: 'd', 'w', 'bw', 'm', 'q', 'sa', 'a', 'wef', 'weth', 'wew', 'wetu', 'wem', 'wesu', 'wesa', 'bwew', 'bwem'. Optional, default: no value for no frequency aggregation.
            aggregation_method (str): A key that indicates the aggregation method used for frequency aggregation. This parameter has no affect if the frequency parameter is not set. Posible values: 'avg', 'sum', 'eop'. Optional, default: "avg".
            output_type (int): The output type of the observations. Optional, default: 1.
            vintage_dates (str): A comma-separated list of vintage dates to return. Optional, default: no vintage dates are set by default.
    
        Returns:
            dict[str, str]: A dictionary containing the observations or data values for an economic data series.
        """
        params = {
            "series_id": series_id, # ✅
            "realtime_start": realtime_start, # ❌
            "realtime_end": realtime_end, # ❌
            "limit": limit, # ✅
            "offset": offset, # ✅
            "sort_order": sort_order, # ✅
            "observation_start": observation_start, # ❌
            "observation_end": observation_end, # ❌
            "units": units, # ✅
            "frequency": frequency, # ✅
            "aggregation_method": aggregation_method, # ✅
            "output_type": output_type, # ✅
            "vintage_dates": vintage_dates, # ❌
            "file_type": "json"
        }
        
        data = await make_request(f"{FRED_API_URL}/series/observations", params)
    
        if not data:
            raise ConnectionError("Failed to fetch data from the FRED API")
        
        observations = data["observations"]
    
        if not observations:
            raise ValueError("No observations found for the given series")
        
        return observations
  • Input schema defined in the function parameters using Annotated with Pydantic Field for validation, descriptions, and types (e.g., series_id: str, limit: Optional[int|str], etc.).
    async def get_fred_series_observations(
        series_id: Annotated[str, Field(description="The id for a series.")],
        realtime_start: Annotated[Optional[str], Field(description="The start of the real-time period. Format: YYYY-MM-DD. Defaults to today's date.")] = None,
        realtime_end: Annotated[Optional[str], Field(description="The end of the real-time period. Format: YYYY-MM-DD. Defaults to today's date.")] = None,
        limit: Annotated[Optional[int | str], Field(description="Maximum number of observations to return. Defaults to 10.")] = 10,
        offset: Annotated[Optional[int | str], Field(description="Number of observations to offset from first. Defaults to 0.")] = 0,
        sort_order: Annotated[Literal['asc', 'desc'], Field(description="Sort order of observations. Options: 'asc' or 'desc'. Defaults to 'asc'.")] = 'asc',
        observation_start: Annotated[Optional[str], Field(description="Start date of observations. Format: YYYY-MM-DD.")] = None,
        observation_end: Annotated[Optional[str], Field(description="End date of observations. Format: YYYY-MM-DD.")] = None,
        units: Annotated[Literal['lin', 'chg', 'ch1', 'pch', 'pc1', 'pca', 'cch', 'cca', 'log'], Field(description="Data value transformation. Options: 'lin', 'chg', 'ch1', 'pch', 'pc1', 'pca', 'cch', 'cca', 'log'. Defaults to 'lin'.")] = 'lin',
        frequency: Annotated[Literal['d', 'w', 'bw', 'm', 'q', 'sa', 'a', 'wef', 'weth', 'wew', 'wetu', 'wem', 'wesu', 'wesa', 'bwew', 'bwem'], Field(description="Frequency of observations. Options: 'd', 'w', 'bw', 'm', 'q', 'sa', 'a', 'wef', 'weth', 'wew', 'wetu', 'wem', 'wesu', 'wesa', 'bwew', 'bwem'. Defaults to no value for no frequency aggregation.")] = None,
        aggregation_method: Annotated[Literal['avg', 'sum', 'eop'], Field(description="Aggregation method for frequency. Options: 'avg', 'sum', 'eop'. Defaults to 'avg'.")] = 'avg',
        output_type: Annotated[Literal[1, 2, 3, 4], Field(description="Output type of observations. Options: 1, 2, 3, 4. Defaults to 1.")] = 1,
        vintage_dates: Annotated[Optional[str], Field(description="Comma-separated list of vintage dates.")] = None,
    ):
  • server.py:30-30 (registration)
    Tool registration decorator @mcp.tool(name="get_fred_series_observations", description=...).
    @mcp.tool(name="get_fred_series_observations", description="""Get series observations from the Fred API.""")
  • make_request helper function that performs authenticated async HTTP GET requests to FRED API using httpx, adding API key from env.
    async def make_request(url: str, params: dict):
        """Make a request to the Federal Reserve Economic Data API."""
        
        if FRED_API_KEY := os.getenv("FRED_API_KEY"):
            params["api_key"] = FRED_API_KEY
    
        async with httpx.AsyncClient() as client:
            try:
                response = await client.get(url, params=params)
                response.raise_for_status()
                return response.json()
    
            except httpx.HTTPStatusError as e:
                raise ConnectionError(f"Failed to fetch data from the FRED API: {e}")

Schema Changelog

Changes observed during successful MCP inspections.

  1. First observed

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It only says 'Get', implying a read operation, but does not describe response format, pagination behavior, real-time period semantics, potential errors, or any side effects. The description is too thin to inform the agent about how the tool behaves beyond the obvious.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single concise sentence with zero wasted words and is front-loaded with the core verb and resource. It is appropriately brief, though given the tool's complexity, a little more structure could have made it more useful without losing conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

This is a 13-parameter tool with no output schema and no annotations. The description does not explain what an 'observation' is, what the return payload looks like, or how concepts like vintage dates and real-time periods work. The schema covers parameters, but the overall tool context is under-specified for an agent to use it confidently.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 100% description coverage across all 13 parameters, so the baseline is 3. The description itself contributes nothing to parameter understanding, but the schema adequately documents defaults, formats, and enums, so no deduction beyond baseline is warranted.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a clear verb ('Get') and resource ('series observations') with the API ('Fred'), which adequately identifies the operation. However, it does not elaborate on what 'observations' actually are or provide any differentiating detail, and it closely mirrors the tool name.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is given about when to use this tool, what conditions favor it, or what alternatives exist. Since there are no sibling tools, there is no differentiation burden, but there is also no scenario or prerequisite context to help an agent decide to invoke it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Deploy Server

Other Tools