Skip to main content
Glama

@aiotic/mcp

The Model Context Protocol server for the AIOTIC Integrator Guide. It gives your coding assistant (Claude Code, Cursor, VS Code or any other MCP client) exact answers while you integrate AIOTIC purchase-order processing with your ERP: it searches the guide, returns endpoint contracts and schemas from the public OpenAPI document and hands out payload examples. On your own machine it can also look at your test tenant.

Use it

The entry differs per assistant: Claude Code and Cursor read mcpServers, VS Code reads servers.

Claude Code, in .mcp.json in your project:

{ "mcpServers": { "aiotic": { "command": "npx", "args": ["-y", "@aiotic/mcp"] } } }

Cursor, in .cursor/mcp.json in your project, or in ~/.cursor/mcp.json for every project:

{ "mcpServers": { "aiotic": { "type": "stdio", "command": "npx", "args": ["-y", "@aiotic/mcp"] } } }

VS Code, in .vscode/mcp.json in your project:

{ "servers": { "aiotic": { "type": "stdio", "command": "npx", "args": ["-y", "@aiotic/mcp"] } } }

Other assistants and where their configuration lives: MCP server in the guide. Node.js 20 or newer. There is nothing else to configure: docs mode needs no key and sends nothing anywhere.

Each version carries one edition of the guide and of the API document, so pin a version ("args": ["-y", "@aiotic/mcp@<version>"]) when you want the same answers every time. The server reports the edition to your client when it connects.

Prefer no installation at all? The hosted endpoint https://mcp.aiotic.ai/mcp runs the same server in docs mode and always serves the latest revision of the guide. For Claude Code:

{ "mcpServers": { "aiotic": { "type": "http", "url": "https://mcp.aiotic.ai/mcp" } } }

The guide has the entry, a one-line command or a one-click link for every other assistant: Connect your coding assistant.

Related MCP server: MCP Server for Odoo

Docs mode (default)

Tool

What it returns

search_guide(query, limit?)

Best-matching sections with page, heading and snippet

list_pages()

Every page of the guide with section, title and summary

get_page(path)

One page as Markdown

list_endpoints(tag?)

Method, path, summary and authentication per endpoint, plus the outbound webhooks

get_endpoint(operationId | "METHOD /path")

The full contract: parameters, request and response schemas, examples

get_schema(name)

One schema from the OpenAPI components

get_example(name)

Payload samples

get_status_lifecycle()

Status values, their meaning and the transitions between them

Tenant mode (opt-in, local only)

Set AIOTIC_BASE_URL and AIOTIC_API_KEY in the server's environment and the assistant can also read your test tenant or the mock from the AIOTIC Python SDK: orders and their status, rejected e-mails, customers, products and customer item mappings.

{ "mcpServers": { "aiotic": {
    "command": "npx", "args": ["-y", "@aiotic/mcp"],
    "env": { "AIOTIC_BASE_URL": "http://localhost:8080", "AIOTIC_API_KEY": "mock-integration-key" } } } }

That is the entry for Claude Code and Cursor; in VS Code the same command, args and env go under servers, with "type": "stdio".

  • Read tools are on. Write tools need AIOTIC_MCP_ALLOW_WRITES=true. Deletes and send_order_to_erp also need AIOTIC_MCP_ALLOW_DANGEROUS=true and confirm: true in the call.

  • Keys come from the environment, never from tool arguments, and are removed from everything the server returns.

  • Tenant tools exist on the stdio transport only. Use a test tenant: whatever key you put in an assistant's environment, the assistant can use.

Run it over HTTP yourself

npx -y @aiotic/mcp --http 3333      # http://127.0.0.1:3333/mcp and /healthz, docs mode only

The HTTP transport refuses to start when any tenant variable is set. Behind a reverse proxy, set AIOTIC_MCP_TRUST_PROXY to the peers whose X-Real-IP and X-Forwarded-For headers may be believed: 1 (loopback), gateway (the container's default gateway), private, CIDR ranges or any.

Variable

Purpose

Default

AIOTIC_MCP_HOST

Address the server listens on

127.0.0.1

AIOTIC_MCP_RATE_BURST, AIOTIC_MCP_RATE_PER_SECOND

Requests per client address: a burst, then a steady rate

60, 1

AIOTIC_MCP_ALLOWED_HOSTS

Host header allow-list

any host

AIOTIC_MCP_ALLOWED_ORIGINS

Browser origins that may call; a request with any other Origin gets 403

none

AIOTIC_MCP_MAX_BODY

Largest request body, in bytes

262144

AIOTIC_MCP_BLOCKLIST

File with addresses and CIDR ranges to refuse

none

AIOTIC_MCP_ANALYTICS_DIR

Usage log, one JSON line per request; node dist/stats.js --dir <dir> --days 30 aggregates it

off

AIOTIC_MCP_RETENTION_DAYS

Days the usage log is kept

180

AIOTIC_MCP_LOG_DAY_MAX_MB, AIOTIC_MCP_LOG_MAX_MB

Size limits of the usage log, per day and in total

128, 512

AIOTIC_MCP_GEOIP_DB

MMDB country database for the usage log

none

Development

npm ci
npm test        # builds, then runs the smoke test over stdio and HTTP

This repository is published release by release from the AIOTIC documentation sources, one commit per release, and each release is published to npm from here by .github/workflows/publish-npm.yml. Pull requests cannot be merged here directly; please open an issue and we will take the change into the next release.

License

MIT, see LICENSE.

Available Tools

28 tools
delete_customerDelete customer (dangerous)B

DELETE /customer/{number}. Requires AIOTIC_MCP_ALLOW_DANGEROUS=true and confirm:true.

Inputs: number (required), confirm.

delete_customer_productDelete customer item mapping (dangerous)A

DELETE /customer-product/{customer_number}/{customer_item_number}. Requires AIOTIC_MCP_ALLOW_DANGEROUS=true and confirm:true.

Inputs: customer_number (required), customer_item_number (required), confirm.

delete_productDelete product (dangerous)B

DELETE /product/{item_number}/{language_code}. Requires AIOTIC_MCP_ALLOW_DANGEROUS=true and confirm:true.

Inputs: item_number (required), language_code (required), confirm.

get_customerGet customerD

GET /customer/{number}.

Inputs: number (required).

get_endpointGet an endpoint contractA

Full contract of one endpoint by operationId (e.g. sendOrderToErp, uploadOrder, upsertCustomer) or "METHOD /path", or a webhook name (erpReceiveOrder, processingCompleted). Schemas are inlined.

Inputs: ref (required).

get_exampleGet a payload exampleB

Real payload samples. Names: erp-receive-request, erp-receive-response-accepted, erp-receive-response-rejected, order-status, upload-response-split, raw-upload-rejection, customer-upsert, product-upsert, customer-product-upsert, sync-events.

Inputs: name (required).

get_order_groupGet split e-mail groupD

GET /order/group/{email_group_id}.

Inputs: email_group_id (required).

get_order_statusGet order statusB

GET /order_status/{request_id} — status, extracted purchase order (result), erp_ref, errors.

Inputs: request_id (required).

get_pageGet a guide pageA

Return one guide page as Markdown. Paths look like /receiving/erp-receive-endpoint or /sdk/pipeline. Use list_pages to discover paths.

Inputs: path (required).

get_productGet productD

GET /product/{item_number}/{language_code}.

Inputs: item_number (required), language_code (required).

get_schemaGet a schemaA

One JSON schema from the API components, with $refs inlined. Names: Address, ClassifiedEmail, Customer, CustomerListResponse, CustomerProduct, CustomerProductListResponse, CustomerProductUpsert, CustomerSearchResponse, CustomerUpsert, EmailClassificationResponse, ErpAddress, ErpCustomer, ErpOrderItem, ErpPurchaseOrder, ErpReceiveRequest, ErpReceiveResponse, ErpRecipient, ErpSendResponse, ErpShippingDetails, ErrorResponse, FetchAllEmailsResponse, HTTPValidationError, OrderCustomer, OrderGroup, OrderItem, OrderListResponse, OrderRef, OrderRetryBody, OrderStatus, OrderStatusValue, OrderUploadBody, OrderUploadResponse, ProcessingWebhookRequest, Product, ProductListResponse, ProductUpsert, PurchaseOrder, RawEmailClassifyBody, RawEmailUploadBody, RawUploadRejection, RejectedEmailListResponse, ReprocessResponse, ShippingDetails, ShippingRecipient, Supplier, SystemStatus, ValidationError.

Inputs: name (required).

get_status_lifecycleOrder status lifecycleB

Status values, which are sendable / landed / terminal, and the transitions between them.

Inputs: no named parameters.

list_customer_productsList customer item mappingsC

GET /customer-product/list with optional filters.

Inputs: size, item_number, customer_number.

list_endpointsList API endpointsA

Every public AIOTIC endpoint (method, path, summary, auth) plus the outbound webhooks you implement. Optional tag filter: health, orders, order-status, erp, rejected, customers, products, customer-products, email-watcher, webhooks.

Inputs: tag.

list_ordersList ordersC

GET /order_status/list — newest first.

Inputs: page, size.

list_pagesList guide pagesA

All pages of the guide with section, title and one-line summary, in reading order.

Inputs: no named parameters.

list_productsList productsD

GET /product/list.

Inputs: page, size, language_code.

list_rejected_emailsList rejected e-mailsD

GET /rejected/list.

Inputs: size, status.

reprocess_rejected_emailReprocess a rejected e-mail (write)C

POST /rejected/{request_id}/reprocess. Requires AIOTIC_MCP_ALLOW_WRITES=true.

Inputs: request_id (required).

retry_orderRetry a FAILED order (write)B

POST /order/retry/{request_id}. Requires AIOTIC_MCP_ALLOW_WRITES=true.

Inputs: request_id (required).

search_customersSearch customersC

GET /customer/search/{query} — fuzzy search over your customer records, comparable to how AIOTIC matches order senders.

Inputs: query (required), top_k.

search_guideSearch the Integrator GuideA

Full-text search over the guide (sections). Returns page, heading, URL and a snippet. Use before answering any AIOTIC integration question.

Inputs: query (required), limit.

send_order_to_erpSend order to ERP (dangerous)A

POST /erp/send/{request_id} — calls the tenant's ERP receive endpoint. Requires AIOTIC_MCP_ALLOW_DANGEROUS=true and confirm:true.

Inputs: request_id (required), confirm.

tenant_healthTenant healthA

GET /healthcheck and /system-status of the configured tenant (no key needed).

Inputs: no named parameters.

upload_orderUpload a text order (write)B

POST /order/upload with one text/markdown file built from the given content — for exercising the flow against the mock/test tenant. Requires AIOTIC_MCP_ALLOW_WRITES=true.

Inputs: content (required), filename (required), request_id.

upsert_customerUpsert customer (write)C

PUT /customer/{number}. Requires AIOTIC_MCP_ALLOW_WRITES=true.

Inputs: data (required), number (required).

upsert_customer_productUpsert customer item mapping (write)C

PUT /customer-product/{customer_number}/{customer_item_number}. Requires AIOTIC_MCP_ALLOW_WRITES=true.

Inputs: item_number (required), language_code (required), customer_number (required), customer_item_number (required).

upsert_productUpsert product (write)C

PUT /product/{item_number}/{language_code}. Requires AIOTIC_MCP_ALLOW_WRITES=true.

Inputs: description (required), item_number (required), language_code (required), remark.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    C2.8/5.0

    Scored across 28 tools

    Disambiguation4/5

    Tools are largely distinct: documentation tools (search_guide, get_page, list_pages) vs. contract tools (list_endpoints, get_endpoint, get_schema, get_example) vs. domain operations are clearly separated by resource and action. The only mild overlap is among the order-flow write tools (retry_order, upload_order, send_order_to_erp, reprocess_rejected_email), but their descriptions distinguish them well enough.

    Naming Consistency4/5

    The set follows a consistent snake_case verb_noun pattern (list_orders, get_customer, upsert_product, delete_customer, search_customers). The main deviation is tenant_health, which uses a noun_noun form rather than a verb prefix, but everything else is predictable.

    Tool Count3/5

    At 28 tools this is heavy and sits at the upper edge of what an agent can scan efficiently. The breadth is partly justified by the wide domain (full docs surface plus orders, customers, products, and rejected-email operations), and most tools earn their place, but the count is borderline excessive.

    Completeness4/5

    Coverage is strong: full CRUD for customers, products, and customer-products, plus order lifecycle (upload, retry, send, status, group), rejected-email handling, and comprehensive docs/contract tooling. Minor gaps remain (no explicit order deletion, webhook configuration management, or batch operations), but core workflows have no dead ends.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      Not graded
      maintenance
      Enables AI assistants to interact with Odoo ERP systems through natural language to search records, create entries, update data, and manage business operations. Supports secure authentication and configurable access controls for production environments.
      Mozilla Public 2.0
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables AI assistants to interact with Odoo ERP systems through natural language, allowing users to search, create, update, and manage business records like customers, products, and invoices across any Odoo instance.
      1
      Mozilla Public 2.0
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables AI agents to query and operate on ERP data through a unified tool interface, working across CSV exports, SFTP drop folders, SQLite/ODBC, and optional enterprise APIs. It supports purchase orders, vendors, and inventory lookups while keeping agent-facing tools consistent regardless of backend.
      MIT
    • F
      license
      Not graded
      quality
      C
      maintenance
      Enables AI assistants to query and execute Slingrs ERP endpoints for sales orders, inventory, production, purchasing, shipments, and custom entities through dynamically loaded OpenAPI tools.
      9 npm
      -