Programmatic access to your cheats and Tasks, for external tools acting on your behalf (e.g. a local Claude Code project). Every account can generate a key from the User page's API Access section. Free accounts get read-only access; Pro unlocks write access (create/update/delete) plus a much higher daily limit. See Billing for pricing.
Send your key as a bearer token on every request:
Authorization: Bearer csk_live_...
Keys are shown to you only once, at creation, and can be revoked at any time from the User page. Each key is scoped to either read or read + write — a write-scoped key can also do everything a read-scoped key can.
https://cheats.aarontrotter.com
For an MCP client (Claude Code, Claude Desktop) rather than a custom integration, add this app directly as a remote MCP server instead of calling the REST endpoints below yourself:
URL: https://cheats.aarontrotter.com/mcp Header: Authorization: Bearer csk_live_...
Exposes 11 tools over the same key/quota/tier rules as the REST API: search_cheats, get_cheat, get_revisions, search_tasks, get_task (all read-scoped), and add_cheat, update_cheat, delete_cheat, add_task, update_task, delete_task (all write-scoped). Each maps directly to one of the endpoints documented below.
429. Free: 50 requests/day, read-only. Pro: 500 requests/day fair use, full read + write.add/update/delete, for both cheats and Tasks) require the calling account to be Pro; a Free account's key returns 403 on those, but can still use every read endpoint.Errors are returned as { "error": "message" } with a matching HTTP status: 400 bad request, 401 missing/invalid key, 403 forbidden (wrong scope, not Pro, not the owner), 404 not found, 429 rate limited, 500 server error.
Search your visible cheats — public cheats plus your own (and any linked account's) private ones.
Scope: read
| Parameter | Type | Required | Description |
|---|---|---|---|
q | string | No | Search text; omitted means the most recently created cheats |
type | string | No | Restrict results to one type/category name |
limit | number | No | Results per page — default 8, max 25 |
page | number | No | 0-indexed page number, default 0 — use with hasMore to fetch further pages |
Returns { results: [{ id, title, type, snippet, private, stars, points }], total, page, hasMore }. snippet is the cheat body truncated to 400 characters. total is the number of cheats matching the search across all pages; hasMore is true when a further page exists — request it with page + 1.
GET /mcp/search?q=docker&limit=5&page=1 Authorization: Bearer csk_live_...
Fetch the full body of one cheat.
Scope: read
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id | query string | string | Yes | The cheat id, as returned by /mcp/search |
Returns { id, title, type, body: { text, highlights, links }, private, stars, points }.
404 if the cheat doesn't exist; 403 if it's private and you're not its owner (or a linked account).
GET /mcp/getCheat?id=abc123 Authorization: Bearer csk_live_...
List the full append-only revision history for a cheat's lineage — every past and current version, oldest first.
Scope: read
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id | query string | string | Yes | Id of any revision in the lineage — not just the original |
Returns { originalId, revisions: [{ id, title, type, snippet, private, ceased, createdDateMs, stars, points }] }. Exactly one entry has ceased: false — that's the current version; the others are prior edits kept for history.
404 if the cheat doesn't exist; 403 if it's private and you're not its owner (or a linked account).
GET /mcp/getRevisions?id=abc123 Authorization: Bearer csk_live_...
Create a new cheat. Starts with 0 stars and 0 points regardless of what's sent.
Scope: write
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Max 40 characters |
typeName | string | Yes | Max 15 characters, case-insensitive; created automatically if it doesn't already exist |
body.text | string | Yes | Max 100 lines, 600 characters per line; whole record capped at 10 KB |
private | boolean | Yes | Must be sent explicitly — there is no default |
Returns { id } — the new cheat's id.
POST /mcp/addCheat
Authorization: Bearer csk_live_...
Content-Type: application/json
{
"title": "Restart nginx",
"typeName": "linux",
"body": { "text": "sudo systemctl restart nginx" },
"private": true
}
Revise a cheat you own. This is append-only, same as editing a cheat in the browser: the old revision is marked ceased and a new one is created and linked to it, nothing is overwritten in place.
Scope: write
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Id of the cheat to revise |
title | string | Yes | Max 40 characters |
typeName | string | Yes | Max 15 characters, case-insensitive; created automatically if it doesn't already exist |
body.text | string | Yes | Max 100 lines, 600 characters per line; whole record capped at 10 KB |
private | boolean | Yes | Must be sent explicitly — there is no default |
Returns { id } — the new revision's id (different from the id you sent in). 404 if the original doesn't exist; 403 if you don't own it.
POST /mcp/updateCheat
Authorization: Bearer csk_live_...
Content-Type: application/json
{
"id": "abc123",
"title": "Restart nginx",
"typeName": "linux",
"body": { "text": "sudo systemctl restart nginx --now" },
"private": true
}
Delete a cheat you own. Not a hard delete — same as the browser's delete button, the cheat is marked ceased and stops appearing in search/getCheat, but the record and its revision history aren't erased.
Scope: write
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Id of the cheat to delete |
Returns { success: true }. 404 if the cheat doesn't exist; 403 if you don't own it.
POST /mcp/deleteCheat
Authorization: Bearer csk_live_...
Content-Type: application/json
{
"id": "abc123"
}
Tasks are unencrypted, private-only notes (to-do lists, AI plans, and so on) that live outside cheat search entirely, in a separate collection with its own endpoints below. Unlike cheats they have no type taxonomy (just a freeform category string you choose) and no private field (always private), and no revision history is ever exposed, even though an edit is append-only under the hood. A task is either permanent or auto-expires and is then automatically deleted (soft-ceased).
Search your own tasks. Not Algolia-backed like cheat search, just a plain title/text/category substring match over your tasks, since a personal task list is small.
Scope: read
| Parameter | Type | Required | Description |
|---|---|---|---|
q | string | No | Search text matched against title/text/category; omitted means the most recently created tasks |
page | number | No | 1-indexed page number, default 1 |
Returns { tasks: [{ id, title, category, text, highlights, links, createdDateMs, expiresAtMs }], totalPages }. expiresAtMs is null for a permanent task; category is "" if none was set.
GET /mcp/searchTasks?q=groceries Authorization: Bearer csk_live_...
Fetch one task.
Scope: read
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id | query string | string | Yes | The task id, as returned by /mcp/searchTasks |
Returns { id, title, category, text, highlights, links, createdDateMs, expiresAtMs }. 404 if the task doesn't exist; 403 if you don't own it.
GET /mcp/getTask?id=abc123 Authorization: Bearer csk_live_...
Create a new task.
Scope: write
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Max 40 characters |
category | string | No | Freeform grouping label you choose, e.g. "AI" or a project name; max 30 characters. Not a shared taxonomy like cheats' types |
text | string | Yes | Max 100 lines, 600 characters per line; whole record capped at 10 KB |
duration | string | No | One of permanent, 1h, 1d, 1w; defaults to permanent |
Returns { id }, the new task's id.
POST /mcp/addTask
Authorization: Bearer csk_live_...
Content-Type: application/json
{
"title": "Ship the release",
"category": "AI",
"text": "1. Tag the branch\n2. Deploy\n3. Announce",
"duration": "1d"
}
Revise a task you own. Append-only, same as /mcp/updateCheat (the old revision is ceased and a new one created), but there is no endpoint to view that history for Tasks.
Scope: write
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Id of the task to revise |
title | string | Yes | Max 40 characters |
category | string | No | New freeform grouping label; max 30 characters |
text | string | Yes | Max 100 lines, 600 characters per line; whole record capped at 10 KB |
duration | string | No | One of permanent, 1h, 1d, 1w; defaults to permanent |
Returns { id }, the new revision's id. 404 if the original doesn't exist; 403 if you don't own it.
POST /mcp/updateTask
Authorization: Bearer csk_live_...
Content-Type: application/json
{
"id": "abc123",
"title": "Ship the release",
"category": "AI",
"text": "1. Tag the branch\n2. Deploy\n3. Announce\n4. Watch dashboards",
"duration": "1d"
}
Delete a task you own. Not a hard delete, same soft-cease as /mcp/deleteCheat.
Scope: write
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Id of the task to delete |
Returns { success: true }. 404 if the task doesn't exist; 403 if you don't own it.
POST /mcp/deleteTask
Authorization: Bearer csk_live_...
Content-Type: application/json
{
"id": "abc123"
}
The recommended way to add this as a remote MCP server in Claude Code (or any other client that reads a .mcp.json config) is a small local proxy that reads your key from a gitignored .env.local file and forwards every call to the hosted connector above, so the key never has to sit in .mcp.json itself or in a shell environment variable:
{
"mcpServers": {
"cheatsheet": {
"command": "node",
"args": ["live-proxy.js"],
"env": {
"CHEATSHEET_ENV_FILE": ".env.local"
}
}
}
}
See Setting up the MCP proxy for the full script and step-by-step setup.
If you'd rather skip the local process and are fine putting the key in a real shell environment variable instead, you can also add this as a direct "type": "http" entry:
{
"mcpServers": {
"cheatsheet": {
"type": "http",
"url": "https://cheats.aarontrotter.com/mcp",
"headers": {
"Authorization": "Bearer ${CHEATSHEET_API_KEY}"
}
}
}
}
For a "type": "http" entry, Claude Code can only expand ${...} from a real environment variable already set before it starts, it has no way to read one out of a file for this entry type. Either way, create the key first from the User page's API Access section, choosing read-only or read + write depending on what you want the client to be able to do, and restart Claude Code (or start a new session) after adding the config to approve the cheatsheet server when prompted.