This documentation always describes the current state of the main branch.
The server is a Node.js program written in TypeScript. It speaks the Model Context Protocol over stdio (standard input and output) and offers tools only. It reports claude-mcp-shopwareadmin as its server name. The reported version number is hard-coded and does not follow the package version.
Queries run through Shopware's search API (POST /api/search/<entity>) with filters, associations and aggregations. Writes go through single endpoints (PATCH, POST) and, for product updates, through the sync API (/api/_action/sync).
src/
βββ index.ts entry point, MCP server, tool dispatch, error handling
βββ bootstrap.ts load configuration, wire services
βββ config/ .env loader, content profiles (schema, loader, defaults)
βββ application/schemas/ Zod schemas per tool area
βββ core/
β βββ domain/ entities and error types
β βββ services/ business logic per area
βββ infrastructure/
β βββ shopware/ OAuth2 authenticator and HTTP client
β βββ cache/ in-memory cache with TTL
β βββ logging/ logger to stderr
β βββ wikijs/ wiki service (currently without callers)
βββ tools/
βββ definitions.ts tool descriptions for the tool list
βββ handlers/ handlers per area
The tool descriptions in definitions.ts are maintained by hand. Validation is governed by the Zod schemas, and the two differ in details. For IDs definitions.ts advertises the pattern ^[0-9a-f]{32}$, while Zod additionally accepts uppercase letters and UUIDs with hyphens and converts them to lowercase hex. For date values (format YYYY-MM-DD or with time) and mimeTypePrefix (format type/), on the other hand, Zod is stricter than the advertised JSON description.
The cache lives in the process's memory, holds at most 500 entries and removes expired entries every minute. The durations are fixed in the code and cannot be changed through environment variables.
| Data | Duration |
|---|---|
| Product (single lookup by ID or product number) | 5 minutes |
| Medium, flow, cross-selling (single lookup) | 5 minutes |
| Order (single lookup) | 2 minutes |
| Categories (list and single lookup), manufacturer list without search, property groups | 10 minutes |
| Snippets, mail templates (single lookup) | 10 minutes |
| Lists and searches for products, media, orders, flows, mail templates, SEO URLs | no cache |
Changes made through the server remove the affected entries. Content profiles are loaded once at startup.
Domain errors arrive as JSON text with isError: true:
{
"error": true,
"code": "NOT_FOUND",
"message": "Resource not found: <segment>",
"recoverable": false,
"suggestion": "Verify the resource exists",
"context": {}
}
| Code | Trigger |
|---|---|
AUTH_FAILED |
Token request rejected or timed out |
API_ERROR |
Error response or timeout from the Shopware API, context.httpStatus names the status |
RATE_LIMITED |
429 after three retries or the server's own test mail limit |
NOT_FOUND |
404 from the API |
INVALID_INPUT |
Unknown style, missing required value, schema violation (with details per field) |
PRODUCT_NUMBER_EXISTS |
Duplicate product number in product_create |
Timeouts, the statuses 500, 502 and 503 and 429 count as retryable (recoverable: true). Tools that fetch a single record answer a miss with {"error": true, "message": "... not found"}. An unknown tool yields the text Unknown tool: <name>, any other error the text Error: <message>.
| Package | Purpose |
|---|---|
@modelcontextprotocol/sdk |
MCP server and stdio transport |
zod |
Input validation and configuration schema |
zod-to-json-schema |
Runtime dependency according to package.json |
Development dependencies are TypeScript, ESLint, Vitest, MSW (HTTP mocks in tests) and tsx.
npm run typecheck # check TypeScript
npm run lint # ESLint
npm run build # compile to dist/
npm run dev # watch mode with tsx
npm test # tests with Vitest
CI runs type check, lint, tests and build on Node.js 20 and 22. A new tool needs a Zod schema, a service method, a handler in the matching area under tools/handlers/, an entry in definitions.ts and tests.
On SIGINT and SIGTERM the server shuts down in an orderly way. Uncaught errors are logged, then the process exits.