safe-dev-tools
This server gives an editor LLM a fixed, safe set of development tools: linting, testing, and read-only Git inspection.
git_status– show working tree status (read-only)git_diff– show unstaged changes, optionally scoped to one filegit_log– show recent commit history (max_count capped at 50)git_show– show a specific commit's diff by hash/refrun_lint– run lint commands defined in.safe-dev.tomlrun_tests– run test commands defined in.safe-dev.toml, with path-aware target routing
Provides read-only Git repository inspection tools for showing working tree status, unstaged changes (optionally scoped to a file), recent commit history, and a specific commit's diff.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@safe-dev-tools run the linter and tests, then show git status"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
safe-dev-mcp
A minimal MCP server that gives an editor LLM a fixed set of abilities:
lint, test, git status, git diff, git log, git show.
Requirements
Python 3.11 or newer (the config parser is the standard library tomllib).
On macOS the built-in python3 is 3.9, which is too old for both this server
and the mcp package. If pip install mcp reports "No matching distribution
found", that is the cause. Install a current Python with Homebrew:
brew install python@3.12Related MCP server: MCP ToolHub
One-time setup
Create a virtualenv inside this clone from the newer interpreter and install the MCP SDK:
cd /path/to/safe-dev-mcp
/opt/homebrew/bin/python3.12 -m venv .venv
.venv/bin/pip install mcpRegister the server once at Claude Code user scope. The Claude agent in Zed is Claude Code running over the Agent Client Protocol, so it reads this config:
claude mcp add --scope user safe-dev-tools -- \
/path/to/safe-dev-mcp/.venv/bin/python \
/path/to/safe-dev-mcp/server.pyIf you prefer to configure it in Zed itself, add the same command to
~/.config/zed/settings.json. Zed forwards these to external agents:
{
"context_servers": {
"safe-dev-tools": {
"command": "/path/to/safe-dev-mcp/.venv/bin/python",
"args": ["/path/to/safe-dev-mcp/server.py"]
}
}
}Then, in the agent's permissions, allow this server's tools and leave general terminal access denied.
Per-repo configuration
In each repo where you want lint or test tools:
cp /path/to/safe-dev-mcp/safe-dev.example.toml .safe-dev.toml
echo .safe-dev.toml >> .git/info/excludeEdit .safe-dev.toml for that repo. Commands are grouped into targets. A
target is a part of the repo with its own lint and test commands. Every key
is optional, and a tool is only offered when at least one target defines it.
Single-surface repos
Top-level lint and test define one target that owns every path:
lint = ["ruff", "check", "."]
test = ["pytest", "-q"]Monorepos
Use one [[targets]] table per surface instead:
[[targets]]
name = "frontend"
path_prefix = "apps/frontend"
cwd = "apps/frontend"
lint = ["yarn", "lint"]
test = ["yarn", "test"]
[[targets]]
name = "backend"
path_prefix = "apps/backend"
cwd = "apps/backend"
test = ["yarn", "test"]
[[targets]]
name = "e2e"
path_prefix = "e2e"
test = ["yarn", "test:e2e"]
timeout_seconds = 600Key | Where | Effect |
| target | Label used in results. Required |
| target | Repo-relative directory this target owns. Omit to own every path |
| target | Repo-relative directory the commands run from. Default is the repo root |
| top level or target | Command for |
| top level or target | Command for |
| top level or target | Per-command timeout. Default 60. Target value overrides top level |
| top level or target | Output truncation limit. Default 20000. Target value overrides top level |
Top-level keys must appear before the first [[targets]] table, which is a
TOML rule.
How the tools behave with targets:
run_tests(path)runs only the target whosepath_prefixowns that path. When several match, the longest prefix wins. If none match, the tool returns an error naming the configured targets rather than guessing.The scoped path is rewritten relative to the target's
cwdbefore it is appended, and dropped entirely when it is thecwditself. This matters for workspace scripts:yarn workspace backend testruns Vitest insideapps/backend, so a repo-relative path would be doubled. Setcwdto the workspace and call the script directly, as in the example above.run_tests()with no path runs every target that has atestcommand and returns a summary line followed by a section per target.run_lint()runs every target that has alintcommand, skips the rest, and reports per target the same way.The tool descriptions shown to the model list the target names and prefixes, so it knows which paths route where.
Repos that only need the read-only git tools need no config file at all.
Git worktrees
Because .safe-dev.toml is excluded from git, a linked worktree created with
git worktree add does not get a copy. When the server starts in a worktree
that has no config of its own, it follows the worktree's .git pointer back
to the main worktree and reads the config there. path_prefix and cwd
still resolve against the worktree you are in, so commands run on that
worktree's files. Put a .safe-dev.toml inside a worktree to override the
shared one for that worktree only.
The tool list is fixed when the server starts, so restart the agent thread after editing the config.
How the server finds the repo
First match wins:
SAFE_DEV_REPO_ROOTenvironment variable, for manual testing.CLAUDE_PROJECT_DIR, which Claude Code sets for every MCP server it launches. User-scope servers run with~/.claudeas their working directory, so this is what makes a global registration work per repo.Walk up from the current working directory until a directory containing
.gitor.safe-dev.tomlis found.The current working directory.
Testing it standalone
The MCP Inspector lets you see the tool list and call tools by hand. Launch it from inside the repo you want to test so the server resolves that repo as its root:
cd /path/to/some/repo
npx @modelcontextprotocol/inspector \
/path/to/safe-dev-mcp/.venv/bin/python \
/path/to/safe-dev-mcp/server.pyThe SDK's mcp dev shortcut is not used here because it always launches the
server through uv, which fails if uv is not installed.
Troubleshooting
On startup the server writes two lines to stderr: the repo root it resolved and the tools it registered. Run it directly from inside a repo to see them, then press Ctrl-C:
cd /path/to/some/repo
/path/to/safe-dev-mcp/.venv/bin/python /path/to/safe-dev-mcp/server.pyA malformed lint or test value (for example a plain string instead of a
list) is reported on stderr and that tool is left out. The server still
starts.
Extending it
To add another safe capability (git blame, a formatter check, a type
checker), add a plain function following the same pattern and register it in
_register_tools, conditionally if it depends on config. Fixed command list,
validated and bounded parameters, no shell string concatenation. Resist the
temptation to add a generic "run this git subcommand" tool. Enumerate the ones
you actually want.
Available Tools
4 toolsgit_diffA
Show unstaged changes (read-only), optionally scoped to one file.
Inputs: path. Returns: result
git_logA
Show recent commit history (read-only). max_count is capped at 50.
Inputs: max_count. Returns: result
git_showA
Show a specific commit's diff by hash/ref (read-only).
Inputs: ref (required). Returns: result
git_statusA
Show the working tree status (read-only).
Inputs: no named parameters. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 4 tools
Each tool targets a distinct git inspection operation: working tree status (git_status), unstaged content changes (git_diff), commit history (git_log), and a single commit's changes (git_show). While git_diff and git_show both display diffs, their inputs and purposes are clearly different. No ambiguity exists within this small set.
All tool names follow the exact pattern of git_<command>, mirroring native git subcommands (status, diff, log, show). The naming is uniform and predictable, making it trivial for an agent to infer usage.
Four tools is a focused, well-scoped set for the stated purpose of safe, read-only git inspection. Each tool earns its place without redundancy or bloat, and the count falls comfortably within the ideal range.
The set covers the core read-only git workflows: checking status, reviewing working-tree changes, browsing history, and inspecting specific commits. Minor gaps include no direct way to view staged changes (git diff --cached) or list branches, but these can be worked around and do not cripple the domain.
Maintenance
Related MCP Connectors
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Autonomous agent guardrails, bash sandboxing, MCP rugpull diffing & prompt firewalls.
The trust harness for AI agents. Set what an agent can do before it acts.
Run AI agent tasks in isolated sandboxes with a cost cap, saved workflows and scoped connections.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides safe shell command execution capabilities for AI agents and tools like VS Code Copilot through a whitelist-based filtering system.-
- FlicenseAqualityBmaintenanceEnables coding agents to perform workspace-confined file operations, read-only Git inspection, and structured shell commands, while requiring out-of-band human approval for mutations and external executions and maintaining an audit trail.143-
- AlicenseAqualityBmaintenanceEnables coding agents to safely inspect and modify project files within explicitly allowed workspace roots, with controls for file operations, git status/diff, and optionally allowlisted command execution.11Apache 2.0
- AlicenseNot gradedqualityBmaintenanceEnables MCP-compatible agents to execute bash and subprocess commands through a zero-dependency sandbox guard that blocks destructive system mutations, path traversals, reverse shells, and other unsafe execution patterns.7MIT