intermediate40 mincombo

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 range
  • write_file — write or append content to a file
  • run_command — execute a shell command and return output
  • git_status — get the git status of a directory
  • git_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.