Building a Reliable Financial Assistant with Model Context Protocol
This guide details building a reliable personal financial assistant using the Model Context Protocol (MCP) and a "Narrator" architectural pattern. By separating deterministic data computation in Python from LLM narration, the system ensures factual accuracy, reduces hallucinations, and provides auditable, data-backed financial insights. It covers MCP client wrappers, budget enforcement, simple request parsing, and precise metric calculation.

LLMs are powerful tools, but in data-sensitive domains like finance, where precision and factual accuracy are non-negotiable, their propensity to "hallucinate" or confidently assert information without supporting data can be a significant drawback. Relying on an LLM for market commentary without real-time data or for financial analysis based on invented metrics is simply not viable for product features or internal tools. This is precisely where the Model Context Protocol (MCP) offers a robust solution, enabling the construction of LLM applications that are grounded in verifiable data and deterministic computations.
This guide will walk you through building a personal financial assistant using MCP. Our primary objective is to generate trustworthy, data-backed insights, ensuring the LLM acts purely as a narrator of established facts, rather than an originator of information.
What is the Model Context Protocol (MCP)?
MCP is a standardized protocol designed to simplify how Language Model (LLM) applications discover and interact with external tools provided by an MCP server. Instead of the cumbersome task of hardcoding function schemas or developing custom connectors for each framework, MCP offers a consistent, streamlined method for tool integration. For development teams, this translates into reduced integration complexity, predictable tool discovery, and a clear architectural separation between the LLM and its data sources.
In our financial assistant, we'll connect to EOD Historical Data (EODHD)'s MCP server. This server exposes crucial market data tools, allowing our application to programmatically fetch prices and fundamental data. A key design choice here is that our Python application, not the LLM, deterministically controls which MCP tools are called and with what parameters. We process the raw data and then provide a curated "facts object" to the LLM for narration, ensuring auditable and factual outputs.
Architecture: The "Narrator" Pattern
The core architectural principle of our financial assistant is the "Narrator" pattern, which rigidly separates the processes of acquiring and computing facts from generating natural language. The LLM's role is strictly limited to transforming pre-computed, verified facts into coherent narrative.
The workflow unfolds as follows:
- Request Parsing: When a user submits a query like "Give me a 30-day brief for AAPL," a lightweight parser extracts essential operational parameters, such as ticker symbols and a lookback window, without attempting complex natural language interpretation.
- MCP Tool Calls: Using the parsed details, our application makes asynchronous calls to the EODHD MCP server. Tools like "get historical prices" and "get fundamentals" are invoked to retrieve the necessary raw market data, ensuring that the assistant operates on current information.
- Deterministic Python Metrics: Upon receiving raw data, Python takes over to compute all financial metrics deterministically. This includes calculations for returns, volatility, maximum drawdown, trend slopes, and volatility regime labels. This stage ensures that all numerical outputs are quantifiable and repeatable.
- LLM Narration: A compact "facts object" containing these computed metrics is then passed to the LLM. The LLM is prompted to use only these provided facts to generate a market brief or watchlist snapshot, explicitly preventing it from performing its own analysis or calculations.
- Structured Response: The final output is a structured object, comprising the narrative (
answer), the precise computed metrics (metrics), a record ofdata_used(tickers, date range, tools called), and atool_trace_idfor debugging. This pattern significantly mitigates hallucinations, guarantees numerical repeatability, and provides full auditability, making it highly suitable for production deployment.
Step 1: MCP Client Wrapper (client.py)
The client.py module serves as the essential interface for interacting with the MCP server. Its primary functions include establishing streamable HTTP MCP sessions, reliably calling tools with built-in timeouts and retries, and augmenting tool outputs with crucial metadata. The module provides a list_tools function to discover and cache available tools and a core call_tool asynchronous function. This call_tool handles the session initiation, tool invocation with specified arguments, and packaging the result with a meta object. This meta object is critical for tracing, containing details like the trace_id, the tool name, its args, and latency_s, offering clear visibility into all data access operations.
Step 2: The Assistant Core (core.py)
This module is the operational heart of the financial assistant, managing everything from initial request processing to the final narrative generation.
Safeguards and Parsing
When interacting with external APIs and LLMs, implementing robust safeguards is crucial. core.py defines critical safety parameters such as MAX_LOOKBACK_DAYS, MAX_TOOL_CALLS, and MAX_TICKERS to prevent overly expensive or slow requests. Each incoming request is assigned a unique trace_id, and a log_event utility emits JSON-formatted log lines, facilitating comprehensive debugging and event flow reconstruction. For stable and predictable behavior, the request parsing is intentionally simple, using basic regular expressions to extract ticker symbols and a numerical lookback window. A blacklist filters common words, and an enforce_budgets function clamps these values to adhere to predefined limits, ensuring resource efficiency.
Data Fetching and Metrics
This section orchestrates the interaction with the EODHD MCP server to retrieve raw financial data and then processes it deterministically. Functions such as fetch_prices and fetch_fundamentals wrap the MCP tool calls. Each tool invocation is tracked by a _bump function, which increments a counter and stores metadata in a tool_trace list, enforcing the MAX_TOOL_CALLS budget. The fetch_prices function specifically normalizes historical data into a concise DataFrame, containing only date and price, optimized for subsequent calculations. Crucially, the LLM is explicitly prevented from performing any numerical analysis. Instead, a compute_metrics function in Python calculates a comprehensive set of financial indicators for each ticker. These include total return, realized volatility (both daily and annualized), maximum drawdown (the worst peak-to-trough decline), a simple trend slope derived from log prices, and a lightweight volatility regime classification. The deterministic nature of these calculations means that identical inputs will always yield identical numerical outputs, making the assistant's financial insights transparent and verifiable.
Conclusion
By embracing the Model Context Protocol and the "Narrator" architectural pattern, developers can construct LLM-powered applications that are not only intelligent but also highly reliable, auditable, and firmly rooted in real-world data. This methodology is especially valuable in sensitive domains like finance, where confidence must derive from verifiable facts, not merely from linguistic fluency. The financial assistant outlined here exemplifies how to leverage LLMs for effective communication while rigorously maintaining numerical integrity.
FAQ
Q: Why not let the LLM decide which MCP tools to call directly?
A: While LLMs can be powerful tool orchestrators, in applications demanding high factual accuracy and auditability, such as finance, directly guiding tool calls through deterministic Python logic significantly mitigates the risk of hallucinations or incorrect data requests. This approach guarantees that data fetching is precise, controlled, and fully traceable.
Q: How does the "Narrator" pattern reduce hallucinations?
A: Hallucinations occur when an LLM invents information. By strictly confining the LLM's role to narrating a pre-computed "facts object," we eliminate its capacity to generate numerical data or perform analysis. It only articulates the precise, verified metrics supplied by the Python logic, thereby effectively preventing numerical hallucinations.
Q: What are the main benefits of using MCP over traditional API integrations?
A: MCP provides a standardized protocol for tool discovery and invocation, simplifying integration across diverse services. It reduces development churn by offering a consistent interface, removing the need for custom wrappers per API or framework, and promotes a clean separation of concerns between the LLM layer and the data access layer. This leads to more maintainable and scalable systems.
Related articles
TCG Pocket Responds: A Much-Needed Pace Shift for Pokémon Fans
Pokémon TCG Pocket is rolling out a major update for its second anniversary, primarily addressing player concerns about overwhelming content releases by shifting to a six-week set schedule. This aims to curb player decline and improve overall engagement by giving trainers more time to collect and strategize. The update also adds new collection methods, improved deck-building features, and enhanced trading functionality.
AI's Confidence vs. Formal Methods' Rigor: Design Flaws & Verification
While AI accelerates code generation, formal methods remain critical for ensuring system correctness. Languages like TLA+ and tools like Quint enable developers to model and verify system designs before coding, catching subtle flaws. Quint makes formal methods more accessible with developer-friendly syntax and executability. This approach is vital for verifying AI-generated code through trace validation and model-based testing, ensuring reliability against real-world data.
Ephemeral PR Preview Environments on GKE: A Deep Dive
Every development team eventually grapples with the limitations of shared staging environments. The familiar scenario: multiple features deployed simultaneously, database migrations clashing, and the phrase "it works on
Secure Internal API Access for AI Agents with MCP
AI agents accessing internal APIs directly pose significant risks, including identity loss, unrestricted queries, and security bypasses. The Model Context Protocol (MCP) offers a solution by defining explicit tools. A secure architecture involves an MCP server wrapping the API with strict input validation, coupled with a gateway that handles authentication, rate limiting, and audit logging, ensuring safe and accountable access.
regional: ‘What is fusion?’ Helion Energy harnesses the power of
Helion Energy, the Everett-based fusion startup, gained mainstream attention this week after being featured as a clue on the popular game show "Jeopardy!". The $800 clue, part of a "Y Combinator" category, highlighted Helion's mission to build the first fusion power plant, bringing the concept of clean energy to a wider audience. CEO David Kirtley celebrated the "surreal" moment as a sign that reliable clean power is becoming more accessible.
Netflix is laying off around 1,000 employees: Layoffs — Key Details
Netflix is laying off approximately 1,000 employees, or six percent of its global workforce, in its largest-ever job cut. This move targets product, tech, HR, and legal teams to reduce costs and re-prioritize investments despite recent financial growth.






