Add an MCP server that mimics the dashboard#389
Open
jbrooksuk wants to merge 5 commits into
Open
Conversation
Introduces a first-party MCP server built on laravel/mcp, exposed as a
streamable HTTP endpoint at {cachet.path}/mcp and gated by two new admin
settings that mirror the existing API settings pair:
- "Enable MCP server" (mcp_enabled, default off) returns 404 for all MCP
requests when disabled.
- "Require authentication" (mcp_protected, default on) requires a Sanctum
API token for every MCP connection. When off, read-only tools are
public while write tools still require a token with the matching
ability, mirroring the REST API's semantics.
The server registers 41 tools covering the ten API token resources:
components, component groups, incidents, incident updates, incident
templates, schedules, schedule updates, metrics, metric points, and
subscribers. Write tools call the same Action classes and request data
objects as the dashboard and REST API, so validation, webhooks, and
subscriber notifications fire identically. Tools are hidden from both
tools/list and tools/call unless the session's token holds the matching
ability, using the existing ability names so dashboard-issued API keys
work unchanged. Subscriber reads stay ability-guarded since they expose
PII.
laravel/mcp moves from require-dev to require at ^0.8, which raises the
Laravel 11 floor to ^11.45.3 across the illuminate dependencies.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0157S7dDNDwYuqWsqeg1DB94
Applies the GHSA-6ghm-wf22-pvx5 fix (#367) to the MCP server, which was written against the pre-fix pattern: read tools now scope incidents, metrics, and component groups with the HasVisibility scope, and components inherit their group's visibility, mirroring ComponentController. Disabled components are hidden by default and only reachable by authenticated callers via the enabled argument; get tools return not-found errors for out-of-scope records. Guests also no longer see disabled components inside component groups. The caller check reuses the ChecksApiAuthentication concern introduced by the fix. The demo seeder now enables the MCP server with authentication not required, so demo instances expose the public read tools while write tools continue to require API token abilities. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0157S7dDNDwYuqWsqeg1DB94
jbrooksuk
force-pushed
the
claude/cachet-mcp-server-3fi8l8
branch
from
July 14, 2026 07:49
9981c78 to
f0a55ee
Compare
On the dependency floor, spatie/laravel-data skips a data object's validation rules for absent properties that declare default values, so create_incident calls with neither message nor template passed validation and failed on the database's NOT NULL constraint instead of returning a validation error. Enforce the required_without pair at the tool boundary so the behaviour is identical across all supported laravel-data versions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0157S7dDNDwYuqWsqeg1DB94
Linking components to an incident writes the incident_components pivot, not the component's own status column - the status page overlays the pivot via Component::latest_status while the incident is unresolved. That is invisible over MCP, where the component presenter only returned the raw status column, so an agent that created an incident and re-read the component concluded the status write had failed. Component payloads now include latest_status alongside status, the create_incident schema explains that the component status is a display overlay rather than a mutation, and the server instructions describe the base-versus-displayed status model. New tests assert the overlay is visible through get_component after create_incident and reverts when a fixed update is recorded. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0157S7dDNDwYuqWsqeg1DB94
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a first-party MCP server built on
laravel/mcp, so AI agents can operate a Cachet status page over the Model Context Protocol with the same capabilities the dashboard exposes — gated by admin settings and authenticated with the existing API token feature.What changed
Endpoint & settings
{cachet.path}/mcp(default/status/mcp), registered alongside the API routes with its owncachet:mcpmiddleware group (cachet.mcp_middleware) andthrottle:cachet-mcplimiter (CACHET_MCP_RATE_LIMIT, default 300/min).mcp_enabled, default off → all MCP requests 404) and Require authentication (mcp_protected, default on → 401 without a Sanctum token). NewEnsureMcpIsEnabled/AuthenticateMcpIfProtectedmiddleware mirror their API counterparts.Tools (41, one per operation)
record_incident_updateauto-resolves on fixed,record_schedule_updatecompletes viacompleted_at,add_metric_point, subscriber verification on create).Cachet\Actions\**classes and request Data objects as the dashboard and REST API, so validation, webhooks, and subscriber notifications fire identically.incidents.manage,components.delete, …), enforced viashouldRegister()— which gates bothtools/listandtools/call— plus an in-handle check. Dashboard-issued API keys work unchanged. Subscriber reads stay ability-guarded (PII).visible(), components inherit their group's visibility (ungrouped stay public), and disabled components are hidden from guests by default.Composer
laravel/mcpmoves from require-dev torequireat^0.8; the Laravel 11 floor rises to^11.45.3across the illuminate dependencies (laravel/mcp's own minimum).Verification
tools/listvisibility per token ability,tools/callblocked for unregistered tools), per-resource tool tests, and visibility regression tests mirroring Scope public API endpoints to caller visibility (GHSA-6ghm-wf22-pvx5) #367's.hidden/authenticated-only records to guests.🤖 Generated with Claude Code
https://claude.ai/code/session_0157S7dDNDwYuqWsqeg1DB94