AI agents & LLMs

How do I add fund and ETF data as a tool in LangChain or LangGraph?

Wrap one API call in a LangChain @tool so an agent can answer questions about any ISIN with current TER, holdings, exposures and returns. Python code, plus the MCP adapter route.Updated 12 September 2026 · by FundFacts API

Short answer

Define a @tool that calls GET https://fundfactsapi.com/api/v1/funds/{isin} with your API key and returns a compact dict (name, TER, risk indicator, category, top holdings, sector split, returns, dataAsOf), then bind it to your model or LangGraph agent. Alternatively load the MCP server at https://fundfactsapi.com/api/mcp through langchain-mcp-adapters and get all six tools without writing wrappers. Either way the agent answers with current published figures instead of training-data memory.

A tool in twenty lines

python
# pip install langchain langchain-openai fundfacts
import os
from langchain_core.tools import tool
from fundfacts import FundFacts
ff = FundFacts() # reads FUNDFACTS_API_KEY
@tool
def fund_facts(isin: str) -> dict:
"""Current factsheet of a fund or ETF by 12-character ISIN: name, TER, 1-7 risk
indicator, category, fund size, top holdings, sector and country split,
calendar and annualised returns, as-of date. Returns {"error": ...} when the
ISIN is not a covered fund."""
try:
f = ff.get_fund(isin)
except Exception as e: # FundFactsError carries status and code
return {"error": str(e)}
d = f["data"]
return {
"name": f["name"], "category": d["profile"]["category"], "risk_1_to_7": d["riskRating"],
"ter": d["headlineMetrics"]["ter"], "aum": d["keyFacts"]["aum"],
"top_holdings": d["topHoldings"][:10], "sectors": d["sector"][:8], "countries": d["geography"][:8],
"calendar_returns": d["calendarReturns"], "annualised_returns": d["annualisedReturns"],
"as_of": d["dataAsOf"],
}
@tool
def search_funds(query: str) -> list[dict]:
"""Find fund ISINs by name or issuer, e.g. 'msci world' or 'vanguard all-world'. Free."""
return [{"isin": r["isin"], "name": r["name"], "issuer": r["issuer"]} for r in ff.search(query)["results"][:10]]

Bind the tools to a model and run an agent:

python
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(ChatOpenAI(model="gpt-4.1"), [fund_facts, search_funds],
prompt="You answer questions about investment funds. Always quote as_of with figures. Say 'not disclosed' for empty fields; never estimate.")
result = agent.invoke({"messages": [("user", "What does IE00B4L5Y983 hold and what does it cost?")]})
print(result["messages"][-1].content)

Trimming the payload in the tool (the full one is a few kilobytes with the series) keeps the context small; return the whole data object if the agent needs the monthly series for calculations.

Or use the MCP server directly

python
# pip install langchain-mcp-adapters
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient({
"fundfacts": {
"transport": "streamable_http",
"url": "https://fundfactsapi.com/api/mcp",
"headers": {"Authorization": f"Bearer {os.environ['FUNDFACTS_API_KEY']}"},
}
})
tools = await client.get_tools() # get_fund, search_funds, compare_funds, analyze_portfolio, fund_overlap, get_scpi

The MCP server exposes six tools, each counted like the REST endpoint it wraps: get_fund (ISIN → the full factsheet payload), search_funds (name → ISINs, free), compare_funds (side-by-side table for several ISINs), analyze_portfolio (weighted look-through of a list of positions, Pro and above), fund_overlap (shared holdings between funds, Pro and above) and get_scpi (French SCPI data by name or ISIN). Authentication is the same bearer API key as the REST API, sent as an Authorization header.

Notes for production agents

  • The first call for a cold ISIN can take up to a few minutes; give the tool a 300-second timeout and tell the model a first lookup can be slow.
  • One request per ISIN answered. Cache tool results by ISIN until expiresAt if users repeat questions.
  • The fund data for AI agents guide covers prompt design and guardrails in more depth.

Verify it yourself

The demo endpoint returns the live payload for a fund that is already in the store, without a key. Everything on this page can be checked against it.
bash
curl -s https://fundfactsapi.com/api/v1/demo/funds/IE00B4L5Y983 | jq '{name, asOf: .data.dataAsOf, ter: .data.headlineMetrics.ter, risk: .data.riskRating, top: .data.topHoldings[:3]}'

Frequently asked questions

Do I need a credit card to try it?

No. The Free plan is 15 lookups per month with no card; sign up with an e-mail address or Google and the key is shown in the dashboard.

Which ISINs work?

Any share class of a UCITS fund, ETF, money-market fund or open-end fund whose management company publishes a product page, factsheet and KID. Each share class has its own ISIN and is looked up on its own. Stocks, bonds and indices are not funds and return 404 fund_not_found.

Try it on your own ISINs

One request returns key facts, holdings, risk and performance as JSON. Free plan, no card.