Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Backoffice Mcp Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Update the package (composer update) and check the server definition you already have — the $description property is still the first thing to fill in.

  2. Look first at four places, in this order:

    • The server class — where $description lives. This is the string handed to the agent before the generic instructions, so it is your highest-leverage piece of context.
    • The generic instructions — shipped by the package, they tell the agent to read your application's code (models, migrations, casts, relationships) to work out what the data means. Read them once so your description complements rather than repeats them.
    • The registration/config — wherever servers are listed or resolved, to confirm the description is picked up (and to see whether it can be set per environment).
    • The OAuth routes — as of 0.3.1 the discovery and client-registration endpoints are throttled to 30 requests per minute per IP. Know where they live and whether the limit is configurable in your install, because you will hit it in local development and CI long before production does.
  3. First use case: pick your busiest domain server (billing, orders, tenancy) and write a short description that names the domain, the vocabulary, and the invariants the code doesn't make obvious. Something like:

    protected ?string $description = <<<'TXT'
    Billing domain. Invoices are immutable once `status` is `paid`; corrections
    are new invoices with `parent_id` set. `amount_cents` is integer cents in
    the tenant's currency, never floats. All timestamps are UTC; `paid_at` is
    null for anything not settled. `status` is a string enum, not an int.
    TXT;
    

That single change typically removes the most common class of wrong answers: the agent inferring semantics from column names.

Implementation Patterns

Treat $description as an onboarding note, not documentation. The generic instructions already cover "go read the code." Your description should carry what code reading cannot reveal: business meaning, historical baggage, unit conventions, enum semantics, soft-delete expectations, which tables are legacy/deprecated, which columns are denormalized caches, and which connection is a read replica.

Ordering matters. Because the description precedes the generic instructions, it sets the frame the agent reads everything else through. Use it to establish domain vocabulary ("in this app, a 'customer' is an organisation, not a user") so subsequent tool results are interpreted correctly. Keep procedural instructions out of it — those belong to the generic layer.

One server per bounded context. In multi-server setups, give each a description scoped to its own domain rather than repeating an app-wide preamble. App-wide conventions belong in the published instructions stub, which you should publish and keep in version control if the package allows it.

Layer your descriptions. Roughly:

  • server $description → domain framing and invariants;
  • individual tool/resource/model descriptions → what that thing is and when to use it;
  • the generic instructions → how to explore the codebase.

Avoid three copies of the same sentence.

Dynamic descriptions where the environment differs. If a description is resolved from config or a method rather than a literal, use it for environment-specific caveats (read-only replica, tenant isolation, seeded demo data). Keep closures out of config/*.php — they break config:cache.

Register OAuth clients out of band, not in a loop. With the 0.3.1 throttle, anything that calls discovery or registration repeatedly will get a 429: test suites that register a client per test, seeders that re-register on every migrate:fresh, local scripts that re-run php artisan serve workflows. Register once (a seeder guarded by firstOrCreate on the client id, or a committed fixture) and have tests reuse that client. If you genuinely need to exercise the registration flow, isolate it in one test and reset the rate limiter in setUp.

Cache the discovery document. Discovery is throttled alongside registration, so a client that refetches metadata before every call burns the same 30-per-minute budget. Fetch it once at boot and reuse it.

Review description changes like migrations. They change agent behaviour. A diff to $description deserves the same scrutiny as a diff to a query scope.

Gotchas and Tips

  • Stale descriptions beat no description at all — in the wrong direction. The agent will trust the description over the code, because it arrives first. If you rename a column or change an enum, update the description in the same PR. A confident, outdated description produces more damage than an empty one.
  • Don't fight the generic instructions. Writing "do not read the source, just answer from this description" contradicts the package's designed flow and degrades results. Point at the code if anything ("see App\Models\Invoice for the full cast list").
  • Watch the token budget. This text is sent at the start of every session. A 2,000-word schema dump crowds out the actual conversation and costs you on every call. Aim for a few tight paragraphs; push detail down into per-tool descriptions.
  • No secrets, no PII. Descriptions commonly leak internal hostnames, credentials hints, customer names, and table names from other tenants. Treat the string as public-facing output.
  • Verify what the agent actually sees. Log or dump the assembled prompt once. Formatting bugs (heredoc indentation, trailing whitespace in YAML/front-matter config, unescaped quotes) are the usual culprit when a good description has no effect.
  • Config and view caching. If the description comes from a config value or a published stub, remember php artisan config:clear / view:clear in local development — otherwise you will edit the file and see no change.
  • The new throttle is per IP, not per client or per user. Two consequences. First, CI runners behind a shared NAT or a single egress IP share one 30-per-minute budget across every parallel job — intermittent 429s on green-looking code. Second, behind a load balancer or reverse proxy without TrustProxies configured for your infrastructure, every request looks like it came from the proxy's IP, so the limit is global. Check app/Http/Middleware/TrustProxies.php before you tune anything.
  • 429s look like auth failures. A throttled registration returns a rate-limit response, not a validation error, and clients often surface it as a generic "could not register" — check the response status and Retry-After header before debugging credentials or DCR metadata.
  • The throttle is DoS mitigation, not authorisation. Client registration is still unauthenticated and still inserts a row. Don't treat 30/min as a security boundary: keep the endpoint off public hosts where you can, and be aware that abandoned or malicious registrations leave orphaned client rows you'll want a cleanup command for.
  • Extension points worth using: publish the generic instructions stub to add application-wide conventions; add a short server description per context; add per-tool descriptions only for tools whose purpose is not obvious from the name. Do not add a fourth layer of prose.
  • Debugging a bad answer: first check whether the agent read the right files. If it did and still got semantics wrong, the gap belongs in $description. If it never looked at the code, your description is probably too prescriptive and is suppressing exploration.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin