MCP server
AI agents use your app through tools made from its own surface. No install, no plugin.
Every Yatta app is also an MCP server, on /mcp. MCP is the standard way AI agents (coding assistants, chat apps, automation tools) use an app: the client asks for the tool list, then calls tools. Yatta builds that list from your app itself — you write nothing extra.
List tools
The caller must be signed in — a Yatta session, or an OAuth access token from this same server. Without that, the answer is 401, and the caller learns nothing, not even the tool names.
curl http://localhost:4000/mcp \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' # Answer (shortened){ "jsonrpc": "2.0", "id": 1, "result": { "tools": [ { "name": "list_posts", "description": "List rows in the posts collection." }, { "name": "get_posts", "description": "Get one row from the posts collection by id." } ] }}The five collection tools
Every collection becomes five tools, named after the collection itself. A collection called posts becomes list_posts, get_posts, and so on.
list_<name>get_<name>create_<name>update_<name>delete_<name>Call a tool
Send tools/call with the tool name and its arguments. The answer comes back as text. A tool that fails answers with isError: true instead of crashing the server.
curl http://localhost:4000/mcp \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call", "params":{"name":"create_posts", "arguments":{"fields":{"title":"Hello","body":"First post"}}}}' # Answer (shortened){ "jsonrpc": "2.0", "id": 2, "result": { "content": [{ "type": "text", "text": "{\"id\":1,\"title\":\"Hello\",\"body\":\"First post\"}" }] }}Your own functions
A function you register becomes one tool under its own name, and it receives the caller’s user id — so it can enforce its own rules, like “only touch your own rows”. A function whose name collides with a collection tool is skipped, so every tool name stays unique.
curl http://localhost:4000/mcp \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":3,"method":"tools/call", "params":{"name":"my_function","arguments":{"text":"hello"}}}'Start a session
There is no session id to keep. Every request stands on its own. Say hello with initialize, and check the connection with ping.
curl http://localhost:4000/mcp \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":4,"method":"initialize", "params":{"protocolVersion":"2025-06-18"}}' # Answer{ "jsonrpc": "2.0", "id": 4, "result": { "protocolVersion": "2025-06-18", "capabilities": { "tools": {} }, "serverInfo": { "name": "yatta", "version": "1.0.5" } }} # Ping — answers an empty result# {"jsonrpc":"2.0","id":5,"method":"ping"} -> {"jsonrpc":"2.0","id":5,"result":{}}A request without an id is a notification: it answers 202 with an empty body. You can also send several requests at once, as a JSON array, and get several answers back.
Errors
-32700 (HTTP 400)-32600-32601-32602isError: trueHTTP 405Turn it off
The endpoint is on by default. One line turns it off.
MCP_ENABLED=0