使用说明
Plytix MCP Server
A lightweight, stateless Model Context Protocol (MCP) server that provides AI assistants with live access to Plytix PIM (Product Information Management) data. This server enables AI tools like Claude Desktop, Claude mobile app, and other MCP clients to search, look up, and retrieve product information directly from the Plytix API.
Note: This is a stateless, live API tool for read and write operations. For sync, caching, or ETL workflows, pair it with a separate persistence layer of your choosing.
Features
- 51 MCP tools via stdio and 46 via the remote worker
- Smart product lookup with automatic identifier detection (SKU, MPN, GTIN, label)
- Family & inheritance tracking with overwritten_attributes support
- Schema discovery for attributes and search filters
- Automatic authentication with token refresh
- Rate limit handling — proactive pacing to the account's advertised window plus jittered 429/5xx backoff
- Zero persistence — stateless, no database required
- Remote server support — Deploy to Cloudflare Workers for mobile/web access
Installation
Prerequisites
- Node.js 20+
- Plytix PIM account with API access
Setup
- Clone and install:
git clone https://github.com/Supplyline/plytix-mcp.git
cd plytix-mcp
npm install
- Configure credentials:
cp .env.example .env
# Edit .env with your Plytix API credentials
- Build the project:
npm run build
Usage
With Claude Desktop
Add to your Claude Desktop MCP configuration (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"plytix": {
"command": "node",
"args": ["/path/to/plytix-mcp/dist/index.js"],
"env": {
"PLYTIX_API_KEY": "your_api_key_here",
"PLYTIX_API_PASSWORD": "your_api_password_here"
}
}
}
}
Standalone
npm start # Production mode
npm run dev # Development with hot reload
Remote Server (Cloudflare Workers)
Deploy as a remote MCP server for access from Claude mobile app, web clients, or shared team access.
Quick Deploy
# Install dependencies (includes wrangler)
npm install
# Login to Cloudflare
wrangler login
# Deploy to Cloudflare Workers
npm run deploy
Using the Remote Server
Once deployed, connect from any MCP client using the deployed URL and your Plytix credentials:
# With Claude Desktop (using mcp-remote)
npx mcp-remote https://plytix-mcp.your-subdomain.workers.dev/mcp \
--header "X-Plytix-API-Key: YOUR_API_KEY" \
--header "X-Plytix-API-Password: YOUR_API_PASSWORD"
The remote worker exposes 56 tools. It intentionally omits local-only utilities and filesystem tools: identifier_detect, identifier_normalize, match_score, products_batch_update_manifest, and products_batch_export_to_file.
Protocol versions
The worker is dual-era: it serves both the stateless 2026-07-28 revision and the
older handshake-based revisions on the same endpoint, choosing per request.
| Client sends | Served as |
|---|---|
_meta with io.modelcontextprotocol/protocolVersion, or an MCP-Protocol-Version header naming a non-legacy version |
2026-07-28 — mirrored-header validation, server/discover, resultType/serverInfo on results, spec HTTP status codes |
initialize handshake (2025-11-25 … 2024-11-05) |
Legacy — responses unchanged from previous releases |
A client newer than this server receives -32022 with the supported list and can
renegotiate down. The 2026-07-28 transport dropped the standalone GET stream and
DELETE teardown, so both now answer 405; Mcp-Session-Id is ignored rather than
echoed.
The stdio server still speaks the legacy handshake — it delegates the protocol to
@modelcontextprotocol/sdk, which has not yet shipped 2026-07-28.
Local Development
npm run dev:worker # Start local worker at localhost:8787
npm run test:worker # Test the worker endpoints
For detailed setup instructions, see docs/remote-setup.md.
Available Tools
Product Tools
| Tool | Description |
|---|---|
products_lookup |
Smart lookup by any identifier (auto-detects ID, SKU, MPN, GTIN, label) |
products_get |
Get single product by ID with full details and overwritten_attributes |
products_get_full |
Get one product with related family, variants, categories, and assets |
products_search |
Advanced search with filters, pagination, and sorting |
products_find |
Simple multi-criteria search (SKU, MPN, MNO, GTIN, label, fuzzy) |
products_batch_export |
Capped inline product snapshot by search, SKU, or product ID |
products_batch_export_to_file |
Stdio-only JSONL/NDJSON product export under PLYTIX_MCP_EXPORT_DIR |
products_create |
Create a new product |
products_update |
Partial update to product fields/attributes |
products_batch_update |
Apply a small guarded product-update batch |
products_batch_update_manifest |
Stdio-only guarded product updates from a local JSON manifest |
products_bulk_update |
Submit up to 1,000 updates as ONE async Plytix bulk job and wait for it to settle (no drift guards; pending + job_id if the wait budget runs out; stdio also accepts manifest_path) |
products_bulk_status |
Poll a bulk job by job_id; pass expected_total so completion can be confirmed (Plytix reports "Finished" before the summary is populated) |
products_assign_family |
Assign or unassign a product family |
products_delete |
Delete one product (two-step dry run + confirm; unlink_variants keeps variants as standalone products) |
products_set_attribute |
Atomic set of one attribute value |
products_clear_attribute |
Atomic clear of one attribute value |
Family Tools
| Tool | Description |
|---|---|
families_list |
List or search product families |
families_get |
Get single family with linked attributes |
families_create |
Create a new product family |
families_link_attribute |
Link one or more attributes to a family |
families_unlink_attribute |
Unlink one or more attributes from a family |
families_list_attributes |
List attributes directly linked to a family |
families_list_all_attributes |
List direct and inherited family attributes |
Attribute & Filter Tools
| Tool | Description |
|---|---|
attributes_list |
List all attributes (system + custom) with types and options |
attributes_get |
Get full metadata for one attribute label |
attributes_get_options |
Get allowed values for a selectable attribute |
attributes_create |
Create an attribute definition (any type; options, sorting, family links, completeness tracking) |
attributes_update |
Rename, describe, and edit dropdown/multiselect options (add_options, remove_options, renamed_options, or a full options list) |
attributes_delete |
Delete an attribute definition (two-step dry run + confirm; refused while a catalog or channel uses it) |
attributes_filters |
Deprecated alias for product filter discovery |
products_filters |
Get product search filter metadata |
assets_filters |
Get asset search filter metadata |
relationships_filters |
Get relationship search filter metadata |
Asset Tools
| Tool | Description |
|---|---|
assets_get |
Get one asset by ID |
assets_search |
Search account assets |
assets_update |
Update asset metadata (filename, categories) |
assets_list |
List assets (images, videos, documents) linked to a product |
assets_link |
Link an asset to a product |
assets_unlink |
Unlink an asset from a product |
Category Tools
| Tool | Description |
|---|---|
categories_search |
Search existing categories |
categories_list |
List categories associated with a product |
categories_link |
Link a category to a product |
categories_unlink |
Unlink a category from a product |
categories_create |
Create a root category or a subcategory |
categories_update |
Rename, move (parent_id, "" = root) or reorder children (sort_children) |
categories_sort_root |
Reorder the root-level categories |
categories_delete |
Delete a category (two-step dry run + confirm; move_children_to rescues the subtree) |
Variant Tools
| Tool | Description |
|---|---|
variants_create |
Create a variant under a parent product |
variants_link |
Link an existing product as a variant |
variants_unlink |
Unlink a variant from its parent without deleting it |
variants_list |
List variants for a product |
variants_resync |
Reset variant attributes to inherit parent values |
Relationship Tools
| Tool | Description |
|---|---|
relationships_get |
Get a relationship definition by ID |
relationships_search |
Search relationship definitions |
relationships_link_product |
Link one related product row in a relationship |
relationships_unlink_product |
Unlink one related product row in a relationship |
relationships_set_quantity |
Update quantity for one related product row |
Identifier Utilities (Stdio Only)
| Tool | Description |
|---|---|
identifier_detect |
Detect identifier type from raw value |
identifier_normalize |
Normalize identifier for matching |
match_score |
Score identifier-product match confidence |
The remote worker exposes every tool above except the three identifier utilities in the final section and the two stdio-only filesystem tools: products_batch_update_manifest and products_batch_export_to_file.
Smart Lookup System
The products_lookup tool automatically detects identifier types and uses staged search strategies:
Detection priority:
- MongoDB ObjectId (24-char hex) →
id(confidence: 1.0) - GTIN (8/12/13/14 digits) →
gtin(confidence: 0.95) - Contains spaces →
label(confidence: 0.9) - Dashed alphanumeric →
mpn(confidence: 0.8) - Alphanumeric with separators →
sku(confidence: 0.7)
Search strategies (in order):
- Direct ID lookup (if detected as ID)
- Exact field matches (SKU, GTIN, MPN, MNO)
- Text search across multiple fields
- Broad LIKE search (last resort)
Example:
Input: "LMI-PD-123"
→ Detected as: sku (confidence: 0.7)
→ Tries: sku_eq, mpn fields, text_search, broad_like
→ Returns: best match with confidence score
Inheritance Tracking
Products return an overwritten_attributes array listing which attributes are explicitly set (not inherited from family). Use this with:
product_family_id— The family this product belongs tofamilies_get— Retrieve family-level default values- Compare to determine inherited vs overwritten values
Configuration
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
PLYTIX_API_KEY |
✅ | — | Your Plytix API key |
PLYTIX_API_PASSWORD |
✅ | — | Your Plytix API password |
PLYTIX_API_BASE |
❌ | https://pim.plytix.com |
Plytix API base URL |
PLYTIX_AUTH_URL |
❌ | https://auth.plytix.com/auth/api/get-token |
Auth endpoint |
PLYTIX_MPN_LABELS |
❌ | ["attributes.mpn"] |
JSON array of MPN attribute labels |
PLYTIX_MNO_LABELS |
❌ | ["attributes.model_no"] |
JSON array of MNO attribute labels |
PLYTIX_MCP_EXPORT_DIR |
❌ | — | Required only for products_batch_export_to_file; limits file exports to this directory |
PLYTIX_MCP_MAX_DELETES |
❌ | 3 |
Deletes one server process (or Worker isolate, via a [vars] binding) will perform before refusing further ones. 0 disables deletes entirely. See Delete safety gate |
Delete safety gate
src/safety.ts provides a two-call gate for the destructive tools
(products_delete, attributes_delete, categories_delete). A caller first
invokes the tool with dry_run: true and gets back a preview of what would be
removed plus a confirm_token; executing requires calling again with that
token. Tokens are single-use, scoped to one tool and one target, and expire
after 5 minutes. A per-process cap (PLYTIX_MCP_MAX_DELETES, default 3) bounds
how much any one session can remove.
The execute call must repeat the side-effect options the preview was issued for
(unlink_variants on a product, move_children_to on a category), and it is
refused if the target's variants or children changed since the dry run. Plytix
deletes a parent's variants and a category's whole subtree; those two options
unlink the variants (they become standalone products) or move the direct
children out first, so only the named item is removed. Plytix has no bulk
product delete, so products_delete is one product per call.
What this does and does not protect against. The token goes back to the calling agent, not to a human — an autonomous agent can read it from the dry-run response and immediately call again. So the gate is a forced pause with a visible preview and a hard ceiling, not a human confirmation step. It stops a runaway loop from clearing a catalog; it does not stop an agent that has decided to delete something.
Genuine human confirmation needs the MCP elicitInput capability, where the
server asks the client to prompt the user. A future revision can elicit when the
client advertises that capability and fall back to this token flow otherwise.
Development
Scripts
| Command | Description |
|---|---|
npm run dev |
Development server with hot reload (stdio) |
npm run dev:worker |
Development server for Cloudflare Workers |
npm run build |
Build TypeScript to JavaScript |
npm run deploy |
Deploy to Cloudflare Workers |
npm start |
Start production server (stdio) |
npm test |
Run unit tests (vitest) |
npm run test:watch |
Run tests in watch mode |
npm run test:mcp |
Test MCP protocol handshake |
npm run test:worker |
Test worker endpoints |
npm run test:all |
Build + unit + integration + MCP tests |
npm run typecheck |
Type check without building |
Architecture
src/
index.ts # MCP server entry point (stdio transport)
worker.ts # Cloudflare Worker entry point (HTTP transport)
client.ts # Plytix API client with auth & rate limiting
worker-client.ts # Worker-compatible client (BYOK credentials)
worker-lookup.ts # Worker-compatible smart lookup
types.ts # TypeScript types
lookup/
identifier.ts # Identifier type detection
lookup.ts # Smart lookup with staged search
tools/
products.ts # Product tools (lookup, get, search, find, write ops)
families.ts # Family tools (list, get, create, attribute membership)
attributes.ts # Attribute metadata + filter discovery tools
product-attributes.ts # Atomic product attribute write tools
assets.ts # Asset get/search/update + product asset link tools
categories.ts # Category search + product category link tools
variants.ts # Variant lifecycle tools
relationships.ts # Relationship discovery + product relationship write tools
extensions/ # Optional deployment-specific customizations
wrangler.toml # Cloudflare Workers configuration
docs/
remote-setup.md # Remote server setup guide
Design Principles
This MCP server is intentionally stateless and lightweight:
- No database — All queries go directly to Plytix API
- No sync/caching layer — Fresh data on every request
- No background jobs — Request/response only
- Ephemeral in-memory cache — Brief (60s) request deduplication, cleared on restart
For ETL, sync, or persistent caching needs, pair this server with a separate persistence layer.
License
MIT License — see LICENSE file for details.
Support
- Issues: GitHub Issues
- Plytix API: Plytix Documentation
- MCP Protocol: Model Context Protocol
