Skip to main content
Glama
ccollicutt
by ccollicutt

MCP Makefile Server

TIP

Use this MCP server to easily expose Makefile targets as MCP tools. Let AI agents execute your Makefile targets through the Model Context Protocol.

Table of Contents

What is the Value of mcp-makefile-server?

Value

What you get (benefit)

Why it matters in practice

Turn your workflow into tools instantly

Anything you can run from a Makefile: scripts, CLIs, one-liners, pipelines, etc. become a first-class MCP tool

You stop “rewriting tooling” for every assistant/client and just expose what already works

Tooling without building a tool platform

An MCP server that “just works” off your existing Make targets

You avoid bespoke MCP coding, schemas, and glue logic because your Makefile is the integration layer

No need to remind the coding tool about the Makefile

The coding tool doesn't need to know about the Makefile, it finds out what tools it has automatically via MCP.

You can simply add new targets to the Makefile and the coding tool will automatically know about them.

Self-service automation

Your assistant can add/adjust targets as needs evolve (you review + merge like normal code)

Tooling grows at the speed of your project

One source of truth for “how we do things”

The Makefile becomes the canonical catalog of project actions (build, test, lint, release, migrate, etc.)

No drift between docs, tribal knowledge, CI steps, etc.

Safer execution by design

You expose only what you want (allowlists, internal/skip markers) and keep dangerous stuff hidden

Only give the coding tool access to what it needs to do its job

Better guidance at the point of use

## comments become the tool’s instructions: options, inputs, side effects, outputs

The “how to use it” travels with the command, so it stays accurate as the target evolves

Composable building blocks

Targets can depend on other targets (e.g., build: test lint) and form reliable workflows

You get a clean, modular automation graph

Tooling portability

Makefiles work almost everywhere; you’re not locked into a specific agent ecosystem

Your automation survives client churn. New assistant? Same Make targets

Features

Feature

Description

Automatic Tool Discovery

Parses Makefile and exposes documented targets as MCP tools

Target Filtering

Use allowlists to control which targets are exposed

Progress Notifications

MCP clients receive start/completion status updates for long-running targets

Category Support

Organize targets with ## Category: headers

Internal Targets

Mark targets with @internal or @skip to exclude them

Async Execution

Non-blocking target execution with timeout support

Output Management

Optional truncation, file output with organized subdirectories, customizable temp location

Configurable Timeouts

Set custom timeout per target execution (default: 300s)

TL;DR - Simplest Setup

In your project directory with a Makefile:

# Install uv (if needed)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Add MCP server to your project
claude mcp add-json --scope project makefile-server '{
  "type": "stdio",
  "command": "uvx",
  "args": [
    "--from",
    "git+https://github.com/ccollicutt/mcp-makefile-server",
    "mcp-makefile-server",
    "./Makefile"
  ]
}'

# Restart Claude Code

Done! Your Makefile targets with ## comments are now available as tools.


Usage Patterns

Project-Scoped vs Global Configuration

Recommended: Project-Scoped

The best way to use this MCP server is to point it at your current project's Makefile using --scope project. This approach:

  • Gives Claude Code access to project-specific targets

  • Keeps each project's automation isolated and relevant

  • Allows different projects to have different Makefile targets

Alternative: Global Configuration

You can use --scope global to make the server available across all projects. This is useful if you have:

  • A shared utilities Makefile with common tasks

  • Cross-project tooling that you want available everywhere

Both Configurations

You can configure both a global instance and project-specific instances:

  • Global instance: Points to a shared utilities Makefile (~/makefiles/common.mk)

  • Project instances: Each project points to its own ./Makefile

Each instance can point to a different Makefile and expose different targets. The global instance provides shared tools, while project instances provide project-specific automation.


Quick Start

Prerequisites

Install uv (if you don't have it):

curl -LsSf https://astral.sh/uv/install.sh | sh

This gives you both uv and uvx commands.


No cloning needed! uvx runs directly from GitHub:

# Test it works - preview your Makefile targets
uvx --from git+https://github.com/ccollicutt/mcp-makefile-server mcp-makefile-server preview ./Makefile

What this does:

  • Downloads and caches the server from GitHub

  • Runs the preview command on your ./Makefile

  • Shows what tools would be exposed

Example output:

Found 3 targets in ./Makefile:
  • test - Run test suite
  • build - Build package
  • deploy - Deploy to production

That's it! Now skip to Claude Code Setup below.


Installation Method 2: Local Installation

Use this if you need to modify the code.

Step 1: Clone and install

git clone https://github.com/ccollicutt/mcp-makefile-server.git
cd mcp-makefile-server
uv pip install .

Step 2: Test it works

# Preview your Makefile targets
uv run python -m mcp_makefile preview /path/to/your/Makefile

# Or just list tool names
uv run python -m mcp_makefile list /path/to/your/Makefile

For Development: See DEVELOP.md for development setup instructions.

Claude Code Setup

Configure the MCP server for your project:

If you used Method 1 (uvx):

cd ~/projects/my-app

claude mcp add-json --scope project makefile-server '{
  "type": "stdio",
  "command": "uvx",
  "args": [
    "--from",
    "git+https://github.com/ccollicutt/mcp-makefile-server",
    "mcp-makefile-server",
    "./Makefile"
  ]
}'

If you used Method 2 (local installation):

cd ~/projects/my-app

claude mcp add-json --scope project makefile-server '{
  "type": "stdio",
  "command": "uv",
  "args": [
    "--directory",
    "/path/to/mcp-makefile-server",
    "run",
    "python",
    "-m",
    "mcp_makefile",
    "./Makefile"
  ]
}'

What this does:

  • Creates .mcp.json in your project root (project-scoped)

  • Configures Claude Code to use your Makefile targets as tools when working in this project

For global setup (available in all projects):

Replace --scope project with --scope global in the commands above. This creates a global MCP configuration, though project-scoped is recommended since each project typically has its own Makefile with project-specific targets.

You can configure both: A global instance for shared utilities and project-specific instances for each project's Makefile.

Next step: Restart Claude Code to load the server.

Advanced Configuration

Allowed Targets Filter

Restrict which targets can be executed:

Using uvx:

claude mcp add-json --scope project makefile-server '{
  "type": "stdio",
  "command": "uvx",
  "args": [
    "--from",
    "git+https://github.com/ccollicutt/mcp-makefile-server",
    "mcp-makefile-server",
    "./Makefile",
    "--allowed-targets",
    "test",
    "build",
    "lint"
  ]
}'

Using local installation:

claude mcp add-json --scope project makefile-server '{
  "type": "stdio",
  "command": "uv",
  "args": [
    "--directory",
    "/path/to/mcp-makefile-server",
    "run",
    "python",
    "-m",
    "mcp_makefile",
    "./Makefile",
    "--allowed-targets",
    "test",
    "build",
    "lint"
  ]
}'

Defaults

The server works out of the box with sensible defaults:

Setting

Default Value

What it means

Output Length

Unlimited (0)

All output is returned without truncation

File Output

Disabled

Output is not written to files (only returned in response)

Temp Directory

/tmp

Where temporary files are created (if file output is enabled)

Timeout

300 seconds

Maximum execution time per target

Allowed Targets

All non-internal

All targets with ## comments are exposed (except @internal/@skip)

Log Level

INFO

Standard logging verbosity

In other words: The server returns all output directly to the client with no truncation or file writing, executes any documented target, and times out after 5 minutes.

Environment Variables

The server can also be configured via environment variables:

Environment Variable

Description

Default

MCP_MAKEFILE_PATH

Path to Makefile

./Makefile

MCP_MAKEFILE_LOG_LEVEL

Logging level (DEBUG, INFO, WARNING, ERROR)

INFO

MCP_MAKEFILE_ALLOWED_TARGETS

Comma-separated list of allowed targets

All non-internal targets

MCP_MAKEFILE_MAX_OUTPUT_CHARS

Maximum characters to return from target output (0 = unlimited)

0 (unlimited)

MCP_MAKEFILE_WRITE_TO_FILE

Write full output to temporary files (true/false)

false

MCP_MAKEFILE_TEMP_DIR

Base directory for temporary files

/tmp

Using environment variables in Claude Code:

You can set environment variables in your .mcp.json configuration:

claude mcp add-json --scope project makefile-server '{
  "type": "stdio",
  "command": "uvx",
  "args": [
    "--from",
    "git+https://github.com/ccollicutt/mcp-makefile-server",
    "mcp-makefile-server",
    "./Makefile"
  ],
  "env": {
    "MCP_MAKEFILE_LOG_LEVEL": "DEBUG",
    "MCP_MAKEFILE_MAX_OUTPUT_CHARS": "5000",
    "MCP_MAKEFILE_WRITE_TO_FILE": "true",
    "MCP_MAKEFILE_TEMP_DIR": "/var/tmp"
  }
}'

This configures the server to:

  • Use DEBUG logging

  • Truncate output at 5000 characters

  • Write full output to files in /var/tmp/mcp-makefile-{random-id}/

See Claude Code Settings Documentation for more information.

Setting environment variables in your shell:

export MCP_MAKEFILE_PATH=/path/to/Makefile
export MCP_MAKEFILE_LOG_LEVEL=DEBUG
export MCP_MAKEFILE_ALLOWED_TARGETS="test,build,lint"
export MCP_MAKEFILE_MAX_OUTPUT_CHARS=5000
export MCP_MAKEFILE_WRITE_TO_FILE=true
export MCP_MAKEFILE_TEMP_DIR=/var/tmp

Output Management

The server provides two options for managing large output:

Option 1: Truncate Output (Optional)

By default, output is unlimited. To prevent token overload, you can enable truncation:

Via environment variable:

export MCP_MAKEFILE_MAX_OUTPUT_CHARS=5000  # Set >0 to truncate, 0 = unlimited

Via command-line argument:

mcp-makefile-server serve ./Makefile --max-output-chars 5000

When output is truncated, you'll see a message like:

Note: Output exceeded 5000 characters and was truncated.
Configure targets to log verbose output to files and return summaries instead.

Option 2: Write to Temporary File

Write full output to temporary files and return the file path. The server creates a unique subdirectory for each session to organize output files.

Via environment variable:

export MCP_MAKEFILE_WRITE_TO_FILE=true

Via command-line argument:

mcp-makefile-server serve ./Makefile --write-to-file

When enabled, you'll see:

Full output written to: /tmp/mcp-makefile-4a3f2e1b/test-1234567890.log

Customize temp directory location:

# Via environment variable
export MCP_MAKEFILE_TEMP_DIR=/var/tmp

# Via command-line argument
mcp-makefile-server serve ./Makefile --write-to-file --temp-dir /var/tmp

The server automatically creates a randomized subdirectory (e.g., mcp-makefile-{random-id}) within the temp directory to organize all output files for that session.

You can combine both options to truncate the returned output while keeping a full copy in a file.


Removing and Uninstalling

Remove from Claude Code

To remove the MCP server from your project:

cd ~/projects/my-app
claude mcp remove "makefile-server" -s project

This removes the server from .mcp.json. Restart Claude Code to apply changes.

Uninstall the Server

If you used Method 1 (uvx):

The server is cached automatically. To clear it:

# Clear specific package from cache
uv cache clean mcp-makefile-server

# Or clear entire uv cache
uv cache clean

If you used Method 2 (local installation):

# Uninstall the package
uv pip uninstall mcp-makefile-server

# Optionally, remove the cloned directory
rm -rf /path/to/mcp-makefile-server

Troubleshooting

Connection Failed

If Claude Code shows "Failed to reconnect to makefile-server":

  1. Check the command name is mcp-makefile-server (not mcp-makefile)

  2. Verify the Makefile path is correct

  3. Check the server logs: Look at Claude Code's output panel

  4. Test the server manually:

    uvx --from git+https://github.com/ccollicutt/mcp-makefile-server mcp-makefile-server preview ./Makefile

Makefile Format

Your Makefile must use the standard self-documenting format with ## comments:

.PHONY: test build deploy

## Category: Testing
test: ## Run test suite with pytest (outputs results to stdout)
	pytest

lint: ## Check code style and formatting with ruff (reports issues found)
	ruff check .

## Category: Building
build: test ## Build Python package distribution (runs tests first, creates dist/ directory with wheel and sdist)
	python -m build

# Mark targets as internal (NOT exposed)
deploy-prod: ## @internal Deploy to production
	./deploy.sh --prod

# Regular targets ARE exposed
deploy-staging: test ## Deploy to staging environment (runs tests first, creates deploy.log)
	./deploy.sh --staging

Format Rules:

Target Type

Result

Targets with ## descriptions

Exposed as MCP tools

Targets with ## @internal or ## @skip

NOT exposed

Targets without ##

Ignored

Development

For development setup, testing, Python API usage, and contributing guidelines, see DEVELOP.md.

Best Practices

Efficient Output (Token Usage)

MCP responses consume tokens and bandwidth. Keep output concise:

Good practices:

# Use variables for options, not separate targets
VERBOSE ?= 0
LOG_FILE ?= test-results.log

test: ## Run test suite with pytest (VERBOSE=1 for detailed output, LOG_FILE=path to save results, default: quiet mode with summary)
	@echo "Running tests..."
	@if [ "$(VERBOSE)" = "1" ]; then \
		pytest -v > $(LOG_FILE) 2>&1 && echo "✓ Tests complete (verbose). Full output in $(LOG_FILE)"; \
	else \
		pytest --quiet --tb=short > $(LOG_FILE) 2>&1 && echo "✓ Tests complete. Full output in $(LOG_FILE)" || \
		(echo "✗ Tests failed. Check $(LOG_FILE) for errors" && exit 1); \
	fi

build: ## Build Python package distribution (creates dist/ with wheel and sdist, full output saved to build.log)
	@echo "Building package..."
	@python -m build --quiet > build.log 2>&1 && echo "✓ Build complete. See build.log" || \
		(echo "✗ Build failed. Check build.log for errors" && exit 1)

lint: ## Check code style with ruff (reports only issues found, use FIX=1 to auto-fix problems)
	@if [ "$(FIX)" = "1" ]; then \
		ruff check --fix . && echo "✓ Linting complete (auto-fixed)"; \
	else \
		ruff check . --quiet && echo "✓ No linting issues" || echo "✗ Linting failed"; \
	fi

Avoid:

# DON'T: Create many similar targets
test: ## Run tests
	pytest --quiet

test-verbose: ## Run tests verbosely
	pytest -vvv  # Separate target for same thing!

test-coverage: ## Run tests with coverage
	pytest --cov  # Another target!

# DON'T: Poor descriptions
build: ## Build  # What does it build? What are the options?
	python -m build

# DON'T: Print everything
deploy: ## Deploy
	npm install  # Prints hundreds of lines
	npm run build  # Prints more lines
	kubectl apply -f .  # Even more output

Description Best Practices:

The ## description is sent to the MCP client/AI, so make it informative:

# GOOD: Clear description with options explained
test: ## Run test suite (VERBOSE=1 for details, TEST=pattern to filter, COVERAGE=1 for coverage report)
	...

# GOOD: Explains what it does and what happens
deploy-staging: ## Deploy to staging environment (runs tests first, creates deploy.log with details)
	...

# BAD: Too vague
test: ## Test
	...

# BAD: Missing important info
deploy: ## Deploy
	...

Tips:

Tip

Description

Example

Write AI-friendly descriptions

Use human-readable comments (#) for developers, but make ## comments verbose natural language instructions for the AI. Include all variables, options, and capabilities. Keep targets multi-purpose to reduce total count.

test: ## Run test suite with pytest. Options: VERBOSE=1 for detailed output, TEST=pattern to filter, COVERAGE=1 for coverage report, PARALLEL=1 for parallel execution. Creates test-results.log with full output.

Mark helper targets as internal

Sub-functions and helpers the AI doesn't need should be marked @internal or @skip to keep the tool list focused

_setup-env: ## @internal Initialize environment variables

Use variables, not multiple targets

Pass options via variables instead of creating separate targets

make test VERBOSE=1 instead of make test-verbose

Write clear descriptions

Explain what it does and what options are available

See Description Best Practices above

Log verbose output to files

Commands that produce lots of output should log to a file and return only a summary to avoid overloading tokens

command > output.log 2>&1 && echo "✓ Done. See output.log"

Suppress command echo to reduce output noise

@pytest instead of pytest

Use quiet flags when available

pytest --quiet, ruff check --quiet

Redirect to log files

Save verbose output for later analysis

pytest -v > test.log 2>&1

Print concise summaries

Show brief success/failure instead of full output

echo "✓ Tests passed (23 tests, 2.5s)"

Combine redirect + summary

Redirect full output to file, then echo summary message

pytest -v > test.log 2>&1 && echo "✓ Done. See test.log"

Exit codes matter

Return non-zero on failure for AI to detect errors

Always preserve exit codes

Examples

See tests/fixtures/ for example Makefiles:

File

Description

simple.mk

Basic targets

categorized.mk

With category organization

mixed.mk

Shows internal targets and filtering

License

MIT License

Install Server
A
license - permissive license
B
quality
D
maintenance

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

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/ccollicutt/mcp-makefile-server'

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