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

Mcp Bundle Laravel Package

sulu/mcp-bundle

Sulu MCP Bundle integrates the Model Context Protocol into Sulu CMS, letting AI assistants and MCP clients query content, manage pages, and automate editorial workflows through configurable, secure tools and resources.

View on GitHub
Deep Wiki
Context7

Getting Started

Fit check first. This is now 1.0.0-RC4 and PR #48 confirms it's tested against Sulu 3.1, so the supported matrix is wider than the earlier builds — but "RC" still means tool schemas are actively moving (this very release added resourceKey to the results of pages, snippets, articles, media, taxonomies and contacts, and re-keyed the unified content tools). Pin the exact tag ("sulu/mcp-bundle": "1.0.0-RC4") and plan to re-snapshot tool schemas on every upgrade.

Install and register:

composer require sulu/mcp-bundle:1.0.0-RC4
// config/bundles.php
Sulu\McpBundle\SuluMcpBundle::class => ['all' => true],

Transport is HTTP with OAuth, not a stdio script. The release notes describe a stateless MCP protocol, allowed hosts config, Dynamic Client Registration (now switchable), OAuth Client ID Metadata Documents (CIMD), and a sulu:mcp:create-client command with custom and mistral-le-chat client types. So the setup path is:

  1. Register a client: bin/console sulu:mcp:create-client — pick the client type matching your assistant.
  2. Set your allowed hosts (the key is allowed_hosts-style, and PR #69 fixed the README's copy of it — re-read the README, don't trust older blog posts).
  3. Point Claude Desktop / Cursor / Mistral Le Chat at your MCP endpoint, behind your existing security.yaml firewall.
  4. Only if the bundle still ships a stdio command should you use the command/args JSON config; everything in this release assumes network + OAuth.

Tools are disabled by default. PR #73 exists because the assistant prompt was mentioning disabled tools and the tool count was wrong. Don't debug an empty tool list — enable the groups you need in DependencyInjection/Configuration.php first.

Where to look first:

  1. bin/console list sulu — every tool is prefixed sulu_ (sulu_page_list, sulu_block_remove, sulu_media_get, sulu_content_search, plus the new admin-link tool). That listing plus the generated assistant prompt is your API surface.
  2. DependencyInjection/Configuration.php — tool groups, write gating, allowed hosts, DCR toggle, locale defaults.
  3. The tool classes themselves — note the release also documents that a stateless protocol is supported, so tool code must not assume state between calls.

First use case: a read-only content audit. Call sulu_content_search to find candidate pages, then fetch a handful by path and summarise stale content or missing SEO metadata. Search → get → reason never touches write paths.

Implementation Patterns

Use resourceKey as the routing discriminator. The unified content tools now return resourceKey on every result, which is how you tell a page from a snippet from an article from a media item without guessing from the shape of the payload. In your own prompt/agent logic, branch on resourceKey, never on field presence.

Search before fetch — now with products. sulu_content_search covers products as well as content (PR #54), with product hits gated behind the product permission (PR #53). Start every workflow with a search call, then get by ID/path. Full page structures are token-expensive; this one pattern does more for reliability and cost than any prompt tuning.

Extend the unified tools instead of writing parallel ones. PR #55 adds a content-type extension point, so custom entities can participate in the generic content tools rather than needing a bespoke tool each. If you have a project-specific content type, that extension point is the cheaper integration.

Add your own tools for your domain. One tool per intent beats one tool with a mode parameter — models choose between well-named tools far more reliably than they fill in enum switches. Autoconfigure via the bundle's tool tag and inject Sulu services directly.

Gate dangerous third-party tools. PR #52 lets a third-party bundle gate its own dangerous tools. If you're shipping a bundle that registers MCP tools, use it; if you're consuming one, check whether it did.

Declare accurate hints. Every tool now carries readOnlyHint, destructiveHint, idempotentHint, openWorldHint. Clients use these for permission UX, so your own tools should declare them honestly — but never treat them as enforcement; the server-side security checks are what actually protect the content.

Permissions are per-scope, so call the checker. This release tightened real ACLs: delete requires the permission in every locale of the content (PR #61), snippet security context resolves per group (PR #49), products are gated behind the product permission (PR #53). Mirror that in custom tools via sulu_security.security_checker — don't assume the OAuth token's scopes cover Sulu content ACLs.

Always require locale and webspace. Sulu content is locale-scoped and webspace-partitioned; deriving them implicitly gets the German draft edited when you asked about English. Echo the resolved locale back in the result.

Separate draft from publish. Write tools create drafts; publication is a second, visible step with the path in its schema. Never a side effect.

Hand humans a link. The new admin-link tool (PRs #63/#64 — resource id typed as string) turns a resource into a clickable admin URL. Great tail step for an assistant workflow: "here's the page I changed, go review it."

Product tools live elsewhere now. PR #57 moved the product MCP tools into SuluProductBundle. If your workflow needs commerce operations you're installing two bundles, with two upgrades to track.

Integration tips:

  • Snapshot tool JSON schemas in CI — this RC changed result shapes, so expect more of the same up to 1.0.
  • Test tool classes as plain services with mocked managers; the OAuth/HTTP layer is separately covered by the bundle's own stateless-protocol tests.
  • Clear sulu_http_cache after write tools in dev.

Gotchas and Tips

sulu_page_list without parentId returns every page in the webspace. PR #77 is literally a doc fix for this. Always pass parentId (or an explicit limit) unless you genuinely want the full tree — otherwise you'll blow the context window on the first call.

Nested blocks need the block _id. sulu_block_remove now finds nested blocks by _id (PR #74), not by index. Index-based addressing was ambiguous once blocks nest; pass the _id you got back from the read tool.

Media returns one format URI and lists the keys. sulu_media_get (PR #76) returns a single format URI plus the available format keys — so choose the format explicitly instead of expecting every rendition inline.

The protocol is stateless. PRs #65/#67 split the request body into messages the way the SDK does and documented stateless operation. Don't build workflows that depend on a previous tool call's session state; pass identifiers explicitly between calls.

OAuth misconfiguration looks like "tool missing". DCR is switchable (PR #66), CIMD is supported (PR #68), and the allowed-hosts key was wrong in the README until PR #69. A 401/403 from the endpoint surfaces in most clients as a generic failure, not an auth error. Check the endpoint with curl before blaming your client config.

Disabled-by-default tools confuse the model. The assistant prompt now names disabled tools and reports the tool count (PR #73), so the model may confidently reference a capability you never enabled. Enable the groups you actually use and keep the set small — fifteen tools select noticeably worse than five.

stdout is still sacred if you run locally. On any stdio path, a stray echo, dump(), or console output corrupts JSON-RPC and the client reports "server failed to start". With the HTTP transport this moves to: don't let tool logging leak into the response body, and keep verbose logging to a file.

Tool errors need catching, not throwing. ContentNotFoundException, document manager exceptions and PHPCR path errors surface as opaque client-side failures. Catch and return a normal result listing what does exist.

Strip HTML; truncate aggressively. Sulu stores rich text and blocks as HTML — convert to markdown, return template structure (block names, field names) separately from copy, and default fields/maxDepth low with a note that the model can ask for more.

Path vs UUID. Both work in Sulu; mixing them in tool inputs produces confusing not-found errors. Pick one canonical identifier per tool, say so in the schema, and be consistent with the resourceKey you return.

RC churn is the real gotcha. resourceKey was added to result payloads in this RC, and four tool edge cases were fixed in PR #58. Anything you hardcode against a tool's output shape is a liability until 1.0. Wrap tool responses in your own normalising layer so a schema change is one file to fix, not every saved prompt.

Extension points worth building before you enable writes: a decorator over the tagged tools — it gives you audit logging, rate limiting, dry-run mode and human-approval gates without forking vendor code. Combined with the new per-tool hints, the decorator can auto-require approval for anything not marked readOnlyHint: true.

Debugging: MCP clients swallow server-side errors. Log every incoming tool call with arguments and response size to a file and tail it while you interact. Half of all "the assistant ignored my instruction" reports are a tool returning an empty or malformed result — and in this release, an empty result is the most likely symptom of a locale, webspace or permission gate doing its job quietly.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle