DEV Community

Cover image for Fixing Laravel Boost in Windsurf: A Global MCP Setup Guide
Olusola Ojewunmi
Olusola Ojewunmi

Posted on

Fixing Laravel Boost in Windsurf: A Global MCP Setup Guide

Fixing Laravel Boost in Windsurf: A Global MCP Setup Guide

If you’ve tried adding Laravel Boost as an MCP server in Windsurf and hit “cannot initialize server”, you’re not alone.

The most common cause is simple:

  • Windsurf often starts MCP servers from a working directory that is NOT your Laravel project root.
  • So a “normal” MCP command like php artisan boost:mcp fails because artisan isn’t in the current directory (or it runs with the wrong PHP).

In other words: this is usually not a Boost problem — it’s a Windsurf MCP launch context problem.

When Laravel announced Boost, I was thrilled.
I rushed over to the docs expecting to see a simple “Use this with Windsurf” section.
But as I kept scrolling… that smile gradually dropped from my face.
I saw Cursor, Junie, and a bunch of familiar integrations — but not Windsurf.
So I kept searching until I landed on a setup that’s boringly reliable.

This tutorial shows a robust approach that works across all your Laravel projects:

  • Install Boost per project (required)
  • Add a Windsurf MCP server that calls a wrapper script
  • The wrapper script finds the correct Laravel project and runs php artisan boost:mcp

If you keep multiple Laravel projects open at the same time, you’ll also see how to configure per-project MCP entries so each project stays isolated.

Note: While we’re configuring Windsurf “globally” so it can work with any project, Laravel Boost itself must still be installed locally in every Laravel project via Composer. This wrapper simply helps Windsurf find the correct local installation.

Bonus:

  • Add Herd MCP to Windsurf too (handy if you use Herd for local sites/PHP)

The target architecture (what we’re building)

Windsurf can launch MCP servers from arbitrary directories, so the reliable design is to put an adaptive layer in front of Boost:

Windsurf (any cwd)
  -> wrapper script (stable entrypoint)
       -> find Laravel project root (locate artisan)
       -> choose correct PHP (prefer Herd / isolated PHP)
       -> exec: php artisan boost:mcp
Enter fullscreen mode Exit fullscreen mode

Once you understand that flow, every config choice in this guide makes sense.

Prerequisites

  • You have Windsurf installed
  • You have PHP installed (Herd/Homebrew/Linux packages/Windows PHP)
  • Python 3 is recommended (only needed for the optional auto-detection fallback; without it the script falls back to $PWD / SITE_PATH)
  • You have at least one Laravel project

Install Boost in each Laravel project (required)

In every Laravel project you want Boost to work with:

composer require laravel/boost --dev
php artisan boost:install
Enter fullscreen mode Exit fullscreen mode

Then verify inside that project:

php artisan boost:mcp
Enter fullscreen mode Exit fullscreen mode

If this fails, fix your Laravel app boot/dependencies first. MCP depends on the app being able to boot.


Understanding Windsurf MCP config files

Windsurf follows the Claude Desktop MCP config schema.

  • Windsurf Editor:

    • macOS/Linux: ~/.codeium/mcp_config.json
    • Windows: C:\Users\<you>\.codeium\mcp_config.json
  • Windsurf JetBrains plugin (PhpStorm/IntelliJ):

    • macOS/Linux: ~/.codeium/windsurf/mcp_config.json
    • Windows: C:\Users\<you>\.codeium\windsurf\mcp_config.json

Warning: If you edit the wrong file, you’ll keep seeing “cannot initialise server” even though the JSON looks correct.

Quick way to confirm you’re editing the right file:

  • Temporarily point the command to a definitely-invalid path (or rename your wrapper script).
  • Refresh MCP servers in Windsurf.
  • If the error message doesn’t change, you’re editing the wrong config file.

For the rest of this guide:

  • If you’re using the Windsurf Editor, edit ~/.codeium/mcp_config.json
  • If you’re using Windsurf inside PhpStorm, edit ~/.codeium/windsurf/mcp_config.json

Tip: You can include multiple servers (Boost, Herd, etc.) inside the same mcpServers object.


The Fix: Use a Wrapper Script

Instead of configuring laravel-boost as:

{
  "command": "php",
  "args": ["artisan", "boost:mcp"]
}
Enter fullscreen mode Exit fullscreen mode

…we configure it to run a wrapper script. The wrapper script:

Phase 1 — Locate the Laravel project root

  • Search upward for artisan
  • Fall back to other hints like SITE_PATH
  • (Optional) Use Windsurf trackers to guess active workspaces (requires Python 3)

Phase 2 — Choose the right PHP

  • Prefer Herd’s per-site PHP when available (so isolated sites use their own PHP)
  • Fall back to a usable php binary

Phase 3 — Launch MCP

  • exec herd php artisan boost:mcp (preferred)
  • or exec <php_bin> artisan boost:mcp

Using the right PHP version per project (Herd + alternatives)

One subtle issue when you have lots of Laravel projects is PHP version drift: one project might require PHP 8.1 while another needs PHP 8.3.

If you use Laravel Herd (recommended)

Herd supports per-site PHP versions via “isolation”. Once a project is isolated, Herd can automatically run the correct PHP when you execute commands from that project.

Set a PHP version for a project:

cd /path/to/your-project
herd isolate 8.3
Enter fullscreen mode Exit fullscreen mode

Confirm what PHP Herd will use for that project:

cd /path/to/your-project
herd which-php
Enter fullscreen mode Exit fullscreen mode

That’s why the wrapper script in this tutorial prefers:

herd php artisan boost:mcp
Enter fullscreen mode Exit fullscreen mode

If you’re not using Herd

You still have options:

  • asdf / mise / phpenv

    • These can select PHP based on the current directory (e.g. .tool-versions / .mise.toml).
    • The key is ensuring the tool’s “shims” are available to Windsurf (non-interactive process).
  • Docker / Laravel Sail

    • You can run Boost using the project’s containerized PHP instead of your host PHP.
    • This is heavier, but very consistent across teams.
  • One global PHP

    • If all your projects support the same PHP version, the simplest option is to keep one PHP installed globally (Herd/Homebrew/etc.).

macOS / Linux Setup

Step 1: Create the wrapper script

Create a file at:

  • macOS/Linux: ~/.codeium/laravel-boost-mcp.sh

Then make it executable:

chmod +x ~/.codeium/laravel-boost-mcp.sh
Enter fullscreen mode Exit fullscreen mode

Step 2: Add laravel-boost to Windsurf MCP config

Edit:

  • Windsurf Editor (macOS/Linux): ~/.codeium/mcp_config.json
  • Windsurf JetBrains plugin (macOS/Linux): ~/.codeium/windsurf/mcp_config.json

Add (or replace) your laravel-boost entry:

{
  "mcpServers": {
    "laravel-boost": {
      "command": "/Users/<you>/.codeium/laravel-boost-mcp.sh",
      "args": ["${workspaceFolder}"],
      "disabled": false,
      "env": {}
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Multi-project isolation (recommended)

If you work on multiple Laravel projects in parallel, create one Boost entry per project (same wrapper, different env), and give each entry a unique server name.

{
  "mcpServers": {
    "laravel-boost-project-name": {
      "command": "/Users/<you>/.codeium/laravel-boost-mcp.sh",
      "args": ["${workspaceFolder}"],
      "disabled": false,
      "env": { "LARAVEL_PROJECT_ROOT": "/path/to/project-name" }
    },
    "laravel-boost-another-project": {
      "command": "/Users/<you>/.codeium/laravel-boost-mcp.sh",
      "args": ["${workspaceFolder}"],
      "disabled": false,
      "env": { "LARAVEL_PROJECT_ROOT": "/path/to/another-project" }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Notes:

  • Keep your other MCP servers in the same file; just add this entry inside the existing mcpServers object.
  • The path must be the full absolute path to the script.

If you’re adding multiple MCP servers, don’t replace the whole file—just add laravel-boost inside the existing mcpServers object.

Step 3: Restart/refresh MCP servers in Windsurf

  • Open Windsurf settings
  • Go to MCP / Tools
  • Click refresh (or restart Windsurf)

Step 4: Quick sanity check

Run:

~/.codeium/laravel-boost-mcp.sh --check
Enter fullscreen mode Exit fullscreen mode

You should see:

  • what directory it decided is the Laravel project root (artisan_dir)
  • which php binary it found as a fallback (php_bin)
  • whether Herd CLI is available (herd_bin)
  • what Herd would use as the PHP for that project (herd_which_php) if available

If this output looks correct but Windsurf still can’t start the server, jump to the Troubleshooting section below.

Step 5: Test the wrapper in real-world scenarios

This wrapper is designed to behave well even when Windsurf starts it from a “random” working directory.

Scenario A: Not a Laravel project (expected: skipped)

From any folder that is not a Laravel app:

~/.codeium/laravel-boost-mcp.sh --check
Enter fullscreen mode Exit fullscreen mode

Expected output includes:

  • skipped (no Laravel project detected; artisan not found)

Scenario B: Laravel project without Boost installed (expected: skipped)

Inside a Laravel project that does NOT have Boost:

cd /path/to/laravel-project
~/.codeium/laravel-boost-mcp.sh --check
Enter fullscreen mode Exit fullscreen mode

Expected output includes:

  • skipped (Boost not installed in this project)

Scenario C: Laravel project with Boost + Herd per-site PHP (expected: Herd isolated PHP)

Inside a Laravel project with Boost installed:

cd /path/to/laravel-project
composer require laravel/boost --dev
herd isolate 8.3
herd which-php
~/.codeium/laravel-boost-mcp.sh --check
Enter fullscreen mode Exit fullscreen mode

Expected output includes:

  • herd_bin: ...
  • herd_which_php: ... (matching your isolated version)

Then, to confirm it can actually start, run the wrapper (this is a long-running process; stop with Ctrl+C):

~/.codeium/laravel-boost-mcp.sh
Enter fullscreen mode Exit fullscreen mode

Final macOS/Linux wrapper script (multi-project safe)

Save as: ~/.codeium/laravel-boost-mcp.sh

#!/usr/bin/env bash
set -euo pipefail

find_artisan_dir() {
  local dir="$1"
  while true; do
    if [[ -f "$dir/artisan" ]]; then
      printf "%s" "$dir"
      return 0
    fi

    local parent
    parent="$(dirname "$dir")"
    if [[ "$parent" == "$dir" ]]; then
      return 1
    fi
    dir="$parent"
  done
}

find_php() {
  if command -v php >/dev/null 2>&1; then
    command -v php
    return 0
  fi

  local candidates=(
    "/opt/homebrew/bin/php"
    "/usr/local/bin/php"
    "$HOME/Library/Application Support/Herd/bin/php"
  )

  local p
  for p in "${candidates[@]}"; do
    if [[ -x "$p" ]]; then
      printf "%s" "$p"
      return 0
    fi
  done

  return 1
}

get_windsurf_active_paths() {
  local py=""
  if [[ -x "/usr/bin/python3" ]]; then
    py="/usr/bin/python3"
  elif command -v python3 >/dev/null 2>&1; then
    py="$(command -v python3)"
  else
    return 0
  fi

  "$py" - <<'PY'
from pathlib import Path
import re

base = Path.home() / '.codeium' / 'windsurf' / 'code_tracker' / 'active'
if not base.exists():
    raise SystemExit(0)

paths = []
for f in base.rglob('*_mcp.json'):
    try:
        b = f.read_bytes()
    except Exception:
        continue

    for m in re.finditer(br'file:///[^\x00\s"]+', b):
        u = m.group(0).decode('utf-8', 'ignore')
        if u.startswith('file:///'):
            paths.append(u[7:])

seen = set()
for p in paths:
    if p in seen:
        continue
    seen.add(p)
    print(p)
PY
}

collect_candidate_start_dirs() {
  local candidates=()

  candidates+=("$PWD")

  if [[ -n "${SITE_PATH:-}" ]]; then
    candidates+=("$SITE_PATH")
  fi

  local p
  while IFS= read -r p; do
    [[ -n "$p" ]] && candidates+=("$p")
  done < <(get_windsurf_active_paths 2>/dev/null || true)

  printf "%s\n" "${candidates[@]}" | awk 'NF && !seen[$0]++'
}

start_dir="${PWD}"
artisan_dir=""

check_mode=0
root_arg=""
if [[ "${1:-}" == "--check" ]]; then
  check_mode=1
  shift
fi

if [[ -n "${1:-}" ]]; then
  root_arg="$1"
  shift
fi

if [[ -n "${root_arg}" ]] && [[ "${root_arg}" != "\${workspaceFolder}" ]] && [[ "${root_arg}" != "${workspaceFolder}" ]] && [[ "${root_arg}" != "\${workspaceRoot}" ]] && [[ "${root_arg}" != "${workspaceRoot}" ]]; then
  if [[ -d "${root_arg}" ]]; then
    artisan_dir="$(find_artisan_dir "${root_arg}" 2>/dev/null || true)"
  fi
fi

if [[ -z "${artisan_dir}" ]] && [[ -n "${LARAVEL_PROJECT_ROOT:-}" ]]; then
  if ! artisan_dir="$(find_artisan_dir "${LARAVEL_PROJECT_ROOT}" 2>/dev/null)"; then
    echo "laravel-boost MCP: LARAVEL_PROJECT_ROOT set but artisan not found." >&2
    echo "- LARAVEL_PROJECT_ROOT: ${LARAVEL_PROJECT_ROOT}" >&2
    exit 1
  fi
fi

if [[ -z "${artisan_dir}" ]]; then
  while IFS= read -r candidate; do
    if artisan_dir="$(find_artisan_dir "$candidate" 2>/dev/null)"; then
      break
    fi
  done < <(collect_candidate_start_dirs)
fi

if [[ -z "$artisan_dir" ]]; then
  echo "laravel-boost MCP: skipped (no Laravel project detected; artisan not found)." >&2
  echo "- starting directory: $start_dir" >&2
  if [[ -n "${SITE_PATH:-}" ]]; then
    echo "- SITE_PATH: ${SITE_PATH}" >&2
  fi
  exit 0
fi

if [[ ! -d "${artisan_dir}/vendor/laravel/boost" ]]; then
  echo "laravel-boost MCP: skipped (Boost not installed in this project)." >&2
  echo "- artisan_dir: ${artisan_dir}" >&2
  echo "Tip: run 'composer require laravel/boost --dev' in this project." >&2
  exit 0
fi

php_bin=""
if ! php_bin="$(find_php)"; then
  echo "laravel-boost MCP: php binary not found in PATH or common locations." >&2
  echo "Ensure PHP is installed and available to your IDE (Herd/Homebrew)." >&2
  exit 1
fi

if [[ "${check_mode}" == "1" ]]; then
  echo "laravel-boost MCP wrapper check" >&2
  echo "- starting directory: ${start_dir}" >&2
  if [[ -n "${root_arg}" ]]; then
    echo "- root_arg: ${root_arg}" >&2
  fi
  if [[ -n "${LARAVEL_PROJECT_ROOT:-}" ]]; then
    echo "- LARAVEL_PROJECT_ROOT: ${LARAVEL_PROJECT_ROOT}" >&2
  fi
  if [[ -n "${SITE_PATH:-}" ]]; then
    echo "- SITE_PATH: ${SITE_PATH}" >&2
  fi
  echo "- artisan_dir: ${artisan_dir}" >&2
  echo "- php_bin: ${php_bin}" >&2
  herd_bin=""
  if command -v herd >/dev/null 2>&1; then
    herd_bin="$(command -v herd)"
  fi
  if [[ -n "${herd_bin}" ]]; then
    echo "- herd_bin: ${herd_bin}" >&2
    herd_php="$(cd "${artisan_dir}" && herd which-php 2>/dev/null || true)"
    if [[ -n "${herd_php}" ]]; then
      echo "- herd_which_php: ${herd_php}" >&2
    fi
  else
    echo "- herd_bin: <not found>" >&2
  fi
  exit 0
fi

cd "$artisan_dir"
if command -v herd >/dev/null 2>&1; then
  exec herd php artisan boost:mcp
fi

exec "$php_bin" artisan boost:mcp
Enter fullscreen mode Exit fullscreen mode

Add Herd MCP to Windsurf (macOS, Linux, Windows notes)

If you use Laravel Herd, you can also add Herd’s MCP server to Windsurf.

What Herd MCP does

Herd MCP provides tools around Herd’s local dev environment (sites, PHP versions, etc.).

Important OS note

  • macOS: Fully supported.
  • Windows: Fully supported.
  • Linux: Herd is not typically available, so you can skip this section.

Step 1: Create a Herd wrapper script

Create a file at:

  • macOS: ~/.codeium/herd-mcp.sh

Make it executable:

chmod +x ~/.codeium/herd-mcp.sh
Enter fullscreen mode Exit fullscreen mode

Step 2: Add the herd server in Windsurf MCP config

Edit:

  • macOS: ~/.codeium/windsurf/mcp_config.json

Add (or update) this entry inside mcpServers:

{
  "mcpServers": {
    "herd": {
      "command": "bash",
      "args": [
        "/Users/<you>/.codeium/herd-mcp.sh",
        "${workspaceFolder}"
      ],
      "disabled": false,
      "env": {}
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Why run it with bash?

  • On macOS, some security/xattr quirks can cause direct execution errors.
  • Running via bash <script> tends to be more reliable inside GUI apps.

Windows Herd MCP (no wrapper required)

On Windows, Herd installs its MCP PHAR under:

  • %USERPROFILE%\.config\herd\bin\herd-mcp.phar

You can add it directly in your MCP config (Windsurf Editor or the JetBrains plugin config file, depending on what you use):

{
  "mcpServers": {
    "herd": {
      "command": "php",
      "args": [
        "%USERPROFILE%/.config/herd/bin/herd-mcp.phar"
      ],
      "env": {
        "SITE_PATH": "YOUR-SITE-PATH"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Restart/refresh MCP servers

In Windsurf MCP settings, click Refresh (or restart Windsurf).

Step 4: Sanity check

~/.codeium/herd-mcp.sh --check
Enter fullscreen mode Exit fullscreen mode

You should see:

  • detected project root (exported as SITE_PATH)
  • php binary used
  • Herd MCP phar path

Final macOS Herd wrapper script (multi-project safe)

Save as: ~/.codeium/herd-mcp.sh

#!/usr/bin/env bash

# A robust wrapper to start Herd MCP in Windsurf.
#
# Why this exists:
# - Windsurf may launch MCP servers from a directory that is NOT your project.
# - Herd MCP benefits from knowing the project root via SITE_PATH.
#
# What this script does:
# 1) Finds a Laravel project root by searching upwards for an `artisan` file.
# 2) Falls back to SITE_PATH if provided.
# 3) Optionally uses Windsurf trackers to guess your active workspace.
# 4) Finds a usable PHP binary (PATH first, then common locations like Herd).
# 5) Runs Herd's MCP PHAR with SITE_PATH exported.

set -euo pipefail

find_artisan_dir() {
  local dir="$1"
  while true; do
    if [[ -f "$dir/artisan" ]]; then
      printf "%s" "$dir"
      return 0
    fi

    local parent
    parent="$(dirname "$dir")"
    if [[ "$parent" == "$dir" ]]; then
      return 1
    fi
    dir="$parent"
  done
}

find_php() {
  if command -v php >/dev/null 2>&1; then
    command -v php
    return 0
  fi

  local candidates=(
    "/opt/homebrew/bin/php"
    "/usr/local/bin/php"
    "$HOME/Library/Application Support/Herd/bin/php"
    "$HOME/Library/Application Support/Herd/bin/php82"
  )

  local p
  for p in "${candidates[@]}"; do
    if [[ -x "$p" ]]; then
      printf "%s" "$p"
      return 0
    fi
  done

  return 1
}

get_windsurf_active_paths() {
  local py=""
  if [[ -x "/usr/bin/python3" ]]; then
    py="/usr/bin/python3"
  elif command -v python3 >/dev/null 2>&1; then
    py="$(command -v python3)"
  else
    return 0
  fi

  "$py" - <<'PY'
from pathlib import Path
import re

base = Path.home() / '.codeium' / 'windsurf' / 'code_tracker' / 'active'
if not base.exists():
    raise SystemExit(0)

paths = []
for f in base.rglob('*_mcp.json'):
    try:
        b = f.read_bytes()
    except Exception:
        continue

    for m in re.finditer(br'file:///[\x21-\x7E]+', b):
        u = m.group(0).decode('utf-8', 'ignore')
        if u.startswith('file:///'):
            paths.append(u[7:])

seen = set()
for p in paths:
    if p in seen:
        continue
    seen.add(p)
    print(p)
PY
}

find_herd_mcp_phar() {
  local candidates=(
    "/Applications/Herd.app/Contents/Resources/herd-mcp.phar"
  )

  local p
  for p in "${candidates[@]}"; do
    if [[ -f "$p" ]]; then
      printf "%s" "$p"
      return 0
    fi
  done

  return 1
}

start_dir="${PWD}"
project_dir=""

check_mode=0
root_arg=""
if [[ "${1:-}" == "--check" ]]; then
  check_mode=1
  shift
fi

if [[ -n "${1:-}" ]]; then
  root_arg="$1"
  shift
fi

if [[ -n "${root_arg}" ]] && [[ "${root_arg}" != "\${workspaceFolder}" ]] && [[ "${root_arg}" != "${workspaceFolder}" ]] && [[ "${root_arg}" != "\${workspaceRoot}" ]] && [[ "${root_arg}" != "${workspaceRoot}" ]]; then
  if [[ -d "${root_arg}" ]]; then
    project_dir="$(find_artisan_dir "${root_arg}" 2>/dev/null || true)"
  fi
fi

if [[ -z "${project_dir}" ]] && [[ -n "${LARAVEL_PROJECT_ROOT:-}" ]]; then
  if ! project_dir="$(find_artisan_dir "${LARAVEL_PROJECT_ROOT}" 2>/dev/null)"; then
    echo "herd MCP: LARAVEL_PROJECT_ROOT set but artisan not found." >&2
    echo "- LARAVEL_PROJECT_ROOT: ${LARAVEL_PROJECT_ROOT}" >&2
    exit 1
  fi
fi

if [[ -z "${project_dir}" ]]; then
  while IFS= read -r candidate; do
    if project_dir="$(find_artisan_dir "$candidate" 2>/dev/null)"; then
      break
    fi
  done < <(collect_candidate_start_dirs)
fi

if [[ -z "$project_dir" ]]; then
  echo "herd MCP: could not find artisan." >&2
  echo "- starting directory: $start_dir" >&2
  if [[ -n "${SITE_PATH:-}" ]]; then
    echo "- SITE_PATH: ${SITE_PATH}" >&2
  fi
  echo "Tip: Open a Laravel project folder (or set SITE_PATH to the project root) and try again." >&2
  exit 1
fi

php_bin=""
if ! php_bin="$(find_php)"; then
  echo "herd MCP: php binary not found in PATH or common locations." >&2
  exit 1
fi

herd_phar=""
if ! herd_phar="$(find_herd_mcp_phar)"; then
  echo "herd MCP: herd-mcp.phar not found." >&2
  echo "Tip: Ensure Laravel Herd is installed, or update find_herd_mcp_phar() with your Herd path." >&2
  exit 1
fi

if [[ "${check_mode}" == "1" ]]; then
  echo "herd MCP wrapper check" >&2
  echo "- starting directory: ${start_dir}" >&2
  if [[ -n "${root_arg}" ]]; then
    echo "- root_arg: ${root_arg}" >&2
  fi
  if [[ -n "${LARAVEL_PROJECT_ROOT:-}" ]]; then
    echo "- LARAVEL_PROJECT_ROOT: ${LARAVEL_PROJECT_ROOT}" >&2
  fi
  if [[ -n "${SITE_PATH:-}" ]]; then
    echo "- SITE_PATH (env): ${SITE_PATH}" >&2
  fi
  echo "- SITE_PATH (resolved): ${project_dir}" >&2
  echo "- php_bin: ${php_bin}" >&2
  echo "- herd_phar: ${herd_phar}" >&2
  exit 0
fi

export SITE_PATH="${project_dir}"
exec "$php_bin" "$herd_phar"
Enter fullscreen mode Exit fullscreen mode

Combined mcp_config.json example (Boost + Herd)

This is how your MCP config can look with both servers configured (same schema, different file location depending on Windsurf Editor vs JetBrains plugin):

{
  "mcpServers": {
    "laravel-boost": {
      "command": "/Users/<you>/.codeium/laravel-boost-mcp.sh",
      "args": ["${workspaceFolder}"],
      "disabled": false,
      "env": {}
    },
    "herd": {
      "command": "bash",
      "args": [
        "/Users/<you>/.codeium/herd-mcp.sh",
        "${workspaceFolder}"
      ],
      "disabled": false,
      "env": {}
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Windows Setup (PowerShell)

Windsurf on Windows can also launch MCP servers from an unexpected working directory. The fix is the same idea: use a wrapper.

Step 1: Create the wrapper script

Create:

  • C:\Users\<you>\.codeium\laravel-boost-mcp.ps1

Step 2: Configure Windsurf MCP to run the script

Edit:

  • C:\Users\<you>\.codeium\windsurf\mcp_config.json

Add:

{
  "mcpServers": {
    "laravel-boost": {
      "command": "powershell.exe",
      "args": [
        "-NoProfile",
        "-ExecutionPolicy",
        "Bypass",
        "-File",
        "C:\\Users\\<you>\\.codeium\\laravel-boost-mcp.ps1",
        "${workspaceFolder}"
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Restart/refresh MCP servers in Windsurf

Refresh MCP servers (or restart Windsurf).


Final Windows PowerShell wrapper script (well-commented)

Save as: C:\Users\<you>\.codeium\laravel-boost-mcp.ps1

<#
A robust wrapper to start Laravel Boost MCP in Windsurf on Windows.

Why this exists:
- Windsurf may start MCP servers from a non-project directory.
- `php artisan boost:mcp` fails if it can’t find `artisan`.

What this script does:
1) Finds a Laravel project root by walking up directories looking for `artisan`.
2) Falls back to SITE_PATH if provided.
3) Finds a usable php binary.
4) Runs `php artisan boost:mcp` inside the detected project.

Usage:
- Check mode:
  .\laravel-boost-mcp.ps1 --check
#>

param(
  [Parameter(ValueFromRemainingArguments=$true)]
  [string[]]$Args
)

function Find-ArtisanDir([string]$StartDir) {
  $dir = Resolve-Path $StartDir

  while ($true) {
    if (Test-Path (Join-Path $dir 'artisan')) {
      return $dir
    }

    $parent = Split-Path $dir -Parent
    if ($parent -eq $dir) {
      return $null
    }

    $dir = $parent
  }
}

function Find-Php() {
  # Prefer php on PATH
  $php = Get-Command php -ErrorAction SilentlyContinue
  if ($php) { return $php.Source }

  # Common candidates
  $candidates = @(
    "C:\\Program Files\\PHP\\php.exe",
    "C:\\PHP\\php.exe"
  )

  foreach ($c in $candidates) {
    if (Test-Path $c) { return $c }
  }

  return $null
}

$startDir = Get-Location
$artisanDir = $null
$checkMode = $false
$rootArg = $null

 # Support: --check [<workspaceFolder>]
 if ($Args.Count -gt 0 -and $Args[0] -eq '--check') {
   $checkMode = $true
   if ($Args.Count -gt 1) {
     $Args = $Args[1..($Args.Count - 1)]
   } else {
     $Args = @()
   }
 }

 if ($Args.Count -gt 0) {
   $rootArg = $Args[0]
 }

 # 1) If Windsurf passed the project path explicitly (via ${workspaceFolder}), use it first
 if ($rootArg -and $rootArg -ne '${workspaceFolder}' -and (Test-Path $rootArg)) {
   $artisanDir = Find-ArtisanDir $rootArg
 }

 # 2) Try from current directory
 if (-not $artisanDir) {
   $artisanDir = Find-ArtisanDir $startDir
 }

 # 3) Fallback to SITE_PATH if provided
 if (-not $artisanDir -and $env:SITE_PATH) {
   $artisanDir = Find-ArtisanDir $env:SITE_PATH
 }

if (-not $artisanDir) {
  Write-Error "laravel-boost MCP: could not find artisan. Starting directory: $startDir"
  if ($env:SITE_PATH) { Write-Error "SITE_PATH: $($env:SITE_PATH)" }
  exit 1
}

$phpBin = Find-Php
if (-not $phpBin) {
  Write-Error "laravel-boost MCP: php binary not found. Ensure PHP is installed and available in PATH."
  exit 1
}

 if ($checkMode) {
   Write-Host "laravel-boost MCP wrapper check"
   Write-Host "- starting directory: $startDir"
   if ($rootArg) { Write-Host "- root_arg: $rootArg" }
   if ($env:SITE_PATH) { Write-Host "- SITE_PATH: $($env:SITE_PATH)" }
   Write-Host "- artisan_dir: $artisanDir"
   Write-Host "- php_bin: $phpBin"
   exit 0
 }

Set-Location $artisanDir
& $phpBin artisan boost:mcp
Enter fullscreen mode Exit fullscreen mode

Troubleshooting

Symptom Likely cause Fix
Could not open input file: ./artisan MCP server started outside project root Use the wrapper script (it finds artisan by walking up directories)
“Cannot initialize server” never changes Edited the wrong MCP config file Verify the config path; use the temporary “invalid command” test above
MCP starts, but Boost tools are missing Boost not installed in that project composer require laravel/boost --dev in the target project
php artisan boost:mcp fails in terminal Laravel app can’t boot Fix the underlying Laravel error first (env/config/extensions)
Wrong PHP version / missing extensions Windsurf uses PATH PHP, not project PHP
Wrong project info returned (multi-project) MCP server reused across projects, or wrapper guessed the wrong root
Auto-detection doesn’t work python3 not available

Quick checks

  • Run ~/.codeium/laravel-boost-mcp.sh --check and confirm the resolved artisan_dir is the correct project.

- If you use Herd, confirm herd which-php matches what you expect in that directory.

Summary

  • Windsurf MCP servers can fail if started from the wrong working directory.
  • A wrapper script that finds artisan and a working php makes Boost reliable.
  • Configure Windsurf to run the wrapper instead of php artisan boost:mcp directly.

What this teaches us about AI tooling (meta takeaway)

This isn’t unique to Windsurf or Boost.
Any AI tool that shells out to a project-specific CLI will eventually hit the same class of issues:

  • The tool assumes cwd is the project root.
  • The tool assumes the runtime (PHP, Node, Python, etc.) matches the project.

The durable solution is the same pattern you used here: create an adaptive entrypoint that can find the project, select the right runtime, and print diagnostics when things go wrong.

If this helped, consider sharing your wrapper suggestions and or improvements back to the community.

Top comments (0)