mnapoli/backoffice-mcp
Laravel package that exposes your backoffice as an MCP (Model Context Protocol) server, letting AI assistants securely query and manage admin resources through a standardized interface. It bridges existing CRUD and dashboard actions with LLM-powered tools without custom API code.
Architecture fit: 0.3.1 confirms that the package is no longer just a context-injection layer for agent instructions; it now ships an OAuth authorization surface. The $description feature from 0.2.0 (server-level context passed to the agent before generic instructions) remains the agent-behavior concern, but the release adds two unauthenticated HTTP endpoints: OAuth discovery and dynamic client registration (DCR). That is a meaningfully larger architectural footprint — new routes, new persistence (client registrations write a DB row), and a new public attack surface. Rate limiting 30 requests/minute/IP is a correct and expected hardening step for DCR, which by specification cannot require authentication. It should be read as a mitigation, not a complete control.
Integration feasibility: Low effort to adopt technically (no migration implied, additive throttling), but higher effort to adopt safely, because correctness depends on deployment topology rather than application code. Two things determine whether the control works: (1) client IP resolution — behind a load balancer, CDN, or reverse proxy, Laravel will see the proxy IP unless TrustProxies is configured, which either collapses all traffic into one shared bucket (false 429s) or trusts spoofable X-Forwarded-For headers (trivial bypass); (2) cache store — Laravel's rate limiter is cache-backed, so a per-node array/file cache in a multi-instance deployment yields an effective limit of 30 × N. Also confirm the limiter is keyed per IP and per endpoint, and that 429s return Retry-After.
Technical risk: The dominant risk is unauthenticated write amplification. DCR inserts rows with no authentication, so the throttle is the only thing standing between a trivial script and unbounded table growth. 30/min/IP is still ~43k rows/day per IP, and IPs are cheap. Without expiry/GC of unregistered or unused clients, this is a slow-burn storage and cleanup problem rather than a crash. Secondary risks: DCR abuse for redirect-URI manipulation, client-name spoofing, or using your registration endpoint as a phishing bootstrap; NAT concentration (many users behind one corporate egress IP sharing a 30/min budget); and retry storms from agents that register on startup across a fleet. Note also the version jump 0.2.0 → 0.3.1; two minor releases of pre-1.0 code can carry breaking changes the release note does not describe. The OAuth surface itself almost certainly arrived in 0.3.0 and is undocumented in this note.
Key questions: Is the 30/min limit publishable/configurable per route, and can it be disabled or raised? Which cache store backs the limiter, and is it shared across instances? Are TrustProxies/TrustHosts correctly configured for your ingress? Do discovery responses carry cache headers so clients are not re-fetching constantly? Do 429 responses include Retry-After, and do agent clients honor it? Are dynamically registered clients expired, revoked, or garbage-collected on a schedule? Is there an allowlist, admin approval, or kill switch for DCR? Are redirect URIs validated strictly (exact match, no wildcards, no fragments)? What broke between 0.2.0 and 0.3.1, and is there a changelog/migration guide? Does the OAuth server integrate with existing Laravel auth (Passport/Sanctum) or maintain its own client table?
Stack fit: Still a conventional Laravel integration — service provider, publishable config, routes — but it now assumes operational prerequisites the earlier release did not: a shared cache backend (Redis/Memcached) for rate limiting, correct proxy trust configuration, and a database table you own the lifecycle of. Those are standard in a mature Laravel deployment, but they are prerequisites, not defaults; a single-server dev setup will pass tests and behave differently in production.
Migration path: Treat 0.2.0 → 0.3.1 as a real upgrade, not a patch. Read the full changelog for 0.3.0 and 0.3.1, diff published config, confirm whether the OAuth routes are registered by default (and whether they can be disabled if you are not yet ready to expose them), and verify that adding the OAuth surface did not alter the agent instruction/description ordering validated in the 0.2.0 assessment. For new adopters, install, publish config, configure the rate limiter and proxy trust before exposing routes publicly.
Compatibility: Confirm PHP/Laravel constraints for 0.3.x, cache driver requirements, and whether the package now pulls in an OAuth server dependency. Verify the package's route registration composes with your existing middleware stack (throttle middleware ordering, CORS, HTTPS enforcement) and with any API gateway already rate limiting at the edge. Pin the version; do not float a pre-1.0 constraint.
Sequencing: 1) Pin and audit 0.3.1; read 0.3.0/0.3.1 changelogs for breaking changes. 2) Inventory the new routes and confirm they are gated as expected. 3) Configure shared cache + TrustProxies; test the limiter from multiple source IPs and from behind the proxy. 4) Define DCR policy: redirect URI validation, client expiry/GC job, monitoring. 5) Re-validate $description and generic-instruction behavior from the 0.2.0 baseline. 6) Security review covering prompt injection and the new unauthenticated endpoints. 7) Staging soak with realistic agent client behavior, then production with alerting on 429 volume and registration rate.
Maintenance: Two new ongoing obligations. First, the throttling configuration is deployment-coupled — proxy settings, cache backend, and limit values must stay in sync across environments or the control silently fails. Second, DCR creates a client table that will accumulate rows; without an expiry or cleanup job this becomes a recurring manual chore. The $description-as-documentation concern from 0.2.0 still stands and still needs an owner.
Support: Expect tickets of the shape "the agent can't connect" that are actually 429s, especially for users behind shared corporate NAT or running multiple agents. The runbook needs to cover: how to identify a throttled request, how to tune the limit, how to clear or revoke a registration, and how to roll back the package version. Support should also be able to distinguish "rate limited" from "registration rejected" from "agent misconfigured," which requires structured logging on the OAuth routes.
Scaling: IP-keyed limiting scales poorly in two directions. Horizontally, it requires a shared cache or the limit multiplies by instance count. Organizationally, it penalizes legitimate concentration — a customer with 200 users behind one egress IP shares 30 requests/minute. If the agent client re-registers per session or per process, that budget is consumed quickly. Consider whether limits should also be layered at the edge/gateway, and whether per-client or per-tenant limits are needed in addition to per-IP. Prompt size and cost concerns from the $description plus generic instructions remain.
Failure modes: Misconfigured proxy trust, producing either global false 429s or a bypassable limiter. Per-node cache in a multi-instance deployment, multiplying the effective limit. Cache outage — the limiter fails closed (500s) or open depending on configuration; decide which you want and test it. Unbounded client table growth from unauthenticated DCR. Retry storms from agents that do not honor Retry-After. Redirect-URI abuse turning your endpoint into a link in someone else's flow. And the pre-1.0 upgrade churn risk, now realized once: 0.2.0 to 0.3.1 is not a patch-level move.
Ramp-up: Engineering needs Laravel rate-limiting and proxy-trust literacy, not just package familiarity — this is infrastructure-adjacent work. A TPM should sequence a short internal design review before enabling the OAuth routes publicly, confirm the shared-cache and proxy prerequisites with platform/ops, scope a client-cleanup job in the same sprint as the upgrade, and keep the 0.2.0 agent-behavior validation as a regression check rather than treating 0.3.1 as a pure security patch.
How can I help you explore Laravel packages today?