This repository is a Sylius-based wishlist-concierge plugin that enables AI agents + humans to co-curate themed, budget-aware gift registries. It integrates:
- Sylius 2.0 with the WishlistPlugin for wishlist management
- WebMCP (Web Machine Learning Control Plane) to expose structured tools to AI agents
- Sylius TestApplication for the demo storefront
Demo URL: https://wishlist-concierge.ddev.site/en_US/
- Product attribute:
concierge_tags(type:selection, multiple:true) - Tags are populated via console command
bitexpert:wishlist-concierge:setup-tags - Themes are used to filter products for curation (agent can search by theme)
summer, casual, gift, birthday, formal, winter
Rationale:
summer,casual,formal,winter→ style/season categoriesgift,birthday→ occasion-based tags
- Hard match: Product's
concierge_tagsattribute must contain the theme value (case-insensitive) - Soft match: If no hard match, theme is matched against the product name (case-insensitive)
- Fallback: If no products match, returns all enabled products for the channel
ddev exec "php vendor/bin/console bitexpert:wishlist-concierge:setup-tags"Options:
--channel=CHANNEL_CODE(default:FASHION_WEB)--dry-run→ show what would be done without persisting
What it does:
- Creates
concierge_tagsproduct attribute if missing - Creates attribute values for all tags in
ConciergeTagsSetupCommand::PRODUCT_TAGS - Assigns tags to products in the specified channel
ddev exec "php vendor/bin/console --version" # Check console availability
ddev exec "php vendor/bin/console debug:config concierge_tags" # Debug configImportant: All Symfony console commands require PHP ≥ 8.4.1. Always use ddev exec to access the container's correct PHP version.
- Project name:
wishlist-concierge - DDEV version: v1.25.3
- Web container:
PHP 8.4(required for Sylius 2.0) - Database: MariaDB 11.8
- Web root:
vendor/sylius/test-application/public
| Service | URL | Description |
|---|---|---|
| Web (https) | https://wishlist-concierge.ddev.site |
Main app (HTTPS) |
| Web (http) | http://wishlist-concierge.ddev.site |
Main app (HTTP) |
| Mailpit | https://wishlist-concierge.ddev.site:8026 |
Email testing |
| DDEV host | 127.0.0.1:32772 |
HTTP proxy |
| Database | db:3306 (db/db) |
MariaDB |
db/db(normal user)root/root(admin user)
.env.local contains database, mailer, and other configuration for the DDEV environment.
The vendor/sylius/test-application provides a fully-featured Sylius demo storefront with:
- Pre-seeded products, variants, taxons, channels
- Pre-configured catalog promotions
- Shop API (
/api/v2/shop/...) - Test-specific configuration
- Web root is
vendor/sylius/test-application/public - The application shares services with the plugin
- Console commands run against this application
- API endpoints like
/api/v2/shop/products/{code}do NOT accept locale prefixes
- API URLs with locale: The
apiFetch()helper inregistry.jsprepends locale prefix (/en_US). For Sylius Shop API endpoints, this causes 404 errors. UsegetBaseUrl(false)or construct URLs without locale for Shop API.
| Package | Version | Purpose |
|---|---|---|
sylius/sylius |
^2.0 | Core e-commerce platform |
sylius/wishlist-plugin |
^1.3 | Wishlist entities and services |
sylius/test-application |
^2.0.0@alpha | Demo storefront for testing |
sylius-labs/coding-standard |
^4.4 | Code style enforcement |
The plugin exposes 12 imperative tools for AI agents:
| Tool | Description | readOnlyHint |
|---|---|---|
wishlist.list |
List recent wishlists | ✅ |
wishlist.get |
Get wishlist details | ✅ |
wishlist.create |
Create a new themed wishlist | ❌ |
wishlist.delete |
Delete a wishlist permanently | ❌ |
wishlist.add_item |
Add product variant to wishlist | ❌ |
wishlist.bulk_add |
Add multiple variants in one call | ❌ |
wishlist.clear |
Remove all items from a wishlist | ❌ |
wishlist.remove_item |
Remove item from wishlist | ❌ |
product.search |
Search products by theme | ✅ |
product.get_details |
Get product details | ✅ |
wishlist.optimize_for_budget |
Optimize for budget with promotions | ✅ |
wishlist.move_to_cart |
Move items to cart | ❌ |
Note: 12 tools defined in registry.js.
- Single source of truth: the
#[ModelContextTool]attribute on each shop controller method (name, description,dtoClass,pathParams, annotations), plus the Symfony route looked up byrouteName - Routes are defined explicitly in
config/routes/shop.yaml(no#[Route]attributes, no wildcard import); the host app imports the bundle routes with a/{_locale}prefix, so paths inshop.yamlmust NOT include the locale ModelContextToolCollectorreads the attributes, resolves each route via the Symfony router (router.default), and builds a JSON manifest- Manifest served at
/_webmcp/wishlist_concierge/tools.json;assets/shop/webmcp/registry.jsfetches it and registers each tool viadocument.modelContext.registerTool()at runtime — adding a tool needs no JS - The "WebMCP Toolbox" view now renders dynamically from
document.modelContext.getTools()— always reflects what's registered - Frontend UI: WebMCP status badge (clicks open toolbox modal)
- Update
ConciergeTagsSetupCommand::PRODUCT_TAGSwith new tag - Run
ddev exec "php vendor/bin/console bitexpert:wishlist-concierge:setup-tags --dry-run"to verify - Run without
--dry-runto persist - Update README examples if needed
- Update
assets/shop/webmcp/registry.jstool descriptions
ddev exec "php vendor/bin/console doctrine:cache:clear-metadata"
ddev exec "php vendor/bin/console cache:clear"
ddev exec "php vendor/bin/console cache:warmup"ddev exec "cd /var/www/html && yarn encore dev"
# or for production
ddev exec "cd /var/www/html && yarn encore production"| Issue | Solution |
|---|---|
requires PHP ≥ 8.4.1 |
Always use ddev exec for console commands |
Cannot load resource "config/services/webmcp.xml" |
Check XML syntax, ensure services are registered in config/services/xml |
404 on product.get_details |
Sylius Shop API does not accept locale prefix |
| "Registered 0/12 — failed" | Webpack duplicates registry.js; ensure lazy loading is configured correctly |
class not found errors |
Run ddev exec "php vendor/bin/console cache:clear" |
- Tool names: snake_case (
wishlist.create,product.search) - Theme tags: lowercase, hyphenated if compound (
birthday,birthday-gift) - Product codes: PascalCase with underscores (
Ethereal_Drift_T_Shirt) - Controller actions: lowercase_with_underscore (
wishlist.create,product.search)
- DDEV handles environment-specific config via
.env.local - TestApplication is git-ignored in
vendor/
| Path | Purpose |
|---|---|
config/routes/shop.yaml |
Explicit WebMCP route definitions (no attribute routing) |
src/Command/ConciergeTagsSetupCommand.php |
Tag setup logic |
src/Service/ThemedProductFinder.php |
Theme-based product filtering |
src/Service/ModelContextToolCollector.php |
WebMCP tool manifest generation (reads #[ModelContextTool] + router) |
src/Attribute/ModelContextTool.php |
Tool attribute with routeName property |
src/Dto/WishlistCreateRequest.php |
Wishlist creation DTO |
src/Security/WishlistAccessChecker.php |
Wishlist access rules |
assets/shop/webmcp/registry.js |
Fetches manifest, registers tools at runtime |
assets/shop/webmcp/controllers/toolbox_controller.js |
Toolbox UI controller |
config/services/webmcp.xml |
Service wiring |
config/packages/bitexpert_wishlist_concierge.yaml |
Plugin parameters |