Skip to content

shift mcp server changelog

io.github.cyanheads/shift-mcp-server

4 changes recorded. MCP Harbor re-reads this listing from the official registry every six hours and asks the live server what it exposes, and keeps what changed between one look and the next.

  • AGENTS.md +27 −23

    https://raw.githubusercontent.com/cyanheads/shift-mcp-server/HEAD/AGENTS.md

    − **Version:** 0.1.8− **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.13`− **MCP SDK:** `@modelcontextprotocol/server` ^2.2.0− **Zod:** ^4.6.5− - **Use `ctx.state`** for tenant-scoped storage. Never access persistence directly.− import { formatWorkersTable, type WorkerSession, workers } from '@/services/worker-store/worker-store.js';−     const session: WorkerSession = upsertSession(input);−     // Every mutation of the roster notifies shift://status subscribers.−     ctx.notifyResourceUpdated?.('shift://status');−     return { workerId: session.workerId, activeWorkers: [...workers.values()] };− import { formatWorkersTable, workers } from '@/services/worker-store/worker-store.js';−     if (workers.size === 0) return '## Active Workers (0)\nNo agents are currently active.';−     return `## Active Workers (${workers.size})\n${formatWorkersTable([...workers.values()])}`;− No server-specific environment variables — worker sessions live in memory and clear on restart, so there is no `src/config/server-config.ts`. Add one (`parseEnvConfig` over a Zod schema) only if a real knob appears; use `z.stringbool()` for env booleans, never `z.coerce.boolean()`.−   resources: [statusResource],− This server declares `sessionMode: 'stateless'` and neither hook: no tool calls `ctx.requestInput`, and the worker roster is a plain in-memory `Map` with nothing to release.− | `ctx.notifyResourceUpdated` | Signals that `shift://status` changed. Called on every check-in, session update, and check-out. Subscription-scoped — see `framework-skills/api-context`. |− `ctx.state`, `ctx.requestInput` / `ctx.inputs`, `ctx.enrich`, and `ctx.content` are unused here — the worker roster is a module-level `Map`, not tenant-scoped storage. `framework-skills/api-context` documents the full surface if one becomes relevant.−       worker-store.ts                             # In-memory session Map, ID generation, table formatting− - [ ] Any change to the roster (check-in, session update, check-out) calls `ctx.notifyResourceUpdated('shift://status')`− - [ ] `workerId` inputs keep the `WORKER_ID_PATTERN` regex, so a malformed ID is rejected before the handler runs− - [ ] Every field rendered into the active-workers table appears verbatim — `format-parity` walks nested array fields, so a truncated or reformatted value fails `lint:mcp`− - [ ] Tests clear `workers` in `beforeEach` — the store is module-level and persists across cases+ **Version:** 0.2.0+ **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.15`+ **MCP SDK:** `@modelcontextprotocol/server` ^2.3.1+ **Zod:** ^4.6.7+ - **Use `ctx.state`** for tenant-scoped KV. The workspace roster uses its transactional `WorkerStore` service; handlers never issue SQL directly.+ import { formatWorkersTable, getWorkerStore, notifyWorkspace, resolveWorkspace } from '@/services/worker-store/worker-store.js';+     const workspace = resolveWorkspace();+     const { session, activeWorkers } = getWorkerStore().checkIn(workspace, input);+     if (!session) throw ctx.fail('unknown_worker');+     // Publish through the server notifier after the transaction commits.+     notifyWorkspace(workspace);+     return { workerId: session.workerId, activeWorkers };+ import { formatWorkersTable, getWorkerStore, resolveWorkspace } from '@/services/worker-store/worker-store.js';+     const workers = getWorkerStore().list(resolveWorkspace());+     return `## Active Workers (${workers.length})\n${formatWorkersTable(workers)}`;+ `src/config/server-config.ts` parses `SHIFT_STATE_DIR` and `SHIFT_WORKSPACE` during setup. SQLite defaults to `~/.local/state/shift-mcp-server/roster.sqlite`; the default workspace is `SHIFT_WORKSPACE`, otherwise the real enclosing Git root or launch cwd. Explicit workspace selectors are opaque. Sessions persist across restarts until check-out. `docs/design.md` records transaction and namespace rules.+   resources: [statusResource, workspaceStatusResource],+ This server declares `sessionMode: 'stateless'`: no tool calls `ctx.requestInput`. Setup opens the SQLite store and captures `core.notify.resourceUpdated`; teardown closes storage. Modern subscriptions receive process-local committed mutations from either protocol era. The framework's legacy adapter and other processes require polling; this is not a restriction of the 2025 protocol.+ | `ctx.enrich.notice` | Carries the composed coordination protocol and solo notice once on both production output surfaces. |+ `ctx.state`, `ctx.requestInput` / `ctx.inputs`, and `ctx.content` are unused here. Roster mutations call `notifyWorkspace()` only after commit, replacing request-scoped notifications to avoid duplicates. It publishes the qualified URI, plus the bare alias only for the default workspace.+   config/server-config.ts                          # SHIFT_STATE_DIR and SHIFT_WORKSPACE+       worker-store.ts                             # SQLite transactions, workspace identity, table formatting+       workspace-status.resource.ts                # shift://status{?workspace}+ - [ ] Actual roster mutations publish through `notifyWorkspace()` after commit; no-op check-out emits nothing+ - [ ] `workerId` inputs validate six ASCII letters/digits before uppercasing; Unicode expansion, whitespace and punctuation stay invalid+ - [ ] Table cells escape backslashes before pipes and flatten newlines; raw stored/structured values and full timestamps are preserved+ - [ ] Tests isolate SQLite state in scratch directories; never read or mutate an installed user's roster

  • server.json 2 fields changed
    env_vars
    MCP_LOG_LEVEL SHIFT_WORKSPACE, SHIFT_STATE_DIR, MCP_LOG_LEVEL
    version
    0.1.8 0.2.0

  • AGENTS.md +7 −7

    https://raw.githubusercontent.com/cyanheads/shift-mcp-server/HEAD/AGENTS.md

    − **Version:** 0.1.7− **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.6`− **MCP SDK:** `@modelcontextprotocol/server` ^2.0.0− | `ctx.requestId` | Unique request ID. |− **Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable?, severity?, thrownBy? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos at compile time, `data.reason` is auto-populated for observability, linter enforces conformance against the handler body. `recovery` is required (≥ 5 words, lint-validated) — the single source of truth for the agent's next move. Pass `ctx.recoveryFor('reaso−   if (!item) throw ctx.fail('no_match', `No item ${input.id}`, ctx.recoveryFor('no_match'));− **Every release goes through a release PR, straight-through** — `git-wrapup`'s "Release PR mode", mode `straight-through`. One run: `git-wrapup` lands the commit stack on `release/<version>`, pushes it, and opens the PR (title = the release commit subject, body = the changelog entry plus a gates section); `release-and-publish` then fast-forwards `main` locally with `git merge --ff-only`, creates the tag on `main`'s tip, pushes `main` and the tag, deletes the branch, and publishes. A caller's bri+ **Version:** 0.1.8+ **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.13`+ **MCP SDK:** `@modelcontextprotocol/server` ^2.2.0+ | `ctx.requestId` | Request ID — the one every log record of the call carries and its error envelope returns as `data.requestId`. |+ **Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable?, severity?, thrownBy? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos at compile time, `data.reason` is auto-populated for observability, linter enforces conformance against the handler body. `recovery` is required (≥ 5 words, lint-validated) — the single source of truth for the agent's next move. The framework puts it on the+   if (!item) throw ctx.fail('no_match', `No item ${input.id}`);+ **Every release goes through a release PR, straight-through** — `git-wrapup`'s "Release PR mode", mode `straight-through`. One run: `git-wrapup` lands the commit stack on `release/<version>`, pushes it, and opens the PR (title = the release commit subject, body = the release digest: theme line, `## Changes`, `## Gates`, changelog link last); `release-and-publish` then fast-forwards `main` locally with `git merge --ff-only`, creates the tag on `main`'s tip, pushes `main` and the tag, deletes the 

  • server.json 1 field changed
    version
    0.1.7 0.1.8