{
  "markdown": "# Laravel MCP Companion\n*formerly Laravel Docs MCP Server*\n\n[![GitHub release (latest by date)](https://img.shields.io/github/v/release/brianirish/laravel-mcp-companion)](https://github.com/brianirish/laravel-mcp-companion/releases)\n[![Python Version](https://img.shields.io/badge/python-3.12%2B-blue)](https://www.python.org/downloads/)\n[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/brianirish/laravel-mcp-companion/ci.yaml?branch=main&label=tests)](https://github.com/brianirish/laravel-mcp-companion/actions/workflows/ci.yaml)\n[![codecov](https://codecov.io/gh/brianirish/laravel-mcp-companion/graph/badge.svg?token=VC93Y921KR)](https://codecov.io/gh/brianirish/laravel-mcp-companion)\n[![License](https://img.shields.io/github/license/brianirish/laravel-mcp-companion)](https://github.com/brianirish/laravel-mcp-companion/blob/main/LICENSE)\n[![Docker Image](https://img.shields.io/badge/docker-ghcr.io-blue)](https://github.com/brianirish/laravel-mcp-companion/pkgs/container/laravel-mcp-companion)\n[![GitHub Stars](https://img.shields.io/github/stars/brianirish/laravel-mcp-companion?style=social)](https://github.com/brianirish/laravel-mcp-companion)\n[![GitHub Forks](https://img.shields.io/github/forks/brianirish/laravel-mcp-companion?style=social)](https://github.com/brianirish/laravel-mcp-companion)\n\n> ⚠️ **BETA SOFTWARE** - This project is in active development. Features may change and breaking changes may occur.\n\n**Laravel MCP Companion** is a documentation aggregator and navigator for the Laravel ecosystem. It centralizes and organizes high-quality documentation from across the Laravel ecosystem, making it easily discoverable through your AI assistant.\n\n## How It Compares\n\n| Feature | [Laravel Boost](https://github.com/laravel/boost) | Context7 | Laravel MCP Companion |\n|---------|:--------:|:--------:|:--------------------:|\n| **Focus** | Code generation | General docs | Laravel documentation |\n| **Best for** | Active development | Any library | Learning & reference |\n| **Project-aware context** | ✅ | ❌ | ❌ |\n| **Laravel multi-version support** (6.x - latest) | ❌ | ❌ | ✅ |\n| **Laravel service docs** (Forge, Vapor, Nova, Envoyer) | ❌ | ❌ | ✅ |\n| **Learning paths & difficulty levels** | ❌ | ❌ | ✅ |\n| **\"I need X\" documentation finder** | ❌ | ❌ | ✅ |\n| **Curated Laravel package recommendations** | ❌ | ❌ | ✅ |\n| **Offline documentation access** | ❌ | ❌ | ✅ |\n| **TOON format output** (30-60% fewer tokens) | ❌ | ❌ | ✅ |\n| **General documentation** (non-Laravel) | ❌ | ✅ | ❌ |\n\n**Use Boost** when writing code and you need project-aware context. **Use Context7** for non-Laravel libraries. **Use Companion** when learning, researching, or need Laravel documentation reference.\n\n### What you get:\n- **Multi-version Laravel documentation** (6.x through latest) with enhanced search\n- **Learning paths** - Structured learning sequences by topic and skill level\n- **\"I need X\" finder** - Describe what you need, get relevant documentation\n- **Difficulty filtering** - Content organized by beginner/intermediate/advanced\n- **15 semantic categories** - Browse documentation by topic area\n- **Auto-discovery Laravel services** - Forge, Vapor, Envoyer, Nova (117+ sections)\n- **Community package documentation** - 42,000+ lines from Spatie, Livewire, Inertia, Filament\n- **Package integration guides** - Installation and setup for 22 curated packages\n- **Cross-package compatibility** - Learn which packages work well together\n- **Unified search** across core Laravel docs, services, packages, and learning resources\n- **Daily updates** - Automatically syncs with latest documentation\n\n## Installation\n\nListed in the [official MCP Registry](https://registry.modelcontextprotocol.io/?search=laravel-mcp-companion)\nas `io.github.brianirish/laravel-mcp-companion` — clients with registry\nsupport can install it from there directly. Manual setup:\n\n### Claude Desktop\n\n1. **Open Claude Desktop Settings**\n   - Click Claude menu → Settings → Developer → Edit Config\n\n2. **Add to your configuration file:**\n   ```json\n   {\n     \"mcpServers\": {\n       \"laravel-mcp-companion\": {\n         \"command\": \"docker\",\n         \"args\": [\"run\", \"--rm\", \"-i\", \"ghcr.io/brianirish/laravel-mcp-companion:latest\"]\n       }\n     }\n   }\n   ```\n\n3. **Restart Claude Desktop** for changes to take effect\n\n**Config file locations:**\n- Windows: `%APPDATA%\\Claude\\claude_desktop_config.json`\n- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`\n\n### Claude Code\n\nUse the `claude mcp add` command:\n\n```bash\n# Add with Docker\nclaude mcp add laravel-mcp-companion -- docker run --rm -i ghcr.io/brianirish/laravel-mcp-companion:latest\n\n# Or add to project-specific config (for team sharing)\nclaude mcp add laravel-mcp-companion --scope project -- docker run --rm -i ghcr.io/brianirish/laravel-mcp-companion:latest\n```\n\nThe `--scope project` option creates a `.mcp.json` file in your project root that can be committed to version control.\n\n### Configuration Options\n\nThese options can be used with the Docker command. For example:\n\n```bash\n# Pin to a specific older Laravel version\ndocker run --rm -i ghcr.io/brianirish/laravel-mcp-companion:latest --version 11.x\n\n# Force update all documentation\ndocker run --rm -i ghcr.io/brianirish/laravel-mcp-companion:latest --force-update\n```\n\n| Option | Description | Default |\n|--------|-------------|---------|\n| `--version VERSION` | Laravel version (e.g., \"11.x\", \"12.x\") | Latest |\n| `--docs-path PATH` | Documentation directory | `./docs` |\n| `--log-level LEVEL` | DEBUG, INFO, WARNING, ERROR, CRITICAL | INFO |\n| `--update-docs` | Update documentation on startup | false |\n| `--force-update` | Force documentation update | false |\n| `--transform-mode MODE` | Tool exposure mode: `search`, `code`, or `none` (env: `TRANSFORM_MODE`) | search |\n| `--host HOST` | Interface to bind in HTTP mode (env: `HOST`) | `127.0.0.1` (`0.0.0.0` in Docker) |\n| `--cors-origin ORIGIN` | Browser origin allowed to call the HTTP transport, repeatable (env: `CORS_ORIGINS`) | none (CORS off) |\n| `--allowed-host HOST` | Additional `Host` header accepted in HTTP mode, repeatable (env: `ALLOWED_HOSTS`) | `localhost`, `127.0.0.1`, `::1` |\n| `--auth-jwks-uri URI` | JWKS endpoint enabling bearer-token auth in HTTP mode (env: `AUTH_JWKS_URI`) | none (auth off) |\n| `--auth-issuer ISSUER` | Required token issuer, with `--auth-jwks-uri` (env: `AUTH_ISSUER`) | none |\n| `--auth-audience AUD` | Required token audience, with `--auth-jwks-uri` (env: `AUTH_AUDIENCE`) | none |\n| `--auth-required-scope SCOPE` | Scope every token must carry, repeatable (env: `AUTH_REQUIRED_SCOPES`) | none |\n| `--rate-limit RPS` | MCP requests/second accepted in HTTP mode; operational endpoints are never limited (env: `RATE_LIMIT_RPS`) | none (no limiting) |\n| `--rate-limit-burst N` | Token-bucket burst capacity (env: `RATE_LIMIT_BURST`) | `max(10, 2×RPS)` |\n\n### Keeping documentation current\n\nDocumentation ships inside the image, and a new image is published whenever the\ndocumentation is refreshed, so `:latest` carries the most recently published\nsnapshot. The catch is that **`docker run` reuses the copy you already have** —\nonce you've pulled the image, you keep running it until you pull again. Refresh\nwhenever you like:\n\n```bash\ndocker pull ghcr.io/brianirish/laravel-mcp-companion:latest\n```\n\nOr add `--pull=always` to your MCP config so every start checks for a newer image.\nIt costs a moment of startup time and needs a working connection, so it's opt-in\nrather than the default:\n\n```jsonc\n\"args\": [\"run\", \"--rm\", \"-i\", \"--pull=always\",\n         \"ghcr.io/brianirish/laravel-mcp-companion:latest\"]\n```\n\nYou don't have to track this yourself. The server tells your assistant how old the\ndocumentation is for the Laravel version it's serving, so if you ask about something\nnewer than that snapshot it will say so and offer to refresh instead of answering\nfrom stale pages. You can also just ask — *\"how current are your Laravel docs?\"*\n\nTo update in place without pulling a new image, `--update-docs` fetches fresh\ndocumentation for the selected Laravel version during startup. Documentation for\nForge, Vapor, Nova, Envoyer and community packages refreshes separately, through the\n`update_external_laravel_docs` tool your assistant can call.\n\nWith `--rm` the download is discarded when the container exits, so it repeats on\nevery start. A named volume keeps it — but note the trade-off:\n\n```bash\ndocker run --rm -i -v laravel-mcp-docs:/app/docs \\\n  ghcr.io/brianirish/laravel-mcp-companion:latest --update-docs\n```\n\n> **A volume overrides the image's documentation.** Once populated it masks\n> `/app/docs`, so pulling a newer image no longer updates what the server reads —\n> the volume becomes your source of truth and `--update-docs` becomes the way you\n> refresh it. Use a volume when you want to control updates explicitly; stick to\n> plain `docker pull` if you'd rather the image stay in charge.\n\n### Transform Modes\n\nBy default the server no longer lists all of its tools. Instead it exposes a compact, search-first interface that keeps your AI client's context window lean:\n\n- **`search`** (default) — Exposes `search_tools` (BM25 relevance search over the tool catalog) and `call_tool` (proxy to invoke any underlying tool). `search_laravel_docs` stays pinned and directly callable.\n- **`code`** (experimental) — Exposes Code Mode meta-tools (`tags`, `search`, `get_schema`, `execute`) that let the client discover tools and orchestrate them with sandboxed Python. Requires the `fastmcp[code-mode]` extra (included in `requirements.txt`). Avoid exposing this publicly over HTTP — `execute` is a code execution endpoint.\n- **`none`** — Pre-0.9 behavior: every tool listed directly. Use this if your MCP client doesn't handle the synthetic search tools well.\n\n```bash\n# Restore the old flat tool listing\ndocker run --rm -i ghcr.io/brianirish/laravel-mcp-companion:latest --transform-mode none\n```\n\n### HTTP transport security\n\n**Authentication is off by default.** Anyone who can reach the HTTP port can call every tool, so treat network exposure as granting full access to the documentation tree — or turn on bearer-token auth:\n\n```bash\n# Validate tokens issued by a real OAuth 2.1 authorization server\npython laravel_mcp_companion.py --transport http \\\n  --auth-jwks-uri https://auth.example/.well-known/jwks.json \\\n  --auth-issuer https://auth.example \\\n  --auth-audience laravel-mcp-companion\n\n# Development only: fixed tokens from the environment (never a CLI flag,\n# so secrets stay out of process listings)\nAUTH_STATIC_TOKENS=\"my-token:my-client\" python laravel_mcp_companion.py --transport http\n```\n\nThe server is a *resource server*: it validates tokens, it never issues them.\nIssuer and audience are mandatory with `--auth-jwks-uri` — accepting any\nissuer's tokens, or tokens minted for another service, would be authentication\ntheater. Unauthenticated requests get `401` with a `WWW-Authenticate` header\n(RFC 9728), and misconfiguration fails at startup rather than at request time.\nAuth applies to the HTTP transport only; stdio's access control is the process\nboundary.\n\nDefaults are conservative:\n\n- **Binds `127.0.0.1`** outside Docker. Inside the container it binds `0.0.0.0`, where the container boundary and explicit `-p` publishing are the access control.\n- **Host and Origin validation is on**, which blocks DNS-rebinding and drive-by-localhost attacks from a victim's browser.\n- **CORS is disabled** unless you pass `--cors-origin`. Wildcard origins are rejected; credentials are never allowed cross-origin.\n\nOnly `localhost`, `127.0.0.1`, and `::1` are accepted as `Host` values out of the box. **If you bind a non-loopback interface you must add the hostname clients actually use**, or every request is rejected with `421`:\n\n```bash\npython laravel_mcp_companion.py --transport http \\\n  --host 0.0.0.0 \\\n  --allowed-host mcp.internal.example \\\n  --cors-origin https://app.example\n```\n\nRequests with an unrecognized `Host` get `421`; requests from an unlisted `Origin` get `403`. Passing `--allowed-host` or `--cors-origin` on the command line replaces the corresponding environment variable rather than adding to it. If you expose this beyond localhost, put an authenticating reverse proxy in front of it. Avoid `--transform-mode code` over HTTP entirely — `execute` is a code execution endpoint.\n\n### Rate limiting (HTTP mode)\n\nOff by default. `--rate-limit 20` caps **MCP requests** — tool calls,\nsearches, the protocol surface — at 20/second with a single global token\nbucket: a total throughput cap, not per-client fairness (without auth there\nis no reliable client identity to key on). The operational endpoints\n(`/healthz`, `/metrics`, `/.well-known/...`) are deliberately outside the\nlimit: throttling a load balancer's health checks marks healthy instances\ndown, and those handlers are trivial reads. The limit counts every MCP\nrequest including the initialize handshake, which is why the burst default\nstays at `max(10, 2×RPS)`; keep the burst comfortably above your clients'\nhandshake size if you lower it. Throttled requests receive a clean MCP error\nand succeed again once the bucket refills.\n\n### Operational endpoints (HTTP mode)\n\n- **`GET /healthz`** — liveness/readiness JSON, always public (load balancers\n  can't do OAuth). `ok` and `degraded` both return 200 — degraded means the\n  documentation copy is stale and a newer image should be pulled; 503 means no\n  documentation is readable and traffic should not be routed here.\n- **`GET /metrics`** — Prometheus text format: per-tool call counters, a\n  latency histogram, request counts, uptime, and documentation age. Public on\n  unauthenticated deployments; requires a valid bearer token whenever auth is\n  configured.\n\n\n## Features (v0.13.0)\n\n### Documentation Aggregation\n- **Multi-version Laravel docs** - All versions from 6.x to latest\n- **Auto-discovery engine** - Finds new docs across Forge, Vapor, Nova, Envoyer\n- **Community package docs** - 42,000+ lines from Spatie, Livewire, Inertia, Filament\n- **Daily updates** - Automatic sync with latest documentation\n\n### Learning & Discovery\n- **Learning paths** - Structured sequences for any Laravel topic, offered\n  interactively: ask without naming one and the server asks which of the ten\n  curated paths you want\n- **Difficulty levels** - Filter by beginner, intermediate, or advanced\n- **15 categories** - Browse by authentication, database, testing, etc.\n- **\"I need X\" finder** - Natural language documentation discovery\n- **Related resources** - Find connected documentation automatically\n\n### Search & Navigation\n- **Ranked section search** - Ask in plain language (\"how do I retry a failed\n  queue job\") and get the relevant *sections* ranked by relevance, each with a\n  snippet, an anchor, and a source label\n- **Section-level reads** - Fetch just the section you need. A whole\n  documentation file can exceed 30,000 tokens; a section is typically a few\n  hundred, so answers leave room for your actual code\n- **Use case mapping** - Describe what you need, get relevant packages\n- **Package integration guides** - Installation and setup for 22 curated packages\n- **Cross-package compatibility** - Documentation for package combinations\n- **Unified search** - One search across every corpus: core versions,\n  services, fetched package docs, and learning resources, with a `sources`\n  filter to narrow it\n\n### MCP 2025-11-25 capabilities\n- **Task-capable updates** - Documentation updates run as MCP tasks: submit,\n  poll, fetch the result, instead of holding the connection for minutes\n- **Structured output** - Tabular tools return `structuredContent` with real\n  schemas alongside their TOON text\n- **Elicitation** - Interactive choices where they help, with plain listings\n  as the fallback for clients without the capability\n- **Registry listed** - Installable from the [official MCP Registry](https://registry.modelcontextprotocol.io/?search=laravel-mcp-companion),\n  with `server.json` metadata, `.well-known` discovery in HTTP mode, and\n  automated publishing on release tags\n\n### Production Operations (HTTP mode)\n- **Health & metrics** - `GET /healthz` for load balancers and a Prometheus\n  `GET /metrics` with per-tool counters, latency histogram, and docs age\n- **OAuth 2.1 resource server** - Optional bearer-token validation (JWKS or\n  static dev tokens); misconfiguration fails at startup, outages fail closed\n- **Rate limiting** - Opt-in token bucket over the MCP surface with a\n  handshake-aware burst default\n- **Hardened by default** - Loopback bind, Host/Origin validation, no\n  wildcard CORS, path containment enforced identically for search, listing,\n  and reads\n\n### Quality\n- **81% product coverage** with an 80% CI gate, end-to-end tests over real\n  stdio and HTTP transports, and report-only latency benchmarks — warm\n  search p95 is a few milliseconds against the 100ms v1.0.0 target\n\n### Upcoming\n- **v1.0.0**: First stable release — API freeze, breaking-change policy,\n  and an LTS commitment\n\nFor detailed roadmap information, see [ROADMAP.md](ROADMAP.md).\n\n## TOON Format Output\n\nLaravel MCP Companion uses [TOON (Token-Oriented Object Notation)](https://github.com/toon-format/toon) for structured output, saving **30-60% on tokens** compared to JSON/markdown.\n\n### Example Output\n\nWhen you search for packages or list documentation, you get efficient structured data:\n\n```\ncontext: \"authentication for SPA\"\ncount: 2\npackages[2]{id,name,description,categories,install}:\n  laravel/sanctum,Laravel Sanctum,\"Featherweight authentication for SPAs\",[authentication,spa],\"composer require laravel/sanctum\"\n  laravel/passport,Laravel Passport,\"Full OAuth2 implementation\",[authentication,api],\"composer require laravel/passport\"\n```\n\nCompare to the equivalent JSON (nearly 2x the tokens):\n\n```json\n{\"context\":\"authentication for SPA\",\"count\":2,\"packages\":[{\"id\":\"laravel/sanctum\",\"name\":\"Laravel Sanctum\",...}]}\n```\n\n### Why TOON?\n\n- **Token efficient**: LLMs understand TOON natively - no parsing overhead\n- **Structured data**: Arrays, objects, and metadata without JSON verbosity\n- **AI-friendly**: Designed specifically for LLM context windows\n\n## Auto-Discovery & Update Frequency\n\nThis application features an **intelligent auto-discovery system** that automatically finds and indexes Laravel documentation. Every day, it:\n\n- **Auto-discovers** new documentation sections across Laravel services (Forge, Vapor, Nova, Envoyer)\n- **Retrieves** the latest Laravel core documentation for all versions since 6.x\n- **Fetches** community package documentation (Spatie, Livewire, Inertia, Filament)\n- **Adapts** automatically to structural changes in documentation websites\n- **Generates** new patch releases automatically when updates are found\n\n## Development\n\n### Prerequisites\n- Python 3.12+\n- Node.js 18+ (for MCP Inspector)\n\n### Setup\n```bash\ngit clone https://github.com/brianirish/laravel-mcp-companion\ncd laravel-mcp-companion\npython -m venv venv\nsource venv/bin/activate  # Windows: venv\\Scripts\\activate\npip install -r requirements.txt -r requirements-dev.txt\n```\n\n### Running Tests\n```bash\n# All tests with coverage\npytest --cov --cov-report=html\n\n# Unit tests only\npytest tests/unit/\n\n# Integration tests only\npytest tests/integration/\n\n# Protocol compliance tests\npytest tests/protocol/ -m protocol\n```\n\n### Manual Testing with MCP Inspector\nThe [MCP Inspector](https://github.com/modelcontextprotocol/inspector) provides a visual UI for testing MCP servers.\n\n```bash\n# Launch Inspector (opens browser at http://localhost:6274)\nnpx @modelcontextprotocol/inspector python laravel_mcp_companion.py\n\n# With specific version\nnpx @modelcontextprotocol/inspector python laravel_mcp_companion.py --version 11.x\n```\n\nUse the Inspector to:\n- **Tools tab**: Test all tools with auto-generated input forms\n- **Resources tab**: Browse `laravel://` and `laravel-external://` resources\n- **Prompts tab**: Test prompt templates\n\n### Code Quality\n```bash\nruff check --fix .     # Linting\nmypy --ignore-missing-imports .  # Type checking\nblack .                # Formatting\n```\n\n## License\n\nThis project is licensed under the MIT License - see the LICENSE file for details.\n\n## Contributing\n\nContributions are welcome! See CONTRIBUTING.md for guidelines.\n\n## Acknowledgements\n\n- Laravel for their excellent documentation\n- Laravel package authors for their contributions to the ecosystem\n",
  "bytes": 20434,
  "sha": "efa1935756913e69fb0093dc27f7e17855f2775cc85b70c93ebb9ef45e4e75cf",
  "repo_slug": "brianirish/laravel-mcp-companion",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_brianirish_laravel_mcp_compani_be872d6f/readme"
}