| name | setup-mcp |
| description | Configures developer environment -- MCP servers, tokens, and permissions |
| allowed-tools | Read, Glob, Write, Edit, Bash, mcp__* |
| argument-hint | [--update] [--tracker-type <type>] [--tracker-instance <url>] [--sc-remote <owner/repo>] |
Init
Set up the developer environment for agent-flow pipeline. Generates .mcp.json (MCP server configuration) and .claude/settings.json (tool permissions).
This command is the counterpart to /agent-flow:onboard:
- onboard = project config (Automation Config in CLAUDE.md)
- init = developer environment (MCP servers, tokens, permissions)
Input: $ARGUMENTS = (none) | --update | --tracker-type <type> | --tracker-instance <url> | --sc-remote <owner/repo> (flags may be combined)
Scope
This command writes to the CURRENT WORKING DIRECTORY:
.mcp.json — MCP server configuration
.claude/settings.json — tool auto-approval (optional)
.gitignore — adds .mcp.json if not present
Step 0: Parameter Override
Parse $ARGUMENTS for optional CLI flags:
--tracker-type <type> → cli_tracker_type
--tracker-instance <url> → cli_tracker_instance
--sc-remote <owner/repo> → cli_sc_remote
If ANY of these flags is provided:
- Validate
--tracker-type (if provided) against the lookup table in ../../core/mcp-detection.md Process step 1. Valid values: youtrack, github, jira, linear, gitea, redmine. If invalid → error: "Invalid tracker type '{value}'. Valid types: youtrack, github, jira, linear, gitea, redmine."
- Skip Step 1 (Automation Config read). Use flag values instead:
-
Type = cli_tracker_type (if not provided, infer from cli_sc_remote hostname: github.com → github; otherwise → error: "--tracker-type is required when CLAUDE.md is not available.")
-
Instance = cli_tracker_instance (if not provided, derive default:
Path note: trackers.md lives in the plugin installation directory. Resolve via Glob before reading defaults.
Resolve {trackers_md_path}: Glob .claude/plugins/**/docs/reference/trackers.md (prefer path containing .claude/plugins/ or agent-flow/); fallback **/docs/reference/trackers.md; last resort docs/reference/trackers.md. If not found → use hardcoded defaults per tracker type.
Read the Instance & Project Defaults table from {trackers_md_path} for the given type.)
-
Remote = cli_sc_remote (if not provided, skip SC server — tracker-only setup)
- Proceed to Step 1b (detect .mcp.json.example) with the overridden values.
If NO flags provided: proceed to Step 1 as normal.
Composability with --update: The 3 new flags compose with --update. Example: --update --tracker-type gitea updates an existing .mcp.json with a new/changed tracker type. The --update flag controls Step 2 behavior (preserve existing servers); the new flags control Step 1 behavior (value source).
Step 1: Read Automation Config
If Step 0 provided CLI overrides → skip this step entirely (values already set).
Read Automation Config from CLAUDE.md. Extract:
- Type from Issue Tracker (determines tracker MCP server)
- Instance from Issue Tracker (determines server URL/env vars)
- Remote from Source Control (determines SC MCP server and hostname)
If no Automation Config found → error: "No Automation Config found. Run /agent-flow:onboard first."
Step 1b: Detect .mcp.json.example
If .mcp.json.example exists in CWD (typically generated by /agent-flow:scaffold):
-
Parse the file to extract pre-fill values:
- Tracker type: Identify from MCP server package name using the reverse mapping from
../../core/mcp-detection.md lookup table (e.g., @vitalyostanin/youtrack-mcp → youtrack, gitea-mcp → gitea)
- Instance URL: Extract from environment variable values (e.g.,
YOUTRACK_URL, GITEA_HOST, REDMINE_URL)
- Remote: Extract from SC MCP server config if present (e.g., GitHub server implies GitHub remote)
-
If parsing succeeds:
- Display:
Detected .mcp.json.example from previous /scaffold run. Pre-filling: Tracker={type}, Instance={url}, Remote={remote} (omit fields that were not detected)
- Use extracted values as defaults for Steps 3-4 (user can still override at token collection)
- Skip redundant questions where values are already known
-
If .mcp.json.example does not exist or parsing fails:
- No action — proceed normally to Step 2 (no warning needed)
Step 2: Detect existing .mcp.json
- If
.mcp.json exists in CWD:
- If
--update → parse existing config, preserve non-agent-flow servers
- If no flag → "Found existing .mcp.json. Update it? [Y/n]"
- Y → parse and preserve
- N → skip MCP setup, go to Step 6
- If
.mcp.json does NOT exist → fresh mode
Step 2b: Prerequisite check
Before determining MCP servers, verify required tooling is available:
-
Node.js / npx check: npx is only needed for the YouTrack community fallback path (@vitalyostanin/youtrack-mcp@latest) — specifically when the user explicitly selects the legacy on-prem route for YouTrack Server <2026.1. For all other tracker types (github, jira, linear — HTTP transport; redmine — uvx; gitea — binary), npx is NOT required.
If the user later selects the YouTrack legacy fallback in Step 3 and npx is not found:
- Display error:
"npx not found. Node.js is required for the YouTrack community fallback (vitalyostanin). Install Node.js from https://nodejs.org/ and retry, or use the default HTTP transport if your YouTrack is 2026.1+." → STOP that fallback path.
Do NOT perform an upfront npx check for all tracker types — it is not needed by default.
Step 3: Determine MCP servers needed
For each required MCP server, follow ../../core/mcp-detection.md Process step 1 to determine the expected package name and tool prefix for the declared tracker type.
If Step 1b pre-filled tracker type from .mcp.json.example: use the pre-filled value as default (user can override).
Transport, endpoint, and credential information per tracker type:
| Tracker Type | Transport | Endpoint / Invocation | Credentials |
|---|
| youtrack | HTTP | https://<INSTANCE>.youtrack.cloud/mcp | Bearer header YOUTRACK_TOKEN (env var) |
| github | HTTP | https://api.githubcopilot.com/mcp/ | Bearer header GITHUB_PERSONAL_ACCESS_TOKEN (env var) |
| jira | HTTP | https://mcp.atlassian.com/v1/mcp | OAuth via Claude Code (no env vars required in template; Cloud only) |
| linear | HTTP | https://mcp.linear.app/mcp | OAuth via Claude Code (no env vars required in template) |
| gitea | stdio (binary) | gitea-mcp binary | GITEA_ACCESS_TOKEN env var, GITEA_HOST env var |
| redmine | stdio (uvx) | uvx --from mcp-redmine==2026.01.13.152335 mcp-redmine | REDMINE_URL env var, REDMINE_API_KEY env var (requires Python 3.10+ and uv toolchain) |
YouTrack fallback for Server <2026.1 (on-prem legacy): If the user explicitly indicates their YouTrack is an on-prem instance older than version 2026.1, offer the community fallback:
- Use
npx -y @vitalyostanin/youtrack-mcp@latest (stdio transport) with YOUTRACK_URL and YOUTRACK_TOKEN environment variables.
- Inform the user:
"For YouTrack Server <2026.1, use community fallback: npx -y @vitalyostanin/youtrack-mcp@latest with YOUTRACK_URL + YOUTRACK_TOKEN env vars. For YouTrack Cloud or Server 2026.1+, the default HTTP transport is recommended."
- Check npx availability at this point only (lazy check, NOT upfront in Step 2b).
Redmine uvx prereq (lazy check): When redmine is selected, verify uv is installed (which uv or where uv on Windows). If not found, display: "uv not found. Install the uv toolchain (Python 3.10+ required) from https://docs.astral.sh/uv/getting-started/installation/ and retry." → STOP redmine setup.
Shared server detection: Compare tracker Type hostname with Source Control Remote hostname.
- Gitea tracker + Gitea SC → single
gitea-mcp instance (shared)
- GitHub tracker + GitHub SC → single GitHub HTTP server instance (shared)
- Mixed (e.g. Jira + GitHub SC) → two separate servers
Determine which servers to configure:
- Tracker MCP server (always)
- Source control MCP server (if different from tracker)
Step 4: Collect tokens
For each required MCP server, offer two options:
Your tracker is {Type}. You need a {token_name} token.
See docs/guides/tokens.md for how to create one.
(a) Paste token now — I'll add it to .mcp.json directly
(b) Skip — I'll generate .mcp.json with a placeholder (<YOUR_*>).
You can edit .mcp.json manually later with your token.
If user pastes a token → use it in Step 6.
If user skips → keep <YOUR_*> placeholder in generated .mcp.json.
For extra env vars (Instance URL, email):
- Auto-fill from Automation Config where possible (Instance → base URL)
- Ask for remaining (e.g. ATLASSIAN_EMAIL for Jira)
If shared server detected:
"Your tracker ({Type}) and source control ({Remote}) use the same MCP server. One configuration covers both."
If separate SC server needed:
Your source control is on {hostname}. You need a {sc_token_name} token.
(a) Paste token now
(b) Skip — edit .mcp.json manually later
Step 5: Platform-specific handling
For gitea-mcp (Gitea tracker):
Detect platform via Bash:
uname -s
uname -m
Based on result, determine the asset name (pinned to v1.1.0):
| Platform | uname -s | uname -m | Binary name | Asset name |
|---|
| macOS ARM | Darwin | arm64 | gitea-mcp | gitea-mcp_1.1.0_Darwin_arm64.tar.gz |
| macOS x86_64 | Darwin | x86_64 | gitea-mcp | gitea-mcp_1.1.0_Darwin_x86_64.tar.gz |
| Linux ARM64 | Linux | arm64 / aarch64 | gitea-mcp | gitea-mcp_1.1.0_Linux_arm64.tar.gz |
| Linux i386 | Linux | i386 / i686 | gitea-mcp | gitea-mcp_1.1.0_Linux_i386.tar.gz |
| Linux x86_64 | Linux | x86_64 | gitea-mcp | gitea-mcp_1.1.0_Linux_x86_64.tar.gz |
| Windows ARM64 | MINGW*/MSYS* | arm64 | gitea-mcp.exe | gitea-mcp_1.1.0_Windows_arm64.zip |
| Windows i386 | MINGW*/MSYS* | i386 / i686 | gitea-mcp.exe | gitea-mcp_1.1.0_Windows_i386.zip |
| Windows x86_64 | MINGW*/MSYS* | x86_64 | gitea-mcp.exe | gitea-mcp_1.1.0_Windows_x86_64.zip |
Version is pinned to v1.1.0. Download base URL: https://gitea.com/gitea/gitea-mcp/releases/download/v1.1.0/{asset_name}
Auto-download (default behavior):
- Check if already installed: Run
test -f ~/.claude/bin/{binary_name}. If exists → reuse, skip download. Display: "gitea-mcp already installed at ~/.claude/bin/{binary_name}"
- Create bin directory:
mkdir -p ~/.claude/bin
- Download archive (with failure detection):
curl -sfL -o ~/.claude/bin/{asset_name} "https://gitea.com/gitea/gitea-mcp/releases/download/v1.1.0/{asset_name}"
Note: The -f (--fail) flag causes curl to exit non-zero on HTTP errors (e.g. 404) instead of saving the error page as a file.
- Extract archive:
- Linux/macOS:
tar xf ~/.claude/bin/{asset_name} -C ~/.claude/bin/ gitea-mcp
- Windows (MINGW*/MSYS*):
Expand-Archive -Path ~/.claude/bin/{asset_name} -DestinationPath ~/.claude/bin/ -Force or unzip -o ~/.claude/bin/{asset_name} gitea-mcp.exe -d ~/.claude/bin/
- Validate file size (guards against truncated downloads, error pages, or missing platform assets):
FILESIZE=$(wc -c < ~/.claude/bin/{binary_name} 2>/dev/null || echo 0)
If FILESIZE < 102400 (100 KB) → remove the file (rm -f ~/.claude/bin/{binary_name}), treat download as failed.
Valid gitea-mcp binaries are several MiB; anything under 100 KB is corrupt or an error page.
- Set permissions (Linux/macOS only):
chmod +x ~/.claude/bin/{binary_name}
- Verify download: If
~/.claude/bin/{binary_name} exists and passed size validation:
- Success → Display:
"Downloaded gitea-mcp v1.1.0 to ~/.claude/bin/{binary_name}"
- Failure → continue to step 9
- Windows download fallback sequence: If curl download failed AND platform is Windows (
MINGW*/MSYS*):
a. PowerShell fallback (try first): curl via Bash is unreliable on Windows — use PowerShell's Invoke-WebRequest which does not have this limitation:
$binDir = "$env:USERPROFILE\.claude\bin"
New-Item -ItemType Directory -Force -Path $binDir | Out-Null
Invoke-WebRequest -Uri "https://gitea.com/gitea/gitea-mcp/releases/download/v1.1.0/{asset_name}" -OutFile "$binDir\{asset_name}" -UseBasicParsing
Expand-Archive -Path "$binDir\{asset_name}" -DestinationPath $binDir -Force
- Non-Windows download fallback (Linux/macOS): If curl download failed AND platform is NOT Windows:
a. wget fallback: Check if wget is available:
command -v wget
The binary path for .mcp.json: resolve ~/.claude/bin/{binary_name} to its absolute path.
Manual path collection (fallback only — if auto-download fails):
Display: "Auto-download failed. Download gitea-mcp manually from: https://gitea.com/gitea/gitea-mcp/releases"
"Enter the path to your gitea-mcp binary:"
Path validation (MANDATORY):
- Run
test -f "{path}" to verify the file exists.
- If file does NOT exist → display:
"File not found at {path}. Please check the path and try again." → re-ask for the path. Max 3 attempts, then STOP with error: "gitea-mcp binary not found. Download it from https://gitea.com/gitea/gitea-mcp/releases and re-run /agent-flow:setup-mcp."
- On Linux/macOS: verify the file is executable (
test -x "{path}"). If not → run chmod +x "{path}" and inform user.
For mcp-redmine (Redmine tracker):
Redmine uses the mcp-redmine Python package via uvx — no local clone or --prefix path required.
Invocation:
uvx --from mcp-redmine==2026.01.13.152335 mcp-redmine
Prerequisites: Python 3.10+ and the uv toolchain. Install from: https://docs.astral.sh/uv/getting-started/installation/
Lazy prereq check (at this point only — NOT upfront in Step 2b):
Run which uv (or where uv on Windows). If uv is not found → display:
"uv not found. Install the uv toolchain (Python 3.10+ required) from https://docs.astral.sh/uv/getting-started/installation/ and retry." → STOP redmine setup.
Environment variables required:
REDMINE_URL — full URL of your Redmine instance (e.g., https://redmine.example.com)
REDMINE_API_KEY — your Redmine API key
No path collection is needed — uvx handles the package download and execution automatically.
Step 6: Generate .mcp.json
Load the appropriate template from examples/mcp-configs/{type}.json.
- Replace placeholder tokens with user-provided values (or keep
<YOUR_*> if skipped)
- Replace placeholder URLs with values from Automation Config
- If update mode: merge into existing
.mcp.json (preserve unrelated servers)
- If shared server: emit only one server entry
Write .mcp.json to CWD.
Post-write placeholder validation (MANDATORY): After writing .mcp.json, scan every "command" field in the generated JSON:
- If any
command value contains <path-to-binary> or any args value contains <PATH_TO_ → the path collection in Step 5 was incomplete.
- Display:
"ERROR: .mcp.json contains unresolved placeholder in server '{server_name}'. Returning to path collection."
- Return to Step 5 for the affected server type and re-collect the path.
- After re-collection, rewrite the affected server entry in
.mcp.json.
- If all
command and args values are placeholder-free → proceed.
If .mcp.json not in .gitignore:
- Add
.mcp.json to .gitignore
Create .mcp.json.example (same structure, all tokens replaced with <YOUR_*>).
Step 7: Validate connectivity
For each configured MCP server with non-placeholder tokens:
-
Pre-flight: binary/command existence check (for stdio servers — gitea binary, redmine uvx, YouTrack fallback npx):
- Read the
command field from the server entry in .mcp.json.
- For HTTP-transport servers (github, jira, linear, youtrack default): skip this check (no local binary needed).
- For stdio-transport servers: run
command -v "{command}" (or where "{command}" on Windows) to verify the command exists in PATH.
- If command not found →
"[FAIL] {server_name}: command '{command}' not found. Re-run /agent-flow:setup-mcp to fix the setup." Skip connectivity check for this server.
-
Connectivity check: Follow ../../core/mcp-detection.md (with check_write: false):
- If
mcp_available: true → "[OK] {server_name} connected successfully"
- If
mcp_available: false → "[FAIL] {server_name}: {error}. Check your token and URL." (If error_type is "tls", append: " Try adding NODE_OPTIONS: --use-system-ca to the env block in .mcp.json.")
If any placeholder tokens remain:
"[SKIP] {server_name}: token not configured. Add it to .mcp.json later."
Step 8: Permission setup
"Would you like to configure permanent tool permissions? This prevents permission prompts when resuming sessions."
Offer 4 levels:
[1] Full pipeline (recommended) — all tools needed for fix/implement/scaffold
[2] Read-only — analysis commands only (analyze-bug, status, dashboard)
[3] Minimal — basic tools, approve MCP per-call
[4] Custom — choose specific tools
Generate .claude/settings.json based on choice:
Full pipeline:
{
"permissions": {
"allow": [
"Read", "Write", "Edit", "Glob", "Grep", "Bash",
"mcp__{tracker_prefix}__*", "mcp__{sc_prefix}__*"
]
}
}
Where {tracker_prefix} and {sc_prefix} are specific to the configured servers (e.g., youtrack, gitea, github). Use specific prefixes, NOT wildcard mcp__*.
Read-only:
{
"permissions": {
"allow": [
"Read", "Glob", "Grep",
"mcp__{tracker_prefix}__*"
]
}
}
Minimal:
{
"permissions": {
"allow": ["Read", "Glob", "Grep"]
}
}
Custom: Let user select from list of tools.
If .claude/settings.json already exists:
- Merge: add missing permissions, don't remove existing ones
- Show diff before writing
Step 9: Closing message
Developer environment configured successfully.
.mcp.json — MCP server configuration ({N} servers)
.mcp.json.example — template for team sharing (no secrets)
.claude/settings.json — tool permissions ({level})
Next steps:
1. Run /agent-flow:check-setup to verify everything works
2. If you skipped tokens, add them to .mcp.json before running the pipeline
Tip: You can re-run /agent-flow:setup-mcp --update anytime to update your setup.
Rules
- NEVER write tokens into CLAUDE.md — only into .mcp.json
- NEVER commit .mcp.json to git — always add to .gitignore
- In update mode: preserve existing non-agent-flow MCP servers in .mcp.json
- In update mode: preserve existing permissions in .claude/settings.json
- Auto-fill from Automation Config where possible — minimize questions
- All wizard text in English