mcp-artisan
Provides read-only introspection of a Laravel application, including routes, migrations, models, jobs, config values, and composer dependencies, with structural guarantees against mutation, secret disclosure, and path escape.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-artisanwhat jobs run on the payments queue?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-artisan
Point an AI agent at a Laravel codebase and ask it to explain the routes, the
data model, the queued jobs, or a config value — without giving it any way to
change the code, run a console command, or read a secret. mcp-artisan is a
Model Context Protocol server that exposes a Laravel project to an agent
read-only. The interesting part is not the list of things it can report; it
is that the things it cannot do are enforced structurally, not by convention.
The server runs over stdio, speaks MCP, and needs no framework installed and no LLM API key. It works against a project whether or not PHP is present on the machine.
The problem
An agent is genuinely useful on a large PHP application: "which routes are
unauthenticated?", "what does the orders table look like?", "which jobs run on
the payments queue?". But the moment you hand a general-purpose agent a shell
and a project directory to answer those questions, you have also handed it the
ability to run php artisan migrate:fresh, read .env, or edit a controller.
On a production or legacy codebase that trade is unacceptable, so the questions
go unanswered or a human does the archaeology by hand.
The useful shape is a tool that can only look. mcp-artisan gives an agent a
faithful, bounded map of the application and makes mutation impossible by
construction — there is no write path and no arbitrary-command path to abuse.
Related MCP server: Local Code MCP Server
Threat model
The assumed adversary is the agent itself: a capable, possibly-confused, or prompt-injected LLM that will call any tool it is offered with any argument it can construct. The design goal is that no sequence of tool calls can change the project, exfiltrate a secret, or read a file outside the project root.
What that means in practice, and where each guarantee lives:
No mutation. The server exposes no tool that writes. The static backend only ever opens files for reading; the artisan backend only ever runs verbs from a frozen allowlist (
route:list,migrate:status,about), all of which are read-only. The allowlist is checked before a subprocess is created (mcp_artisan/artisan_backend.py), so a request formigrateortinkernever reachesphp.No arbitrary commands. Artisan verbs are constants in the code, never built from tool input. The subprocess is invoked with a fixed argument vector (no shell), so there is nothing to inject into, and each call has a hard wall-clock timeout.
No secret disclosure.
.envis never read. Config values come fromconfig/*.php, and every value is passed through key-based redaction (mcp_artisan/redaction.py): a key matchingpassword,secret,token,key,dsn, and similar returns<redacted>, including nested keys inside a returned subtree. Redaction is deliberately broad — it prefers hiding a harmless value to leaking a credential.No path escape. Every filesystem read is funnelled through one containment check (
mcp_artisan/paths.py) that resolves the real path and rejects anything outside the configured project root, including via a crafted config key or a symlink that points out of the tree.
Every one of these is covered by a negative test; see
tests/test_paths.py, tests/test_config_redaction.py,
tests/test_artisan_backend.py, and tests/test_server_protocol.py.
What is explicitly out of scope: this is not a sandbox for the agent's other tools, and it does not defend against a compromised host or a malicious PHP runtime. It hardens the one surface it owns — introspection of the codebase.
Tools and resources
Tools (all read-only):
Tool | Returns |
| Counts and versions, in one call, for cheap orientation. |
| Every route: methods, URI, name, middleware, |
| One route by name or URI. |
| Migration files on disk, plus applied/pending state when a database is reachable. |
| Eloquent models: table, |
| Queued job classes with |
| Dotted config lookup with mandatory secret redaction. |
| Direct requires with versions, plus Laravel and PHP versions. |
Resources: laravel://routes, laravel://schema, laravel://composer — the
same data as JSON documents, for clients that prefer resources to tool calls.
Two backends, auto-detected
static (default, and the only one used in CI). Pure parsing of
composer.json,routes/*.php,database/migrations/*.php,app/Models/*.php,app/Jobs/*.php, andconfig/*.php. Requires no PHP.artisan. Used only when
phpis onPATHandphp artisan aboutsucceeds. Routes and migration status then come fromroute:list --jsonandmigrate:status, which are exact where the static parser is best-effort. Models, jobs, config, and composer data stay static even here — no read-only artisan verb exposes them.
The backend is chosen once at startup and reported in every response so an agent
knows how much to trust the data. Set MCP_ARTISAN_STATIC_ONLY=1 to force the
static backend even when PHP is available.
Usage
Install and run against a project:
pip install -e .
MCP_ARTISAN_PROJECT=/path/to/laravel-app python -m mcp_artisanOr register it with an MCP client (the entry point is the mcp-artisan
console script):
{
"mcpServers": {
"artisan": {
"command": "mcp-artisan",
"env": { "MCP_ARTISAN_PROJECT": "/path/to/laravel-app" }
}
}
}The project root defaults to the current working directory if
MCP_ARTISAN_PROJECT is unset.
Reproducing the numbers
This repository ships a small hand-built fixture Laravel app under
tests/fixtures/laravel-app (no framework was downloaded). Every count quoted
below is produced by a command here, not asserted in prose.
python scripts/demo.pyprints, for the fixture: 8 tools exposed, and a project_summary of
6 routes, 2 models, 2 migrations, 2 jobs, 3 direct dependencies, on the
static backend — followed by a redacted database password to show the masking.
The artisan allowlist is three verbs:
python -c "from mcp_artisan.artisan_backend import ALLOWED_VERBS; print(sorted(ALLOWED_VERBS))"
# ['about', 'migrate:status', 'route:list']The full test suite (unit tests for both backends, plus protocol-level tests that drive the server through an in-memory MCP client) runs with:
pip install -e ".[dev]"
pytestCI runs exactly this on every push (.github/workflows/ci.yml), with no PHP
installed and no secrets.
Design notes
Choices made in the interest of a smaller, safer, more predictable server. Where a fuller behaviour was possible, the simpler option was taken and recorded here.
The static route parser does not resolve
Route::groupprefixes/middleware,Route::resourceexpansion, or closures' internals. It parses top-levelRoute::<verb>statements and their chained->name()/->middleware(). This is a best-effort map; where exactness matters, the artisan backend provides the real route table. Closures are reported with an action ofClosure.The static backend cannot know which migrations have run — that needs a database connection. It lists the files and reports
applied/pendingas unknown rather than guessing. The artisan backend fills in real status.The config parser understands a subset of PHP: scalars, arrays (both
[...]andarray(...)),env()(evaluated as its default argument only, since.envis never read), string concatenation, andClass::class. Anything it cannot evaluate —storage_path(), closures, other calls — resolves tonullrather than raising. It never executes PHP.Redaction is keyed on the config key, not the value, because the key is the trustworthy signal. It over-redacts by design: a false positive hides a value the agent could have seen; a false negative leaks a credential.
composer_depsreports therequireblock only, notrequire-dev, since the target is the application's runtime dependency surface.Default model table names are derived with a small snake-case + pluralisation rule (
User→users,Category→categories). It covers the common cases, not every English irregular; models with an explicit$tableare always exact.Jobs are read from
app/Jobsonly. Queueable classes elsewhere are not discovered by the static backend.The backend is selected once at startup, not per call, so a project does not flip between backends mid-session.
Layout
mcp_artisan/
paths.py project-root resolution and the path-containment check
redaction.py key-based secret redaction
phpparse.py defensive parser for the PHP subset in config/routes/models
static_backend.py source-only parsers (the default backend)
artisan_backend.py guarded, allowlisted php-artisan subprocess backend
service.py backend selection and the per-tool responses
server.py the MCP tool/resource surface over stdio
tests/
fixtures/laravel-app/ hand-built minimal Laravel app
test_*.py unit, protocol, and negative safety testsRequirements
Python 3.12+. The only runtime dependency is the official mcp SDK. PHP is
optional and only enables the artisan backend.
License
MIT.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityCmaintenanceProvides secure and efficient tools for codebase analysis, including file management, metadata retrieval, and dependency tree traversal. It allows LLMs to explore project structures and search for configuration files within a restricted root directory.Last updated213MIT
- FlicenseBqualityDmaintenanceProvides LLMs with safe, read-only access to local codebases for searching, reading files, and finding function definitions. All source code remains local, ensuring privacy while enabling AI assistants to explore project structures and functionality.Last updated4
- FlicenseAqualityDmaintenanceProvides AI assistants with direct access to Laravel documentation, coding rules, and implementation templates stored locally. It enables searching documentation, retrieving design system guides, and accessing domain-specific code examples to streamline Laravel development.Last updated8
- Alicense-qualityCmaintenanceProvides AI agents with secure, read-only file system access to analyze and understand project codebases, enabling multi-repository context aggregation and cross-project code tracing.Last updated5MIT
Related MCP Connectors
Read-only tools over the Safer Agentic AI framework: 238 patterns + 14 heuristics.
Give your AI agent a persistent map of your project's structure, dependencies, and bugs.
Read-only bank access for your AI agent. Connects Claude, ChatGPT, Cursor, Gemini, Codex.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/0mandrock1/mcp-artisan'
If you have feedback or need assistance with the MCP directory API, please join our Discord server