Skip to main content
Glama

mcp-dev-tools

An MCP (Model Context Protocol) server I built to expose everyday dev commands — git status, recent commits, running tests, running the linter — as tools an AI coding assistant (Claude Code, Claude Desktop, or any other MCP-compatible client) can call directly against a real repository.

Why I built this

I wanted to actually understand how MCP servers work end to end — the handshake, the transport, tool schemas — rather than just wiring one up from a template. So this was built from an empty folder, one piece at a time, verifying each step before adding the next.

How I built it

  1. Scaffolded the projectnpm init, TypeScript config for Node ESM (NodeNext module/resolution), installed @modelcontextprotocol/sdk and zod.

  2. Wrote the smallest possible server — an McpServer instance, a single dummy ping tool, connected over a stdio transport.

  3. Verified it with the MCP Inspector before writing anything real — spawned the server as a subprocess, confirmed the initialize handshake completed and tools/list/tools/call worked, using the raw protocol traffic rather than assuming it worked.

  4. Added the real tools one at a time (git_status, recent_commits, run_tests, run_linter), re-testing after each addition rather than batching changes.

  5. Made the target repo configurable — moved from hardcoding process.cwd() to reading a CLI argument, so the server can run against any project, not just itself.

  6. Hit and fixed a real platform bug along the way — see below.

A real bug this surfaced

run_tests and run_linter initially failed on Windows with a cryptic spawn EINVAL. Cause: Node deliberately blocks execFile/spawn from directly invoking .cmd/.bat files (like npm.cmd) without shell: true — a security fix (CVE-2024-27980) to stop unsafe argument injection into batch files. The git calls were unaffected since git.exe is a real executable, not a shell shim. Fixed by scoping shell: true to just the two npm calls, where the arguments are fixed literals rather than dynamic input, so the shell-parsing risk the restriction exists to prevent doesn't actually apply here.

Tools

Tool

Description

Arguments

ping

Echoes a message back; used to verify the server is wired up

message: string

git_status

Working tree status (staged / unstaged / untracked) of the target repo

recent_commits

Recent commit history on the current branch

count?: number (default 10, max 50)

run_tests

Runs npm test in the target repo and returns output, including failures

run_linter

Runs npm run lint in the target repo and returns output, including lint errors

How it works

  • Transport: stdio — the client spawns this process and communicates over stdin/stdout using JSON-RPC 2.0. stdout is reserved exclusively for protocol traffic; all logging goes to stderr (console.error), otherwise it would corrupt the stream.

  • Tool execution: each tool shells out to a real command (git, npm) via Node's child_process.execFile, using an argument array rather than a single shell string — this avoids shell injection entirely for the git-based tools.

  • Error handling: a failing command (e.g. failing tests, a missing lint script) is not treated as a protocol error. It's caught and returned as a normal tool result with isError: true and the real command output attached, so the calling model can see what went wrong rather than getting an opaque failure.

  • Target repo: a single REPO_DIR constant, resolved once at startup from a CLI argument (falling back to the current working directory), is threaded through every tool — so the server can be pointed at any project without code changes.

How to use it yourself

Prerequisites: Node.js 20+ and npm.

git clone <this-repo-url>
cd mcp-dev-tools
npm install

Run directly against the source with tsx (no build step needed):

npm run dev -- C:\path\to\some\other\repo

Or compile and run the built output:

npm run build
npm start -- C:\path\to\some\other\repo

If no path is given, it defaults to the directory the server is launched from.

Wiring it into an MCP client (Claude Code / Claude Desktop)

Add an entry to the client's MCP server config, pointing args at the built server and the repo you want it to operate on:

{
  "mcpServers": {
    "dev-tools": {
      "command": "node",
      "args": [
        "C:\\path\\to\\mcp-dev-tools\\build\\index.js",
        "C:\\path\\to\\the\\project\\you\\want\\to\\work\\on"
      ]
    }
  }
}

Debugging with the MCP Inspector

npx @modelcontextprotocol/inspector npx tsx src/index.ts C:\path\to\some\other\repo

Opens a browser UI showing the live tool list and lets you call each tool manually while watching the raw JSON-RPC exchange.

Tech stack

  • TypeScript, compiled with tsc to ES2022/NodeNext modules

  • @modelcontextprotocol/sdk — official MCP server implementation

  • zod — runtime validation for tool input schemas

  • tsx for zero-build local development

Project structure

mcp-dev-tools/
├── src/
│   └── index.ts      # server setup + all tool definitions
├── tsconfig.json
├── package.json
└── README.md

License

ISC

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/rishitudikeri3-rgb/mcp-dev-tools'

If you have feedback or need assistance with the MCP directory API, please join our Discord server