Browse documentation
MCP server reference
Every tool and resource the FactIQ MCP server offers: what each one does, the arguments it takes, what it returns, and the limits that apply.
Start here
https://api.factiq.com/mcp. It gives an AI assistant tools that find and read data. The assistant does the analysis; the server runs no model of its own.Reads only
50 rows per call
Described by the server
tools/list. This page is a summary of that answer.Connect
https://api.factiq.com/mcpThe server accepts two kinds of credential.
- 01
Browser sign-in
Claude, ChatGPT, Claude Code and Codex CLI register themselves with the server and open a FactIQ sign-in page in the browser (OAuth 2.1). The client receives the read-onlyfactiq:readscope. An access token lasts one hour and the client renews it without a new sign-in. Follow the setup guide for your client. - 02
API key
A script, a service, or a coding agent on a machine with no browser sends a FactIQ API key as a bearer token. See Programmatic access for how to create the key and for curl and Python examples.
Read the tool list from the server
This request returns the name, the full description and the JSON schema of the arguments for every tool. When this page and that answer differ, the answer from the server is correct.
curl -X POST https://api.factiq.com/mcp \
-H "Authorization: Bearer $FACTIQ_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}'Order of calls
- 01
Read the catalog
Callget_data_catalogonce. Ignore the schemas listed underschemas_without_data. - 02
Find the series
Usesearch_datasetsandsearch_seriesfirst. When they find nothing, query theseriesanddimensionstables withrun_sql. - 03
Fetch the numbers
Useget_seriesfor one known series. Userun_sqlfor several series or for an aggregate. - 04
Add other evidence
Use the company, earnings-call, media, news, market and satellite tools when the question needs them. Each tool has acoverageoption or a catalog that shows what it holds. - 05
Write it up
Callget_style_guidesbefore you build a chart or a report. Put the returnedsource_urlnext to each figure or quote you use.
All tools
| Tool | Purpose |
|---|---|
| get_data_catalog | Lists every data source the account can read, plus the table structure that all sources share. Call it once at the start of a session. |
| search_datasets | Keyword search over dataset titles and topics in every schema. The ranking is by keyword, not by meaning. |
| describe_dataset | Full metadata for one dataset. Call it after search_datasets has identified the dataset. |
| search_series | Finds series in one schema by words in the title. The match is a substring match, so short word stems work best ("rare" finds more than "rare earth"). |
| get_series | Returns one series with its metadata. It accepts ordinary time series, tabular series and COMPOUND:: series. |
| run_sql | Runs one read-only SELECT statement against one schema. Use it for joins, pivots, aggregation, and catalog searches that the search tools cannot express. |
| get_market_data | Recent prices and company profiles from a market-data provider. Use it for quotes, currencies and commodities that the stored series do not yet cover. |
| get_geo_data | Satellite-derived indicators for a country, one state or province, or a bounding box. FactIQ computes the result from the provider at the time of the call, so a call can take 30 seconds or more. |
| search_company_filings | Figures and statements from the reports one company filed: US SEC filers, and companies listed in Germany, the UK and France. |
| search_earnings_transcripts | What management and analysts said on earnings calls, stored as separate claims with an exact quote each. It never returns a whole transcript. |
| search_media_appearances | Claims made on podcasts, in television interviews and at conferences, and in official documents such as Federal Reserve speeches, testimony, statements and minutes. |
| search_news | Headlines and short publisher summaries from the news feeds FactIQ collects. It holds recent news, not an archive, and it never returns the body of an article. |
| get_style_guides | Returns FactIQ’s written guides for charts, reports, SQL and earnings-call work as Markdown text. |
| render_chart | Draws an interactive line, bar or area chart inside the conversation from numbers the assistant has already fetched. The server lists this tool only for ChatGPT and Codex, which can display the chart component. |
| send_feedback | Sends a report about wrong data or a failing tool to the FactIQ team. It is the only tool that does more than read. |
Find data
get_data_catalog
Lists every data source the account can read, plus the table structure that all sources share. Call it once at the start of a session.
| Parameter | Type | Meaning |
|---|---|---|
schemasstring | string | Comma-separated list of schema names to return, for example "bls,bea". Omit it to get every schema. |
fullboolean | boolean | Return the long description of every dataset instead of the compact index. Default: false |
Returns. The visible schemas with their organization and country, a list named schemas_without_data for schemas that hold no rows yet, a dataset index per schema, and the definitions of the series, data_points, dimensions and compound_series tables.
Example arguments
{
"schemas": "bls,bea"
}search_datasets
Keyword search over dataset titles and topics in every schema. The ranking is by keyword, not by meaning.
| Parameter | Type | Meaning |
|---|---|---|
queryRequiredstring | string | Search words. |
schemasstring[] | string[] | Restrict the search to these schemas. |
limitinteger | integer | Maximum number of datasets to return. Default: 15 |
Returns. Ranked rows of schema, dataset_code, title and topic.
Example arguments
{
"query": "consumer prices",
"schemas": [
"bls"
]
}describe_dataset
Full metadata for one dataset. Call it after search_datasets has identified the dataset.
| Parameter | Type | Meaning |
|---|---|---|
schemaRequiredstring | string | Schema that holds the dataset. |
dataset_codeRequiredstring | string | Dataset code from search_datasets or the catalog. |
Returns. Topic, methodology, known breaks in the series, any notice of a changed base year, the dimensions that exist in the data, and example series.
Example arguments
{
"schema": "bls",
"dataset_code": "cu"
}search_series
Finds series in one schema by words in the title. The match is a substring match, so short word stems work best ("rare" finds more than "rare earth").
| Parameter | Type | Meaning |
|---|---|---|
schemaRequiredstring | string | Schema to search. |
termsRequiredstring[] | string[] | Title words. The tool first looks for titles that contain every term. If none match, it returns titles that contain any term. |
limitinteger | integer | Maximum number of series to return. Default: 15 |
include_compoundboolean | boolean | Include series that FactIQ computes from other series. Their ids start with COMPOUND::. Default: true |
Returns. Matching series with series_id, title, dataset_code, frequency, units, seasonal adjustment, begin_time and end_time, plus a note that says whether all terms or any term matched.
- When this tool finds nothing, query the series and dimensions tables with run_sql.
Example arguments
{
"schema": "bls",
"terms": [
"unemployment",
"rate"
]
}Fetch data
get_series
Returns one series with its metadata. It accepts ordinary time series, tabular series and COMPOUND:: series.
| Parameter | Type | Meaning |
|---|---|---|
schemaRequiredstring | string | Schema that holds the series. |
series_idRequiredstring | string | Series id from search_series or run_sql. |
from_yearinteger | integer | First year to return. |
to_yearinteger | integer | Last year to return. |
transformstring | string | "yoy_pct" adds the percent change from the same period one year earlier. "yoy_diff" adds the difference, which is the right choice for a rate. Periods are matched by calendar date, so a missing month does not shift later comparisons. |
Returns. Title, units, frequency, notes, source metadata and the observations. A coverage_note and a missing_periods list appear when the series has periods with no observation. Series built from company filings also carry row_sources, which names the filing behind each row.
Example arguments
{
"schema": "bls",
"series_id": "LNS14000000",
"from_year": 2024,
"transform": "yoy_diff"
}run_sql
Runs one read-only SELECT statement against one schema. Use it for joins, pivots, aggregation, and catalog searches that the search tools cannot express.
| Parameter | Type | Meaning |
|---|---|---|
schemaRequiredstring | string | Schema the statement reads. |
sqlRequiredstring | string | One SELECT statement. Qualify table names with the schema, for example bls.data_points. |
questionstring | string | The question the statement answers. It is stored with the call and helps FactIQ diagnose a failed query. |
exploreboolean | boolean | Set it to true for a statement that only looks for which data exists. The result is then marked exclude_from_data_panel. Default: false |
auto_retryboolean | boolean | When the statement returns zero rows, let the server revise it once and run it again. Default: false |
pageinteger | integer | Page number. It works only on the nasa_fires schema, where each row is one fire detection and cannot be aggregated into a series. Default: 1 |
Returns. row_count, columns and results. When the statement matches more than 50 rows, truncated is true and a note says how many rows exist. On nasa_fires the result carries page and has_more instead.
- The database role is read-only. INSERT, UPDATE, DELETE and DDL statements are rejected.
- A statement is cancelled after 30 seconds.
- For a year-over-year comparison, join on the calendar period with date_trunc. Do not use LAG(value, 12): one missing month makes every later comparison wrong.
Example arguments
{
"schema": "bls",
"sql": "SELECT date_trunc('year', time) AS year, avg(value) AS unemployment_rate FROM bls.data_points WHERE series_id = 'LNS14000000' AND time >= '2015-01-01' GROUP BY 1 ORDER BY 1"
}get_market_data
Recent prices and company profiles from a market-data provider. Use it for quotes, currencies and commodities that the stored series do not yet cover.
| Parameter | Type | Meaning |
|---|---|---|
assetRequiredstring | string | Ticker, currency pair, commodity name, or company search text. Examples: "AAPL", "EUR/USD", "WTI", "NVIDIA". |
data_typestring | string | One of price_history, quote, company_profile, etf_profile, symbol_search. Default: "price_history" |
frequencystring | string | For price_history: daily, weekly or monthly. Default: "daily" |
limitinteger | integer | Maximum number of price rows, from 1 to 5,000. Default: 100 |
Returns. Price rows with open, high, low, close and volume, or the requested quote or profile.
- Financial statements and reported company figures come from search_company_filings, not from this tool.
Example arguments
{
"asset": "EUR/USD",
"data_type": "price_history",
"frequency": "weekly",
"limit": 52
}get_geo_data
Satellite-derived indicators for a country, one state or province, or a bounding box. FactIQ computes the result from the provider at the time of the call, so a call can take 30 seconds or more.
| Parameter | Type | Meaning |
|---|---|---|
datasetRequiredstring | string | One of fires_viirs, no2_tropomi, so2_tropomi, co_tropomi, aerosol_index_tropomi, ndvi_s2, precip_chirps, precip_imerg, temperature_power, soil_moisture_power. |
regionRequiredstring | string | A country name or ISO3 code ("India", "IND"); "Country/State" for a state or province ("India/Punjab", "CHN/Guangdong"); or "bbox:west,south,east,north" in degrees. |
start_dateRequiredstring | string | First day, as YYYY-MM-DD. |
end_dateRequiredstring | string | Last day, as YYYY-MM-DD. |
aggregationstring | string | "monthly" or "daily" returns a time series. fires_viirs, ndvi_s2 and the *_tropomi datasets also accept "grid", which returns one row per latitude and longitude cell. fires_viirs also accepts "seasons" and "points". Default: "monthly" |
resolutionnumber | number | Grid cell size in degrees. Only for fires_viirs with aggregation "grid". |
include_flaresboolean | boolean | Only for fires_viirs. Set it to true to count gas flares, industrial heat sources, volcanoes and offshore detections. Default: false |
Returns. Rows for each interval or grid cell, with units, the source attribution to cite, and caveats for the dataset.
- State and province boundaries exist for IND, CHN, IDN, VNM, THA, MYS, PHL, PAK, BGD, LKA, MMR, KHM, NPL, KOR, JPN, TWN and USA.
- Most datasets allow at most 50 intervals per call. fires_viirs allows 200.
Example arguments
{
"dataset": "fires_viirs",
"region": "India/Punjab",
"start_date": "2025-10-01",
"end_date": "2025-11-30",
"aggregation": "daily"
}Research companies and news
search_company_filings
Figures and statements from the reports one company filed: US SEC filers, and companies listed in Germany, the UK and France.
| Parameter | Type | Meaning |
|---|---|---|
companyRequiredstring | string | An exact ticker is best. A full company name or an LEI also works when it identifies one company. |
search_targetstring | string | coverage lists the reports and dates held. filings lists report records and their source URLs. metrics lists the available measures. facts returns reported numbers. commentary returns management statements with exact quotes. risk_changes returns year-over-year changes to the stated risk factors. Default: "facts" |
conceptstring | string | One measure, for example "revenue". The tool selects the best stored match and returns it across periods. Only for metrics and facts. |
querystring | string | Word search across measure names, labels and segment names. For commentary and risk_changes it searches the statements and quotes. |
report_typestring | string | annual, quarterly or half_year, or a form name such as 10-K or 10-Q. |
fiscal_yearinteger | integer | Company fiscal year, for example 2026. |
fiscal_periodstring | string | Q1, Q2, Q3, Q4 or FY. |
metric_classstring | string | Class of measure, for example financial, ifrs, segment, kpi or apm. |
segmentstring | string | Business segment, product or region. |
date_fromdate | date | Earliest period-end date, inclusive. |
date_todate | date | Latest period-end date, inclusive. |
formatstring | string | "json" returns the result as a JSON tree. "pretty" returns the same tree as readable text. A call returns one form, never both. Default: "json" |
limitinteger | integer | Maximum matched rows, from 1 to 50. Each reported number is one row. Default: 20 |
Returns. A tree grouped by filing or by measure. Each filing and each figure carries source_url and a source_link object that points to the original document.
- commentary and risk_changes cover US SEC filers only.
- When an exact ticker has no stored figure for a metrics or facts request, the tool answers from a market-data provider’s standardized statements. Those values carry no link to a filing.
Example arguments
{
"company": "NVDA",
"search_target": "facts",
"concept": "revenue",
"report_type": "annual"
}search_earnings_transcripts
What management and analysts said on earnings calls, stored as separate claims with an exact quote each. It never returns a whole transcript.
| Parameter | Type | Meaning |
|---|---|---|
search_targetstring | string | claims returns statements by management and analysts. pressure_points returns what analysts asked for and whether management answered. disclosure_profile returns the recorded disclosure habits of one company. coverage lists the calls held. Default: "claims" |
querystring | string | Search words. An empty query returns the most recent rows. |
tickerstring | string | One ticker or a comma-separated list. |
company_namestring | string | One company name or a comma-separated list. Pass ticker or company_name, not both. |
quarter_filterstring | string | Exact fiscal period, for example FY2026Q3. |
claim_familystring | string | Claim category code, for example pricing_mechanics or capital_allocation. The tool description lists all codes. |
sectionstring | string | prepared_remarks or qa. Only for claims. |
detailboolean | boolean | Add the structured fields of each claim, such as period and time horizon. Default: false |
limitinteger | integer | Maximum rows, from 1 to 50. Default: 15 |
Returns. Rows with the speaker, role, fiscal period, a normalized statement, the exact quote, and a source_link. Coverage rows give the number of calls and the first and last period for each company.
- Only verbatim_quote is a quotation. canonical_statement is a rewritten summary and must not be placed in quotation marks.
- An empty result does not prove that management said nothing on the subject. Check coverage first, then try other words.
Example arguments
{
"search_target": "claims",
"ticker": "MU",
"query": "capital expenditure",
"detail": true
}search_media_appearances
Claims made on podcasts, in television interviews and at conferences, and in official documents such as Federal Reserve speeches, testimony, statements and minutes.
| Parameter | Type | Meaning |
|---|---|---|
search_targetstring | string | search returns claims and passage summaries together. claims, passages and pressure_points each return one kind. appearances lists the recordings and documents held. coverage counts them per company. Default: "search" |
querystring | string | Search words. An empty query returns recent rows. |
companystring | string | Tickers and names in one comma-separated list, for example "NVDA,OpenAI,Federal Reserve". |
personstring | string | Part of a speaker name. |
appearance_typestring | string | podcast, tv_interview, conference or other for interviews; speech, testimony, minutes, statement, press_conference or hearing for official documents. |
institutionstring | string | Part of the name of the institution that published an official document, for example "Federal Reserve". |
countrystring | string | ISO country code of that institution, for example "US". |
claim_familystring | string | Claim category code. It cannot be combined with search_target "passages". |
date_fromstring | string | Earliest publication date, as YYYY-MM-DD. |
date_tostring | string | Latest publication date, as YYYY-MM-DD. |
sortstring | string | relevance or newest. Default: "relevance" |
detailboolean | boolean | Add the structured claim fields and the fields that say how the recording was linked to a company. Default: false |
limitinteger | integer | Maximum rows, from 1 to 50. Default: 15 |
Returns. Rows with the speaker, a summary of what was said, topic labels, the channel and publication date, and a source_url that opens the video at the right time or the document at the right page.
- The text in canonical_paraphrase is a summary, not a quotation. Open source_url and check the wording before you quote it.
- A company value that matches nothing is listed under company_unmatched with up to five possible matches. It returns no rows and no error.
Example arguments
{
"search_target": "claims",
"company": "OpenAI",
"query": "compute",
"sort": "newest"
}search_news
Headlines and short publisher summaries from the news feeds FactIQ collects. It holds recent news, not an archive, and it never returns the body of an article.
| Parameter | Type | Meaning |
|---|---|---|
querystring | string | Search words over headline and summary. Every word must match, so start with one distinctive word. Quoted phrases and -exclusion work. |
tickersstring[] | string[] | Return articles that name any of these companies, for example ["NVDA", "RELIANCE"]. |
topicstring | string | One of markets, economics, companies, technology, politics, world, energy, health, india, opinion. |
sourcesstring[] | string[] | Publisher codes, for example bloomberg, ft, wsj, who. |
start_datestring | string | Earliest publication date, as YYYY-MM-DD. |
end_datestring | string | Latest publication date, as YYYY-MM-DD. |
sortstring | string | latest or relevance. relevance needs a query. Default: "latest" |
limitinteger | integer | Maximum rows, from 1 to 50. Default: 20 |
Returns. rows with published_at, source, title, summary, url, the tickers named in the text, and an analysis block with keywords, a geography and one sentence on why the story matters. meta gives the number matched and returned.
Example arguments
{
"query": "copper",
"topic": "markets",
"limit": 10
}Resources
| URI | Type | Content |
|---|---|---|
| factiq://catalog | application/json | The same content as get_data_catalog with no arguments. |
| factiq://guide/chart-style | text/markdown | Chart type choice, titles, colours and sourcing. |
| factiq://guide/report-style | text/markdown | Report structure, narrative style and per-chart sources. |
| factiq://guide/sql | text/markdown | Table structure, query patterns and common mistakes. |
| factiq://guide/earnings-style | text/markdown | Quotation rules and the difference between spoken and filed figures. |
The four guides are the same documents that get_style_guides returns. The tool exists because many clients do not read resources.
Limits
- Rows.
get_series,run_sqland the search tools return at most 50 rows. A longer result is sampled at even intervals and carriestruncated: true. There is no option that returns every row. - SQL time. A statement is cancelled after 30 seconds.
- Rate. Up to 10 calls per second for each account. A faster caller gets a
429tool error. - Market prices.
get_market_datais the exception to the row limit. It returns up to 5,000 price rows whenlimitasks for them.
When a result is truncated
Change the query so that the answer fits in 50 rows: group by month, quarter or year with date_trunc, compute the sum, average, rank or ratio in SQL, or pass from_year and to_year to get_series.
{
"row_count": 1284,
"columns": ["time", "value"],
"results": [ ...50 rows... ],
"truncated": true,
"note": "Showing 50 of 1284 rows. To use the rest, aggregate or compute it in SQL ..."
}Errors and retired tools
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [{ "type": "text", "text": "429: Too many requests. Please wait a moment before asking another question." }],
"isError": true
}
}When search_company_filings cannot identify the company, the error text lists the closest stored companies, so that the next call can use one of them.
Tool names that changed
An older client can still call a tool name that the server no longer lists. The server does not answer with “unknown tool”. It returns a result that names the replacement, so the assistant can call the new name in the same conversation.
search_earningsis nowsearch_earnings_transcripts.search_company_filings_treeis nowsearch_company_filings.share_chart,share_reportandlist_my_artifactswere removed and have no replacement.
What the server does not do
- It does not change stored data. Every SQL statement runs under a read-only database role.
- It does not return a complete earnings-call transcript. It returns separate claims, each with a quote.
- It does not publish a chart or a report to a public page.
render_chartdraws a chart inside the conversation only. - It does not answer questions. It returns data, and the assistant that called it does the analysis.
For how to ask good research questions with these tools, read Get better results. For what each data source covers, read the coverage overview.