task-mcp 0.4.0

MCP server for task runner integration — Agent-safe harness for defined tasks
Documentation

task-mcp

Agent-safe task runner MCP server backed by just.

Exposes predefined justfile recipes as MCP tools, with access control via the [group('allow-agent')] attribute (or the legacy # [allow-agent] doc comment).

allow-agent is a security boundary: in the default agent-only mode, recipes without an allow-agent marker are NEVER exposed via MCP. The mode is selected by the TASK_MCP_MODE environment variable, set OUTSIDE the MCP. Reading the justfile directly bypasses this guard, but is not the canonical path for agent interaction.

Tools

Tool Description Annotations
session_start Set the working directory for this session. Must be called before run or list (unless list is given an explicit justfile path). destructive
list List available tasks from justfile. Returns names, descriptions, parameters, and groups. Requires session_start when no justfile parameter is given. read-only, idempotent
run Execute a predefined task. Only tasks visible in list can be run. Requires session_start. destructive
logs Retrieve execution logs of recent runs. Returns summary list or full output by task ID. read-only, idempotent
info Show current session state: active workdir, resolved justfile path, and task mode. read-only, idempotent

Installation

cargo install --path .

Requires just to be installed and available on PATH.

Usage

Start as MCP server (stdio transport):

task-mcp --mcp

Claude Code integration

Add to your Claude Code MCP configuration:

{
  "mcpServers": {
    "task-mcp": {
      "command": "task-mcp",
      "args": ["--mcp"]
    }
  }
}

Configuration

Configuration is loaded from .task-mcp.env in the current directory (if present), then from environment variables.

Variable Default Description
TASK_MCP_MODE agent-only agent-only: only allow-agent tagged recipes (Pattern A [group('allow-agent')] or Pattern B # [allow-agent]); all: all non-private recipes. This is the security guard switch — set it OUTSIDE the MCP.
TASK_MCP_JUSTFILE auto-detect Path to justfile (relative or absolute)
TASK_MCP_ALLOWED_DIRS (any) Comma-separated list of directories allowed as session working directories. If unset, any directory is accepted. Paths are canonicalized on parse.

.task-mcp.env example:

TASK_MCP_MODE=agent-only
TASK_MCP_JUSTFILE=./justfile
TASK_MCP_ALLOWED_DIRS=/home/user/projects/my-project,/home/user/projects/other-project

Justfile setup

Two equivalent markers are supported for tagging recipes as agent-safe.

Pattern A (recommended): [group('allow-agent')] attribute

This is the just-native form. Stack additional [group('...')] attributes on separate lines if you also want functional grouping.

# Build the project
[group('allow-agent')]
build:
    cargo build --release

# Run tests
[group('allow-agent')]
test filter="":
    cargo test {{filter}}

# Profile build — agent-safe AND in the `profile` functional group
[group('allow-agent')]
[group('profile')]
profile-build:
    cargo build --profile=release-with-debug

# Deploy to production — NOT exposed to agent
deploy:
    ./scripts/deploy.sh

Pattern B (legacy): # [allow-agent] doc comment

Supported for compatibility. Caveat: just only keeps the comment line immediately before a recipe as its doc, so combining # [allow-agent] with a descriptive doc comment causes one of the two to be dropped (the marker becomes invisible). Prefer Pattern A in new recipes.

# [allow-agent]
info:
    echo "task-mcp"

Mode behavior

In agent-only mode (default), only allow-agent tagged recipes are returned by list and executable via run. Untagged recipes are hidden — they never enter the agent context via MCP.

In all mode, all non-private recipes are exposed. Reading the justfile directly always shows everything, but that bypasses the MCP guard and is not the canonical path.

Workflow

The typical agent workflow is:

  1. Call session_start with the project directory to establish the working context.
  2. Call list to discover available tasks.
  3. Call run to execute a task.
  4. Call logs to inspect output of a past run.
  5. Call info at any point to confirm the current session state.

list can also be called without a prior session_start when an explicit justfile path is provided — this is useful for exploration before committing to a working directory.

Tool details

session_start

{ "workdir": "/absolute/path/to/project" }
  • workdir: absolute path to the project directory; must be accessible and, if TASK_MCP_ALLOWED_DIRS is set, must fall within one of the allowed directories
  • Returns a confirmation message with the resolved path on success

info

No parameters required. Returns:

  • workdir: active working directory (or null if session_start has not been called)
  • justfile: resolved justfile path (or null if not resolvable from the current session state)
  • mode: current task mode (agent-only or all)

list

{
  "filter": "profile",
  "justfile": "./justfile"
}
  • filter: optional functional group name (e.g. profile, release) to narrow results. Supports glob wildcards (*, ?). Filtering by allow-agent is not meaningful in agent-only mode (every visible recipe already carries it).
  • justfile: optional path override

run

{
  "task_name": "test",
  "args": { "filter": "unit" },
  "timeout_secs": 120
}
  • task_name: must appear in list output
  • args: named arguments matching recipe parameter names
  • timeout_secs: default 60

Returns a TaskExecution object with id, exit_code, stdout, stderr, duration_ms, and truncated fields.

logs

{ "task_id": "<uuid>", "tail": 50 }
  • task_id: omit to get summary of the 10 most recent executions; provide to get full output
  • tail: restrict stdout to the last N lines (only when task_id is provided)

In-memory only; logs are lost on server restart.

Output truncation

stdout and stderr are capped at 100 KB per execution. When truncated, the truncated field is true and the head and tail of the output are preserved. Use logs with tail to retrieve specific portions.

Security

  • Only recipes whitelisted by list can be executed via run
  • session_start validates the requested directory against TASK_MCP_ALLOWED_DIRS using canonicalized Path::starts_with; symlinks are resolved before comparison to prevent traversal attacks
  • Argument values are validated to reject shell metacharacters
  • Execution timeout is enforced (default: 60 s)
  • open_world_hint = false on all tools: no external network calls

License

MIT OR Apache-2.0