mcpField
F
Finance Toolkit

Finance Toolkit

Remote
github.com/JerBoumaDeveloper Tools5.5kUpdated 2d ago
Repository

About Finance Toolkit

Finance Toolkit is an open-source financial analysis toolkit for Python users and MCP-compatible assistants. It provides documented calculation methods for hundreds of metrics across asset types, alongside historical data, statements, risk measures, and market discovery.

Key features

  1. 01Calculate 500+ financial methods
  2. 02Analyze statements and 80+ ratios
  3. 03Access technical indicators and risk measures
  4. 04Cover equities, funds, currencies, and more
  5. 05Discover symbols and market information

Use cases

  1. 01Compare company financial ratios
  2. 02Review historical returns and technical indicators
  3. 03Measure portfolio risk and performance
  4. 04Query financial methods from an MCP client

MCP support

The MCP server exposes more than 500 Finance Toolkit methods to compatible clients such as Claude, Copilot, Cursor, and Windsurf. It is available as a hosted endpoint or can be set up locally.

Configuration

Remote servers need no local install. Pick your client, then copy the config or install in one click.

Endpointhttps://financetoolkit.jeroenbouma.com/mcp
Copy install command
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

Run commands in a terminal; paste JSON into the client’s MCP config and restart. Servers that need sign-in will prompt on first connect.

Packages
pypifinancetoolkit2.1.2

Tools

25
ParameterTypeRequiredDescription
benchmark_tickerstringNo
daysanyNo
end_datestringNo
growthbooleanNo
indicatorenumYesget_days_of_inventory_outstanding | get_days_of_sales_outstanding | get_operating_cycle | get_days_of_accounts_payable_outstanding | get_cash_conversion_cycle | get_cash_conversion_efficiency | get_receivables_turnover | get_inventory_turnover_ratio | get_accounts_payables_turnover_ratio | get_sga_to_revenue_ratio | get_fixed_asset_turnover | get_asset_turnover_ratio | get_operating_ratio
laganyNo
quarterlybooleanNo
roundinganyNo
start_datestringNo
tickersstringNo
trailinganyNo

Details

From the project README

FinanceToolkit

GitHub Sponsors Buy Me a Coffee LinkedIn MCP Server Download MCP Bundle Smithery Glama Documentation Supported Python Versions PYPI Version PYPI Downloads

While browsing a variety of websites, I repeatedly observed significant fluctuations in the same financial metric among different sources. Similarly, the reported financial statements often didn't line up, and there was limited information on the methodology used to calculate each metric.

For example, Microsoft's Price-to-Earnings (PE) ratio on the 6th of May, 2023 is reported to be 28.93 (Stockopedia), 32.05 (Morningstar), 32.66 (Macrotrends), 33.09 (Finance Charts), 33.66 (Y Charts), 33.67 (Wall Street Journal), 33.80 (Yahoo Finance) and 34.4 (Companies Market Cap). All of these calculations are correct, however the method of calculation varies leading to different results. Therefore, collecting data from multiple sources can lead to wrong interpretation of the results given that one source could apply a different definition than another. And that is, if that definition is even available as often the underlying methods are hidden behind a paid subscription.

This is why I designed the FinanceToolkit, this is an open-source toolkit in which all relevant financial methods (500+) are written down in the most simplistic way allowing for complete transparency of the method of calculation (proof). This enables you to avoid dependence on metrics from other providers that do not provide their methods. With a large selection of financial statements in hand, it facilitates streamlined calculations, promoting the adoption of a consistent and universally understood methods and formulas.

Beyond Equities, it supports Options, Currencies, Cryptocurrencies, ETFs, Mutual Funds, Indices, Money Markets, Commodities, Key Economic Indicators and more, allowing you to obtain historical data as well as important performance and risk measurements such as the Sharpe Ratio and Value at Risk.

Complementing this is the Finance Database 🌎, a database featuring 300.000+ symbols containing Equities, ETFs, Funds, Indices, Currencies, Cryptocurrencies and Money Markets. By utilising both, it is possible to do a fully-fledged competitive analysis with the tickers found from the FinanceDatabase inputted into the FinanceToolkit.


🔌 The Finance Toolkit is also available as an MCP Server

Query 500+ methods from Claude, Copilot, Cursor, Windsurf or any MCP-compatible client without writing code.

  • Hosted: connect to https://financetoolkit.jeroenbouma.com/mcp — OAuth handles the rest on first use.
  • Local: uvx --from "financetoolkit[mcp]" financetoolkit-mcp-setup — sets up your client config and API key automatically. See MCP Server Documentation for manual setup.

Also on Smithery, Glama, MCP Servers and more.


Table of Contents

  1. Installation
  2. Functionality
  3. MCP Server
  4. Questions & Answers
  5. Contributing
  6. Mentions
  7. Contact

Installation

Before installation, consider starring the project on GitHub which helps others find the project as well.

image

To install the Finance Toolkit it simply requires the following:

pip install financetoolkit -U

Then within Python use:

from financetoolkit import Toolkit

companies = Toolkit(
    tickers=['AAPL', 'MSFT'],
    api_key="FINANCIAL_MODELING_PREP_KEY",  # replace with your actual API key
)

To be able to get started, you need to obtain an API Key from FinancialModelingPrep. This is used to gain access to 30+ years of financial statement both annually and quarterly. Note that the Free plan is limited to 250 requests each day, 5 years of data and only features companies listed on US exchanges.


Obtain an API Key from FinancialModelingPrep here.


Through the link you are able to subscribe for the free plan and also premium plans at a 15% discount. This is an affiliate link and thus supports the project at the same time. I have chosen FinancialModelingPrep as a source as I find it to be the most transparent, reliable and at an affordable price. I have yet to find a platform offering such low prices for the amount of data offered. When you notice that the data is inaccurate or have any other issue related to the data, note that I simply provide the means to access this data and I am not responsible for the accuracy of the data itself. For this, use their contact form or provide the data yourself.

By default, the Finance Toolkit prioritizes Financial Modeling Prep for data retrieval. If data acquisition from Financial Modeling Prep is unsuccessful (e.g., due to plan restrictions or API key issues), the toolkit automatically switches to Yahoo Finance as a secondary source. To disable this fallback behavior and exclusively use Financial Modeling Prep, set enforce_source="FinancialModelingPrep" during Toolkit initialization. This configuration ensures that an error is raised if Financial Modeling Prep data cannot be accessed. Alternatively, you can set enforce_source="YahooFinance" to exclusively use Yahoo Finance as the data source.

The same enforce_source argument is also accepted per call on get_historical_data, get_treasury_data and the four statement functions (get_balance_sheet_statement, get_income_statement, get_cash_flow_statement and get_statistics_statement), where it overrides whatever the Toolkit was initialised with.

Functionality

This section is an introduction to the Finance Toolkit. The documentation contains many more examples: every module page opens with a Getting Started section, from the basics to creating custom ratios and working with your own datasets.


Find the Documentation, including the Getting Started guides, here.


The sections below follow one analysis of the semiconductor sector from start to finish, where each step answers the question the previous one raises: which companies make up the sector, how their shares did, what drives their profits, how much risk came with the returns, what the option market expects next, how the economy shaped all of it, whether a fund is the better way in and how the sector fits into a diversified portfolio. Every module of the Finance Toolkit appears once, but each holds far more than shown here: 500+ methods in total, all described with examples in the documentation.

Discovering the Sector

An analysis starts with a set of companies. The Discovery module finds them without needing any tickers yet, through stock screeners, sector performance, news and lists of companies, ETFs, indices, currencies, cryptocurrencies and commodities.

The screener below looks for semiconductor companies on NASDAQ that are worth more than $100 billion:

from financetoolkit import Discovery

# Initialize the standalone Discovery module
discovery = Discovery(api_key="FINANCIAL_MODELING_PREP_KEY")

# Find US semiconductor companies worth more than $100 billion
semiconductors = discovery.get_stock_screener(
    industry="Semiconductors",
    country="US",
    exchange="NASDAQ",
    market_cap_higher=100_000_000_000,
    is_etf=False,
)

# Show the five largest
semiconductors[["Name", "Market Cap", "Beta", "Price", "Dividend"]].head()

For example, the five largest companies the screener returns are shown below.

SymbolNameMarket CapBetaPriceDividend
NVDANVIDIA Corporation50841360000002.216210.960.28
AVGOBroadcom Inc.15355812549731.476321.682.6
MUMicron Technology, Inc.9928776210002.226877.550.565
AMDAdvanced Micro Devices, Inc.8436467769552.454516.790
INTCIntel Corp.4596797135842.2386.960

And below all of them are ranked by market cap.

Discovering the Sector

Following the Market

The rest of this walkthrough follows three of them: Nvidia, AMD and Intel. They are loaded into the Toolkit in one line, and the S&P 500 comes along as the benchmark:

from financetoolkit import Toolkit

# Initialize the Toolkit for Nvidia, AMD and Intel from 2018 to 2025
companies = Toolkit(
    ["NVDA", "AMD", "INTC"],
    api_key="FINANCIAL_MODELING_PREP_KEY",
    start_date="2017-12-31",
    end_date="2025-12-31",
)

Historical data comes on a daily, weekly, monthly, quarterly or yearly basis, with the return and cumulative return of each period, and so do the income statement, balance sheet and cash flow statement on an annual or quarterly basis. How far a share has travelled is one thing; whether the rally was stretched is another. The technicals module answers that with 50+ indicators, such as the Relative Strength Index (RSI), which moves between 0 and 100 and is commonly read as overbought above 70:

# Obtain weekly market data for all tickers and the benchmark
historical_data = companies.get_historical_data(period="weekly")

# The 14-week Relative Strength Index
relative_strength_index = companies.technicals.get_relative_strength_index(period="weekly", window=14)

# Show the highest RSI of each year
relative_strength_index.groupby(relative_strength_index.index.start_time.year).max()

For example, the highest weekly RSI of each year is shown below.

DateNVDAAMDINTCBenchmark
201866.108790.971966.736366.0498
201973.815681.244669.822575.9305
202085.233782.121578.482780.2378
202185.159382.098371.586274.4751
202258.434358.942661.280659.9225
202387.512977.50676.233271.4291
202491.070282.140367.694980.0566
202573.351482.528179.742971.6939

And below the cumulative returns of all three are plotted against the S&P 500, with the RSI underneath.

Following the Market

Zooming in on Competitors

Nvidia's shares outran the other two by far, which raises the question whether its business did as well. From the financial statements the Toolkit calculates 80+ ratios in five categories: efficiency, liquidity, profitability, solvency and valuation. Each ratio has its own function, and a collect_ function returns a whole category at once:

# Collect all Profitability Ratios for all tickers
profitability_ratios = companies.ratios.collect_profitability_ratios()

# Show the first ratios for Nvidia
profitability_ratios.loc["NVDA"].head()

For example, some of Nvidia's profitability ratios are shown below.

201720182019202020212022202320242025
Gross Margin0.59930.61210.61990.62340.64930.56930.72720.74990.7107
Operating Margin0.33050.32470.26070.27180.37310.15660.54120.62420.6038
Net Profit Margin0.31370.35340.25610.25980.36230.16190.48850.55850.556
EBITDA Margin0.35090.3470.29560.33760.41670.21380.5660.63850.617
Free Cash Flow Margin0.29950.26830.39130.28150.30210.14120.44350.46630.4477

And below a few of them are shown with their latest value and their course over the years.

Profitability Ratios

A high return on equity can come from margins, from turnover or from debt. Models combine the ratios to tell these apart: the Extended DuPont Analysis splits the return on equity into five components that multiply into it: interest burden, tax burden, operating margin, asset turnover and equity multiplier.

# Get the Extended DuPont Analysis for all tickers
extended_dupont_analysis = companies.models.get_extended_dupont_analysis()

# Show the results for Nvidia
extended_dupont_analysis.loc["NVDA"]

For example, the components for Nvidia are shown below.

201720182019202020212022202320242025
Interest Burden Ratio0.99561.02421.04360.97290.990.98981.02571.03161.0848
Tax Burden Ratio0.95341.06290.94140.98250.9811.04470.880.86740.8488
Operating Profit Margin0.33050.32470.26070.27180.37310.15660.54120.62420.6038
Asset Turnover0.92150.95510.71340.72330.73760.63191.13971.47181.3564
Equity Multiplier1.59311.45921.42051.58461.67751.75251.64281.44991.3456
Return on Equity0.46050.49260.25950.29780.44830.17930.91461.19181.0149

And below each component is shown for every fiscal year, with the latest value on top, multiplying into the return on equity.

Extended DuPont Analysis

Other models include the Weighted Average Cost of Capital, Altman Z-Score, Piotroski F-Score and Intrinsic Valuation. Almost every function also accepts growth=True for the growth from one period to the next, trailing=4 for trailing twelve-month figures and standardize=True for Z-Scores.

Weighing Risk and Return

Strong businesses do not make for smooth shares. The market data feeds the performance and risk modules, which calculate their metrics for any period, from intraday to yearly:

# The annualized Sharpe Ratio for each year
sharpe_ratio = companies.performance.get_sharpe_ratio(period="yearly", annualize=True)

# The deepest fall within each year
maximum_drawdown = companies.risk.get_maximum_drawdown(period="yearly", within_period=True)

# Show the Sharpe Ratios
sharpe_ratio

For example, the yearly Sharpe Ratios are shown below.

DateNVDAAMDINTC
2018-0.6131.10090.161
20191.54581.91431.048
20201.6561.419-0.0445
20212.00031.23660.2976
2022-0.8393-1.0532-1.5306
20232.69861.91951.8358
20242.0851-0.2615-1.5749
20250.83251.17531.2061

And below both are plotted for each year, the maximum drawdown together with the S&P 500.

Sharpe Ratio and Maximum Drawdown

Together the two modules cover 70+ metrics, such as Value at Risk, GARCH, Jensen's Alpha, the Capital Asset Pricing Model and the Fama-French factors. Most of them also accept rolling=<n> for a value that moves through time.

What the Option Market Expects

The past shows how much risk came with the returns; the option market puts a price on the risk ahead. The options module prices options with Black-Scholes, the Binomial Model and others, calculates the Greeks up to the third order and reads the live option chains: the put-call ratio, max pain, dealer gamma exposure, the volatility skew and term structure and the implied move. As the chains are those of today, the Toolkit below runs up to today, and the numbers are those of the day this README was last updated:

# Initialize the Toolkit up to today, as the option chains are live
companies_today = Toolkit(["NVDA", "AMD", "INTC"], api_key="FINANCIAL_MODELING_PREP_KEY")

# The volatility the options imply for the next 30 days against that of the past 30 days
companies_today.options.get_volatility_risk_premium(days=30)

The implied volatility is model-free, read with the method behind the VIX from all out-of-the-money options around the horizon, and the realized volatility is that of the daily returns over the same number of days. For example, both are shown below for each company.

Implied VolatilityRealized VolatilityVolatility Risk PremiumVariance Risk PremiumImplied to Realized Ratio
NVDA0.48450.27950.20490.15661.7331
AMD0.6570.4980.1590.18361.3192
INTC0.69910.51960.17950.21881.3456

Options usually price more risk than follows, as their sellers want to be paid for taking it on, and here they priced far more turbulence for the coming month than the past month delivered: Nvidia's options implied 1.7 times the volatility its shares showed. And below the implied and realized volatility of each company are plotted next to each other.

Implied and Realized Volatility

The Economic Environment

All three are listed in the United States and valued on earnings that lie years ahead, which makes US inflation and interest rates the backdrop to their share prices. In 2022, the year the maximum drawdown above shows each of them falling by more than half, inflation reached 9% and the Federal Reserve raised its policy rate from 0.12% to 4.38%.

The economics module covers 60+ countries with 50+ indicators, from GDP and unemployment to money supply and interest rates, and the fixed income module adds bond yields, yield curves, central bank rates and bond and derivative valuations. Both are reached through the same Toolkit instance, or on their own with from financetoolkit import Economics, FixedIncome:

# Inflation on the same month a year earlier and the Federal Reserve's policy rate
inflation_rate = companies.economics.get_inflation_rate("United States", period="monthly")
policy_rate = companies.economics.get_central_bank_policy_rate("United States", period="monthly")

# The daily U.S. Treasury par yield curve
treasury_rates = companies.fixedincome.get_treasury_rates()

# Show the curve on the last trading day of each year
treasury_rates.groupby(treasury_rates.index.year).last()

For example, the yield curve at the end of each year is shown below.

Date1 Month2 Month3 Month6 Month1 Year2 Year3 Year5 Year7 Year10 Year20 Year30 Year
20180.02440.02450.02450.02560.02630.02480.02460.02510.02590.02690.02870.0302
20190.01480.01510.01550.0160.01590.01580.01620.01690.01830.01920.02250.0239
20200.00080.00080.00090.00090.0010.00130.00170.00360.00650.00930.01450.0165
20210.00060.00050.00060.00190.00390.00730.00970.01260.01440.01520.01940.019
20220.04120.04410.04420.04760.04730.04410.04220.03990.03960.03880.04140.0397
20230.0560.05590.0540.05260.04790.04230.04010.03840.03880.03880.0420.0403
20240.0440.04390.04370.04240.04160.04250.04270.04380.04480.04580.04860.0478
20250.03740.03670.03670.03590.03480.03470.03550.03730.03940.04180.04790.0484

And below the yield curve at the end of each year is plotted. It went from almost zero at the short end in 2021 to above 4% across all maturities a year later, and when short-term yields lie above long-term ones, as at the end of 2022 and 2023, the curve is inverted.

US Inflation, Policy Rate and Yield Curve

Economic Relations

Rates rose and the shares fell, but a 10-year Treasury yield is made of two parts: the real yield, the return investors demand on top of inflation, and the inflation they expect over those ten years. The econometrics module tells such drivers apart with regressions, tests and forecasts built on statsmodels and linearmodels (pip install financetoolkit[econometrics]). Through the Toolkit it analyzes the returns of its tickers, and on its own, through Econometrics(data=...), any data at all, here the monthly returns of the three next to the monthly change in the US 10-year real yield and in 10-year inflation expectations:

import pandas as pd

from financetoolkit import Econometrics

# The US 10-year real yield and inflation expectations at the end of each month
real_yield = companies.economics.get_real_yield_curve("United States", period="monthly")
inflation_expectations = companies.economics.get_breakeven_inflation_expectations(
    "United States", period="monthly"
)

# The monthly change in both next to the monthly returns
monthly_returns = companies.get_historical_data(period="monthly")["Return"][["NVDA", "AMD", "INTC"]]
monthly_returns["Real Yield"] = real_yield[("United States", "10Y")].diff()
monthly_returns["Inflation Expectations"] = inflation_expectations[("United States", "10Y")].diff()

# The data are changes already
econometrics = Econometrics(data=monthly_returns, changes=None)

# Regress the return of each company on the change in the real yield and inflation expectations
regressions = pd.concat(
    {
        ticker: econometrics.get_ols(
            dependent_ticker=ticker, independent_tickers=["Real Yield", "Inflation Expectations"]
        )
        for ticker in ["NVDA", "AMD", "INTC"]
    }
)

# Show the results for Nvidia
regressions.loc["NVDA"]

For example, the coefficients for Nvidia are shown below.

CoefficientStd. Errort-StatisticP-Value
Intercept0.0490.01293.80280.0003
Real Yield-22.81325.6358-4.04790.0001
Inflation Expectations18.13299.10291.9920.0493

And below each coefficient is shown with its 95% confidence interval. A rise of 0.1 percentage point in the real yield went with a monthly return about 2.3% lower for Nvidia, 3.4% for AMD and 1.9% for Intel, as a higher real yield discounts their distant earnings more heavily. Inflation expectations matter far less: only for Nvidia does their coefficient come close to significance.

Economic Relations

The module also covers unit root and cointegration tests, Granger causality, panel data, causal inference, ARIMA, VAR and VECM forecasts, regime switching, a time-varying beta and pairs trading.

Comparing the Sector's ETFs

Rather than picking three companies, a fund holds the whole industry. The ETF module analyzes the holdings, sector and country weightings, tracking, concentration, overlap, valuation and liquidity of any fund. Below it compares six semiconductor funds: three focused on the United States (SOXX, XSD and PSI), one global fund (SMH) and two that hold a single country, China (SMHC) and South Korea (KCHP):

# Initialize the Toolkit for six semiconductor funds
funds = Toolkit(
    ["SOXX", "XSD", "PSI", "SMH", "SMHC", "KCHP"],
    api_key="FINANCIAL_MODELING_PREP_KEY",
    start_date="2017-12-31",
    end_date="2025-12-31",
)

# Where each fund invests, how concentrated it is and how much the funds hold of the same
country_weightings = funds.etf.get_country_weightings()
concentration = funds.etf.get_concentration()
overlap = funds.etf.get_overlap()

# Show the overlap between every pair of funds
overlap.round(2)

For example, the overlap between every pair of funds is shown below: the share of the two portfolios that is the same. Holdings are those of today, as funds publish their current holdings only.

SOXXXSDPSISMHSMHCKCHP
SOXX10.380.460.700
XSD0.3810.340.2800
PSI0.460.3410.3800
SMH0.70.280.38100
SMHC00001.080
KCHP000001

The three US funds and SMH largely hold the same companies, with SOXX and SMH sharing 70% of their portfolios. SMH holds the most outside the United States, 9% in Taiwan and 6% in the Netherlands. The China and Korea funds share nothing with any other fund, which is what diversification within one sector looks like. Below, the country weights of each fund are plotted next to the overlap.

Comparing the Sector's ETFs

Building a Diversified Portfolio

A fund spreads the risk over the sector, but the sector still moves as one. The portfolio module builds portfolios from the tickers of any Toolkit: minimum variance, maximum Sharpe ratio, mean-variance, risk parity, Hierarchical Risk Parity, minimum CVaR and Black-Litterman weights, the efficient frontier, risk contributions, stress tests and attribution. Below the semiconductor fund is combined with health care (XLV), energy (XLE), long-term Treasuries (TLT) and gold (GLD):

# Initialize the Toolkit for funds across sectors and asset classes from 2021 to 2025
assets = Toolkit(
    ["SMH", "XLV", "XLE", "TLT", "GLD"],
    api_key="FINANCIAL_MODELING_PREP_KEY",
    start_date="2021-01-01",
    end_date="2025-12-31",
)

# The efficient frontier and the maximum Sharpe ratio portfolio, with at most 40% per asset
efficient_frontier = assets.portfolio.get_efficient_frontier(points=25, maximum_weight=0.4)
maximum_sharpe = assets.portfolio.get_maximum_sharpe_weights(maximum_weight=0.4)

# The portfolio in which every asset contributes the same share of the risk
risk_parity = assets.portfolio.get_risk_parity_weights()

# Show the risk parity portfolio
risk_parity

For example, the risk parity portfolio is shown below. Returns and volatilities are annualized and the risk contribution is each asset's share of the portfolio's volatility.

WeightExpected ReturnVolatilitySharpe RatioRisk Contribution
SMH0.10080.30670.35080.77820.2
XLV0.23580.09010.14490.38890.2
XLE0.14810.24630.26720.79540.2
TLT0.275-0.07480.1606-0.67560.2
GLD0.24030.16810.15620.86030.2
Portfolio10.10840.10850.68881

And below the efficient frontier is plotted with both portfolios and each asset on its own, next to the weights of both portfolios.

Building a Diversified Portfolio

Following the Portfolio

Optimal weights on paper still have to be held. The Portfolio class follows a portfolio over time, given as weights, as the shares held, as your own transactions or as one of thirteen classic portfolios such as the 60/40 and the All Weather portfolio. Below the risk parity weights are invested at the start of 2021, brought back to their weights every year and followed up to today:

from financetoolkit import Portfolio

# Invest the risk parity weights and rebalance every year
portfolio = Portfolio(
    weights=risk_parity,
    start_date="2021-01-01",
    rebalancing="yearly",
    api_key="FINANCIAL_MODELING_PREP_KEY",
)

# Get an overview of the positions against the benchmark
overview = portfolio.get_portfolio_overview()

# Show the main figures
overview[["Weight", "Return", "Benchmark Return", "Volatility", "Alpha", "Beta"]]

For example, the main figures of each position are shown below.

IdentifierWeightReturnBenchmark ReturnVolatilityAlphaBeta
GLD0.19690.93990.8490.28450.09090.8392
SMH0.13072.06690.52360.40011.54332.4046
TLT0.2273-0.20380.74570.096-0.94940.2198
XLE0.20341.54580.22360.22121.3222-0.4119
XLV0.24180.55020.79950.1632-0.24930.256
Portfolio10.97031.11430.1047-0.1440.5075

And below the return of each position is plotted against the return of the benchmark over the same period.

Following the Portfolio

With portfolio.toolkit the portfolio, the time-weighted sum of all positions, is loaded into the Toolkit, so every metric above can be calculated for it as well.

MCP Server

The Finance Toolkit MCP Server exposes 500+ financial methods directly to any AI assistant that supports the Model Context Protocol (MCP). Ask questions in plain English — the AI fetches live financial data on your behalf, backed by the transparent, open-source calculation methods of the Finance Toolkit.

See an example of the Finance Toolkit MCP server in action in Claude Desktop below:

https://github.com/user-attachments/assets/96ad5288-d83d-4497-a345-1841c48c29d5

Remote server

Connect directly to the hosted server at https://financetoolkit.jeroenbouma.com/mcp. Nothing needs to be installed locally. On first connection your client opens an OAuth consent page asking for your FMP API key; enter it once and the server handles authentication from there.

ClientSteps
Claude DesktopCustomize → Connectors → Add custom connector → paste the URL
Claude.aiCustomize → Connectors → Add custom connector → paste the URL
Claude Codeclaude mcp add --transport http finance-toolkit https://financetoolkit.jeroenbouma.com/mcp
VS CodeCommand Palette → MCP: Add Server → HTTP → paste the URL
CursorSettings → Features → MCP Servers → Add new → http → paste the URL
WindsurfSettings → MCP Servers → Add Server → Remote/HTTP → paste the URL
Local installation

Run the setup wizard — it locates your client's config file and writes the MCP entry automatically, including the API key:

uvx --from "financetoolkit[mcp]" financetoolkit-mcp-setup

For manual config, add the following to your client's MCP config file (e.g. claude_desktop_config.json, .cursor/mcp.json, .vscode/mcp.json):

{
  "mcpServers": {
    "finance-toolkit": {
      "command": "uvx",
      "args": ["--from", "financetoolkit[mcp]", "financetoolkit-mcp"],
      "env": { "FINANCIAL_MODELING_PREP_API_KEY": "YOUR_API_KEY_HERE" }
    }
  }
}

Alternatively, download the Finance Toolkit MCPB bundle and open it with Claude Desktop. An installation dialog will prompt for your FMP API key.

Questions & Answers

This section includes frequently asked questions and is meant to clear up confusion about certain results and/or deviations from other sources. If you have any questions that are not answered here, feel free to reach out to me via the contact details below.

How do you deal with companies that have different fiscal years?

For any financial statement, I make sure to line it up with the corresponding calendar period. For example, Apple's Q4 2023 relates to July to September of 2023. This corresponds to the calendar period Q3 which is why I normalize Apple's numbers to Q3 2023 instead. This is done to allow for comparison between companies that have different fiscal years.

Why do the numbers in the financial statements sometimes deviate from the data from FinancialModelingPrep?

When looking at a company such as Hyundai Motor Company (ticker: 005380.KS), you will notice that the financial statements are reported in KRW (South Korean won). As this specific ticker is listed on the Korean Exchange, the historical market data will also be reported in KRW. However, if you use the ticker HYMTF, which is listed on the American OTC market, the historical market data will be reported in USD. To deal with this discrepancy, the end of year or end of quarter exchange rate is retrieved which is used to convert the financial statements to USD. This is done to prevent ratio calculations such as the Free Cash Flow Yield (which is based on the market capitalization) or Price Earnings Ratio (which is based on the stock price) from being incorrect. This can be disabled by setting convert_currency=False in the Toolkit initialization. It is recommended to always use the ticker that is listed on the exchange where the company is based.

How can I get TTM (Trailing Twelve Months) and Growth metrics?

Most functions will have the option to define the trailing parameter. This lets you define the number of periods that you want to use to calculate the trailing metrics. For example, if you want to calculate the trailing 12-month (TTM) Price-to-Earnings Ratio, you can set trailing=4 when you have set quarterly=True in the Toolkit initialization. The same goes for growth metrics which can be calculated by setting growth=True. This will calculate the growth for each period based on the previous period. This also includes a lag parameter in which you can define lagged growth. Furthermore, you can also combine the trailing and growth parameters to get trailing growth. For example, set trailing=4 and growth=True for the Price-to-Earnings Ratio which will then calculate the TTM growth.

Does the Finance Toolkit retrieve the same data every time I run it?

No. Any data that comes from an external source (financial statements, historical prices, economic indicators, yield curves, news and so on) is cached automatically in a local SQLite database and reused on the next run, in the Toolkit as well as in the Economics, Fixed Income, Discovery and Portfolio modules. Anything the Finance Toolkit calculates itself, such as ratios, models and risk metrics, is never cached: it is always derived from that data on demand, so it reflects the latest version of the Finance Toolkit.

Cached data does not go stale. Each dataset is retrieved again once it may have changed: prices and financial statements after a day (prices only for the last week, since older bars no longer change), quotes after a minute, company profiles after a month and economic releases according to how often they are published. An answer that a source has no data, such as the ETF holdings of a company, is cached as well, while a failed request, such as a rate limit, is not.

The cache keeps track of what it already holds per ticker and per date range, which means changing a parameter does not throw the rest away:

  • Repeating the same request retrieves nothing at all.
  • Widening the period only retrieves the years that were missing.
  • Adding a ticker only retrieves that one ticker.

The database lives in your user configuration directory, which is the same one the MCP server uses, so both share a single cache. You can choose where it is stored, or switch caching off:

from financetoolkit import Economics, Toolkit

# Store the cache in a specific folder
toolkit = Toolkit(["AAPL", "MSFT"], use_cached_data="datasets")

# Retrieve everything every time
toolkit = Toolkit(["AAPL", "MSFT"], use_cached_data=False)
economics = Economics(use_cached_data=False)

Setting the FINANCE_TOOLKIT_CACHE_ENABLED environment variable to 0 switches caching off by default everywhere, which suits environments where nothing should be written to disk, such as a continuous integration job. FINANCE_TOOLKIT_CACHE_DB moves the shared database to another file.

To see what is currently stored, use toolkit.get_cache_contents(). It reports the entries grouped by source and dataset:

sourcedatasetentitiesentriesoldest_writenewest_write
FinancialModelingPrephistorical222025-01-14 09:12:032025-01-14 09:12:05
FinancialModelingPrepstatements222025-01-14 09:12:012025-01-14 09:12:02

The Finance Toolkit never clears the cache on its own, not even when its own internal structure changes. Removing data is always something you ask for explicitly with toolkit.clear_cache(), and it can be narrowed instead of wholesale:

# Remove only the price history of a single ticker
toolkit.clear_cache(source="FinancialModelingPrep", ticker="AAPL")

# Remove everything retrieved from the OECD
toolkit.clear_cache(source="OECD")

# Remove the entire cache, which has to be confirmed
toolkit.clear_cache(confirm=True)

The source names match the ones used by the enforce_source parameter, so "FinancialModelingPrep" and "YahooFinance" mean the same thing in both places.

What is the "Benchmark" that is automatically obtained when acquiring historical data?

This is related to the benchmark_ticker parameter which is set to "SPY" (S&P 500) by default. This is important when calculating performance metrics such as the Sharpe Ratio or Treynor Ratio that require a market return. This can be disabled by setting benchmark_ticker=None in the Toolkit initialization.

Data collection seems to be slow, what could be the issue?

Generally, it should take less than 15 seconds to retrieve the historical data of 100 tickers. If it takes much longer, this could be due to reaching the API limit (the Starter plan has 250 requests per minute), due to a slow internet connection or due to unoptimized code. The Finance Toolkit collects data with a bounded pool of worker threads (10 by default, configurable through the FINANCETOOLKIT_MAX_WORKERS environment variable) over a shared connection, so it is recommended to initialize the Toolkit with all tickers you want to analyze at once rather than one at a time. If it is taking 10+ minutes consider having a look at this issue that managed to resolve the problem.

I work behind a corporate proxy and get "certificate verify failed" errors, how do I solve this?

Many corporate networks inspect encrypted traffic. The proxy opens every HTTPS connection on your behalf and presents a certificate signed by your company's own root certificate instead of the website's real one. Your browser trusts that root certificate because IT installed it on your computer, but Python does not: it checks certificates against its own list of public certificate authorities (the certifi package), which does not include your company's. The result is an error such as SSLError: certificate verify failed: self-signed certificate in certificate chain.

When a certificate cannot be verified, the Finance Toolkit first retries with your operating system's certificate file, where Python can find one (usually on Linux, not on Windows). If that fails as well, what happens next depends on whether the request carries an API key:

  • Requests without an API key, such as those to the ECB, Eurostat or the BIS, are retried without verifying the certificate. A warning is logged when this happens.
  • Requests with an API key, such as those to FinancialModelingPrep and FRED, are not retried without verification. The key is part of the web address, so anyone who can intercept an unverified connection could read it and use your subscription. The request fails with an error that explains the options below.

The recommended solution is to tell Python to trust your company's root certificate, so every connection stays verified:

  1. Obtain the root certificate as a .pem (or .crt) file. Your IT department can usually provide it. You can also export it from your browser by opening the certificate details of any HTTPS website and exporting the top certificate in the chain ("Base-64 encoded" on Windows).

  2. Combine it with Python's public certificates. The next step replaces Python's list rather than adding to it, so without the public certificates every connection that does not go through the proxy would fail:

    # Prints the location of Python's public certificates
    python -c "import certifi; print(certifi.where())"
    
    # macOS and Linux: combine both into one file
    cat /path/printed/above/cacert.pem /path/to/company-root.pem > ~/combined-certificates.pem
    

    On Windows you can open both files in a text editor and paste the company certificate at the end of a copy of cacert.pem.

  3. Point REQUESTS_CA_BUNDLE to the combined file before using the Finance Toolkit:

    # macOS and Linux, e.g. in ~/.bashrc or ~/.zshrc
    export REQUESTS_CA_BUNDLE=~/combined-certificates.pem
    
    # Windows (PowerShell), for every window opened afterwards
    setx REQUESTS_CA_BUNDLE "C:\Users\you\combined-certificates.pem"
    

    setx does not change the window it runs in, so open a new terminal (or restart your editor) afterwards.

    Or set it within Python, before the first request:

    import os
    
    os.environ["REQUESTS_CA_BUNDLE"] = "/path/to/combined-certificates.pem"
    
    from financetoolkit import Toolkit
    

    When you use the MCP server, add the variable to the env section of the server in your AI assistant's configuration instead.

Alternatively, if your company's root certificate is already installed in your operating system (which is usually the case on managed Windows and macOS computers), the truststore package lets Python use the operating system's certificates directly. Install it with pip install truststore and run import truststore; truststore.inject_into_ssl() at the start of your script.

If none of this is possible, you can accept the risk and allow requests with an API key to be sent without verification by setting FINANCETOOLKIT_ALLOW_UNVERIFIED_SSL=1 in the same way as above. Only do so on a network you trust: the connection is then encrypted to whoever answers it, which may not be the website you think you are talking to, and your API key is readable to them.

Are you part of FinancialModelingPrep?

No, I am not. I've merely picked them as the primary data provider given that they have a generous free tier and fair pricing compared to other providers. Therefore, any questions related to the data should go through their contact form. When it comes to any type of ratios, performance metrics, risk metrics, technical indicators or economic indicators, feel free to reach out to me as this is my own work.

Contributing

First off all, thank you for taking the time to contribute (or at least read the Contributing Guidelines)! 🚀


Find the Contributing Guidelines here.


The goal of the Finance Toolkit is to make any type of financial calculation as transparent and efficient as possible. I want to make these type of calculations as accessible to anyone as possible and seeing how many websites exists that do the same thing (but instead you have to pay) gave me plenty of reasons to work on this.

Mentions

The Finance Toolkit has been mentioned in various blogposts, research papers, newsletters and social media. Below is a list of some of the mentions that I am aware of. If you have any other mentions, feel free to reach out to me so I can add them to this list.

Blogposts

Research

Newsletters & Social Media

Contact

If you have any questions about the Finance Toolkit or would like to share with me what you have been working on, feel free to reach out to me via:

If you'd like to support my efforts, either help me out by contributing to the package or Sponsor Me.

Star History Chart

Comments

Markdown supported

New to MCP?

From what the protocol is to installing your first server, these answers cover most first questions.

An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.