baselinker-mcp

baselinker-mcp

Enables natural language interaction with BaseLinker (orders, invoices, returns, inventory, CRM, and more) through the Model Context Protocol, with optional write access.

Category
访问服务器

README

baselinker-mcp

CI License: MIT Node

An MCP server that puts the whole BaseLinker API — orders, invoices, returns, couriers, CRM, warehouses, products — in front of an LLM client such as Claude Code, Claude Desktop or Cursor.

  • Complete. All 179 documented API methods, none of them stubbed.
  • Read-only until you say otherwise. The 92 write methods stay invisible unless you opt in; with writes off, every tool reports readOnlyHint: true.
  • Local or remote. stdio for a client on your machine, or Streamable HTTP with OAuth 2.1 (Keycloak) for a shared endpoint on the internet.
"How many orders came in yesterday that aren't paid yet?"
"Which catalog products dropped below 5 in stock this week?"
"Pull the courier label for order 1234567 and tell me the tracking number."

Contents

Quickstart

Requirements: Node.js 20 or newer, and a BaseLinker API token from the BaseLinker panel under Account & other → My account → API.

git clone https://github.com/PiotrRaszkowski/baselinker-mcp.git
cd baselinker-mcp
npm install
npm run build
cp .env.example .env     # paste your token into BASELINKER_API_TOKEN

The token can also come straight from the environment, which takes precedence over .env. .env is read from the package root, so the server starts correctly no matter which directory your MCP client launches it from.

Connecting a client

Claude Code

claude mcp add baselinker -e BASELINKER_API_TOKEN=your-token -- node /path/to/baselinker-mcp/dist/index.js

Claude Desktop, Cursor, or any mcpServers config

{
  "mcpServers": {
    "baselinker": {
      "command": "node",
      "args": ["/path/to/baselinker-mcp/dist/index.js"],
      "env": { "BASELINKER_API_TOKEN": "your-token" }
    }
  }
}

For a shared endpoint reachable from claude.ai, see Remote deployment.

Tools

179 separate tools would swamp a model's context and its ability to choose between them, so methods are grouped the way BaseLinker itself groups them: ten tools, one per API category. Each takes a method name and a parameters object, and each tool's description lists the methods it accepts along with their parameters and pagination hints.

Counts below are read + write; write methods only appear when BASELINKER_ALLOW_WRITES=true.

Tool Scope Methods
baselinker_orders Orders, statuses, payments, journal, PickPack carts 15 + 22
baselinker_invoices Invoices, invoice files, numbering series, receipts 6 + 6
baselinker_returns Order returns, statuses, reasons, payments, journal 8 + 13
baselinker_courier Couriers, packages, labels, protocols, documents 11 + 4
baselinker_crm CRM clients and statuses 5 + 6
baselinker_inventory Catalogs, warehouses, locations, categories, manufacturers, suppliers, payers, tags 18 + 24
baselinker_products Product lists, data, stock, prices, logs 5 + 5
baselinker_documents Warehouse documents, purchase orders, fulfillment deliveries 10 + 9
baselinker_connect Base Connect integrations and contractor credit 3 + 2
baselinker_external_storage External storages (shops, wholesalers) 6 + 1
87 + 92

Parameters are validated against a Zod schema per method before anything is sent, so a malformed call comes back as a readable error instead of a BaseLinker error code. Unknown keys are forwarded untouched — BaseLinker adds parameters without warning, and the server does not break when it does.

Write methods

Disabled by default. To enable:

BASELINKER_ALLOW_WRITES=true

While disabled, write methods are neither listed in any tool's method enum nor callable. Enabling turns on all 92 at once — creating, updating and deleting orders, products, stock, prices, invoices, shipments, returns and warehouse documents. Some of them delete records; some dispatch real courier shipments that cost real money. There is no per-method gating, so enable writes only for a client you trust, and consider running a second read-only instance for everything else.

Behaviour worth knowing

Rate limiting. BaseLinker allows 100 requests per minute. A client-side sliding-window limiter enforces it — excess calls wait their turn rather than failing.

Pagination. List responses are capped (typically 100 items for orders, invoices and returns; 1000 for catalog products). Each method's description carries the specific hint, for example getOrders wants date_confirmed_from set to the last returned order's date_confirmed plus one second, while getInventoryProductsList takes a 1-based page.

File downloads. getLabel, getProtocol, getCourierDocument, getInvoiceFile, getInventoryDocumentFile and getInventoryFulfillmentDeliveryLabels return the file as an MCP embedded resource with a real MIME type. Pass the extra save_to_path parameter — handled locally, never sent to BaseLinker — to decode it to disk instead and get back { saved_to, extension, bytes }. This only makes sense over stdio, where the server runs on your own machine; over HTTP it is rejected with an explanatory error.

Remote deployment (HTTP + OAuth)

With --transport http the server speaks Streamable HTTP and acts as an OAuth 2.0 Resource Server (RFC 9728): it publishes protected resource metadata, answers unauthenticated calls with 401 plus a WWW-Authenticate challenge, and verifies every access token as an RS256 JWT against a Keycloak realm's JWKS. Clients discover the realm from that metadata and register themselves through Dynamic Client Registration, so no client ID or secret is configured on either side.

node dist/index.js --transport http --host 0.0.0.0 --port 8000 --path /mcp
Path Auth Purpose
POST /mcp Bearer MCP Streamable HTTP, stateless — a fresh server per request
GET / DELETE /mcp Bearer 405; stateless mode has no server-initiated streams
/.well-known/oauth-protected-resource[/mcp] public RFC 9728 resource metadata
/healthz public Liveness probe

HTTP transport refuses to start without an auth realm unless you opt out explicitly with BASELINKER_MCP_AUTH_DISABLED=true. That is deliberate: with writes enabled, an unauthenticated endpoint hands the internet your BaseLinker account.

deploy/ has the full guide — Keycloak realm setup, a hardened Compose service with Traefik labels, reverse-proxy snippets for Caddy and nginx, verification commands and a threat model. The short version:

docker build -t baselinker-mcp:0.2.0 .
docker run -d --name baselinker-mcp -p 8000:8000 \
  -e BASELINKER_API_TOKEN=your-token \
  -e BASELINKER_MCP_AUTH_REALM_URL=https://keycloak.example.com/realms/myrealm \
  -e BASELINKER_MCP_AUTH_BASE_URL=https://mcp.example.com \
  baselinker-mcp:0.2.0

Then point a client at it:

claude mcp add --transport http baselinker https://mcp.example.com/mcp

In claude.ai it is Settings → Connectors → Add custom connector, URL https://mcp.example.com/mcp, with Client ID and Client Secret left empty.

One thing to be clear about before you expose it: the BaseLinker token is shared. Everyone who can log into the realm operates on the same BaseLinker account. See SECURITY.md for the rest of the boundaries.

Configuration reference

Everything is an environment variable; .env in the package root is loaded automatically.

Always

Variable Default Purpose
BASELINKER_API_TOKEN — Required. BaseLinker API token
BASELINKER_ALLOW_WRITES false true exposes all 92 write methods

Transport

CLI flags win over these.

Variable Flag Default Purpose
BASELINKER_MCP_TRANSPORT --transport stdio stdio or http
BASELINKER_MCP_HOST --host 0.0.0.0 Bind address, HTTP only
BASELINKER_MCP_PORT --port 8000 Bind port, HTTP only
BASELINKER_MCP_PATH --path /mcp Endpoint path, HTTP only

OAuth — required when transport is http

Variable Default Purpose
BASELINKER_MCP_AUTH_REALM_URL — Keycloak realm issuing tokens, e.g. https://keycloak.example.com/realms/myrealm
BASELINKER_MCP_AUTH_BASE_URL — Public URL of this server; with the path it forms the OAuth resource identifier
BASELINKER_MCP_AUTH_AUDIENCE unset Audience(s) a token must carry. Needs an audience mapper in Keycloak; unset skips the check
BASELINKER_MCP_AUTH_REQUIRED_SCOPES openid Scopes every token must carry. openid guarantees a sub claim
BASELINKER_MCP_AUTH_DISABLED false true starts HTTP with no authentication. Never on a public address
BASELINKER_MCP_ALLOWED_HOSTS unset DNS-rebinding protection: accepted Host headers. Redundant behind a host-routing proxy
BASELINKER_MCP_ALLOWED_ORIGINS unset DNS-rebinding protection: accepted Origin headers

Lists accept commas or spaces.

Troubleshooting

Symptom Cause
Missing BASELINKER_API_TOKEN No token in the environment or in .env at the package root
BaseLinker API error [ERROR_AUTH_TOKEN] Token rejected by BaseLinker — regenerate it in the panel
A write method is "unknown" BASELINKER_ALLOW_WRITES is not true
Calls get slower under load The rate limiter is pacing you to 100 requests/minute. Working as intended
HTTP transport requires BASELINKER_MCP_AUTH_REALM_URL Set the realm and base URL, or opt out with BASELINKER_MCP_AUTH_DISABLED
401 no applicable key found in the JSON Web Key Set Token was not signed by the configured realm
403 insufficient_scope Token lacks openid

More OAuth-specific cases are in deploy/README.md.

Development

npm run dev         # run from sources (tsx), stdio transport
npm run start:http  # built server, HTTP transport
npm test            # unit tests — fully offline, no live API calls
npm run check       # format check + typecheck + tests, what CI runs
npm run smoke       # manual smoke test against the live API (uses .env)
npm run inspect     # MCP Inspector against the built server

CONTRIBUTING.md covers how the tool registry is put together and what to watch out for when adding a method.

License

MIT. Not affiliated with or endorsed by BaseLinker.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选