MCP server
Pasting an export is fine, but it goes stale the moment your next migration runs. The Truss MCP server lets an agent that speaks the Model Context Protocol (Claude Code, Cursor, and others) query your current schema on demand instead. It is read-only and structure only by construction: it answers with structure, it never returns row data, and there is no AI inside Truss.
Install and start
The server is optional and adds no required dependency. Opt in by installing the first-party laravel/mcp package, then start the server:
composer require laravel/mcpphp artisan mcp:start trussTruss registers the server itself, so there is nothing to add to routes/ai.php. It is enabled by default once laravel/mcp is installed; set truss.mcp.enabled to false to turn it off.
Connect your client
Point your MCP client at the local command. For Claude Code or Cursor, which run inside your project, add a stdio server to your MCP config with the short form:
{ "mcpServers": { "truss": { "command": "php", "args": ["artisan", "mcp:start", "truss"] } }}Claude Desktop
Claude Desktop launches the server from its own working directory with a minimal environment, so it does not see your shell’s PATH or your project folder. Use absolute paths for both the PHP binary and artisan, and pass any environment the app needs. Edit claude_desktop_config.json (Settings, Developer, Edit Config; on macOS it lives at ~/Library/Application Support/Claude/claude_desktop_config.json):
{ "mcpServers": { "truss": { "command": "/absolute/path/to/php", "args": ["/absolute/path/to/your/app/artisan", "mcp:start", "truss"], "env": { "APP_ENV": "local" } } }}Find the paths with which php and the app’s pwd, then fully quit and reopen Desktop. The truss tools then appear in the tools list. If it does not connect, check ~/Library/Logs/Claude/mcp*.log; the usual causes are a wrong php path or a missing environment variable the app needs to boot.
The tools declare themselves read-only (they advertise the MCP readOnlyHint), so a client that surfaces that hint can present them as read-only rather than prompting for write approval on every call.
Tools and resource
The server exposes five tools and one resource, all read-only and structure only:
| Name | What it returns |
|---|---|
list_tables | Every table with a one-line structural summary (column count, whether it has a primary key, foreign-key count) |
describe_table | One table’s columns, primary key, indexes, foreign keys, and annotations |
get_schema | The whole structure in any format (dbml, json, csv, markdown, mermaid, llm), optionally compact or limited to some tables |
focus_table | A table and its foreign-key neighbourhood, out to a given depth |
get_structural_review | The deterministic truss:doctor findings for the schema |
The resource truss://schema is the “read the whole thing” convenience: the entire structure as one compact, annotated document.
Each tool takes an optional connection argument and reads the same annotations you configure for the export, so the meaning you declare shows up here too.
The same guarantees, everywhere
Every tool drives the same engine as the CLI and the facade, so it inherits every safeguard automatically:
- Structure only, never data. Proven by the same canary test that guards the exports.
- Excluded tables stay excluded.
truss.excluded_tablesis stripped before anything is returned, so an excluded table can never surface through a tool or the resource. - Only managed connections. A connection you have not configured under
truss.connectionsis rejected.
The web (HTTP) transport is a planned follow-up; today the server runs over local stdio, which adds no new remote surface and no new authentication question. To build context without a running server, see Truss as AI context.