Connect
MCP server
Connect Claude or any MCP-compatible client to your notes, drafts, literature notes and media.
ThinkerNotes runs a Model Context Protocol server at a single endpoint. Once an assistant is connected, it can search, list and fetch anything in your account, and that's as far as it goes. Every tool is read-only, so there's no way for a connected assistant to create, edit or delete anything. If you need read and write access instead, that's what the REST API is for.
Endpoint
https://thinkernotes.com/mcp
The server speaks Streamable HTTP and is stateless. Every request gets authenticated and handled entirely on its own, so there's no session sitting around that needs to be kept alive.
Connect a client
There are two ways to connect, depending on your client.
Claude Desktop or claude.ai
Open Settings → Connectors → Add custom connector and paste in the endpoint above.
Claude will open ThinkerNotes in a browser tab and ask you to sign in if you aren't already. Approve the connection on the screen that follows, and you're done. There's no token to copy anywhere for this path, ThinkerNotes and Claude handle that between themselves over OAuth.
Claude Code and other config-file clients
Create an API token from Settings → API tokens if you haven't already. See Getting started for the details.
Add ThinkerNotes as a remote MCP server in your client's config, passing the token along as a bearer header, something like this:
{
"mcpServers": {
"thinkernotes": {
"type": "http",
"url": "https://thinkernotes.com/mcp",
"headers": {
"Authorization": "Bearer tn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
}
}
}
Ask the assistant something that needs one of your notes. If it's connected, it'll call a tool like
search_notes on its own.
Available tools
Three read-only tools per resource: search by keyword, list the most recent, and fetch one by id.
| Tool | What it does |
|---|---|
search_notes | Search notes by keyword or tag |
list_recent_notes | List the most recently created notes |
get_note | Fetch one note's full text, tags and linked notes by id |
search_drafts | Search inbox drafts by keyword |
list_recent_drafts | List the most recently created drafts |
get_draft | Fetch one draft's full text by id |
search_literature_notes | Search literature notes by keyword |
list_recent_literature_notes | List the most recently created literature notes |
get_literature_note | Fetch one literature note's full text by id |
search_media | Search media by title or author |
list_recent_media | List the most recently added media |
get_media | Fetch one media item by id |
Every tool is read-only and scoped to the account the token belongs to. An assistant connected with your token can never see another user's data.
Calling a tool directly
The endpoint is also just a plain JSON-RPC 2.0 server underneath, so you can call a tool yourself without going through an MCP client at all. That's handy for testing a connection:
curl https://thinkernotes.com/mcp \
-H "Authorization: Bearer tn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "search_notes",
"arguments": { "query": "stoicism" }
}
}'
require "net/http"
require "json"
uri = URI("https://thinkernotes.com/mcp")
request = Net::HTTP::Post.new(uri,
"Content-Type" => "application/json",
"Accept" => "application/json, text/event-stream")
request["Authorization"] = "Bearer tn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
request.body = {
jsonrpc: "2.0", id: 1, method: "tools/call",
params: { name: "search_notes", arguments: { query: "stoicism" } }
}.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
puts response.body
const response = await fetch("https://thinkernotes.com/mcp", {
method: "POST",
headers: {
"Authorization": "Bearer tn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "tools/call",
params: { name: "search_notes", arguments: { query: "stoicism" } },
}),
});
const result = await response.json();
console.log(result);
import requests
response = requests.post(
"https://thinkernotes.com/mcp",
headers={
"Authorization": "Bearer tn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Accept": "application/json, text/event-stream",
},
json={
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {"name": "search_notes", "arguments": {"query": "stoicism"}},
},
)
print(response.json())
The response wraps the tool's result as JSON text inside the standard MCP content array:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{ "type": "text", "text": "[{ ...note... }]" }
]
}
}
If the id you asked for doesn't exist, or belongs to someone else, the tool just returns an error result instead of raising:
No note found with id 42