Combo: Full Developer Tools Suite
A multi-tool MCP server combining file operations, shell commands, git integration, and environment inspection. The complete developer productivity package.
title: "Combo: Full Developer Tools Suite" description: "A multi-tool MCP server combining file operations, shell commands, git integration, and environment inspection. The complete developer productivity package." order: 7 category: "combo" level: "intermediate" duration: "40 min" date: "2026-04-01" tags:
- tools
- resources
- prompts
- devtools keywords:
- mcp developer tools
- mcp-framework multi-tool
- developer productivity mcp
- mcp file operations
What You Get
The full combo meal. This server bundles multiple developer-focused tools into a single MCP server: file operations, shell command execution, git helpers, and system environment inspection. It also demonstrates MCP prompts for guided workflows.
Tools included:
read_file— read a file with optional line rangewrite_file— write or append content to a filerun_command— execute a shell command and return outputgit_status— get the git status of a directorygit_diff— get the git diff for staged or unstaged changes
Resources included:
env://info— system environment info (OS, Node version, cwd)
Prompts included:
code_review— guided code review prompt template
Quick Start
npx mcp-framework create devtools-server
cd devtools-server
File Operations
Create src/tools/ReadFileTool.ts:
import { MCPTool } from "mcp-framework";
import { z } from "zod";
import fs from "fs/promises";
const ReadFileInput = z.object({
path: z.string().describe("Absolute file path"),
startLine: z.number().optional().describe("Start reading from this line"),
endLine: z.number().optional().describe("Stop reading at this line"),
});
class ReadFileTool extends MCPTool<typeof ReadFileInput> {
name = "read_file";
description = "Read a file, optionally specifying a line range";
schema = { input: ReadFileInput };
async execute(input: z.infer<typeof ReadFileInput>) {
const content = await fs.readFile(input.path, "utf-8");
const lines = content.split("\n");
const start = (input.startLine ?? 1) - 1;
const end = input.endLine ?? lines.length;
const selectedLines = lines.slice(start, end);
return {
path: input.path,
totalLines: lines.length,
range: { start: start + 1, end },
content: selectedLines.join("\n"),
};
}
}
export default ReadFileTool;
Shell Commands
Create src/tools/RunCommandTool.ts:
import { MCPTool } from "mcp-framework";
import { z } from "zod";
import { exec } from "child_process";
import { promisify } from "util";
const execAsync = promisify(exec);
const CommandInput = z.object({
command: z.string().describe("Shell command to execute"),
cwd: z.string().optional().describe("Working directory"),
timeout: z.number().default(10000).describe("Timeout in milliseconds"),
});
class RunCommandTool extends MCPTool<typeof CommandInput> {
name = "run_command";
description = "Execute a shell command and return its output";
schema = { input: CommandInput };
async execute(input: z.infer<typeof CommandInput>) {
try {
const { stdout, stderr } = await execAsync(input.command, {
cwd: input.cwd || process.cwd(),
timeout: input.timeout,
maxBuffer: 1024 * 1024, // 1MB
});
return {
exitCode: 0,
stdout: stdout.trim(),
stderr: stderr.trim(),
};
} catch (error: unknown) {
const execError = error as {
code?: number;
stdout?: string;
stderr?: string;
message: string;
};
return {
exitCode: execError.code ?? 1,
stdout: execError.stdout?.trim() || "",
stderr: execError.stderr?.trim() || execError.message,
};
}
}
}
export default RunCommandTool;
Git Integration
Create src/tools/GitStatusTool.ts:
import { MCPTool } from "mcp-framework";
import { z } from "zod";
import { exec } from "child_process";
import { promisify } from "util";
const execAsync = promisify(exec);
const GitStatusInput = z.object({
path: z.string().default(".").describe("Repository path"),
});
class GitStatusTool extends MCPTool<typeof GitStatusInput> {
name = "git_status";
description = "Get the git status of a repository";
schema = { input: GitStatusInput };
async execute(input: z.infer<typeof GitStatusInput>) {
const { stdout: status } = await execAsync("git status --porcelain", {
cwd: input.path,
});
const { stdout: branch } = await execAsync(
"git branch --show-current",
{ cwd: input.path }
);
return {
branch: branch.trim(),
changes: status
.trim()
.split("\n")
.filter(Boolean)
.map((line) => ({
status: line.substring(0, 2).trim(),
file: line.substring(3),
})),
};
}
}
export default GitStatusTool;
The Code Review Prompt
Create src/prompts/CodeReviewPrompt.ts:
import { MCPPrompt } from "mcp-framework";
import { z } from "zod";
const CodeReviewArgs = z.object({
language: z.string().default("TypeScript"),
focus: z
.enum(["security", "performance", "readability", "all"])
.default("all"),
});
class CodeReviewPrompt extends MCPPrompt<typeof CodeReviewArgs> {
name = "code_review";
description = "Guided code review prompt";
schema = { args: CodeReviewArgs };
async buildMessages(args: z.infer<typeof CodeReviewArgs>) {
return [
{
role: "user" as const,
content: {
type: "text" as const,
text: `Please review the following ${args.language} code with a focus on ${args.focus}. Check for:
- Potential bugs and edge cases
- ${args.focus === "security" || args.focus === "all" ? "Security vulnerabilities\n- " : ""}${args.focus === "performance" || args.focus === "all" ? "Performance issues\n- " : ""}Code style and readability
- Suggestions for improvement
I will provide the code in my next message.`,
},
},
];
}
}
export default CodeReviewPrompt;
Build & Connect
npm run build
{
"mcpServers": {
"devtools": {
"command": "node",
"args": ["./dist/index.js"]
}
}
}
What You Learn
- Building multi-tool MCP servers
- Using all three MCP primitives: tools, resources, and prompts
- Safe shell command execution with timeouts
- File system operations with line-range support
- Git integration patterns
- Prompt templates for guided AI workflows
Next Up
Learn to ship your server with the Docker-Ready Template, or explore individual concepts deeper with the Weather API and Database entrees.
Built with mcp-framework (3.3M+ downloads) by @QuantGeekDev. Validated by Anthropic.