Skip to main content
Glama

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

Related MCP server: TextQL MCP Server

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.

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • Manage your Savanto store from your AI: catalog, content, prompts, and analytics, by chat.

  • Manage your Jumpseller store with AI. Products, orders, customers, and more.

  • Stop re-explaining yourself to Agents. Give it the right context, right when needed.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/PiotrRaszkowski/baselinker-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server