MCP Servers

模型上下文协议服务器、框架、SDK 和模板的综合目录。

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.

创建于 3/25/2026
更新于 about 5 hours ago
Repository documentation and setup instructions

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

  1. What This Is
  2. Requirements
  3. Installation
  4. Configuration
  5. MCP Client Setup
  6. Tool Reference
  7. Error Handling
  8. Logging
  9. Project Structure
  10. Implementation Notes
  11. 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:

  1. Call with dry_run: true → returns list of affected products
  2. 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_LIMIT error 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:

  1. POST /storage/upload — uploads the image from the provided URL to keyCRM Storage, returns a file_id
  2. PUT /products/{productId} — attaches the file_id to 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:

  1. Phase 1 (dry_run: true): Fetches matching products using the provided filter, returns the list without modifying anything
  2. 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

快速设置
此服务器的安装指南

安装包 (如果需要)

npx @modelcontextprotocol/server-keycrm-mcp

Cursor 配置 (mcp.json)

{ "mcpServers": { "ivanklymenko-keycrm-mcp": { "command": "npx", "args": [ "ivanklymenko-keycrm-mcp" ] } } }