Skip to main content
Glama

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.12

Related 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 mcp

Register 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.py

If 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/exclude

Edit .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 = 600

Key

Where

Effect

name

target

Label used in results. Required

path_prefix

target

Repo-relative directory this target owns. Omit to own every path

cwd

target

Repo-relative directory the commands run from. Default is the repo root

lint

top level or target

Command for run_lint

test

top level or target

Command for run_tests. A scoped path is appended to it

timeout_seconds

top level or target

Per-command timeout. Default 60. Target value overrides top level

max_output_chars

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 whose path_prefix owns 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 cwd before it is appended, and dropped entirely when it is the cwd itself. This matters for workspace scripts: yarn workspace backend test runs Vitest inside apps/backend, so a repo-relative path would be doubled. Set cwd to the workspace and call the script directly, as in the example above.

  • run_tests() with no path runs every target that has a test command and returns a summary line followed by a section per target.

  • run_lint() runs every target that has a lint command, 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:

  1. SAFE_DEV_REPO_ROOT environment variable, for manual testing.

  2. CLAUDE_PROJECT_DIR, which Claude Code sets for every MCP server it launches. User-scope servers run with ~/.claude as their working directory, so this is what makes a global registration work per repo.

  3. Walk up from the current working directory until a directory containing .git or .safe-dev.toml is found.

  4. 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.py

The 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.py

A 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 tools
git_diffA

Show unstaged changes (read-only), optionally scoped to one file.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
max_countNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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).

ParametersJSON Schema
NameRequiredDescriptionDefault
refYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines2/5

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.

  1. 4 tool updatesv0.1.0
    • First observedgit_diff
    • First observedgit_log
    • First observedgit_show
    • First observedgit_status

TDQS

A4.3/5.0

Scored across 4 tools

Disambiguation5/5

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.

Naming Consistency5/5

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.

Tool Count5/5

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.

Completeness4/5

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

ActivityMaintained
ResponsivenessNo issues

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

Related MCP Servers

  • A
    license
    A
    quality
    F
    maintenance
    Enables 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.
    6
    Apache 2.0
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables 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.
    3
    MIT

Latest Blog Posts

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