Skip to content

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:

Terminal window
composer require laravel/mcp
php artisan mcp:start truss

Truss 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:

NameWhat it returns
list_tablesEvery table with a one-line structural summary (column count, whether it has a primary key, foreign-key count)
describe_tableOne table’s columns, primary key, indexes, foreign keys, and annotations
get_schemaThe whole structure in any format (dbml, json, csv, markdown, mermaid, llm), optionally compact or limited to some tables
focus_tableA table and its foreign-key neighbourhood, out to a given depth
get_structural_reviewThe 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_tables is 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.connections is 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.