The MCP server
Every MADATA workspace ships a
Model Context Protocol server
at /mia/mcp. An AI assistant, or any program, connects to it
and calls the workspace's business tools.
01What it is
The MCP server is the second façade over the tool engine of Mia, the built-in assistant. Where Mia runs its loop internally, the MCP server publishes exactly the same tools to an external client: Claude, ChatGPT, Gemini, Mistral Le Chat, or your code.
The client receives a tool catalog (tools/list), calls
tools (tools/call), and reads read-only resources. Every call
runs with the permissions of the user who owns the key.
02Endpoint & transport
- URL
https://<workspace>.madata.app/mia/mcp- Method
POST: JSON-RPC 2.0 body- Auth
Authorization: Bearer mia_…header (or OAuth 2.1)- Content-Type
application/json
The transport is plain HTTP, compatible with modern "Streamable HTTP" clients. There is no server→client SSE stream:
| HTTP method | Response | Role |
|---|---|---|
POST | 200 + JSON-RPC body | Main channel: all protocol methods. |
GET | 405 | Would open a notification stream; the server has none. |
DELETE | 204 | End of session; stateless server, no effect. |
OPTIONS | 204 + CORS | Preflight (extensions, web clients). Access-Control-Allow-Origin: *. |
03Handshake (initialize)
The first call of any session. The server negotiates the protocol
version: it returns the requested one if it is supported
(2025-06-18, 2025-03-26, 2024-11-05),
otherwise the most recent.
{"jsonrpc":"2.0","id":1,"method":"initialize",
"params":{"protocolVersion":"2025-06-18","capabilities":{},
"clientInfo":{"name":"my-app","version":"1.0"}}}
{"jsonrpc":"2.0","id":1,"result":{
"protocolVersion":"2025-06-18",
"capabilities":{"tools":{},"resources":{},"prompts":{}},
"serverInfo":{"name":"madata-mia","version":"1.1.0","title":"Madata",
"websiteUrl":"https://<workspace>.madata.app"},
"instructions":"This management platform is called Madata. Act through your tools…"
}}
The instructions field reminds the client to call the
platform "MADATA" and to act through the tools rather than sending the user
to the UI.
04Protocol methods
| Method | Role |
|---|---|
initialize | Version negotiation, capabilities, serverInfo. |
notifications/initialized | Acknowledgement (the server replies empty). |
tools/list | Tool catalog, filtered by the key scope. |
tools/call | Runs a tool. |
resources/list · resources/read | 4 read-only resources (see Resources). |
resources/templates/list | Returns an empty list (no URI templates). |
prompts/list · prompts/get | 8 ready-to-use prompts. |
ping | Returns {}. |
Any other method (logging/setLevel, completion/complete,
roots/list…) returns the JSON-RPC error -32601
"method not found" with HTTP 200: this is normal
discovery, not a failure.
05Calling a tool (tools/call)
{"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{"name":"get_kpi","arguments":{"period":"month"}}}
{"jsonrpc":"2.0","id":2,"result":{
"content":[{"type":"text","text":"{ \"ca_ttc\": 4210000, … }"}],
"isError":false
}}
The result comes back in content (text blocks,
or resource for a generated file). Write tools get a
company_name parameter injected automatically for
multi-company workspaces.
When a call succeeds but the answer is
"not found", "argument to fix", "empty target" or "forbidden",
isError stays false: the response carries usable
information (near matches, the field name to correct). The client uses it
instead of replaying the same call verbatim.
06Error codes & status contract
The distinction matters for an AI connector: a 401 makes it drop its key and restart an OAuth consent; a 403 keeps it connected and it retries.
| Situation | HTTP | JSON-RPC | Headers |
|---|---|---|---|
| Key missing / invalid / expired / revoked | 401 | -32001 | WWW-Authenticate: Bearer resource_metadata="…" |
| Mia disabled on the workspace | 403 | -32001 | Retry-After: 300 |
| Mia subscription inactive | 403 | -32001 | Retry-After: 300 |
| Billed resource touched | 403 | -32003 | Business message: "manage this in the portal". |
| Rate limit exceeded | 429 | -32029 | Retry-After: 60 |
| Unknown protocol method | 200 | -32601 | Normal discovery. |
| Tool execution error | 200 | result with isError:true | |
| Internal failure | 500 | -32603 | |
| Unparseable JSON / workspace not found | 400 | -32700 / -32600 |
07Rate limit
120 requests / minute per user, sliding window.
Handshake and catalog methods
(initialize, tools/list, prompts/list,
resources/list, ping…) do not count:
only tool calls are capped. Over the limit →
429 + Retry-After: 60.
08Scope & permissions
Three levels combine:
- Key scope:
read_only,full_access(read + write) orcustom(an allow-list of tools). - The user's access mode, set in the portal ("Read only" or "Read and write"): a "Read only" user never writes, whatever the key scope.
- The user's permissions in the workspace: a tool the
user is not allowed to use does not appear in
tools/list.
Whatever the scope, a key can never create or
modify billed resources: users, companies, points of sale,
apps. Any attempt returns -32003. No point asking to raise
permissions: that is not where the refusal comes from.
09Availability
MCP access requires an active Mia subscription on the workspace. If the
subscription is inactive, the server replies 403 +
Retry-After: the connection stays and the client retries.