MCP uses JSON-RPC 2.0. A request has jsonrpc, id, method, and optional params. A success result repeats the id. An error has a code and a message. That is the whole wire format you must implement.
Three methods are enough for this course.
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": { "tools": {} },
"clientInfo": { "name": "edge-fde-app", "version": "1.0" }
}
}
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "lookup_order",
"arguments": { "orderId": "A-1042" }
}
}
After initialize, the client may send a notification notifications/initialized with no id. Notifications do not get a result. Keep request ids unique for the life of the connection.
On iOS you usually pass these JSON objects through an actor in the same process, or through an XPC helper. On macOS you can also use a local socket. Do not start with HTTP unless you need a second device. A local in-process pipe is enough to learn the messages. The official messages live in the MCP specification.
Read Run tools in a safe box, Stop prompt attacks and leaks, and Core AI vs Core ML vs MLX when you later wrap tools/call in a safe box or a guardrail.
Next, build a small on-device server that answers those three methods.
Key concepts
- MCP uses JSON-RPC 2.0 with
jsonrpc,id,method, and optionalparams. - The three methods are
initialize,tools/list, andtools/call. - After initialize, the client sends
notifications/initializedwith no id. - On iOS pass JSON through an in-process actor or XPC.
Takeaways
- Implement the raw methods before hiding them in a client library.
- Keep request ids unique for the life of the connection.
- Do not start with HTTP unless you need a second device.