Skip to main content
Glama
Roms504318
by Roms504318
README.md
# Clockify MCP Server

A **scoped** Clockify MCP server for `mcp.sco-mo.com`. Exposes a fixed read/write
tool set plus a **code-defined structure scaffold** that replaces Clockify's
paid-gated project templates. The structure lives as code (`lib/structure.ts`) —
a single source of truth that's editable, re-runnable, and version-controlled.

> **v0.1 DRAFT.** The `STRUCTURE` config is a draft pending Oel's Excel
> reconciliation. The mechanism is built; **do not run `scaffoldStructure`
> against the live workspace yet** (see [Build sequence](#build-sequence)).

---

## Stack

- **Next.js App Router** route handler + [`mcp-handler`](https://www.npmjs.com/package/mcp-handler) (Vercel adapter)
- Pipeline: **GitHub → Vercel → Cloudflare**, custom domain `mcp.sco-mo.com`
- Clockify base API: `https://api.clockify.me/api/v1`

MCP endpoint (streamable-http): `https://mcp.sco-mo.com/api/mcp`
Health probe (open): `https://mcp.sco-mo.com/api/health`

---

## Environment variables

Set these in the **Vercel dashboard** (never in code, never committed):

| Var | Value | Notes |
| --- | --- | --- |
| `CLOCKIFY_API_KEY` | the raw `NDQ…` key | Sent as `X-Api-Key`. Never logged. |
| `CLOCKIFY_WORKSPACE_ID` | `69476cbc9bfb39506eedab0a` | Fixed target workspace. |
| `MCP_BEARER_TOKEN` | a strong random token | Guards the endpoint. Clients send `Authorization: Bearer <token>`. |

`.env` is git-ignored. Copy `.env.example` → `.env.local` for local dev.
If `MCP_BEARER_TOKEN` is unset the endpoint **fails closed** (401), never open.

---

## Tools — the complete scoped set (do not add to this)

**Read** — `getCurrentUser`, `listUsers`, `listTimeEntries`, `getTimeEntry`,
`listProjects`, `listClients`, `listTasks`, `listTags`

**Write** — `upsertTimeEntry`, `upsertProject`, `upsertClient`, `upsertTask`,
`upsertTag`, `archiveProject`, `archiveClient`, `deleteProject` (gated),
`deleteClient` (gated), `scaffoldStructure`, `newProjectFromShape`

### Delete discipline (the one irreversible surface)

- Clockify enforces **archive-before-delete**. `deleteProject` / `deleteClient`
  verify the target is archived and refuse otherwise.
- Both require an explicit `confirm: true` argument (typed as `literal(true)`),
  and are **never** called by an unattended agent — the review gate.
- Deleting a project removes it from time entries but leaves the underlying time
  data intact.

### `scaffoldStructure`

Idempotent, additive-only reconcile of the workspace toward `STRUCTURE`:
creates any missing client/project/task/tag, skips what exists, never deletes.

**`dryRun` defaults to `true`** — it returns the plan without writing. Pass
`dryRun: false` to apply. Idempotency is by name.

### `newProjectFromShape`

The template replacement. Instantiates a project + its standard task list from a
shape in `STRUCTURE.shapes` (e.g. `matter`). Creates the client if a `clientName`
is given and missing.

---

## Local development

```bash
npm install
cp .env.example .env.local   # fill in the three vars
npm run dev                  # http://localhost:3000/api/mcp
npm run typecheck
```

Smoke-test the endpoint (expects 401 without the token):

```bash
curl -s http://localhost:3000/api/health
```

---

## Deploy

1. Push to GitHub; import into Vercel (framework auto-detected as Next.js).
2. Add the three environment variables in Vercel → Settings → Environment Variables.
3. Add the domain `mcp.sco-mo.com` (Vercel → Domains); point Cloudflare DNS per
   the existing pipeline.
4. Redeploy. Verify `GET /api/health` returns `config` all `true`.

---

## Build sequence

1. ✅ **Now:** server, scoped tool set, delete gate, and
   `scaffoldStructure` / `newProjectFromShape` built and deployed.
2. ⛔ **Do not** run `scaffoldStructure` with `dryRun:false` against the live
   workspace yet.
3. Oel sends the Excel of the existing structure. Reconcile `lib/structure.ts`
   against it — Scottmoore project granularity, kill dead old-company projects,
   confirm the Personal breakdown.
4. **Then** run `scaffoldStructure` to build/adjust the live workspace, and
   archive/delete old-company remnants (delete gated, one `confirm` each).

Maintenance

ActivitySlowing
ResponsivenessNo issues