@studiometa/forge-mcp
v0.3.0
Published
MCP server for Laravel Forge — Model Context Protocol integration for AI agents
Maintainers
Readme
@studiometa/forge-mcp
MCP (Model Context Protocol) server for Laravel Forge. Enables Claude Desktop and other MCP clients to manage servers, sites, deployments, and more through natural language.
Features
- Two tools with clear safety split —
forge(read) andforge_write(write) - MCP clients auto-approve
forgereads, always prompt forforge_writewrites - Resource/action routing from centralized constants
- Built-in help system —
action=helpfor any resource - Stdio and Streamable HTTP transports
- Configuration tools for interactive token setup
Installation
npm install -g @studiometa/forge-mcpClaude Desktop Configuration
Add to your Claude Desktop config:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%/Claude/claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"forge": {
"command": "forge-mcp",
"env": {
"FORGE_API_TOKEN": "your-api-token"
}
}
}
}Alternatively, omit the env block and ask Claude to configure credentials using the forge_configure tool.
Read-Only Mode
To guarantee no write operations are possible at the server level:
{
"mcpServers": {
"forge": {
"command": "forge-mcp",
"args": ["--read-only"],
"env": {
"FORGE_API_TOKEN": "your-api-token"
}
}
}
}Or via environment variable: FORGE_READ_ONLY=true.
When enabled, the forge_write tool is not registered at all — only forge, forge_configure, and forge_get_config are available.
Tools
forge — Read Operations
Safe, read-only queries. Annotated readOnlyHint: true so MCP clients can auto-approve.
Actions: list, get, resolve, context, help, schema
{ "resource": "servers", "action": "list" }
{ "resource": "servers", "action": "get", "id": "123" }
{ "resource": "sites", "action": "list", "server_id": "123" }
{ "resource": "servers", "action": "help" }
{ "resource": "servers", "action": "resolve", "query": "prod" }
{ "resource": "servers", "action": "context", "id": "123" }
{ "resource": "sites", "action": "context", "server_id": "123", "id": "456" }
{ "resource": "batch", "action": "run", "operations": [{ "resource": "servers", "action": "list" }, { "resource": "recipes", "action": "list" }] }forge_write — Write Operations
Mutating operations. Annotated destructiveHint: true so MCP clients always prompt for confirmation.
Actions: create, update, delete, deploy, reboot, restart, activate, run
{ "resource": "deployments", "action": "deploy", "server_id": "123", "site_id": "456" }
// deploy blocks until complete, returning: status, deployment log, elapsed time
{ "resource": "servers", "action": "reboot", "id": "123" }
{ "resource": "daemons", "action": "create", "server_id": "123", "command": "php artisan queue:work" }Resources & Actions
| Resource | Read Actions | Write Actions | Required Fields | | --------------- | --------------------------- | ------------------------ | -------------------------- | | servers | list, get, resolve, context | create, delete, reboot | id (for get/delete/reboot) | | sites | list, get, resolve, context | create, delete | server_id | | deployments | list, get | deploy, update | server_id, site_id | | env | get | update | server_id, site_id | | nginx | get | update | server_id, site_id | | certificates | list, get | create, delete, activate | server_id, site_id | | databases | list, get | create, delete | server_id | | database-users | list, get | create, delete | server_id | | daemons | list, get | create, delete, restart | server_id | | firewall-rules | list, get | create, delete | server_id | | ssh-keys | list, get | create, delete | server_id | | security-rules | list, get | create, delete | server_id, site_id | | redirect-rules | list, get | create, delete | server_id, site_id | | monitors | list, get | create, delete | server_id | | nginx-templates | list, get | create, update, delete | server_id | | scheduled-jobs | list, get | create, delete | server_id | | backups | list, get | create, delete | server_id | | commands | list, get | create | server_id, site_id | | recipes | list, get | create, delete, run | id (for get/delete/run) | | user | get | — | — | | batch | run | — | operations array |
Auto-Resolve: Names Instead of IDs
The server_id and site_id fields accept names in addition to numeric IDs. When a non-numeric value is provided, it is resolved automatically via partial, case-insensitive match against the list of resources.
server_id: "prod"→ resolves to the server whose name contains "prod" (must be unique)site_id: "example"→ resolves to the site whose domain contains "example" (requiresserver_id)
Use action: "resolve" explicitly when you want to search before committing to an ID:
{ "resource": "servers", "action": "resolve", "query": "prod" }
{ "resource": "sites", "action": "resolve", "server_id": "123", "query": "example" }Resolution fails (and returns an error) when the query matches zero or more than one resource — in that case, use the numeric ID directly.
Discovery
Use action: "help" with any resource, or action: "context" to fetch a resource and all its sub-resources in one call:
{ "resource": "servers", "action": "help" }
{ "resource": "deployments", "action": "help" }
{ "resource": "servers", "action": "context", "id": "123" }
{ "resource": "sites", "action": "context", "server_id": "123", "id": "456" }Use resource: "batch" to fan out multiple reads in a single round-trip (max 10 operations):
{
"resource": "batch",
"action": "run",
"operations": [
{ "resource": "servers", "action": "list" },
{ "resource": "sites", "action": "list", "server_id": "123" },
{ "resource": "recipes", "action": "list" }
]
}Stdio-Only Tools
| Tool | Description |
| ------------------ | ---------------------------------- |
| forge_configure | Save API token to local config |
| forge_get_config | Show current config (token masked) |
Audit Logging
All write operations (forge_write tool calls) are automatically logged for traceability:
- Default path:
~/.config/forge-tools/audit.log - Override: Set
FORGE_AUDIT_LOGenvironment variable - Format: JSON lines (via pino) with timestamp, resource, action, sanitized args, and status
- Safety: Logging never interrupts operations — silent on failure
The CLI also logs write commands to the same audit log.
Getting Your API Token
- Log into Laravel Forge
- Go to Account → API Tokens
- Create a new token with the scopes you need
- Copy the token (it's only shown once)
License
MIT © Studio Meta
