syncstaff-mcp
v0.2.11
Published
MCP adapter for Syncstaff cross-agent coordination
Maintainers
Readme
Syncstaff MCP adapter
syncstaff-mcp connects an MCP-capable coding agent to a hosted Syncstaff
server. It contains the local adapter plus the lifecycle hooks and doctor
that run beside it; the Syncstaff API server, PostgreSQL driver, and arbiter SDK
are not part of this package.
Login
Run this from the repository you want your agent to edit:
npx -y [email protected] setup --project your-existing-projectThe project is a Syncstaff project, not the checkout folder. Setup connects to
an existing project by default and never creates one merely because its name
matches the folder. Creating a new project requires --create-project;
replacing a checkout's existing binding requires --rebind. Both are explicit
because an accidental project split also splits its board and agent history.
No sign-in yet? The approval page is where you get one: it asks you to continue with GitHub, then finishes the connection.
It asks for the Syncstaff server, project, and agent vendor, completes device login,
then persistently reconciles every supported client in the repository: generic
MCP clients through .mcp.json, Claude Code through .claude/settings.json,
Codex through .codex/config.toml and .codex/hooks.json, and Gemini through
.gemini/settings.json. Existing unrelated settings and hooks are preserved;
stale Syncstaff entries are replaced. Restart each coding agent after setup.
From the repository the agent will edit, start a device login:
npx -y [email protected] login \
--server https://api.syncstaff.ai \
--project your-project \
--vendor codexOpen the displayed link, approve the short code, and leave the command running
until it confirms the connection. Syncstaff stores the returned credential in
.syncstaff/config.json with owner-only permissions and never prints the token.
Setup automatically adds .syncstaff/ to the repository's .gitignore before
writing the credential, preventing git add -A from staging it.
To intentionally create a project, add --create-project. To intentionally
move a checkout that already has credentials, verify the old and new project
names and add --rebind; without that flag login refuses to overwrite the
binding.
MCP configuration
Run the adapter from the repository the agent will edit so Syncstaff can inspect that checkout for call sites and unleased writes:
{
"mcpServers": {
"sync": {
"command": "npx",
"args": ["-y", "[email protected]"]
}
}
}Node.js 22.5 or newer is required. The adapter communicates over stdio and
registers with the configured Syncstaff server on its first tool call.
Values supplied through SYNCSTAFF_URL, SYNCSTAFF_PROJECT, SYNCSTAFF_TOKEN, or
SYNCSTAFF_VENDOR override the saved login when an explicit per-client setting is
needed.
WSL, remote hosts, containers, and worktrees
Run setup, the coding agent, and doctor in the same execution environment.
The environment that owns the agent process must have Node.js 22.5 or newer,
npm/npx, and Git on its PATH.
- For a repository inside WSL, open the editor or agent in its WSL/remote mode
and run setup from the Linux checkout. Do not launch the generated hooks from
Windows
cmd.exeagainst a\\wsl.localhost\...working directory:cmd.execannot use a UNC path as its current directory, and Windows-side Node/npm/Git installations are separate from the WSL toolchain. - For SSH remotes, dev containers, and hosted coding sandboxes, run setup inside that remote environment after the checkout is available. A credential or npm cache on the local host is not visible automatically inside the remote.
- Each Git worktree is a separate checkout and has its own ignored
.syncstaff/config.json. Run setup in every worktree an agent will edit; never copy the credential into source control.
If a hook reports that node, npm, or git is missing, install the missing
prerequisite in the agent's execution environment, reopen the checkout through
the matching remote mode, run npx -y [email protected] doctor, and then rerun
setup. Host sandbox network or filesystem denials must be resolved in the host
or workspace permissions before retrying; the adapter cannot override them.
Lifecycle hooks and diagnostics
setup also installs lease enforcement for each client. The hooks run
subcommands of this same package, so nothing else needs installing:
npx -y [email protected] hook register --vendor claude_code # SessionStart
npx -y [email protected] hook preflight --vendor claude_code # before each edit
npx -y [email protected] hook deregister --vendor claude_code # SessionEndpreflight blocks an edit to a file the agent holds no lease on. When
something isn't connecting, run:
npx -y [email protected] doctorIt checks Node, credentials, server reachability, the token, project visibility and agent registration in order, prints the command that fixes the first failure, and never prints the token.
When the pre-edit hook is installed, the agent must say which session it is
before using other Sync tools. The SessionStart hook prints the exact
sync_get(session_id="…") call to make; sync_whoami reports whether it is
still needed.
Version 0.2.3 and newer bind every agent registration to the coding client's
task/session id. If a client cannot expose that id automatically, call
sync_get(session_id="<the id shown by the client>") once at session start.
The adapter will not create an anonymous agent record, because an agent that
cannot be correlated cannot be represented reliably in Workforce.
The generated lifecycle hooks always pass an explicit vendor (codex,
claude_code, or gemini) so several clients can safely share the same
repository credential without sharing an agent identity. Re-run setup after
an adapter upgrade to reconcile all generated client entries.
Every HTTP request carries the adapter package version and an independent
protocol version. A server that knows the protocol is incompatible answers
with 426 and the protocol it supports, instead of letting a stale adapter
silently call a changed route. Headerless web and legacy clients remain valid
so the server and adapter can be deployed in either order.
Release verification
From sync/, run:
npm run test:mcp-packageThe smoke test builds only the package's TypeScript dependency graph, packs
the exact npm artifact, installs it into a new temporary directory, starts the
installed syncstaff-mcp executable through an MCP initialize exchange, and
then runs hook register, hook preflight, doctor and hook deregister
from the install against a stub server, after checking --help and
--version. It finishes with the installed token collector: one JSON and one
protobuf telemetry payload must each reach the stub exactly once, normalized
(protobuf decoding uses the protobufjs the install brought with it), and a
malformed payload of either kind must be refused with nothing forwarded.
When changing the release version, regenerate this README's install examples:
node scripts/smoke-mcp-package.mjs --update-readmeThe smoke test checks the source examples and the README inside the installed tarball against its package version, so stale installation pins fail release verification.
Measuring response compaction
The adapter compacts some tool responses (charter, intent declarations and
listings, lease grants, board reads and write receipts) before handing them to
the model. To see what that does to size on identical inputs, from sync/:
npm run build && node scripts/measure-mcp-compaction.mjsIt runs each compactor over a response captured from a real server
(docs/api-contract-v1.fixtures.json) and prints the UTF-8 JSON byte length
before and after, so two runs give the same numbers. It measures bytes only:
not model tokens, and not whole-session cost. On these small fixtures some
compactors come out slightly larger, because they add fixed framing that a tiny
response does not earn back; the reductions they exist for come from long
invariant rationales, quoted call-site reports and long board bodies. What
compaction must preserve (exact paths, value types, dependency identifiers,
timestamps, completed-item history, unknown blast-radius fields) is asserted in
test/mcp-compaction.test.ts, not by this script.
