safe-dev-tools
Click on "Install 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-toolsrun 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: Host Terminal MCP
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It does state 'read-only', which is a key behavioral trait, but does not disclose other aspects like exit codes, empty-output behavior, or performance characteristics. For a simple read-only tool this is acceptable but not rich.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with no filler. It efficiently conveys the core action and optional scope, earning its place without waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with one optional parameter and an existing output schema, the description covers the essential purpose and scoping. It omits explicit sibling differentiation, but given the tool's simplicity, the information provided is sufficient for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must explain the 'path' parameter. It says 'optionally scoped to one file', which clarifies that the path is a file path and optional. This adds meaningful semantics beyond the bare schema definition.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool shows unstaged changes, uses a specific verb ('show') and resource ('unstaged changes'), and mentions optional file scoping. It distinguishes itself from sibling tools like git_status (which shows repository status) and git_log (history), making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use it (to see unstaged changes) but does not explicitly contrast it with siblings or state when not to use it. There is no mention of alternatives, so an agent must infer usage from context. This is adequate but not explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
git_logA
Show recent commit history (read-only). max_count is capped at 50.
| Name | Required | Description | Default |
|---|---|---|---|
| max_count | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations present, the description carries the full burden. It explicitly states the tool is read-only and that max_count is capped at 50, which are useful behavioral constraints. It does not mention ordering or required repository state, but those are minor for a simple log tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the tool's core purpose and safety trait, followed by a parameter constraint. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers purpose, safety, and the key limit, and an output schema exists to explain return values. It lacks explicit selection guidance versus siblings, but for a simple read-only log tool this is sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema has only a type and title for max_count, and coverage is 0% in the description. The description adds a concrete constraint (capped at 50) and the parameter name is self-explanatory about limiting the number of commits. It could state that it controls how many commits are returned, but the cap is a useful addition.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly says 'Show recent commit history,' which clearly identifies the tool's function. It distinguishes itself from sibling tools like git_status and git_diff by naming the resource (commit history). The read-only qualifier adds further precision.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage (showing recent commits) but provides no explicit guidance on when to choose this tool over git_status, git_diff, or git_show. No exclusions or alternative references are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
git_showA
Show a specific commit's diff by hash/ref (read-only).
| Name | Required | Description | Default |
|---|---|---|---|
| ref | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden. It explicitly states 'read-only', which is the key behavioral trait for a show commandiscovers potential side effects or mutation. The output schema covers return format, so no need to describe that here.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One sentence, zero filler, front-loaded with the core behavior. The read-only qualifier is parenthetical but doesn't waste space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple single-command tool, the description covers what the tool does, the parameter format, and reads as read-only. The presence of an output schema means return-value details are already structured elsewhere. Minor gap: no mention of git_diff use case distinction, but not required for calling the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate for the lone 'ref' parameter. It does so by specifying that the value is a hash or ref identifying a commit, which is meaningful beyond the bare schema type 'string'.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Show'), resource ('a specific commit's diff'), and method ('by hash/ref'), with a clear read-only scope. This distinguishes it from git_status and git_log, and the 'specific commit' qualifier separates it from a generic git_diff.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use it (you have a commit hash/ref and want its diff), but it does not explicitly contrast with siblings like git_diff or git_log, nor state exclusions. The context is clear but leaves selection among similar tools to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
git_statusA
Show the working tree status (read-only).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of safety disclosure. The explicit 'read-only' parenthetical covers the only meaningful behavioral trait for a zero-parameter status command. There are no auth, rate-limit, or destruction concerns to disclose.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a short, front-loaded sentence with no filler or redundant wording. Every word adds semantic value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a parameterless read-only command backed by an output schema, the description is nearly complete. It could explicitly situate itself relative to the sibling tools, but nothing needed for a correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the schema is already complete and there is nothing for the description to add. The baseline of 4 for parameterless tools applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb ('Show') and a specific resource ('working tree status'), making the tool's target unmistakable. The parenthetical 'read-only' reinforces the nature of the operation. It is clearly distinct from the sibling git tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance about when to use git_status versus git_diff, git_log, or git_show. The only context is implicit in the resource name, and no decision criteria or exclusions are provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
4 tool updates
v0.1.0- First observed
git_diff - First observed
git_log - First observed
git_show - First observed
git_status
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
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
The trust harness for AI agents. Set what an agent can do before it acts.
Run verified read-only code tools: quant diagnostics + agent-ops preflight, no source exposure.
Fail-closed policy guardrails for AI agents running kubectl, terraform, helm, and argocd.
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.-
- AlicenseAqualityFmaintenanceEnables AI assistants to execute terminal commands on a host machine with configurable, granular permission controls and safety protections. It features multiple security modes, including allowlists and manual approval, to ensure safe command execution within specified directories.6Apache 2.0
- FlicenseNot gradedqualityDmaintenanceEnables AI models to safely execute pre-defined Linux shell commands with a whitelist mechanism, restricting execution to allowed commands only.1-
- AlicenseNot gradedqualityAmaintenanceEnables 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.3MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Neighborkid01/safe-dev-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server