Connect Claude, ChatGPT or Cursor to fund data with an MCP server
Set up the FundFacts MCP server in Claude Code, Cursor and ChatGPT: one URL, a bearer key, and tools for fund lookup, comparison, look-through and overlap.Published 18 September 2026 · 6 min read · by FundFacts APIAn MCP server gives an AI assistant tools it can call, and a fund data MCP server gives it the ability to look up any fund or ETF by ISIN, compare several, aggregate a portfolio and check holdings overlap, with the answers grounded in the fund's own published documents rather than the model's memory. FundFacts runs a remote Model Context Protocol server at https://fundfactsapi.com/api/mcp over Streamable HTTP; any client that supports remote servers with a bearer header (Claude Code, Claude Desktop, Cursor, Windsurf, ChatGPT connectors, or your own agent) can use it with one URL and an API key.
What the Model Context Protocol is, briefly
MCP is an open protocol that standardises how an AI application discovers and calls external tools. A server publishes a list of tools with JSON schemas; the client (Claude, Cursor, ChatGPT, an agent framework) shows those tools to the model, and when the model decides to call one, the client forwards the call and returns the result. The point is that the same server works in every client without per-client integration code. For fund data this replaces a pattern where each team wrote its own getFund function-calling wrapper, which the LLM tooling post describes.
Remote MCP servers speak Streamable HTTP: the client POSTs JSON-RPC messages to one URL and can receive streamed responses. Authentication is a normal HTTP header, so a FundFacts API key works as the bearer token exactly as it does for the REST API.
The seven tools
| Tool | What it does | Input | Cost |
|---|---|---|---|
get_fund | Structured factsheet for one ISIN: key facts, TER, risk indicator, derived profile, holdings, breakdowns, returns, series, risk statistics, as-of date | { isin } | 1 |
search_funds | Find ISINs by name, issuer or ISIN prefix among loaded funds | { query, limit? } | Free |
compare_funds | Side-by-side table for several ISINs: category, TER, risk, size, distribution, 1/3/5-year annualised returns, volatility, Sharpe, max drawdown, top-10 concentration | { isins[], includeFullData? } | 1 per ISIN |
analyze_portfolio | Look-through of weighted positions: blended TER, weighted risk indicator, asset / sector / country / region / credit exposure, currency split, combined top holdings, each with coverage | { positions: [{ isin, weight }] } | 1 per position |
fund_overlap | Pairwise holdings overlap and shared positions for two or more ISINs | { isins[] } | 1 per ISIN |
get_scpi | Structured data for a French SCPI by slug, ISIN or name | { id } | 1 |
search_scpi | Find SCPIs by name, manager or ISIN prefix | { query, limit? } | Free |
The tools behave exactly like the corresponding REST endpoints (GET /funds/{isin}, GET /search, POST /funds, POST /portfolio, GET /overlap, GET /scpi/{id}, GET /scpi?q=) and draw from the same 24-hour store, so a fund the API has served today is answered in well under a second. A fund nobody has requested before is loaded on demand, which can take a few minutes; the tool tells the model to ask again shortly rather than block. Tool descriptions carry the operational rules (no advice, quote the as-of date, one request per ISIN) so the model reads them without a system prompt.
Claude Code
One command:
bashclaude mcp add --transport http fundfacts https://fundfactsapi.com/api/mcp \--header "Authorization: Bearer ffk_live_..."
Then, in a session: "Compare IE00B4L5Y983 and IE00B3RBWM25 on fees, risk and top holdings, and tell me how much they overlap." Claude Code calls compare_funds and fund_overlap and answers from the results. If you are using Claude Code to build a product rather than to ask questions, the coding-agent post covers the AI companion kit (an AGENTS.md, a Claude skill, a Cursor rule and the OpenAPI spec) that ships with every paid plan.
Cursor and Windsurf
Both read an mcp.json (project-level .cursor/mcp.json or the global one in Cursor's settings). The remote-server entry is:
json{"mcpServers": {"fundfacts": {"url": "https://fundfactsapi.com/api/mcp","headers": { "Authorization": "Bearer ffk_live_..." }}}}
Enable the server in the MCP settings panel and the seven tools appear in the agent's tool list. A useful pattern while coding is to let the agent call get_fund on a real ISIN once, so it sees the actual payload shape rather than guessing field names.
Claude Desktop and other remote-capable clients
Clients that support adding a remote MCP server by URL take the same address. Where the client has no field for a custom header, or only speaks stdio, bridge it with mcp-remote, which runs locally, forwards to the remote URL and adds the header:
json{"mcpServers": {"fundfacts": {"command": "npx","args": ["-y", "mcp-remote", "https://fundfactsapi.com/api/mcp", "--header", "Authorization: Bearer ffk_live_..."]}}}
This is the configuration to use for any client whose config format is "command + args".
ChatGPT
ChatGPT connectors that accept a remote MCP server URL can point at the same address with the bearer key as the authorisation header. The tools then show up in the conversation, and a prompt such as "What does LU1681043599 hold and what does it cost?" triggers get_fund. Availability of custom connectors depends on the ChatGPT plan and workspace settings, so check the current OpenAI documentation for where the option lives.
Your own agent
If you are writing the agent, use an MCP client library and connect to the URL with the header. In TypeScript with the official SDK:
typescriptimport { Client } from "@modelcontextprotocol/sdk/client/index.js";import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";const transport = new StreamableHTTPClientTransport(new URL("https://fundfactsapi.com/api/mcp"), {requestInit: { headers: { Authorization: `Bearer ${process.env.FUNDFACTS_API_KEY}` } },});const client = new Client({ name: "my-agent", version: "1.0.0" });await client.connect(transport);const tools = await client.listTools(); // get_fund, search_funds, compare_funds, …const result = await client.callTool({ name: "get_fund", arguments: { isin: "IE00B4L5Y983" } });// result.content[0].text is the JSON envelope: { isin, name, cached, generatedAt, data: { … } }
If you would rather generate tools from a spec, the OpenAPI 3.1 document describes the same endpoints and /llms-full.txt is the whole documentation in one file for a retrieval step.
Prompts that work well
The tools are narrow on purpose (an ISIN in, a factsheet out), so the best prompts give the model an ISIN or a name it can search:
- "Search for 'core msci world' and get the factsheet of the accumulating USD share class."
- "Compare FR0010315770 with IE00B4L5Y983: fees, risk indicator, 3-year volatility, top holdings."
- "I hold 60% IE00B4L5Y983, 30% IE00B3RBWM25 and 10% LU1681043599. What is my country and sector exposure and my blended TER?"
- "How much do IE00B4L5Y983 and IE00B3RBWM25 overlap, and which shared holdings drive it?"
- "Get the SCPI 'perial-o2' and summarise its distribution rate history and occupancy."
Each answer should quote the dataAsOf date, which the tool returns; the tool descriptions ask the model to do so.
Requests, keys and safety
- Requests. The MCP server draws on the same monthly requests as the REST API: Free 150, Starter 1,500 ($9), Pro 9,000 ($49), Scale 60,000 ($249); Enterprise is metered at $0.01 per request. See pricing. Search tools are free; the others cost one request per ISIN answered.
- Keys. The key in your MCP config is a real credential. Keep it in a config file that is not committed, and create a separate key per machine from the dashboard so one can be revoked without touching the others (multiple keys are available from Pro).
- Grounding. The model only sees what the tool returns. It cannot fabricate a TER for a fund the server does not cover, because
get_fundreturns a clear not-found message and the description tells the model not to answer from memory. The grounding and guardrails post covers the rules to add on your side for a customer-facing assistant, and the AI fund assistant use case shows the product shape.
The full setup reference, including the OpenAPI spec and the companion kit, is on the AI agents and MCP docs page. A free key is enough to try every tool.
FAQ
What is the URL of the FundFacts MCP server?
https://fundfactsapi.com/api/mcp, using the Streamable HTTP transport. Authenticate with Authorization: Bearer ffk_..., the same API key used for the REST endpoints.
Which tools does the fund data MCP server expose?
get_fund (factsheet by ISIN), search_funds (find ISINs by name), compare_funds (side-by-side table), analyze_portfolio (look-through of weighted positions), fund_overlap (pairwise holdings overlap), and get_scpi / search_scpi for French SCPIs.
Does the MCP server cost extra?
No. Tool calls draw on the plan's monthly requests exactly like REST calls: one request per ISIN answered, search free. The Free plan's 150 requests are enough to try every tool.
My client only supports stdio MCP servers. Can I still use it?
Yes. Run npx -y mcp-remote https://fundfactsapi.com/api/mcp --header "Authorization: Bearer ffk_..." as the server command; mcp-remote bridges stdio to the remote Streamable HTTP endpoint and adds the header.
Can the model give investment advice through these tools?
The tools return data, not recommendations, and their descriptions instruct the model to describe rather than advise and to quote the as-of date. For a customer-facing assistant you should still enforce a no-advice rule in your own system prompt and code.