Skip to content

Instantly share code, notes, and snippets.

@renezander030
Created June 12, 2026 16:39
Show Gist options
  • Select an option

  • Save renezander030/cd5164e11d82347250cbf03ac36be984 to your computer and use it in GitHub Desktop.

Select an option

Save renezander030/cd5164e11d82347250cbf03ac36be984 to your computer and use it in GitHub Desktop.
TickTick MCP server for Claude Code & Claude Desktop — OAuth setup, config, error strings

TickTick MCP server for Claude Code & Claude Desktop — OAuth setup, config, error strings

Connect TickTick to Claude Code / Claude Desktop / Cursor over MCP, with hybrid retrieval instead of CRUD-only access.

Last tested: 2026-06-12 — @reneza/ats-mcp + @reneza/ats-adapter-ticktick, TickTick Open API v1. See Changelog at the bottom.

If this saves you setup time, follow @renezander030 — practical AI / coding-agent infrastructure notes.

Full repo with the MCP server + adapter source: github.com/renezander030/agentic-task-system

TL;DR cheat sheet

Goal Use
TickTick in Claude Code claude mcp add ats -e ATS_ADAPTER=@reneza/ats-adapter-ticktick -- ats-mcp
TickTick in Claude Desktop / Cursor mcpServers JSON block below
OAuth ats auth login — opens TickTick OAuth, paste the code back
exceed_query_limit errors don't disable the corpus cache; TickTick throttles at 200 req/min per IP
Search that actually finds things hybrid dense + sparse + keyword, fused with RRF — not TickTick's substring-only native search

Recommended setup

npm install -g @reneza/ats-cli @reneza/ats-mcp @reneza/ats-adapter-ticktick
ats auth login                      # TickTick OAuth, paste code back
ats find "deployment runbook"       # verify from the CLI first
claude mcp add ats -e ATS_ADAPTER=@reneza/ats-adapter-ticktick -- ats-mcp

Claude Desktop / Cursor instead:

// claude_desktop_config.json
{
  "mcpServers": {
    "ats": {
      "command": "ats-mcp",
      "env": { "ATS_ADAPTER": "@reneza/ats-adapter-ticktick" }
    }
  }
}

Optional, for the semantic/hybrid retrieval branch (local, no cloud):

docker run -d --name qdrant -p 6333:6333 qdrant/qdrant:latest
docker run -d --name ollama -p 11434:11434 ollama/ollama:latest
docker exec ollama ollama pull nomic-embed-text
ats sync vector

What the agent gets

MCP tool What it does
find hybrid retrieval (dense + sparse + keyword), RRF-fused, per-hit provenance; explain: true shows the rank math
get_task / list_projects read side — full task bodies, project list
create_task / update_task write side — the agent leaves results where you'll see them
similar semantically similar tasks (needs the qdrant + ollama branch)
url_for paste-ready https://ticktick.com/webapp/#p/<proj>/tasks/<task> deep link

Why a retrieval layer instead of a plain TickTick CRUD MCP server?

  • Most community ticktick-mcp servers map the Open API 1:1 — create/read/update/delete, priority filters, due dates. Fine for "add a task," useless for "what did I decide about the staging deploy?"
  • TickTick's own searchByQuery is substring-only. An agent asking "ffmpeg commands" won't match a note titled ffmpeg. Hybrid + RRF catches it (60% hit@1 vs 20% substring in my bench — numbers in the companion gist).
  • The adapter is one implementation of a six-method contract — same MCP server runs over an Obsidian vault or your own backend by swapping ATS_ADAPTER.

Common failures

API request failed (500): exceed_query_limit

Query rate limit exceeded. Maximum 200 requests per minute.

TickTick Open API throttles per-IP at 200 req/min. A cold find walks every project (50+ requests). Fix: keep the corpus cache on (5-min TTL is the default), add sleep 30 between bench loops.

tasks update — Project ID required

TickTick's v1 API rejects bare /task/{id} updates — the project id must be included. Pass both: ats update <project_id> <task_id> --content "...".

qdrant not reachable at http://localhost:6333

docker ps | grep qdrant || docker start qdrant
curl -s http://localhost:6333/collections/ticktick_tasks | jq .result.status

Without qdrant the server still works — you get keyword + native search + RRF, just no dense/sparse branch.

OAuth window opens but the agent still reports unauthenticated

ats auth login completes in the CLI's config (~/.config/ats/config.json); the MCP server reads the same config. Run ats auth status — if the CLI is logged in but Claude isn't picking it up, restart the MCP client so it re-spawns ats-mcp.

Smoke test

ats auth status                                  # active adapter + non-zero corpus
ats find "any real task title" --limit 3 --json | jq '.tasks[].title'
claude mcp list                                  # ats listed as connected

Then in Claude Code: "use ats find to look up " — pass criteria: the answer cites the actual task and includes a sources: [...] provenance array.

Series

Companion to Production AI Automation Notes #3: Claude Code persistent memory between sessions — your task manager as agent memory (bench numbers, agent-data note pattern, debug flow). Series #1: Agent Approval Gates.

Sources

Comment with your setup

If you wire TickTick (or Dida365) into Claude Code another way, comment with: server used, OAuth flow that worked, corpus size, and any error strings you hit that aren't listed here.

Changelog

2026-06-12

  • Initial publication. Skipped gates deliberately: no hardware matrix (not hardware-bound), no companion-repo creation (repo already exists: agentic-task-system).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment