LIVE
← API, MCP & A2A

Developers · MCP

Connect Foral to your AI assistant (MCP)

The Model Context Protocol (MCP) lets AI assistants — Claude, Cursor, ChatGPT and others — call Foral directly as tools. Foral runs two kinds of MCP server: the Foral Data MCP for Premium accounts, and one MCP server for each published company agent.

1. Foral Data MCP

The Foral Data MCP server exposes the Data API as MCP tools: public procurement (Portal BASE), municipal signals, municipalities, your alerts and the indicator catalogue. URL: https://data.foral.ai/mcp.

It is for Premium accounts. Use the same sk_live_… key as the REST API — create it on the API keys page. The key's scopes and your plan decide which tools tools/list shows; a tool your key cannot call is simply not listed.

Same limits as the REST API: every HTTP request counts against your per-minute rate limit, and each tools/call counts as one request against your monthly quota. The handshake (initialize, tools/list, ping) does not use quota. Start with the me tool — it returns your plan, domains, scopes and limits.

ToolData domain
me—
municipalities_searchindicators
municipalities_getindicators
indicators_listindicators
indicators_seriesindicators
indicators_snapshotindicators
signals_listsignals
signals_getsignals
signal_cases_listsignals
procurement_contractsprocurement
procurement_aggregateprocurement
procurement_entitiesprocurement
procurement_entity_profileprocurement
procurement_lookup_municipalitiesprocurement
procurement_lookup_entitiesprocurement
procurement_announcementsprocurement
procurement_amendmentsprocurement
alert_rulesalerts
alert_matchesalerts
Tool results carry structuredContent (the same JSON the REST endpoint returns) and a text copy of it. A failed call (for example, monthly quota exhausted) comes back as a tool result with isError: true and the problem document of the REST API.

2. Company agent MCP

Each company agent published on the MCP channel has its own server: https://agents.foral.ai/<slug>/mcp. <slug> is the deployment slug shown in the company studio.

Authenticate with an agent credential created by a company admin in the studio (Deploy step, MCP channel). The tools are the ones the agent enables — its knowledge, service area and, when enabled, procurement reads. The deployment must be live.

To publish your own company agent, see Foral Agents.

3. Install in your client

The examples use the Data MCP. For a company agent, use https://agents.foral.ai/<slug>/mcp and its credential instead. Replace sk_live_... with your key and keep it secret.

Claude Code

Then run claude mcp list — the server shows as connected.

Terminal

claude mcp add --transport http foral https://data.foral.ai/mcp \
  --header "Authorization: Bearer sk_live_..."

Claude Desktop (through mcp-remote)

Add this block to claude_desktop_config.json (Settings → Developer → Edit config) and restart Claude Desktop. It needs Node.js. The key goes in env so the header survives argument splitting on Windows.

claude_desktop_config.json

{
  "mcpServers": {
    "foral": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote", "https://data.foral.ai/mcp",
        "--header", "Authorization:${AUTH_HEADER}",
        "--transport", "http-only"
      ],
      "env": { "AUTH_HEADER": "Bearer sk_live_..." }
    }
  }
}

claude.ai, Claude Desktop connectors and ChatGPT

These clients connect with OAuth: you sign in to Foral and approve access — no key to paste.

  • claude.ai and Claude Desktop: Customize → Connectors → Add → Add custom connector. Enter a name and the server URL, click Add (Claude detects OAuth and registers itself), then Connect. Foral opens: sign in and click Allow access.
  • ChatGPT: Plugins → Add → Add custom MCP server. Enter a name and the server URL, keep Authentication on OAuth (ChatGPT registers itself), accept the risk notice and click Create as a plugin, then Continue. Foral opens: sign in and click Allow access.
  • You can see and disconnect the apps you connected at any time in Connected apps.

Cursor and Windsurf

Cursor: add the block to ~/.cursor/mcp.json (or .cursor/mcp.json in a project). Windsurf: same block in ~/.codeium/windsurf/mcp_config.json, with serverUrl in place of url.

mcp.json

{
  "mcpServers": {
    "foral": {
      "url": "https://data.foral.ai/mcp",
      "headers": { "Authorization": "Bearer sk_live_..." }
    }
  }
}

Python (MCP SDK 1.x)

Minimal example with the official MCP Python SDK, version 1.x (tested with 1.30). The 2.x SDK changed this client API.

client.py

# pip install "mcp>=1.30,<2" httpx
import asyncio

import httpx
from mcp import ClientSession
from mcp.client.streamable_http import streamable_http_client

URL = "https://data.foral.ai/mcp"
KEY = "sk_live_..."


async def main() -> None:
    headers = {"Authorization": f"Bearer {KEY}"}
    async with httpx.AsyncClient(headers=headers, timeout=30) as http:
        async with streamable_http_client(URL, http_client=http) as (read, write, _):
            async with ClientSession(read, write) as session:
                await session.initialize()
                tools = await session.list_tools()
                print([t.name for t in tools.tools])
                result = await session.call_tool("municipalities_search", {"q": "Faro", "limit": 5})
                print(result.structuredContent)


asyncio.run(main())

Raw JSON-RPC (curl)

The servers speak Streamable HTTP with JSON responses: one JSON-RPC message per POST. There is no session to open — list the tools and call one.

List the tools

curl -s https://data.foral.ai/mcp \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Mcp-Protocol-Version: 2025-06-18" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Call a tool

curl -s https://data.foral.ai/mcp \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Mcp-Protocol-Version: 2025-06-18" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"municipalities_search","arguments":{"q":"Faro","limit":5}}}'

4. Limits

A 429 carries Retry-After (seconds). Wait that long before you retry.

ServerLimit
Foral Data MCPYour plan's per-minute rate limit (every HTTP request) and monthly quota (one request per tools/call), shared with the REST API.
Company agent MCP60 requests/minute per credential, 200/minute per deployment (defaults). Connecting takes about 3 requests.

5. Troubleshooting

AnswerWhat it means
401Missing, wrong, expired or revoked key. Send Authorization: Bearer sk_live_….
403The request came from a browser page on another site (Origin header). Call the server from a desktop client, an IDE or your backend. On the Data MCP, a 403 can also mean your plan does not include Data API access (api-access-required, upgrade to Premium) or the key is restricted to a beta cohort (beta-access-required).
404 (company agent)Wrong <slug>, the deployment is not live, or the credential belongs to another deployment or lacks the MCP channel.
405GET is not served: these servers are POST only. MCP clients handle this on their own.
400Unsupported Mcp-Protocol-Version. Use 2025-06-18 or 2025-11-25.
429Rate limit. Wait Retry-After seconds.
quota-exceeded / 402Monthly quota exhausted. Wait for the reset or upgrade the plan.
A tool is missingYour key lacks the scope or your plan lacks the domain. Call me to see both.
503Temporary. Retry with backoff.