jj-mcp-server
by Cyberistic
README.md
# jj-mcp-server
A [Model Context Protocol](https://modelcontextprotocol.io) server for
[Jujutsu (`jj`)](https://github.com/jj-vcs/jj) version control, built on
[Effect v4](https://effect.website). Optional first-class support for
[`jjCoW`](https://github.com/Cyberistic/jjCoW) (clone-on-write workspace
manager, ~40× faster than `jj workspace add`).
- **Typed end-to-end**: parameter schemas are `effect/Schema` (decoded at the
boundary, not coerced at runtime); results are typed; errors are
`Schema.TaggedError` so the caller can pattern-match on `_tag`.
- **Effect-native**: `Effect.gen`, scoped resources, tagged errors,
`Layer.launch`. No `any`, no thrown exceptions.
- **Curated**: 22 `jj` tools + 7 `jjcow` tools — the day-to-day operations an
agent actually reaches for. Not 40 hand-rolled `args.push` blocks.
- **Stable tool surface**: `jjcow` tools are always registered and fail at
call time with a typed `JjCowNotInstalled` error when `jjw` is missing,
so clients never see a different schema across hosts.
## Install
```sh
# npm
npm install -g @cyberistic/jj-mcp-server
# pnpm
pnpm add -g @cyberistic/jj-mcp-server
# bunx (no install)
bunx @cyberistic/jj-mcp-server
```
Then point your MCP client at the `jj-mcp-server` bin. The exact
configuration depends on the client; for [opencode](https://opencode.ai):
```json
{
"mcp": {
"jj": {
"type": "local",
"command": ["jj-mcp-server"]
}
}
}
```
## Uninstall
```sh
npm uninstall -g @cyberistic/jj-mcp-server
# or
pnpm remove -g @cyberistic/jj-mcp-server
```
Then remove the `jj` entry from your MCP client's config.
## Tools
### Meta — call first
| Tool | Notes |
| ----------------------------- | ------------------------------------------------------------------------------------------- |
| `jj_workflow_how_to_use_info` | Returns the jj mental model + canonical workflow. Read this before any non-trivial jj op. |
### Read-only `jj` tools
| Tool | Wraps |
| ----------------- | -------------------------------------------------------------------- |
| `jj_status` | `jj status` |
| `jj_log` | `jj log [-r revisions] [-n limit] [-T template] [-G] [-p]` |
| `jj_show` | `jj show [revision] [-T template] [-p]` |
| `jj_diff` | `jj diff [-r revset] [-f from] [-t to] [--context N] [--summary\|--stat]` |
| `jj_files` | `jj file list [-r revision] [paths] [-T template]` |
| `jj_bookmark_list`| `jj bookmark list [--all-remotes] [--remote] [--tracked] [-T template]` |
| `jj_git_fetch` | `jj git fetch [--all-remotes] [--remote R] [-b branch]` |
| `jj_workspace_root` | `jj workspace root` |
| `jj_op_log` | `jj op log [-n limit] [-T template] [-G] [-p]` |
### Mutating `jj` tools
| Tool | Wraps |
| --------------------- | ------------------------------------------------------ |
| `jj_describe` | `jj describe -m message [revision]` |
| `jj_new` | `jj new [revisions...] [-m message] [--no-edit]` |
| `jj_abandon` | `jj abandon [revisions...] [--retain-bookmarks]` |
| `jj_rebase` | `jj rebase [-s source] [-d destination]` |
| `jj_squash` | `jj squash [--from] [--into] [-k]` |
| `jj_duplicate` | `jj duplicate [revs...] [-d destination] [-A after] [-B before]` |
| `jj_bookmark_create` | `jj bookmark create <name> [-r revision]` |
| `jj_bookmark_set` | `jj bookmark set <name> -r revision [--allow-backwards]` |
| `jj_bookmark_delete` | `jj bookmark delete <names...>` |
| `jj_git_push` | `jj git push [--remote R] [-b bookmark] [--all] [--tracked]` |
| `jj_resolve` | `jj resolve [-r revision] [--list]` |
| `jj_undo` | `jj undo` |
### Optional `jjcow` tools (always registered; fail with `JjCowNotInstalled` if `jjw` is missing)
| Tool | Wraps |
| -------------- | ----------------------------------------------------------- |
| `jjcow_create` | `jjw create <name> [-r revision] [-b bookmark] [--no-cow] [--lazy]` |
| `jjcow_delete` | `jjw delete [name] [-f] [-k]` |
| `jjcow_list` | `jjw list [-v]` |
| `jjcow_cleanup`| `jjw cleanup [-n] [-f] [-k]` |
| `jjcow_root` | `jjw root` |
| `jjcow_version`| `jjw version` |
| `jjcow_init` | `jjw init <shell>` for `zsh`/`bash`/`fish` shell integration |
Install [`jjCoW`](https://github.com/Cyberistic/jjCoW) to enable these:
```sh
git clone https://github.com/Cyberistic/jjCoW
cd jjCoW
just build && just install
```
Then `jjcow_*` tools start working without any change to the MCP server.
If `jjw` is not on `$PATH`, the tools return a typed `JjCowNotInstalled`
error explaining how to install it.
### What's deliberately **not** exposed
The keanemind-style reference exposes 40+ tools. We keep the surface small.
If an agent needs `bookmark-track`, `git-remote-add`, `file-annotate`,
`evolog`, `interdiff`, `revert`, `restore`, `edit`, or any of the
`operation-*` forensics commands, they can shell out to `jj` directly. This
keeps the tool catalog fast to scan and the LLM prompt smaller.
## Error taxonomy
Every failure is a `Schema.TaggedError` with a stable `_tag`:
| `_tag` | Meaning |
| -------------------- | ---------------------------------------------------------------------- |
| `JjError` | Catch-all for runtime failures (e.g. spawn error when `jj` is missing). |
| `CommandFailed` | `jj` or `jjw` exited non-zero. Carries `exitCode` + `stderr`. |
| `NotARepository` | The target `cwd` / `repoPath` isn't inside a jj repo. |
| `JjCowNotInstalled` | `jjw` isn't on `$PATH`. Install [jjCoW](https://github.com/Cyberistic/jjCoW). |
## Library use
The bin is the canonical entry; this package also exports the underlying
`Layer` and `Toolkit`s so an embedder can splice them into a richer layer
graph:
```ts
import { MainLayer, JjToolkit, JjCowToolkit } from "@cyberistic/jj-mcp-server";
```
## Development
This package uses [nub](https://nubjs.com) and
[bun](https://bun.sh) for tooling. Two CLIs cover the entire lifecycle —
nothing else is required.
```sh
nub install # install deps
nub run typecheck # tsc --noEmit
nub run lint # oxlint .
nub run fmt # oxfmt .
nub scripts/smoke.ts # verify the toolkits expose the expected tools
nub src/cli.ts < scripts/smoke.json
# end-to-end JSON-RPC smoke over stdio
```
`lefthook` runs `oxfmt` + `oxlint` on pre-commit and `tsc --noEmit` on
pre-push (`LEFTHOOK=0` skips).
## License
MIT
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues