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
Google Play's New Stance on 501(c)(6) Donations: AnkiDroid's Challenge
For developers deeply embedded in the open-source ecosystem, the challenge of sustainable funding is ever-present. Many projects rely on community donations, often facilitated by fiscal hosts that simplify legal and
Samsung Galaxy Book 6 ($799 Model) Review: Budget Meets Ambition
Quick Verdict Samsung's latest addition to its Galaxy Book 6 lineup, the new $799 model, is a compelling entry into the budget laptop market. It aims to deliver a balanced experience with solid core performance,
Cold Cases & Data Integrity: Lessons from a Decades-Old Verdict
As software developers, we often deal with complex systems, legacy codebases, and the relentless pursuit of bugs that have evaded detection for years. The recent conviction in the 1996 murder of rapper Tupac Shakur
Achieve Unbreakable 3D Prints: Understanding the New Computational
Learn how a new computational model will revolutionize FFF 3D printing by solving weak interlayer bonding, leading to significantly stronger, more reliable parts with automated optimization.
ai: Musk’s faster path to more gas turbines comes with pollution
Elon Musk's SpaceX is building a secret Texas foundry to produce gas turbine blades, aiming to accelerate AI data center power by 18 months. This addresses a critical energy bottleneck, but faces environmental backlash over pollution and health risks from gas turbines.
Reimagining Classic IM: Exploring Open OSCAR Server in Go
Open OSCAR Server is an open-source, Go-based instant messaging server compatible with classic AIM and ICQ clients. It enables developers and enthusiasts to self-host a private IM server, reviving the functionality of these legacy platforms. The project boasts broad client compatibility, detailed protocol implementations, and a management API for administration.




