MCP server
ThreadPage’s MCP server lets an assistant find, read, add and organize a person’s notes with the access that person chooses.
On this page
Server
| URL | https://thread.page/mcp |
|---|---|
| Transport | Streamable HTTP, stateless, JSON responses |
| Sign-in | OAuth in the browser. ThreadPage asks the person to choose access. Every level. |
| Token | Authorization: Bearer tp_… from a Script or API connection, on Add to Inbox, Add only, Read only or Read and add. Edit and organize through MCP needs OAuth (403 oauth_required). |
| Discovery | /.well-known/oauth-protected-resource, /.well-known/oauth-authorization-server |
| Clients that can sign in | Claude, ChatGPT, Codex, Claude Code |
Add the URL to a client. Opened in a browser, or fetched without a token, it answers 401.
Connect
| Client | How |
|---|---|
| Claude | In ThreadPage, Settings → Connections → Apps, choose Connect an app → Claude app, then Add to Claude. Or in Claude, Customize → Connectors, Add custom connector, and paste the URL. |
| ChatGPT | On the web, choose + and Add custom MCP server, name it ThreadPage and paste the URL, then Create as a plugin and install it. |
| Codex, Claude Code | See Coding agents. |
Sign-in opens ThreadPage, where the person chooses the level and which threads and folders. The default for an assistant is Read and add. Step-by-step setup for each app is in Apps, and for Claude Code and Codex in Coding agents.
What the server tells assistants
When a client connects, the server sends instructions: how ThreadPage is organized and the rules for writing, editing and retrying. Some clients, such as Claude on the web and Claude Desktop, don’t pass them to the model.
get_guide with topic formatting answers every Markdown and document element; working answers the tools, editing, retries, limits and errors. The resources threadpage://instructions, threadpage://guide/formatting and threadpage://guide/working hold the same texts.
The ThreadPage skill gives an assistant the same guides ahead of time, which helps where instructions don’t reach the model. See Assistant guide.
Tools
Every tool has a title, a description, annotations (readOnlyHint, destructiveHint, idempotentHint) and strict arguments. Annotations help a client ask before a change; ThreadPage enforces the level on the server either way.
| Level | Tools |
|---|---|
| Add to Inbox | get_access, create_note (to the Inbox only), get_operation, get_guide |
| Add only | get_access, list_threads (titles), create_note, upload_note_image, get_operation, get_guide |
| Read only | The read tools: threads, folders, search, notes, versions, images, files and reminders |
| Read and add | Every tool. It adds notes, threads and reminders, and changes or trashes the notes it added. Other changes are refused. |
| Edit and organize | Every tool, on any note, thread and folder in its scope |
The full table, with each tool’s levels, annotations and the API operation that does the same:
| Tool | Levels | Changes notes | API operation |
|---|---|---|---|
get_access | Edit and organize · Read and add · Read only · Add only · Add to Inbox | No | GET /connection |
get_operation | Edit and organize · Read and add · Read only · Add only · Add to Inbox | No | GET /operations/{operation_id} |
list_threads | Edit and organize · Read and add · Read only · Add only | No | GET /threads |
get_thread | Edit and organize · Read and add · Read only | No | GET /threads/{thread_id} and GET /threads/{thread_id}/notes |
create_thread | Edit and organize · Read and add | Yes | POST /threads |
update_thread | Edit and organize | Yes | PATCH /threads/{thread_id} |
archive_thread | Edit and organize | Yes | POST /threads/{thread_id}/archive |
unarchive_thread | Edit and organize | Yes | POST /threads/{thread_id}/unarchive |
trash_thread | Edit and organize | Yes | POST /threads/{thread_id}/trash |
restore_thread | Edit and organize | Yes | POST /threads/{thread_id}/restore |
move_thread | Edit and organize | Yes | POST /threads/{thread_id}/move |
create_note | Edit and organize · Read and add · Add only · Add to Inbox | Yes | POST /inbox/notes and POST /threads/{thread_id}/notes |
upload_note_image | Edit and organize · Read and add · Add only | Yes | POST /threads/{thread_id}/images |
get_note | Edit and organize · Read and add · Read only | No | GET /notes/{note_id} |
update_note | Edit and organize · Read and add | Yes | PUT /notes/{note_id}/content |
update_note_properties | Edit and organize | Yes | PATCH /notes/{note_id} |
move_note | Edit and organize · Read and add | Yes | POST /notes/{note_id}/move |
trash_note | Edit and organize · Read and add | Yes | POST /notes/{note_id}/trash |
restore_note | Edit and organize · Read and add | Yes | POST /notes/{note_id}/restore |
get_note_history | Edit and organize · Read and add · Read only | No | GET /notes/{note_id}/versions |
get_note_version | Edit and organize · Read and add · Read only | No | GET /notes/{note_id}/versions/{version_id} |
restore_note_version | Edit and organize · Read and add | Yes | POST /notes/{note_id}/versions/{version_id}/restore |
read_note_attachment | Edit and organize · Read and add · Read only | No | GET /notes/{note_id}/images/{image_id} |
read_note_file | Edit and organize · Read and add · Read only | No | GET /notes/{note_id}/files/{file_id}, GET /notes/{note_id}/files/{file_id}/preview and GET /notes/{note_id}/files/{file_id}/text |
search | Edit and organize · Read and add · Read only | No | GET /search |
list_statuses | Edit and organize | No | GET /statuses |
list_folders | Edit and organize · Read and add · Read only | No | GET /folders |
create_folder | Edit and organize | Yes | POST /folders |
rename_folder | Edit and organize | Yes | PATCH /folders/{folder_id} |
move_folder | Edit and organize | Yes | POST /folders/{folder_id}/move |
trash_folder | Edit and organize | Yes | POST /folders/{folder_id}/trash |
restore_folder | Edit and organize | Yes | POST /folders/{folder_id}/restore |
list_reminders | Edit and organize · Read and add · Read only | No | GET /threads/{thread_id}/reminders |
get_reminder | Edit and organize · Read and add · Read only | No | GET /notes/{note_id}/reminder and GET /threads/{thread_id}/reminder |
set_reminder | Edit and organize · Read and add | Yes | PUT /notes/{note_id}/reminder and PUT /threads/{thread_id}/reminder |
remove_reminder | Edit and organize · Read and add | Yes | DELETE /notes/{note_id}/reminder and DELETE /threads/{thread_id}/reminder |
list_requests | Edit and organize · Read and add | No | GET /requests |
get_request | Edit and organize · Read and add | No | GET /requests/{request_id} |
claim_request | Edit and organize · Read and add | Yes | POST /requests/{request_id}/claim |
report_request_status | Edit and organize · Read and add | Yes | POST /requests/{request_id}/status |
complete_request | Edit and organize · Read and add | Yes | POST /requests/{request_id}/result |
get_guide | Edit and organize · Read and add · Read only · Add only · Add to Inbox | No | MCP only |
delete_folder_container | Edit and organize | Yes | MCP only |
Request tools (list_requests, get_request, claim_request, report_request_status, complete_request) appear for a connection that receives requests.
Tools change with access
tools/list is built from the grant’s scopes:
- Read and add and Edit and organize hold the same scopes, so they list the same tools. A call Read and add may not make is refused with
needsandmanage_url. When the owner raises an assistant’s connection to Edit and organize, the same chat works. Atp_token can’t use Edit and organize on/mcp: raised to it, the token keeps working on the API and stops on/mcp. - Read only lists no write tools, whatever the client asks for.
- A raise that adds scopes, such as Read only to Read and add, needs a new tool list. Claude, Claude Code and Codex read it in a new session. ChatGPT reads it after Refresh in its Plugins settings.
A tool hidden by the level, called from an older list, gets the level’s refusal.
If the person asks for something your tools don’t do, call get_access and give them its manage_url. It opens the connection in ThreadPage with the next level proposed; it changes only the level, and nothing changes until the owner saves and confirms it’s them. The same sentence ends the get_access description and every level refusal, because some clients don’t pass the server’s instructions to the model.
What each level sees: get_access
get_access answers the object GET /connection answers (level, can, cannot, manage_url, shared_places and more), plus the grant’s token_scopes and the connection’s limits in capabilities.
{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "get_access", "arguments": {}}}level | can | cannot |
|---|---|---|
full | Read, add and edit notes, and organize threads and folders, including Archive and Trash. | Can’t delete permanently. |
read_add | Read and search notes. Add notes, threads and reminders, and change or move to Trash the notes it added. | Can’t change other notes. |
read | Read and search notes, including earlier versions. | No changes. |
append | Add notes to threads you choose and see those threads’ titles. | Can’t read notes. |
inbox | Add notes to your Inbox. | Can’t read notes. |
Conventions
| Argument | Rule |
|---|---|
operation_id | Every write takes one: a new UUID for each logical write, in any letter case. Send the same one when you repeat that write. The same ID with different arguments answers operation_id_reused. |
expected_revision, context_receipt | update_note and restore_note_version take both: the content_revision and the context_receipt from the same get_note. The tools that change an existing thread or folder, and update_note_properties, move_note, trash_note and restore_note, take expected_revision alone: the revision you last read. ThreadPage doesn’t compare it, and these writes apply in the order they arrive. |
cursor, limit | Lists take limit (1 to 50) and answer next_cursor; pass it back as cursor. Read every page when the whole list matters. |
content | A Markdown string, {"text": …}, {"markdown": …} or {"document": …}. Markdown up to 32 KiB, a note up to 256 KiB. |
get_thread and search answer previews, and a truncated one is cut. Read a note with get_note before you quote, summarize or edit it.
Replace a note safely
1. Read the note in full. Keep its document, its content revision and the context receipt.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_note",
"arguments": {
"note_id": "4c2f8e19-7a6b-4d3e-b1c0-95e8f2a7d364"
}
}
}2. Change only what you were asked to in that document, and send it whole with a new operation_id. expected_revision is the content_revision you read.
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "update_note",
"arguments": {
"operation_id": "b8e1d4a2-6c3f-4e9b-a751-2d0f8c6e3b19",
"note_id": "4c2f8e19-7a6b-4d3e-b1c0-95e8f2a7d364",
"expected_revision": "$content_revision",
"context_receipt": "$context_receipt",
"content": {
"document": "$document"
}
}
}
}Repeat a write whose answer was lost
1. Add a note. The answer is lost: a timeout, or the connection dropped.
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "create_note",
"arguments": {
"operation_id": "6e2a9c41-0b7d-4f53-8c1e-3a9d5f7b2c80",
"thread_id": "0e7c4b2a-91d3-4f6e-8a25-3c1b9d7f4e60",
"content": "## Release 412\n\n- [x] Tests passed\n- [ ] Tag the build"
}
}
}2. Ask what happened to that operation_id. A receipt means the note exists: don't write again.
{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "get_operation",
"arguments": {
"operation_id": "6e2a9c41-0b7d-4f53-8c1e-3a9d5f7b2c80"
}
}
}3. Or send the identical call again with the same operation_id. It answers the same receipt and adds no second note.
{
"jsonrpc": "2.0",
"id": 5,
"method": "tools/call",
"params": {
"name": "create_note",
"arguments": {
"operation_id": "6e2a9c41-0b7d-4f53-8c1e-3a9d5f7b2c80",
"thread_id": "0e7c4b2a-91d3-4f6e-8a25-3c1b9d7f4e60",
"content": "## Release 412\n\n- [x] Tests passed\n- [ ] Tag the build"
}
}
}If the connection was disconnected or reconnected in between, get_operation can’t see the earlier write. Don’t replay it: ask the person to check in ThreadPage.
Confirmations
Moving a folder, or moving it to Trash with or without its contents, asks a confirmation when the folder holds threads:
- A client that supports elicitation shows the question, such as
Move “Clients” and its 4 threads to Trash?. Accept proceeds; any other answer isdeclined. - Without elicitation, the first call answers
confirmation_requiredwithdetails.confirm, the folder and how many threads and folders it holds. Send the same call withconfirmwithin 10 minutes.
This guards an honest assistant against a mistake. It is not a security control; Trash and Restore from Trash… are.
Errors
A refused call answers a result with isError: true and JSON in its text: {"status": "rejected", "code", "message", "details"}, without retryable. The codes are the same as the API’s; a scope miss is unavailable. See Errors.
rate_limited means nothing was done: wait details.retry_after seconds and send the identical call with the same operation_id.
Limits
MCP calls count toward the same rate limits as the API.
Next
- Assistant guide: install the ThreadPage skill.
- Access levels
- Integration API basics: the same capabilities for code.