Monitly MCP Documentation
MCP Overview
The Monitly MCP server gives AI agents direct access to official statistics and economic indicators (Eurostat, World Bank, OECD, IMF, national statistical offices) through the Model Context Protocol. Clients such as Claude Desktop, Cursor, Windsurf, VS Code or your own agents call structured tools to find datasets, read time series and manage the Monitly account — watchlist, alerts, keys and plan — without leaving the chat.
https://monit.ly/api/mcp2024-11-05 · server name monitlyinitialize, tools/list, tools/call, ping, notifications/initializedQuickstart
- Create a key in Settings → Integrations → MCP. It starts with
mcpk_and is shown only once. - Add the server to your client configuration (below).
- Restart the client if it does not reload MCP configuration, then ask in natural language — the model maps your prompt to tool calls.
{
"mcpServers": {
"monitly": {
"url": "https://monit.ly/api/mcp",
"headers": {
"Authorization": "Bearer mcpk_YOUR_KEY"
}
}
}
}{
"mcpServers": {
"monitly": {
"url": "https://monit.ly/api/mcp",
"headers": {
"Authorization": "Bearer mcpk_YOUR_KEY"
}
}
}
}curl -s https://monit.ly/api/mcp \
-H "Authorization: Bearer mcpk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'Authentication
Every request must carry an MCP key. Keys belong to your account, are stored only as SHA-256 hashes and can be revoked at any time. MCP keys (mcpk_…) are separate from REST API keys (mon_…).
Authorization: Bearer mcpk_…X-API-Key: mcpk_…list_mcp_keys, create_mcp_key, delete_mcp_key. A missing or revoked key returns HTTP 401 with a JSON-RPC error body.
Quota
Data tools — each successful tools/call uses one unit of the monthly mcp_queries meter. Account tools are free. initialize, tools/list and ping are never metered. The meter resets with your billing period; check it any time with get_usage.
| Plan | MCP queries / month | Watchlist datasets | REST API / day |
|---|---|---|---|
| Essential (free) | 10 | 5 | 100 |
| Pro | 500 | 100 | 5,000 |
When the limit is reached, data tools return a JSON-RPC error with the used / limit counts. Upgrade from the agent with upgrade_plan or on the pricing page.
Data tools
DATAsearch_catalog
Hybrid search over the catalog (name/code + embeddings). Returns compact dataset cards with id, code, source, period range and available geographies — not the values. Start every analysis here.
| Name | Type | Description |
|---|---|---|
| query* | string | What to find, e.g. 'unemployment rate monthly'. |
| country | string | Prefer datasets that include this country, e.g. 'Germany'. |
| source_name | string | Filter by source: 'Eurostat', 'World Bank', 'OECD', 'IMF'… |
| limit | integer | 1–16, default 8. |
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "search_catalog",
"arguments": {
"query": "HICP inflation rate",
"country": "Poland",
"limit": 2
}
}
}{
"datasets": [
{
"id": 4179,
"dataset_code": "tec00118",
"dataset_name": "HICP - inflation rate",
"source_name": "Eurostat",
"oldest_period": "2013",
"latest_period": "2024",
"observation_count": 476,
"dim_labels": ["Time frequency", "Unit of measure", "Classification of individual consumption by purpose (COICOP)"],
"default_view": {
"dim1": ["Annual"],
"dim2": ["Annual average rate of change"],
"dim3": ["All-items HICP"],
"country": ["Poland"]
},
"has_country": true,
"geo_count": 38,
"match": "lexical"
}
],
"returned_count": 1
}DATAsearch_datasets
Same as search_catalog — kept for clients that expect this name.
| Name | Type | Description |
|---|---|---|
| query* | string | What to find. |
| country | string | Optional country. |
| source_name | string | Optional source filter. |
| limit | integer | 1–16, default 8. |
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "search_datasets",
"arguments": {
"query": "GDP per capita PPS"
}
}
}{ "datasets": [ … ], "returned_count": 8 }DATAinspect_dataset
Look into one dataset: default slice, dimension values, whether a country is present, the data id to query and the latest observations. Use it before execute_sql.
| Name | Type | Description |
|---|---|---|
| id* | integer | Dataset id (main.id) from search_catalog. |
| country | string | Country to resolve in the series, e.g. 'Poland'. |
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "inspect_dataset",
"arguments": {
"id": 4179,
"country": "Poland"
}
}
}{
"dataset": {
"id": 4179,
"dataset_code": "tec00118",
"dataset_name": "HICP - inflation rate",
"default_view": { "dim1": ["Annual"], "dim2": ["Annual average rate of change"], "dim3": ["All-items HICP"], "country": ["Poland"] }
},
"series": {
"dataId": 7229553,
"dim_values": { "dim1": "Annual", "dim2": "Annual average rate of change", "dim3": "All-items HICP" },
"country_header": "Poland",
"country_in_format": true,
"recent": [
{ "period": "2023", "value": "10.9" },
{ "period": "2024", "value": "3.7" },
{ "period": "2025", "value": "3.3" }
]
}
}DATAget_dataset
Full metadata row for one dataset: description, source and metadata URLs, dimension labels, default view, period range and geographies.
| Name | Type | Description |
|---|---|---|
| id* | integer | Dataset id (main.id). |
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_dataset",
"arguments": {
"id": 4179
}
}
}{
"dataset": {
"id": "4179",
"dataset_code": "tec00118",
"dataset_name": "HICP - inflation rate",
"description": "Harmonised Indices of Consumer Prices (HICPs) are designed for international comparisons…",
"source_name": "Eurostat",
"last_update": "2026-07-17T11:00:00+0200",
"oldest_period": "2013",
"latest_period": "2024",
"observation_count": 476,
"available_geo": { "AT": "Austria", "DE": "Germany", "PL": "Poland", "…": "…" }
}
}DATAexecute_sql
Run one read-only SELECT (or WITH … SELECT) against the tables main and data to pull exact time series for a known dataset. Each data row is one series (dim1_value…dim8_value, unit); format holds the column headers (countries) and values the semicolon-separated rows. Use after search_catalog + inspect_dataset (which gives the dataId); always add LIMIT.
| Name | Type | Description |
|---|---|---|
| query* | string | SELECT statement on main / data only. |
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "execute_sql",
"arguments": {
"query": "SELECT id, dim1_value, dim2_value, dim3_value, unit, format, values FROM data WHERE id = 7229553"
}
}
}{
"rows": [
{
"id": "7229553",
"dim1_value": "Annual",
"dim2_value": "Annual average rate of change",
"dim3_value": "All-items HICP",
"unit": "",
"format": "Data;European Union - 27 countries (from 2020);…;Poland;…",
"values": "2014;0.4;0.4;…"
}
],
"returned_count": 1
}Account tools
ACCOUNTlist_plans
Monitly plans (Essential, Pro, Enterprise) with prices and limits.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_plans",
"arguments": {}
}
}{
"plans": [
{ "id": "essential", "name": "Essential", "price": "$0", "limits": { "mcp": "10", "charts": "5", "api": "100" } },
{ "id": "pro", "name": "Pro", "price": "$49", "period": "per month", "limits": { "mcp": "500", "charts": "100", "api": "5,000" } },
{ "id": "enterprise", "name": "Enterprise", "price": "Custom", "limits": "custom" }
]
}ACCOUNTget_plan
Plan of the key owner: name, status, renewal date and limits. Members of an organization inherit the owner's plan.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_plan",
"arguments": {}
}
}{
"plan": {
"id": "pro",
"name": "Pro",
"status": "active",
"current_period_end": "2026-11-02T10:14:00Z",
"limits": { "api_requests_per_day": 5000, "mcp_queries_per_month": 500, "watchlist_datasets": 100, "api_keys": 10 }
}
}ACCOUNTget_usage
MCP queries in the current billing period, REST API requests today and watchlist slots — used, limit and remaining.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_usage",
"arguments": {}
}
}{
"usage": {
"plan": "Pro",
"mcp_queries": { "used": 42, "limit": 500, "remaining": 458, "period": "2026-10" },
"api_requests_today": { "used": 130, "limit": 5000, "remaining": 4870 },
"watchlist_datasets": { "used": 12, "limit": 100, "remaining": 88 }
}
}ACCOUNTupgrade_plan
Creates a Stripe Checkout session for Pro and returns checkout_url. Open it in the browser to pay; the plan switches automatically after payment.
| Name | Type | Description |
|---|---|---|
| plan_id | string | 'pro' (default). |
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "upgrade_plan",
"arguments": {
"plan_id": "pro"
}
}
}{
"current_plan": "Essential",
"target_plan": "Pro",
"checkout_url": "https://checkout.stripe.com/c/pay/cs_live_…"
}ACCOUNTlist_watchlist
Datasets the user follows, with source, latest period and whether update alerts are on. Organization members see the organization's watchlist.
| Name | Type | Description |
|---|---|---|
| limit | integer | 1–100, default 20. |
| offset | integer | Pagination offset, default 0. |
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_watchlist",
"arguments": {
"limit": 10
}
}
}{
"watchlist": [
{
"dataset_id": 4179,
"dataset_name": "HICP - inflation rate",
"source_name": "Eurostat",
"latest_period": "2024",
"notifications": true,
"url": "https://monit.ly/app/chart?id=4179"
}
],
"total": 12,
"limit": 100
}ACCOUNTadd_to_watchlist
Adds a dataset to the watchlist with e-mail alerts on update. Returns limit_reached when the plan's watchlist is full.
| Name | Type | Description |
|---|---|---|
| dataset_id* | integer | Dataset id from search_catalog. |
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "add_to_watchlist",
"arguments": {
"dataset_id": 4179
}
}
}{
"status": "added",
"dataset": { "dataset_id": 4179, "dataset_name": "HICP - inflation rate", "source_name": "Eurostat" }
}ACCOUNTadd_watchlist_batch
Follows up to 100 datasets in one call. Duplicates are skipped; ids beyond the plan limit are returned in skipped_limit.
| Name | Type | Description |
|---|---|---|
| dataset_ids* | integer[] | Dataset ids. |
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "add_watchlist_batch",
"arguments": {
"dataset_ids": [
4179,
2973,
168
]
}
}
}{
"added": 2,
"total": 3,
"added_ids": [2973, 168],
"already_watched": [4179],
"not_found": [],
"skipped_limit": []
}ACCOUNTremove_from_watchlist
Removes a dataset from the watchlist.
| Name | Type | Description |
|---|---|---|
| dataset_id* | integer | Dataset id. |
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "remove_from_watchlist",
"arguments": {
"dataset_id": 168
}
}
}{ "status": "removed", "dataset_id": 168 }ACCOUNTset_notification_preferences
action='get' returns alert settings. action='set' changes e-mail or Slack alerts for all followed datasets, or switches alerts for one dataset (dataset_id + dataset_notifications). The Slack webhook itself is configured in Settings.
| Name | Type | Description |
|---|---|---|
| action* | 'get' | 'set' | Read or change. |
| email_notifications | boolean | E-mail alerts on/off. |
| slack_notifications | boolean | Slack alerts on/off. |
| dataset_id | integer | Followed dataset to change. |
| dataset_notifications | boolean | Alerts for that dataset on/off. |
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "set_notification_preferences",
"arguments": {
"action": "set",
"email_notifications": true
}
}
}{
"status": "updated",
"preferences": { "email_notifications": true, "slack_notifications": false, "slack_webhook_configured": false }
}ACCOUNTlist_api_keys
Active REST API keys (mon_…): id, name, prefix, created and last used.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_api_keys",
"arguments": {}
}
}{ "api_keys": [ { "id": "8c1e…", "name": "Dashboard", "key_prefix": "mon_3f9a", "is_primary": true } ] }ACCOUNTcreate_api_key
Creates a REST API key for the /api endpoints (send it as x-api-key). The raw key is returned once. Limit: 3 keys on Essential, 10 on Pro.
| Name | Type | Description |
|---|---|---|
| name | string | Label, max 100 characters. |
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_api_key",
"arguments": {
"name": "Power BI"
}
}
}{
"id": "1b7d…",
"name": "Power BI",
"key_prefix": "mon_a1b2",
"api_key": "mon_a1b2c3…",
"daily_limit": 5000
}ACCOUNTdelete_api_key
Revokes a REST API key by id. The last remaining key cannot be deleted.
| Name | Type | Description |
|---|---|---|
| key_id* | string | Key id from list_api_keys. |
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "delete_api_key",
"arguments": {
"key_id": "1b7d…"
}
}
}{ "status": "deleted", "key_id": "1b7d…" }ACCOUNTlist_mcp_keys
Active MCP keys. The key used for the current session is marked current: true.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_mcp_keys",
"arguments": {}
}
}{ "mcp_keys": [ { "id": "f20a…", "name": "Cursor", "key_prefix": "mcpk_9d1c", "current": true } ] }ACCOUNTcreate_mcp_key
Creates another MCP key, e.g. for a second client. The raw key is returned once.
| Name | Type | Description |
|---|---|---|
| name | string | Label, max 100 characters. |
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_mcp_key",
"arguments": {
"name": "Claude Desktop"
}
}
}{ "id": "77c3…", "name": "Claude Desktop", "key_prefix": "mcpk_4e5f", "mcp_key": "mcpk_4e5f…" }ACCOUNTdelete_mcp_key
Revokes an MCP key by id. The key used for the current session cannot be revoked from the agent.
| Name | Type | Description |
|---|---|---|
| key_id* | string | Key id from list_mcp_keys. |
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "delete_mcp_key",
"arguments": {
"key_id": "77c3…"
}
}
}{ "status": "revoked", "key_id": "77c3…" }ACCOUNTexport_dataset
Returns a CSV download link for a dataset, optionally filtered by countries and dimension values (dim1…dim8 from inspect_dataset). The link is a plain GET and needs no key.
| Name | Type | Description |
|---|---|---|
| dataset_id* | integer | Dataset id. |
| countries | string[] | Country names, e.g. ['Poland','Germany']. |
| dimensions | object | e.g. {"dim1": ["Monthly"]}. |
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "export_dataset",
"arguments": {
"dataset_id": 4179,
"countries": [
"Poland",
"Germany"
]
}
}
}{
"dataset": { "dataset_id": 4179, "dataset_name": "HICP - inflation rate" },
"csv_url": "https://monit.ly/api/datasets/4179/export.csv?country=Poland&country=Germany"
}Errors
401Unauthorized
The request has no MCP key, or the key was revoked. Returned with HTTP status 401.
{
"jsonrpc": "2.0",
"id": null,
"error": {
"code": -32603,
"message": "Unauthorized",
"data": { "message": "Invalid or revoked MCP key." }
}
}-32700Parse error
The request body could not be parsed as JSON. Returned with HTTP status 400.
{
"jsonrpc": "2.0",
"id": null,
"error": { "code": -32700, "message": "Parse error: invalid JSON body" }
}-32600Invalid Request
The body is JSON but not a JSON-RPC 2.0 request (jsonrpc: "2.0" is missing).
{
"jsonrpc": "2.0",
"id": null,
"error": { "code": -32600, "message": "Invalid Request: missing jsonrpc field" }
}-32602Invalid params
tools/call was sent without params.name.
{
"jsonrpc": "2.0",
"id": 1,
"error": { "code": -32602, "message": "Missing tool name." }
}-32601Not found
The JSON-RPC method or the tool name does not exist. Call tools/list for the current set.
{
"jsonrpc": "2.0",
"id": 1,
"error": { "code": -32601, "message": "Unknown tool: get_datasets" }
}-32603Limit reached
The monthly mcp_queries limit of the plan is used up. Data tools are blocked until the billing period resets; account tools keep working.
{
"jsonrpc": "2.0",
"id": 7,
"error": {
"code": -32603,
"message": "MCP query limit reached (10/month on Essential).",
"data": { "used": 10, "limit": 10, "remaining": 0, "canUse": false, "planType": "free", "periodYm": "2026-10" }
}
}isErrorTool error
For example an unknown dataset id, a full watchlist or the last API key. The result is a normal response with isError: true and the reason in content[0].text.
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [{ "type": "text", "text": "Error: Dataset 99999999 not found." }],
"isError": true
}
}