MCP Server that wraps the keyCRM REST API. It exposes Claude-callable tools for managing products, variants, stock, orders, customers, pipelines, payments, files, and more in keyCRM.
keycrm-mcp
A Model Context Protocol (MCP) server for keyCRM — lets Claude manage your keyCRM catalogue, stock, orders, customers, pipelines, and more via natural language.
Author: Ivan Klymenko
License: MIT
Node.js: 23.6+
MCP SDK: @modelcontextprotocol/sdk
Table of Contents
- What This Is
- Requirements
- Installation
- Configuration
- MCP Client Setup
- Tool Reference
- 6.1 Products
- 6.2 Product Variants (Offers)
- 6.3 Product Categories
- 6.4 Stock
- 6.5 Orders
- 6.6 Order Reference Data
- 6.7 Payments
- 6.8 Customers
- 6.9 Pipelines
- 6.10 Storage
- 6.11 Custom Fields
- 6.12 Warehouses
- Error Handling
- Logging
- Project Structure
- Implementation Notes
- Contributing
1. What This Is
keycrm-mcp is a Model Context Protocol server that wraps the keyCRM REST API. It exposes Claude-callable tools for managing products, variants, stock, orders, customers, pipelines, payments, files, and more in keyCRM.
Once configured, you can ask Claude things like:
- "Show me all draft products in the Shirts category"
- "Update the price of SKU MNL-SRT-WHT-L to 890"
- "What is the current stock level for SKU ABC-123?"
- "List all orders placed today that are still pending"
- "Publish all draft products in the Jackets category" (with preview + confirmation)
- "Replace the photo on product ID 42 with this image URL"
- "Create a new order for buyer 99 with two items"
- "Show me all cards in the Sales pipeline"
The server runs as a local Node.js process and communicates with your MCP client (Claude Desktop or Claude Code) over stdio.
2. Requirements
| Requirement | Version | |---|---| | Node.js | 23.6+ | | npm | 10+ | | keyCRM account | Any plan | | keyCRM API key | Required |
3. Installation
3.1 Clone the repository
git clone https://github.com/ivanklymenko/keycrm-mcp.git
cd keycrm-mcp
3.2 Install dependencies
npm install
3.3 Create environment file
cp .env.example .env
Edit .env with your values — see Section 4.
3.4 Verify the server starts
node index.js
The server starts in stdio mode and waits for MCP client input. No output means it is working correctly — it only speaks when addressed by a client.
4. Configuration
All configuration is done via environment variables. Copy .env.example to .env and fill in the values.
.env.example
# ─── Required ────────────────────────────────────────────────
# Your keyCRM API key
# Found at: Налаштування → Інтеграції → API
KEYCRM_API_KEY=your_api_key_here
# ─── Optional ────────────────────────────────────────────────
# keyCRM API base URL — only change if keyCRM updates their API endpoint
KEYCRM_API_URL=https://openapi.keycrm.app/v1
# Maximum number of results returned by list tools (default: 50)
LIST_DEFAULT_LIMIT=50
# Log level: error | warn | info | debug (default: info)
LOG_LEVEL=info
# Path to the log file (default: ./logs/keycrm-mcp.log)
LOG_FILE=./logs/keycrm-mcp.log
Configuration reference
| Variable | Required | Default | Description |
|---|---|---|---|
| KEYCRM_API_KEY | ✅ | — | keyCRM API key |
| KEYCRM_API_URL | ❌ | https://openapi.keycrm.app/v1 | keyCRM API base URL |
| LIST_DEFAULT_LIMIT | ❌ | 50 | Default page size for list tools |
| LOG_LEVEL | ❌ | info | Log verbosity |
| LOG_FILE | ❌ | ./logs/keycrm-mcp.log | Log file path |
5. MCP Client Setup
Claude Desktop
Add the following to your claude_desktop_config.json:
{
"mcpServers": {
"keycrm": {
"type": "stdio",
"command": "node",
"args": ["/absolute/path/to/keycrm-mcp/index.js"],
"env": {
"KEYCRM_API_KEY": "your_api_key_here"
}
}
}
}
Restart Claude Desktop after saving the config. The keyCRM tools will appear in the tool list automatically.
Claude Code
claude mcp add keycrm node /absolute/path/to/keycrm-mcp/index.js
Then set the environment variable:
claude mcp env set keycrm KEYCRM_API_KEY your_api_key_here
Running with PM2 (server / VPS)
If you are running the MCP server on a VPS and connecting remotely:
npm install -g pm2
pm2 start index.js --name keycrm-mcp
pm2 save
pm2 startup
6. Tool Reference
6.1 Products
list_products
List products from the keyCRM catalogue with optional filters.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| category_id | number | ❌ | Filter by category ID |
| status | string | ❌ | Filter by status: draft, published, archived |
| query | string | ❌ | Search by product name |
| limit | number | ❌ | Number of results to return (default: LIST_DEFAULT_LIMIT) |
| offset | number | ❌ | Pagination offset (default: 0) |
get_product
Get full details for a single product including all variants and stock levels per warehouse.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| product_id | number | ✅ | keyCRM product ID |
create_product
Create a new product in the keyCRM catalogue.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | ✅ | Product name |
| category_id | number | ❌ | Category ID |
| description | string | ❌ | Product description |
| price | number | ❌ | Base price |
| sku | string | ❌ | Product SKU |
| status | string | ❌ | Initial status: draft (default) or published |
update_product
Update one or more fields on an existing product. Does not change product status — use publish_product, unpublish_product, or archive_product for status changes.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| product_id | number | ✅ | keyCRM product ID |
| name | string | ❌ | Product name |
| description | string | ❌ | Product description |
| price | number | ❌ | Product price |
| category_id | number | ❌ | Category ID |
| sku | string | ❌ | Product SKU |
At least one optional field must be provided.
publish_product
Change a product's status from draft to published. Makes the product visible on the storefront.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| product_id | number | ✅ | keyCRM product ID |
unpublish_product
Change a product's status from published back to draft. Hides the product from the storefront without deleting it.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| product_id | number | ✅ | keyCRM product ID |
archive_product
Archive a product. Archived products are hidden from the storefront but fully preserved in keyCRM and can be unarchived at any time. No confirmation required — this operation is reversible.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| product_id | number | ✅ | keyCRM product ID |
update_product_photo
Replace or add a photo on an existing product. Accepts a publicly accessible image URL. Internally, the file is uploaded to keyCRM Storage first (POST /storage/upload), then attached to the product — this is handled automatically by the server.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| product_id | number | ✅ | keyCRM product ID |
| photo_url | string | ✅ | Publicly accessible URL of the new photo |
| replace_existing | boolean | ❌ | If true, replaces all existing photos. If false, adds alongside existing ones (default: false) |
bulk_update_products
Apply a field update to multiple products matching a filter. Always call with dry_run: true first to preview affected products, then call again with dry_run: false and confirm: true to execute.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| filter | object | ✅ | Filter defining which products to update |
| filter.category_id | number | ❌ | Match products in this category |
| filter.status | string | ❌ | Match products with this status |
| filter.query | string | ❌ | Match products whose name contains this string |
| update | object | ✅ | Fields to update and their new values (same fields as update_product) |
| dry_run | boolean | ✅ | If true, returns preview without making changes |
| confirm | boolean | ❌ | Must be true to execute when dry_run is false |
Two-step flow:
- Call with
dry_run: true→ returns list of affected products - Review the list, then call again with
dry_run: false, confirm: true→ executes the update
6.2 Product Variants (Offers)
In keyCRM, product variants (combinations of size, color, etc.) are called offers. Each offer has its own SKU, price, and stock level.
list_offers
List product variants with optional filters.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| product_id | number | ❌ | Filter offers by parent product ID |
| sku | string | ❌ | Filter by SKU (partial match) |
| limit | number | ❌ | Number of results to return (default: LIST_DEFAULT_LIMIT) |
| offset | number | ❌ | Pagination offset (default: 0) |
create_offer
Create one or more new variants for an existing product.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| product_id | number | ✅ | Parent product ID |
| offers | array | ✅ | Array of offer objects to create |
| offers[].sku | string | ❌ | Variant SKU |
| offers[].price | number | ❌ | Variant price |
| offers[].properties | array | ❌ | Array of {name, value} pairs (e.g. {name: "Розмір", value: "M"}) |
update_offer
Update fields on one or more existing product variants.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| offers | array | ✅ | Array of offer update objects |
| offers[].id | number | ✅ | Offer ID |
| offers[].sku | string | ❌ | New SKU |
| offers[].price | number | ❌ | New price |
| offers[].properties | array | ❌ | Updated properties |
6.3 Product Categories
list_categories
List all product categories.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | number | ❌ | Number of results to return (default: LIST_DEFAULT_LIMIT) |
| offset | number | ❌ | Pagination offset (default: 0) |
create_category
Create a new product category.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | ✅ | Category name |
| parent_id | number | ❌ | Parent category ID for nested categories |
6.4 Stock
get_stock
Get stock levels for a specific SKU across all warehouses, or for a single warehouse.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| sku | string | ✅ | Product variant SKU |
| warehouse_id | number | ❌ | If provided, returns stock for this warehouse only |
adjust_stock
Manually adjust the stock level for a SKU in a specific warehouse. Sets an absolute quantity — not a delta.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| sku | string | ✅ | Product variant SKU |
| warehouse_id | number | ✅ | Warehouse to adjust stock in |
| quantity | number | ✅ | New absolute stock quantity |
| reason | string | ❌ | Optional note explaining the adjustment |
6.5 Orders
list_orders
List orders with optional filters.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| status_id | number | ❌ | Filter by order status ID (use list_order_statuses to get IDs) |
| date_from | string | ❌ | Filter orders created from this date (ISO 8601: YYYY-MM-DD) |
| date_to | string | ❌ | Filter orders created up to this date (ISO 8601: YYYY-MM-DD) |
| source_id | number | ❌ | Filter by source ID (use list_sources to get IDs) |
| warehouse_id | number | ❌ | Filter by fulfillment warehouse |
| limit | number | ❌ | Number of results to return (default: LIST_DEFAULT_LIMIT) |
| offset | number | ❌ | Pagination offset (default: 0) |
get_order
Get full details for a single order including line items, customer, payments, tags, and status history.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| order_id | number | ✅ | keyCRM order ID |
create_order
Create a new order in keyCRM. Requires explicit confirmation.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| buyer_id | number | ❌ | Existing buyer ID |
| buyer_comment | string | ❌ | Comment from the buyer |
| manager_comment | string | ❌ | Internal manager comment |
| source_id | number | ❌ | Source ID (use list_sources to get IDs) |
| status_id | number | ❌ | Initial status ID (use list_order_statuses to get IDs) |
| payment_method_id | number | ❌ | Payment method ID (use list_payment_methods to get IDs) |
| warehouse_id | number | ❌ | Fulfillment warehouse ID |
| products | array | ✅ | Array of line item objects |
| products[].offer_id | number | ✅ | Offer (variant) ID |
| products[].quantity | number | ✅ | Quantity |
| products[].price | number | ❌ | Sale price (overrides catalogue price) |
| shipping | object | ❌ | Shipping details (delivery service, address, TTN, etc.) |
| confirm | boolean | ✅ | Must be true to execute |
update_order
Update fields on an existing order.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| order_id | number | ✅ | keyCRM order ID |
| manager_comment | string | ❌ | Internal manager comment |
| buyer_comment | string | ❌ | Buyer comment |
| shipping | object | ❌ | Updated shipping details |
| payment_method_id | number | ❌ | Payment method ID |
At least one optional field must be provided.
update_order_status
Update the status of an order.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| order_id | number | ✅ | keyCRM order ID |
| status_id | number | ✅ | New status ID (use list_order_statuses to get IDs) |
| note | string | ❌ | Optional internal note |
add_order_payment
Record a payment against an existing order.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| order_id | number | ✅ | keyCRM order ID |
| amount | number | ✅ | Payment amount |
| payment_method_id | number | ❌ | Payment method ID (use list_payment_methods to get IDs) |
| description | string | ❌ | Optional payment note |
add_order_tag
Attach a tag to an existing order.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| order_id | number | ✅ | keyCRM order ID |
| tag_id | number | ✅ | Tag ID (use list_tags to get IDs) |
remove_order_tag
Remove a tag from an existing order.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| order_id | number | ✅ | keyCRM order ID |
| tag_id | number | ✅ | Tag ID |
6.6 Order Reference Data
These tools return the lookup data needed to build valid order requests. Call them to get correct IDs before creating or updating orders.
list_order_statuses
List all available order statuses with their IDs and names.
Input parameters: None
list_payment_methods
List all available payment methods with their IDs and names.
Input parameters: None
list_sources
List all available order sources (e.g. WooCommerce, POS, Telegram) with their IDs and names.
Input parameters: None
list_tags
List all available order tags with their IDs and names.
Input parameters: None
list_delivery_services
List all available delivery services with their IDs and names.
Input parameters: None
6.7 Payments
list_external_transactions
List external payment transactions recorded in keyCRM (e.g. from Monobank or other payment providers).
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | number | ❌ | Number of results to return (default: LIST_DEFAULT_LIMIT) |
| offset | number | ❌ | Pagination offset (default: 0) |
attach_external_transaction
Attach an external transaction to an existing payment record in keyCRM. Used to link a bank transaction to a keyCRM order payment.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| payment_id | number | ✅ | keyCRM payment ID |
| transaction_id | string | ✅ | External transaction identifier (e.g. from Monobank) |
| amount | number | ✅ | Transaction amount |
| description | string | ❌ | Optional description |
6.8 Customers
list_customers
List customers with optional search.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| query | string | ❌ | Search by name, email, or phone |
| limit | number | ❌ | Number of results to return (default: LIST_DEFAULT_LIMIT) |
| offset | number | ❌ | Pagination offset (default: 0) |
get_customer
Get a customer profile including full order history.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| customer_id | number | ✅ | keyCRM customer ID |
create_customer
Create a new customer (buyer) record in keyCRM.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| full_name | string | ✅ | Customer full name |
| email | string | ❌ | Email address |
| phone | string | ❌ | Phone number |
| comment | string | ❌ | Internal note |
update_customer
Update an existing customer record.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| customer_id | number | ✅ | keyCRM customer ID |
| full_name | string | ❌ | Customer full name |
| email | string | ❌ | Email address |
| phone | string | ❌ | Phone number |
| comment | string | ❌ | Internal note |
At least one optional field must be provided.
import_customers
Bulk import a list of customer records into keyCRM. Requires explicit confirmation.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| customers | array | ✅ | Array of customer objects |
| customers[].full_name | string | ✅ | Customer full name |
| customers[].email | string | ❌ | Email address |
| customers[].phone | string | ❌ | Phone number |
| confirm | boolean | ✅ | Must be true to execute |
6.9 Pipelines
Pipelines are keyCRM's sales funnel and lead management feature. Each pipeline contains cards (leads or deals) that move through defined stages.
list_pipelines
List all pipelines with their IDs and names.
Input parameters: None
list_pipeline_statuses
List all stages for a specific pipeline with their IDs and names.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| pipeline_id | number | ✅ | Pipeline ID |
list_pipeline_cards
List cards across pipelines with optional filters.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| pipeline_id | number | ❌ | Filter by pipeline ID |
| status_id | number | ❌ | Filter by pipeline stage ID |
| limit | number | ❌ | Number of results to return (default: LIST_DEFAULT_LIMIT) |
| offset | number | ❌ | Pagination offset (default: 0) |
get_pipeline_card
Get full details for a single pipeline card including contact, products, payments, and status.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| card_id | number | ✅ | Pipeline card ID |
create_pipeline_card
Create a new card in a pipeline.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| pipeline_id | number | ✅ | Pipeline ID |
| status_id | number | ✅ | Initial stage ID (use list_pipeline_statuses to get IDs) |
| title | string | ❌ | Card title |
| contact | object | ❌ | Contact details (full_name, email, phone) |
| products | array | ❌ | Array of product line items |
| manager_comment | string | ❌ | Internal note |
update_pipeline_card
Update an existing pipeline card (move stage, update contact, add notes, etc.).
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| card_id | number | ✅ | Pipeline card ID |
| status_id | number | ❌ | New stage ID |
| title | string | ❌ | Updated title |
| manager_comment | string | ❌ | Updated internal note |
| contact | object | ❌ | Updated contact details (full_name, email, phone) |
At least one optional field must be provided.
6.10 Storage
upload_file
Upload a file to keyCRM Storage from a publicly accessible URL. Returns a file_id that can be used to attach the file to orders, pipeline cards, or products.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| url | string | ✅ | Publicly accessible URL of the file to upload |
| filename | string | ❌ | Optional filename override |
list_files
List files stored in keyCRM Storage, optionally filtered by the entity they are attached to.
Input parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| entity_type | string | ❌ | Filter by entity type: order, pipelines_card, product |
| entity_id | number | ❌ | Filter by entity ID (requires entity_type) |
| limit | number | ❌ | Number of results to return (default: LIST_DEFAULT_LIMIT) |
| offset | number | ❌ | Pagination offset (default: 0) |
6.11 Custom Fields
list_custom_fields
List all custom fields configured in keyCRM with their IDs, names, types, and allowed values.
Input parameters: None
6.12 Warehouses
list_warehouses
List all warehouses configured in keyCRM with their IDs, names, and addresses.
Input parameters: None
7. Error Handling
All keyCRM API errors are caught and returned to Claude as structured error messages — they are never thrown as unhandled exceptions.
Error response shape
{
"error": true,
"code": "KEYCRM_API_ERROR",
"status": 404,
"message": "Product not found",
"detail": "No product with ID 9999 exists in keyCRM"
}
Error codes
| Code | Description |
|---|---|
| KEYCRM_API_ERROR | keyCRM returned a non-2xx response |
| KEYCRM_AUTH_ERROR | API key is invalid or missing |
| KEYCRM_RATE_LIMIT | Rate limit hit — request will be retried |
| KEYCRM_TIMEOUT | Request timed out |
| VALIDATION_ERROR | Tool input failed validation before the API was called |
| INTERNAL_ERROR | Unexpected server error |
Rate limiting
The keyCRM API enforces a limit of 60 requests per minute per IP address per API key. The server handles HTTP 429 responses automatically with exponential backoff:
- First retry: 1 second
- Second retry: 2 seconds
- Third retry: 4 seconds
- After 3 retries: returns a
KEYCRM_RATE_LIMITerror to Claude
Timezone
All timestamps in the keyCRM API use UTC (GMT+0) — for reads, filters, and writes. The server does not perform timezone conversion. Pass and expect UTC values in all date/time fields.
8. Logging
All tool calls and API interactions are logged to a local file for debugging.
Log format
[2026-03-25T14:32:01.123Z] [INFO] tool_call: list_products | params: {"status":"draft"} | duration: 312ms | status: ok
[2026-03-25T14:32:05.456Z] [ERROR] tool_call: get_product | params: {"product_id":9999} | duration: 201ms | status: error | code: KEYCRM_API_ERROR | message: Product not found
Log location
Default: ./logs/keycrm-mcp.log
Override with the LOG_FILE environment variable.
Logs are appended — no automatic rotation is implemented. Use logrotate on Linux/VPS deployments or clear manually as needed.
9. Project Structure
keycrm-mcp/
├── index.js # Entry point — starts the MCP server
├── .env.example # Environment variable template
├── .env # Your local config (not committed)
├── package.json
├── src/
│ ├── server.js # MCP server setup and tool registration
│ ├── tools/
│ │ ├── products.js # list_products, get_product, create_product,
│ │ │ # update_product, publish_product, unpublish_product,
│ │ │ # archive_product, update_product_photo,
│ │ │ # bulk_update_products
│ │ ├── offers.js # list_offers, create_offer, update_offer
│ │ ├── categories.js # list_categories, create_category
│ │ ├── stock.js # get_stock, adjust_stock
│ │ ├── orders.js # list_orders, get_order, create_order,
│ │ │ # update_order, update_order_status,
│ │ │ # add_order_payment, add_order_tag,
│ │ │ # remove_order_tag
│ │ ├── order-reference.js # list_order_statuses, list_payment_methods,
│ │ │ # list_sources, list_tags, list_delivery_services
│ │ ├── payments.js # list_external_transactions,
│ │ │ # attach_external_transaction
│ │ ├── customers.js # list_customers, get_customer, create_customer,
│ │ │ # update_customer, import_customers
│ │ ├── pipelines.js # list_pipelines, list_pipeline_statuses,
│ │ │ # list_pipeline_cards, get_pipeline_card,
│ │ │ # create_pipeline_card, update_pipeline_card
│ │ ├── storage.js # upload_file, list_files
│ │ ├── custom-fields.js # list_custom_fields
│ │ └── warehouses.js # list_warehouses
│ ├── keycrm/
│ │ ├── client.js # keyCRM REST API client (fetch wrapper, auth, retry)
│ │ └── errors.js # Error normalisation
│ └── utils/
│ ├── logger.js # File logger
│ └── validate.js # Input validation helpers
└── logs/
└── keycrm-mcp.log # Runtime log (auto-created)
10. Implementation Notes
MCP SDK
This server is built with the official Anthropic MCP SDK:
npm install @modelcontextprotocol/sdk
Tools are registered using the SDK's server.tool() method. Input schemas are defined using Zod for runtime validation.
Transport
The server uses StdioServerTransport from the MCP SDK:
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const server = new McpServer({ name: 'keycrm-mcp', version: '1.0.0' });
const transport = new StdioServerTransport();
await server.connect(transport);
keyCRM API client
All keyCRM API calls go through a single client module (src/keycrm/client.js) that handles:
- Base URL and API key injection from environment variables
- Bearer token authentication (
Authorization: Bearer YOUR_KEY) - JSON request/response serialisation
- HTTP error normalisation
- Rate limit retry with exponential backoff (max 3 retries)
- Request timeout (default: 10 seconds)
update_product_photo — Storage API flow
This tool performs two sequential API calls internally:
POST /storage/upload— uploads the image from the provided URL to keyCRM Storage, returns afile_idPUT /products/{productId}— attaches thefile_idto the product, optionally replacing existing photos
If the upload succeeds but the attach fails, the error is returned with the file_id included so the attach can be retried manually if needed.
bulk_update_products dry-run flow
Two-phase call on the same tool:
- Phase 1 (
dry_run: true): Fetches matching products using the provided filter, returns the list without modifying anything - Phase 2 (
dry_run: false, confirm: true): Executes the update on all matching products
If dry_run: false is passed without confirm: true, the tool returns a VALIDATION_ERROR — it will not execute without explicit confirmation.
ESM
The project uses ES modules ("type": "module" in package.json). All imports use ESM syntax.
11. Contributing
Contributions are welcome. This is a generic keyCRM MCP server — pull requests that extend coverage of the keyCRM API are encouraged.
Before opening a PR:
- Follow the existing file structure (one file per resource group in
src/tools/) - Add input parameter validation using Zod for every new tool
- Ensure errors are caught and returned as structured error objects, not thrown
- Update this README with the new tool in Section 6
To report a bug or request a tool: open a GitHub issue with the keyCRM API endpoint you need covered and a description of the use case.
keycrm-mcp · Ivan Klymenko · MIT License