# pi-ticktick

Pi coding agent extension that connects to [TickTick's official MCP server](https://help.ticktick.com/articles/7438129581631995904) (`https://mcp.ticktick.com`) and exposes TickTick tools to the agent.

Pi has no built-in MCP — this extension is the bridge.

## What it does

- **MCP tool proxies** — TickTick's MCP tools (tasks, lists, habits, focus) become Pi tools the LLM can call.
- **Lazy connect** — MCP connects on the first agent turn (or when you run `/ticktick-status`), not at Pi startup.
- **Slash commands** — Token setup and status without involving the model:
  - `/ticktick-setup` — How to get your API Token; optionally save it
  - `/ticktick-logout` — Remove stored token
  - `/ticktick-status` — Auth source, connection status, and tool count (also triggers connect)

## Prerequisites

- [Pi coding agent](https://pi.dev) installed
- A TickTick account
- A TickTick **API Token** (from the web app, not the developer portal)

## Get your API Token

Per [TickTick MCP documentation](https://help.ticktick.com/articles/7438129581631995904):

1. Log in to [TickTick web](https://ticktick.com).
2. Click your avatar (top-left) → **Settings → Account → API Token**.
3. Create and copy the token.

This token is sent as `Authorization: Bearer …` to `https://mcp.ticktick.com`.

## Installation

### From npm (when published)

```bash
pi install npm:pi-ticktick
```

### From this repository

```bash
git clone https://github.com/lludol/pi-ticktick.git
cd pi-ticktick
npm install
pi install ./
```

### Try without installing

```bash
pi -e /path/to/pi-ticktick
```

## Configuration

Provide your API Token in one of two ways:

### Option A — Environment variable (recommended for CI)

```bash
export TICKTICK_ACCESS_TOKEN="your_api_token_from_ticktick_settings"
```

### Option B — Saved via `/ticktick-setup`

Run `/ticktick-setup` in Pi and paste your token. Saved to `~/.pi/agent/ticktick/token` (not sent to the LLM).

Resolution order: env → saved file → not configured.

## Usage

1. Install the extension and set your API Token (env or `/ticktick-setup`).
2. Start Pi. Status shows **idle** until the first agent message or `/ticktick-status`.
3. Ask the agent naturally, for example:
   - “List my TickTick tasks due today”
   - “Add a task ‘Review PR’ to Work”
   - “Mark my grocery task complete”

### Limiting which tools the agent sees

Pi lets you restrict active tools per session (built-in tools UI, or programmatically via `pi.setActiveTools()` in another extension). TickTick registers all MCP tools with the `ticktick__` prefix — disable individual tools there if you want a smaller tool surface.

### Slash commands

| Command | Description |
|---------|-------------|
| `/ticktick-setup` | API Token instructions; optionally save token |
| `/ticktick-logout` | Remove saved token (see note below if env token is set) |
| `/ticktick-status` | MCP connection + auth source; connects if a token is available |

**Logout note:** `/ticktick-logout` only deletes the saved file at `~/.pi/agent/ticktick/token`. If `TICKTICK_ACCESS_TOKEN` is set in your shell, Pi will still authenticate from the environment until you unset it and restart.

TickTick MCP also supports OAuth when clients connect without a Bearer header. This extension uses the **API Token** path only.

## Development

Maintainer workflow for MCP upgrades: [AGENTS.md](./AGENTS.md).

Pi has no built-in extension linter — this repo uses **Biome** + **TypeScript**:

```bash
npm install
npm run check        # biome
npm test             # typecheck + unit tests + optional live MCP drift check
```

### Tests

Offline tests use a **frozen snapshot** of TickTick MCP tool schemas at `test/fixtures/mcp-tool-schemas.json`. That file is not used at runtime — production always calls live `listTools()` — but it lets CI validate schema compilation and coercion without your API token.

| Test | Purpose |
|------|---------|
| `test/verify-load.ts` | Extension registers commands and lifecycle hooks |
| `test/coerce-arguments.ts` | JSON-string coercion for nested MCP args |
| `test/schema-fixtures.ts` | All exported MCP schemas compile; `samples` args validate |
| `test/tool-name-collision.ts` | Sanitized MCP names get unique Pi tool names |
| `test/live-mcp-schemas.ts` | With a token, compares live tool names to the fixture |

**Export / refresh the fixture** when TickTick adds or removes MCP tools (or when `live-mcp-schemas` fails):

```bash
export TICKTICK_ACCESS_TOKEN="..."   # or use saved ~/.pi/agent/ticktick/token
npm run export-schemas
npm test
git diff test/fixtures/mcp-tool-schemas.json
```

The export script preserves existing `samples` entries for tools that still exist. Add new samples manually for tools where the LLM sends JSON strings for nested objects (see `filter_tasks` in the fixture).

Full maintainer workflow: **[AGENTS.md](./AGENTS.md)** (upgrading the extension when TickTick MCP changes).

There is no official Pi extension test runner. This repo uses `tsx` smoke tests, a JSON fixture, and an optional live drift check. For end-to-end agent behavior, Pi's SDK `createAgentSession()` can drive a session with your extension loaded — heavier, usually CI-only.

### Test locally before `pi install`

```bash
# 1. Static checks
npm run check
npm test

# 2. Run in Pi without installing (from repo root)
export TICKTICK_ACCESS_TOKEN="your_token"   # optional until MCP connect test
pi -e .

# 3. In Pi TUI
/ticktick-status
# Ask the agent to list your TickTick tasks
```

Install when satisfied: `pi install ./` or `pi install -l ./`

## Troubleshooting

| Problem | Fix |
|---------|-----|
| “Not authenticated” / no tools | Set `TICKTICK_ACCESS_TOKEN` or run `/ticktick-setup` |
| MCP connection failed | Check network; verify token at TickTick Settings → Account → API Token |
| 401 from TickTick | Regenerate API Token in TickTick settings |
| Token in env not picked up | Restart Pi after exporting |
| Logout did not disconnect | Unset `TICKTICK_ACCESS_TOKEN` if set in your shell |

## Security

- This extension runs with the same permissions as Pi itself. Only install from sources you trust.
- API Token grants full account access — treat like a password.
- Token stored at `~/.pi/agent/ticktick/` with restricted permissions.
- Traffic goes only to official `mcp.ticktick.com` over HTTPS.

## License

MIT — see [LICENSE](./LICENSE). Also declared in `package.json` (`"license": "MIT"`).
