Local Develop Server
FreeNot checkedUnified MCP server for the coding pipeline — consolidates git / recipe / sandbox tooling into one process with shared session state
About
Unified MCP server for the coding pipeline — consolidates git / recipe / sandbox tooling into one process with shared session state
README
Unified MCP server for AI-driven coding agents. Bundles git read/write,
just-based recipe execution, file-sandbox operations, and whole-project
archives into one process behind a shared
Session — so an agent opens a repository once with session_start and then
runs every tool against the same project root.
Install
cargo install --path crates/lds
{
"mcpServers": {
"lds": { "command": "lds", "args": [] }
}
}
Launched inside a directory containing .git or a justfile, the first tool
call starts a session on its own; session_start is only needed to switch to a
different root.
Tools
Session
| Tool | Description |
|---|---|
session_start |
Initialize session with project root |
Git (read)
| Tool | Description |
|---|---|
git_status |
Working tree status |
git_log |
Commit log (configurable max_count) |
git_diff |
Diff working tree vs HEAD |
Git (write)
worktree_add registers the worktree it creates in the session's
owned_worktrees set, and commit / merge / worktree_remove /
branch_delete refuse paths and branches that are not session-owned — one agent
cannot destroy another's work.
| Tool | Description |
|---|---|
git_commit |
Stage and commit changes in a session-owned working directory |
git_worktree_add |
Create a worktree on a new branch (session-owned). Placed under SessionConfig::worktrees_dir → env LDS_WORKTREES_DIR → <root>/.worktrees (default; the parent repo must gitignore this path) |
git_worktree_remove |
Remove a session-owned worktree |
git_worktree_list |
List worktrees with session-ownership annotation |
git_merge |
Merge a branch into another in a session-owned working directory |
git_branch_delete |
Delete a session-owned branch |
Gh (read)
GitHub CLI wrapper. Requires gh auth login; every invocation checks
gh auth status and returns a typed error if unauthenticated.
| Tool | Description |
|---|---|
gh_auth_status |
Check gh CLI authentication status |
gh_pr_list / gh_pr_view / gh_pr_diff / gh_pr_checks |
PRs as JSON; limit defaults to 30 |
gh_issue_list / gh_issue_view |
Issues as JSON |
gh_repo_view |
Repository metadata (name/owner/defaultBranchRef) |
gh_run_list / gh_run_view / gh_run_jobs |
Actions workflow runs as JSON |
gh_run_log_failed |
Failed-step logs, parsed into {failed_steps: [{job_name, step_name, log_tail}]} |
gh_release_list / gh_release_view |
Releases as JSON |
gh_workflow_list / gh_workflow_view |
Workflows as JSON |
Write operations are not exposed: gh pr create / gh issue create /
gh release create / gh pr merge are deliberately absent, as are
gh run cancel (a write op) and gh run watch (long-polling, incompatible with
MCP request-response — poll gh_run_view instead). Invoke those from a shell.
Recipe
| Tool | Description |
|---|---|
recipe_list |
List allow-agent recipes (with ResolveInfo source tracking) |
recipe_run |
Run recipe with args + content env vars, timeout + truncation |
Pack
| Tool | Description |
|---|---|
pack_create |
Pack a whole project (.git + untracked local state) into one archive. root defaults to the session root; dry_run classifies without writing |
pack_restore |
Restore a pack, rewriting worktree gitdir wiring for the new location — including worktrees beside the project, wired up once both packs are restored side by side. dry_run predicts without writing |
pack_inspect |
Read a pack's manifest without unpacking; files also lists every packed path |
Publicity
| Tool | Description |
|---|---|
publicity |
Classify the repository as PUBLIC / PRIVATE / INTERNAL / LOCAL / NOT_GIT / FORKED / AMBIGUOUS / UNKNOWN, one result per platform (github via gh repo view, crates via Cargo.toml publish). platform restricts to one; root (absolute path) classifies a directory other than the session root |
lds pack — moving a whole project
A pack carries a project as it exists on this machine: the .git directory
itself, plus the untracked local state that normally never leaves — a
workspace/ tree, journal databases, .mcp.json, sandbox snapshots. .git is
copied rather than bundled, because a bundle is built from an enumerated set of
refs and everything outside it (stashes, the reflog, local-only branches,
unreferenced objects) would not make the trip.
lds pack create # -> <project>-<timestamp>.pack, here
lds pack create --root ~/proj -o p.pack
lds pack create --dry-run # classify only; write nothing
lds pack inspect p.pack # manifest only; no decompression
lds pack restore p.pack --into ~/dest
lds pack restore p.pack --into ~/proj --dry-run # predict the restore
lds pack restore p.pack --into ~/proj --force # restore over a working copy
create --dry-run reports what would travel; restore --dry-run reports what
would happen at the destination — which files get replaced, which survive, which
symlinks land dangling, which worktree pointers get rewritten.
restore refuses an existing destination unless --force, and --force
overwrites without wiping: pack entries replace their counterparts, and files
already there that the pack does not carry are left alone. A restored backup can
therefore end up dirtier than the machine the pack came from.
What is not packed
| class | treatment |
|---|---|
secrets (.env, *.pem, id_rsa, …) |
not packed, reported — moving credentials stays yours to do |
caches (target/, node_modules/, …) |
not packed, recorded with the file count, size, and any credentials inside them |
OS debris (.DS_Store, Thumbs.db) |
not packed, recorded |
| symlinks | packed as links, never followed; recorded so a restore elsewhere names what dangles |
State outside the project root (~/.config/...) is not collected.
Nothing is dropped without a record: a path in your tree and not in the payload
can always be pointed at one of those lists. That matters most for caches, where
one line stands in for a whole subtree — a cache_dirs entry aimed at
hand-written source reads as dist (412 files, 2.1 MB) next to
target (38104 files, 4.2 GB).
Configuring the rules
[pack]
secret_globs = ["my-app-keys.json", "*.vault"] # also treat these as secrets
cache_dirs = ["frontend/dist"] # also treat these as caches
keep = ["docs/samples/*.pem"] # pack these despite a built-in rule
no_link_report = [".zsh/**"] # links here are expected; do not report them
Globs are scoped the way .gitignore scopes them: one with no / matches the
file name at any depth, one containing / is anchored to that path
relative to the project root. keep = ["*.pem"] carries every private key you
own; keep = ["docs/samples/*.pem"] carries the sample.
secret_globs and cache_dirs add to the built-ins rather than replacing them.
keep is the only subtractive list, and the only way a file the secret rules
named gets into the archive — whatever it rescues is named in the manifest's
kept_over_secret. A malformed glob is a hard error naming itself.
Every symlink is reported by default, because a link breaks when the project
lands elsewhere. no_link_report names the exception — a .zsh/ tree shared
across your machines, a vendored link tree — and its links are packed without
being listed. Rules that actually suppressed something come back in
no_link_report_applied, so an empty symlinks list is never ambiguous.
$ lds pack create --dry-run
dry run: /home/u/proj -> proj-20260811-004500.pack (nothing written)
would pack 2 files, 0 symlinks, 38 B
(with [pack] overrides from config.toml)
not packed — secrets (move these yourself):
.env (secret pattern: .env)
my-app-keys.json (secret pattern: my-app-keys.json)
not packed — caches (regenerable):
target (38104 files, 4.2 GB) (cache directory: target)
node_modules (21877 files, 412 MB) (cache directory: node_modules)
credential inside, dropped with it: node_modules/.npmrc
Worktrees
Both halves of a worktree's wiring — .git/worktrees/<name>/gitdir and the
worktree's own .git file — are absolute paths, so restore rewrites them; a
plain tar extract would leave both aimed at the source machine.
A worktree made with git worktree add ../name sits beside the project, so the
two halves belong to two projects and travel in two packs. Restore them beside
each other and whichever lands second wires the pair up:
lds pack create --root ~/projects/proj --out proj.pack
lds pack create --root ~/projects/proj-feature --out proj-feature.pack
lds pack restore proj.pack --into /backup/proj
# worktrees registered outside the project root, not found here: proj-feature
lds pack restore proj-feature.pack --into /backup/proj-feature
# rewrote worktree pointers: proj-feature
Order does not matter, and --force re-restoring one side repairs a pair left
half-attached. A counterpart that is genuinely not on this machine is reported
(missing_worktrees, or missing_worktree_parent when the pack is itself a
worktree) rather than guessed at.
Full field reference: the lds://docs/pack MCP resource.
Plugin recipes
Justfile recipes tagged [group('lds-plugin')] are registered as MCP tools at
startup. Drop a justfile at ~/.config/lds/justfile (global) or in your
project root, and each plugin recipe becomes mcp__lds__<name>.
cp examples/global-justfile.skeleton ~/.config/lds/justfile
# restart the MCP client so the server re-reads the global plugin set
The skeleton ships complexity / search-excluding / remote-url /
text-stats / greet.
Persistent global recipe directories go in ~/.config/lds/config.toml:
[recipes]
dirs = ["/opt/shared-recipes", "~/team-recipes"]
[paths]
global_justfile = "~/.config/lds/justfile"
lds recipe-dir add ~/team-recipes
lds recipe-dir list
lds recipe-dir remove ~/team-recipes
recipe-dir add expands ~ before writing, and preserves existing comments and
sections. config.toml is read once at startup, so changes need a restart.
Resolution priority (low → high): ~/.config/lds/justfile → config.toml
recipes.dirs → LDS_RECIPE_GLOBAL_DIRS → project justfile.
Claude Code mods
examples/mods/ holds Claude Code mods
that put lds's judgement in front of Claude's own tool calls. They need Claude
Code 2.1.287 or later and an lds server that /mcp lists as lds.
| Mod | What it does |
|---|---|
| lds-leak-guard | A tool.check hook on Bash. Before git push / gh ... create / cargo publish / npm publish / docker push and other remote writes it asks publicity: deny on a PUBLIC repository, ask otherwise. Bash git commit / merge / worktree / branch -d are denied with a pointer to mcp__lds__git_*, so the session ownership guard cannot be bypassed from the shell |
| lds-ops-pane | /lds opens a pane with the session root, per-platform publicity (PUBLIC in red), and worktrees with ownership; a one-line band above the prompt repeats the publicity |
claude --plugin-dir examples/mods/lds-leak-guard # one session
claude plugin validate examples/mods/lds-leak-guard
claude plugin test examples/mods/lds-leak-guard
Or install from this repository's marketplace, inside a session:
/plugin install lds-leak-guard --marketplace ynishi/local-develop-server
Further reading
| Document | Contents |
|---|---|
| docs/recipes.md | Full recipe contract, LDS_RECIPE_GLOBAL_DIRS, import |
| docs/plugin-recipe-authoring.md | Writing plugin recipes: IF contract, parameter mapping, pitfalls |
| docs/architecture.md | Internal layout, session model, resolve chain |
lds://docs/pack |
Pack field reference (MCP resource) |
lds://docs/multi-session, lds://docs/routing |
Session and routing guides (MCP resources) |
| examples/mods/ | Claude Code mods built on lds (lds-leak-guard, lds-ops-pane) |
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Installing Local Develop Server
This server has no published package — it is built from source. Open the repository and follow its README.
▸ github.com/ynishi/local-develop-serverFAQ
Is Local Develop Server MCP free?
Yes, Local Develop Server MCP is free — one-click install via Unyly at no cost.
Does Local Develop Server need an API key?
No, Local Develop Server runs without API keys or environment variables.
Is Local Develop Server hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Local Develop Server in Claude Desktop, Claude Code or Cursor?
Open Local Develop Server on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
GitHub
PRs, issues, code search, CI status
by GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Unyly Deploy
Deploy sites and MCP servers to Unyly straight from your AI agent
by UnylyAmap Maps Mcp Server
MCP server for using the AMap Maps API
by duxiaohuiPayMCP
Lightweight payments layer for MCP servers: turn tools into paid endpoints with a two-line decorator. [PyPI](https://pypi.org/project/paymcp/) · [npm](https://w
by blustAIServer For Power BI
Enables exploring Microsoft Fabric / Power BI workspaces and semantic models, and executing ad-hoc DAX queries.
by Mitsubishi-FusoTemplate MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
by mcpdotdirectSupabase
Database, auth and storage
by SupabaseEverything
Reference / test server with prompts, resources, and tools.
Compare Local Develop Server with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All development MCPs
