Keycrm MCP
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.
Ask AI about Keycrm MCP
Powered by Claude Β· Grounded in docs
I know everything about Keycrm MCP. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
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
