MCP
Connect any MCP client to Nifty's read-only tools, over HTTP or through nifty mcp.
Nifty serves its data to AI apps as Model Context Protocol tools at POST /mcp
on your server. The tools only read. For Claude Desktop and Claude Code, follow Use with Claude.
This page is for other clients and your own code.
The endpoint
POST $NIFTY_URL/mcpuses stateless Streamable HTTP. There are no sessions and no server-sent events, so each request gets one JSON response. Other methods get405.- Send one JSON-RPC message per request. A batch gets
400 batch_not_supported. - Send
Accept: application/json, text/event-streamandContent-Type: application/json. Afterinitialize, send the agreed version inMCP-Protocol-Version. - The endpoint accepts only bearer tokens, with full access or read-only access (Authentication). A read-only token is enough, and it's the safer choice. A session cookie isn't accepted.
- A request with an
Originheader other than your server's own gets403 invalid_origin, so a web page can't use the endpoint. - The endpoint has the same rate limit as the API (
429 rate_limited), and it updates the token's last use.
A missing or refused token gets the API's 401 (Errors).
curl "$NIFTY_URL/mcp" \
-H "Authorization: Bearer $NIFTY_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search","arguments":{"query":"maya"}}}'
Results
- A tool's result is its JSON in
structuredContent, and the same JSON as atextblock. - A tool that fails answers
isError: true, with{ "error": { "code", "message", "details" } }as its text. The code isnot_found, orinvalid_argumentswithdetailsfor each argument, such as an id that isn't valid. - An unknown tool or a malformed request is a JSON-RPC error.
- Every tool is marked
readOnlyHint. - Records have the API's shapes. Results that refer to other records include a
namesobject that maps their ids to names. - Times ending in
Zare UTC. Dates (YYYY-MM-DD) are in your time zone, and results with dates give it astime_zone.
Tools
Lists return 20 items unless you pass limit, which can be up to 50. They also return a next_cursor, which you
pass back as cursor for the next page. It's null on the last page.
| Tool | Arguments | Returns |
|---|---|---|
search |
query; types, limit (1–25 per type, default 5) |
Best matches by type: person, project, note, task, document, task_list, folder |
today |
none | Today's date, counts, tasks, meetings and key dates for the next 14 days |
get_person |
id |
person, with contact details, key dates, positions and connections, names, and facts (each label, text and updated_at, in the labels' order) |
list_people |
query, limit, cursor |
People by name, or best matches for a name, email address or phone number |
list_person_meetings |
person_id; from, to |
Events with that person, soonest first (default 30 days back to 60 ahead, at most 92 days) |
get_note |
id |
A note's title and plain text (cut at 20,000 characters, with truncated), people, projects, tags, category and type |
list_notes |
person_id, project_id, tag, category, kind, limit, cursor |
Notes, newest first, with excerpts |
get_project |
id |
A project with its members |
list_projects |
status, person_id, limit, cursor |
Projects by name. status: open (planned, active and on hold), planned, active, on_hold, done, cancelled |
list_tasks |
status, person_id, project_id, due_before, limit, cursor |
Tasks in your order. person_id matches tasks mentioning that person, and project_id tasks filed under or mentioning that project, both at once if you pass both. status: open (default), completed, archived |
list_events |
from, to |
Calendar events between two dates (at most 31 days), attendees matched to people |
get_document |
id |
A document's details, folder and links and, once summarised, its type, summary and the details found in it (money in minor units, as { minor, currency }); not the file |
search_documents |
query; limit |
Documents whose text or summary has the words, best first, with an excerpt |
Arguments before a semicolon are required. tools/list gives each tool's full description and input schema.
nifty mcp, for stdio clients
Clients that only start a command, such as Claude Desktop, use nifty mcp. It passes each message from stdin to
/mcp and writes the answers to stdout. It never opens your database.
| Setting | |
|---|---|
NIFTY_TOKEN |
An API token. Required, and environment only, so it's never on a command line |
NIFTY_URL (or --url) |
Your server's address, no path: https://, or http:// to this machine only. Without it, the server on this machine |
NIFTY_DATA (or --data) |
Without NIFTY_URL: the data folder of the server on this machine. Default: the Mac app's |
A server on this computer
A server that listens only on this computer, such as the Mac app, a development server or one behind
tailscale serve, writes its address and a new key to a file named address in its data folder each time it starts.
It removes the file when it stops. Without NIFTY_URL, nifty mcp reads that file before each request, so it finds
the server wherever its port moves, without restarting Claude. Before every request that carries the token, it asks
the server at that address to prove that it holds the key (POST /mcp/proof). This means another program that takes
the port never sees the token.
For such a server, use a configuration like this one.
{
"mcpServers": {
"nifty": {
"command": "/Applications/Nifty.app/Contents/MacOS/nifty",
"args": ["mcp"],
"env": { "NIFTY_DATA": "/Users/ada/Library/Application Support/Nifty", "NIFTY_TOKEN": "nw_…" }
}
}
}
A server elsewhere
Set NIFTY_URL to its address instead of NIFTY_DATA, such as "NIFTY_URL": "https://box.tailnet.ts.net". The
Mac app includes the command. On a server, it's the nifty you installed.
When it fails
nifty mcp answers a request it can't complete with a JSON-RPC error, and it keeps running.
| Message | Means |
|---|---|
| Nifty isn't running (no address in …) | No server is running from that data folder |
| The address in … isn't this machine's | The address file names a server that isn't on this machine: set NIFTY_URL |
| Nifty isn't running at … | Nothing answered at that address |
| Something else is answering at …. Quit and reopen Nifty. | What answered at the file's address couldn't prove it's your copy of Nifty |
| Update Nifty: the version running at … can't prove it's Nifty, so Claude can't find it on its own. | The server predates the key, so it gets no token: update it, or set NIFTY_URL |
| The token was refused | The token is unknown, expired or revoked |
| … answered with a redirect, which isn't followed | NIFTY_URL isn't the server's own address |
| … doesn't serve MCP | The address isn't Nifty's, or Nifty is out of date |