mark-it

MCP, CLI and API

Connect your archive to Claude, Cursor, the terminal or your own code. All three use the same personal API keys and are included in both plans.

API keys

Make a key in mark under Settings → API, MCP and CLI. Give it a name you'll recognize, like “Claude on my laptop”, and copy it straight away: it's shown once. Keys start with mark_.

  • Send the key on every request as a Bearer token. The MCP setups below do this for you.
  • A key can read your whole archive and add to it. It can't delete anything or touch billing.
  • Keys need an active plan, Starter or Growth. You can have up to 10, and revoke any of them in Settings.
Header
Authorization: Bearer mark_YOUR_KEY

MCP server

With MCP, your assistant can search your archive, read whole posts and articles, quote your highlights, and save or file new links, all from the chat. The server lives at https://mark-it.app/api/mcp.

Claude Code

Terminal
claude mcp add --transport http mark https://mark-it.app/api/mcp \
  --header "Authorization: Bearer mark_YOUR_KEY"

Cursor

Add this to ~/.cursor/mcp.json, or to .cursor/mcp.json in a project.

mcp.json
{
  "mcpServers": {
    "mark": {
      "url": "https://mark-it.app/api/mcp",
      "headers": {
        "Authorization": "Bearer mark_YOUR_KEY"
      }
    }
  }
}

Claude Desktop

Claude Desktop connects through mcp-remote, which needs Node. Add this to claude_desktop_config.json and restart the app.

claude_desktop_config.json
{
  "mcpServers": {
    "mark": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://mark-it.app/api/mcp",
        "--header",
        "Authorization:${MARK_AUTH}"
      ],
      "env": {
        "MARK_AUTH": "Bearer mark_YOUR_KEY"
      }
    }
  }
}

Claude.ai and ChatGPT connectors need OAuth sign-in, which mark doesn't support yet. Any client that can send a header works today.

Tools

ToolWhat it does
search_savesFull-text search across titles, authors and text. Optional folder, kind and limit.
list_savesRecent saves, filtered by folder, kind or unread, and paged with a cursor.
get_saveOne save in full: text, quoted post, media, your note and highlights.
list_foldersYour folders with their paths and how many saves each holds.
save_urlArchive a link, optionally straight into a folder.
move_saveFile a save into a folder, or take it out of one.

The first four only read. The server speaks Streamable HTTP, is stateless and answers with plain JSON (no SSE stream or session id).

CLI

mark brings your archive to the terminal: save a link, search, and read what you kept without leaving the shell. It's a single file with no dependencies and needs Node 20 or later.

Coming soon to npm. Until it's published, the MCP server and REST API above and below do everything the CLI does.

Log in

Terminal
mark login                 # asks for your key without echoing it
mark login --key mark_YOUR_KEY    # or pass it in

The key is saved to ~/.config/mark/config.json, readable only by you (on Windows, %APPDATA%\mark\config.json). Set MARK_API_KEY to use a different key for one command or in CI.

Commands

mark --help
mark whoami                              Account, plan and save count
mark save <url> [--folder <folder>]      Archive a post, article or any web page
mark ls [--folder <f>] [--kind <k>] [--unread] [--limit <n>] [--cursor <c>]
mark search <words…> [--folder <f>] [--kind <k>] [--limit <n>]
mark show <id>                           Full text, quoted post, media, note and highlights
mark mv <id> <folder>                    File a save ("mark mv <id> --none" takes it out)
mark folders                             Folders with paths and counts
mark logout
  • A folder can be its id, its name or its full path, like "Design / Pricing".
  • Kinds are post, article and link.
  • Add --json to any command for the raw API response, ready to pipe into jq. Set NO_COLOR=1 to turn colors off.

REST API

Every endpoint lives under https://mark-it.app/api/v1, takes and returns JSON, and needs your key in the Authorization header.

EndpointWhat it does
GET /meYour account, plan and save count
GET /savesList or search saves
POST /savesSave a link
GET /saves/:idOne save in full
PATCH /saves/:idMove a save to another folder
GET /foldersYour folders

GET/api/v1/me

Who the key belongs to. saveLimit is 20 on Starter and null on Growth.

Request
curl https://mark-it.app/api/v1/me \
  -H "Authorization: Bearer mark_YOUR_KEY"
Response
{
  "email": "you@example.com",
  "name": "Your Name",
  "plan": "Starter",
  "tier": "pro",
  "saves": 12,
  "saveLimit": 20
}

GET/api/v1/saves

Your saves, newest first. Every query parameter is optional.

ParameterDescription
qSearch words. Each word matches as a prefix against titles, authors and text.
folderA folder id, name or full path.
kindOnly post, article or link.
unreadtrue for saves you haven't opened yet.
limit1 to 50. Defaults to 20.
cursorThe nextCursor from the previous page.
Request
curl "https://mark-it.app/api/v1/saves?q=pricing&limit=10" \
  -H "Authorization: Bearer mark_YOUR_KEY"
Response
{
  "saves": [
    {
      "id": "3f2a9c1e-8b7d-4c1a-9e2f-5a6b7c8d9e0f",
      "kind": "post",
      "platform": "x",
      "url": "https://x.com/lenanovak/status/1834000000000000000",
      "appUrl": "https://mark-it.app/home/item/3f2a9c1e-8b7d-4c1a-9e2f-5a6b7c8d9e0f",
      "title": null,
      "author": {
        "name": "Lena Novak",
        "handle": "lenanovak"
      },
      "excerpt": "Show the price before the sign-up button. Hiding it costs you more trust than it saves.",
      "postedAt": "2026-09-02T14:20:00Z",
      "savedAt": "2026-09-03T08:05:12Z",
      "isRead": true,
      "sourceDeletedAt": "2026-09-10T08:12:00Z",
      "folderId": "a1b2c3d4-0000-4000-8000-000000000001"
    }
  ],
  "nextCursor": null
}
  • sourceDeletedAt is set once mark notices the original was deleted. Your copy stays readable.
  • appUrl opens the archived copy in mark. It's null for links, which open their own page.
  • nextCursor is null on the last page.

POST/api/v1/saves

Archives a link: an X post or article, a LinkedIn or Reddit post, or any web page. folder is optional. Returns 201 for a new save, or 200 when you'd already saved it (the copy is refreshed).

Request
curl -X POST https://mark-it.app/api/v1/saves \
  -H "Authorization: Bearer mark_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://x.com/someone/status/123","folder":"Design"}'
Response
{
  "save": { "id": "…", "kind": "post", … },
  "created": true
}

GET/api/v1/saves/:id

One save in full. On top of the list fields, it includes:

FieldDescription
textThe full archived text. Markdown for articles, the post text for posts, the description for links.
quotedThe quoted post, { unavailable: true } if it couldn't be fetched, or null.
mediaImages, videos and GIFs. archivedUrl is mark's copy, a link that works for one hour.
noteYour note on the save, if any.
highlightsEach with its quote, your comment and its color.
Request
curl https://mark-it.app/api/v1/saves/3f2a9c1e-8b7d-4c1a-9e2f-5a6b7c8d9e0f \
  -H "Authorization: Bearer mark_YOUR_KEY"

PATCH/api/v1/saves/:id

Moves a save into a folder, or out of any folder with null. Returns the updated save.

Request
curl -X PATCH https://mark-it.app/api/v1/saves/3f2a9c1e-8b7d-4c1a-9e2f-5a6b7c8d9e0f \
  -H "Authorization: Bearer mark_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"folder":"Design / Pricing"}'

GET/api/v1/folders

Every folder, with its full path and how many saves it holds.

Request
curl https://mark-it.app/api/v1/folders \
  -H "Authorization: Bearer mark_YOUR_KEY"
Response
{
  "folders": [
    {
      "id": "a1b2c3d4-0000-4000-8000-000000000001",
      "name": "Pricing",
      "path": "Design / Pricing",
      "parentId": "a1b2c3d4-0000-4000-8000-000000000000",
      "emoji": "💸",
      "color": "green",
      "count": 7
    }
  ]
}

Referring to folders

Wherever a request takes a folder, you can pass its id, its full path ("Design / Pricing") or just its name. Names are matched without regard to case. If two folders share a name, use the path or id instead; the API answers 409 folder_ambiguous.

Errors and limits

Errors come back with a status code and a JSON body you can branch on:

Response
{
  "error": {
    "code": "not_found",
    "message": "That isn't in your archive."
  }
}
StatusCodeMeaning
400validationA parameter or the body is missing or malformed.
401unauthenticatedThe key is missing, mistyped or revoked.
402subscription_requiredThe account has no active plan.
403limit_reachedStarter's 20 saves are used up.
404not_foundNo such save or folder.
409folder_ambiguousTwo folders share that name. Use the path or id.
422invalid_url, not_availableThe link isn't valid, or the post is private or deleted.
429rate_limitedToo many requests. Wait for Retry-After seconds.
502source_unreachableThe original site didn't answer. Try again shortly.
500unknownSomething broke on mark's side.
  • 120 requests a minute per account, across every key.
  • 30 saves a minute, the same as in the app.
  • Starter holds 20 saves; Growth has no limit.

Stuck? Reach us at support@mark-it.app. No key yet? Pick a plan and make one in Settings.