Skip to main content
Glama
README.md
# skrye-mcp (SKR-80)

A stdio MCP server that gives CC **workspace-parameterized task CRUD** on SKRYE, running
under Row-Level Security **as its own user** (`cc@skrye.agents`). It is a thin, isolated
wrapper over the existing DEFINER RPCs — **no schema changes, no `service_role`**. CC's edits
go through the same RLS-checked paths a human's browser uses, so they surface in the river.

## Verbs

| Verb | Backing path | Surfaces in river? |
|---|---|---|
| `list_workspaces` | `select workspaces` (RLS) | — (discovery entry point; the only verb with no `workspace` param) |
| `list_projects` | `select projects` (RLS) | — |
| `list_tasks` | `select tasks` (RLS) | — |
| `get_task` | `select tasks` + `select subtasks` (RLS) | — (read includes the subtasks checklist; a read never bumps the river) |
| `create_task` | `create_task_with_subtasks` RPC | ✅ (`created` activity) |
| `set_status` | `set_task_status` RPC | ✅ (`status_change`) |
| `claim_task` | `claim_task` RPC | ✅ (`claimed`) |
| `add_comment` | `add_comment` RPC | ✅ (`comment`) |
| `delete_task` | `task_soft_delete` RPC | ✅ (removed) |
| `update_task` | plain `UPDATE` (priority/description) | ❌ **silent** — a field edit does not nudge the river (matches a human field edit, D-2) |

## Invariants

- **Workspace is required on every verb** (except `list_workspaces`). Resolved id-first (uuid)
  or by unique name. Unknown/ambiguous → hard error.
- **Workspace↔task mismatch is a loud error.** A task id whose project lives in another
  workspace is rejected (defense-in-depth atop RLS). A key ref (`ABC-42`) can't mismatch — it
  is resolved by key *within* the workspace.
- **AAA-NNN keys** are accepted anywhere a task id is, and every task payload carries its `key`.
- **0-row writes are hard errors.** PostgREST returns 0 rows (no error) on an RLS-denied plain
  UPDATE; the server treats that as failure, never silent success.
- **Canonical DB vocabulary** (verified against live CHECK constraints): status ∈
  `Backlog / To Do / In Progress / Done / Canceled`; priority ∈ `low / normal / high`.
  Display jargon (Waiting/Flowing/…) is a per-workspace presentation layer the MCP does not touch.

## Auth

Signs in as YOUR agent (`SKRYE_AGENT_EMAIL` on the `@skrye.agents` plane) with
`persistSession:false` + `autoRefreshToken:true`. `JWT_EXPIRY` is 3600s; the long-lived process
auto-refreshes, and each call re-signs-in once if it still comes back JWT-expired.
`SKRYE_CC_EMAIL`/`SKRYE_CC_PW` are accepted as legacy fallbacks (CC's original config, SKR-80).

## Your agent in 5 minutes (SKR-150 — friend quickstart)

1. In Skrye, open **My agents** → name your agent → **Create**. Copy the shown-once snippet.
2. Install the server from the release tarball your operator relayed (sha256 in the release notes):
   `npm install -g ./skrye-mcp-0.2.0.tgz`
3. Paste the snippet into your Claude Code `.mcp.json` — it carries `SKRYE_URL`, `SKRYE_ANON`
   (public), and your agent's `SKRYE_AGENT_EMAIL` / `SKRYE_AGENT_PW`.
4. `chmod 600 .mcp.json` (or keep the password in your secret manager and reference it).
   **Rotate the credential from My agents** if you lose a device or suspect clipboard exposure —
   rotation kills every old session; there is no email recovery on the agent plane, by design.
5. Ask your Claude: *"list my Skrye workspaces."*

## Config & launch (CC's own setup)

Secrets are **op:// references only** in `.env.mcp` (resolved by `op run` at launch; enforced by
`scripts/check-mcp-env-oprefs.sh` in `npm run preflight`). Public config (`SKRYE_URL`,
`SKRYE_CC_EMAIL`) lives in `.mcp.json`'s `env` block. Registered in `.mcp.json` as:

```
op run --env-file=tools/skrye-mcp/.env.mcp --no-masking -- node tools/skrye-mcp/index.mjs
```

Targets **prod** (`api.skrye.team`) today; the server is fully env-parameterized — flip to dev by
pointing the env at the dev stack, no code change.

## Friend-alpha recipe (3 steps)

1. Ensure the `op` service account is authenticated on the host (the same one `deploy`/seed use).
2. In Claude Code, the `skrye` MCP server auto-starts from `.mcp.json`.
3. Ask CC: *"list my Skrye workspaces"* → then *"in CC-dev, create a task in CLYDE titled …"*.

> **Rotation note:** the CC password is read from 1Password **at launch only**. If you rotate
> `Skrye-Prod-CC-Password`, **restart the MCP server** (reload the window) for it to take effect.

## Tests

`npm test` (node:test, offline) — resolution + every verb, including the workspace-mismatch and
RLS-denied 0-row negatives. Live prod smoke test is run out-of-band via `op run` (not committed).