Authentication
Every request to the MCP server (except the health check) must carry a valid MCP token. A token is bound to a single account and user, and every query the agent runs is automatically scoped to that account.
The MCP server is experimental and MCP tokens are issued on request. Contact Smily to have a token created.
Obtaining a token
MCP tokens are issued on request. When you ask for one, specify which flavor you need (see Token types & account selection below):
- a token pinned to a single account (the common case), or
- a token that can operate across several accounts, choosing the active one per request (early access — currently limited to a small number of users; see below).
A token looks like this:
mcp_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p
The plaintext token is displayed only at the moment it is created. Smily stores only a hash of
it (SHA-256) plus a short mcp_… prefix for display, and the original value can never be recovered.
If you lose it, request a new one.
Tokens may optionally have an expiry. An expired or revoked token is rejected with an
Unauthorized error.
Token types & account selection
Every token is one of two types, which differ only in how the active account for a request is determined.
| Token type | Accounts it can reach | How the active account is chosen |
|---|---|---|
| Single-account | exactly one account | Implicit — nothing to specify. |
| Multi-account | a defined set of accounts | Selected per request (see below). |
Single-account tokens
The common case. The token is bound to one account, and every tool call operates on it. You don't specify an account — it's implicit. You can ignore the rest of this section.
Multi-account tokens
Multi-account tokens are in an early-access phase and are being made available to a small number of users first. They are not yet open to everyone — broader availability will follow. If you think you need one, get in touch.
A multi-account token can operate across several accounts — the set of accounts it is authorized
for. Because more than one account is reachable, every request must say which account to act on.
A multi-account token has no default account: a tool call that doesn't pin one fails with an
Invalid params error (account_id is required for this token).
You pin the active account in one of three ways. They are tried in this order, first match wins:
-
JSON-RPC
_metaon the call'sparams, under the keybookingsync.com/account-id:{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "api_v3_list",
"arguments": { "resource": "bookings" },
"_meta": { "bookingsync.com/account-id": 1234 }
}
} -
The
account_idtool argument on atools/call(simplest for most clients — it's a normal tool argument, see Tools):{
"name": "api_v3_list",
"arguments": { "resource": "bookings", "account_id": 1234 }
} -
The
X-BookingSync-Account-IDHTTP header — a request-wide fallback applied to every call in the request when neither of the above is present:X-BookingSync-Account-ID: 1234
The value is the numeric account id. If you pin an account the token isn't authorized for, the
call fails with account_id … is not authorized for this token.
_meta and account_id are per-call, so an agent can switch accounts between calls within one
session. The header is convenient when every call in a session targets the same account. For
single-account tokens these inputs are simply ignored (and a mismatching value is rejected).
Presenting the token
The server accepts the token from three sources. When more than one is present, the highest priority wins:
| Priority | Source | How to send |
|---|---|---|
| 1 | Authorization header (preferred) | Authorization: Bearer mcp_… |
| 2 | X-MCP-Token header (legacy) | X-MCP-Token: mcp_… |
| 3 | token URL query parameter | https://www.bookingsync.com/mcp?token=mcp_… |
1. Authorization header (preferred)
This is the recommended method and what most MCP clients support natively.
curl -X POST https://www.bookingsync.com/mcp \
-H "Authorization: Bearer mcp_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}'
2. X-MCP-Token header (legacy)
Still accepted for backwards compatibility; prefer Authorization: Bearer for new integrations.
curl -X POST https://www.bookingsync.com/mcp \
-H "X-MCP-Token: mcp_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p" \
-H "Content-Type: application/json" \
-d '{ ... }'
3. Token in the URL (for header-less clients)
Some MCP clients — notably Claude Cowork and other "add a connector by URL" experiences — can
only be configured with a URL and cannot attach a custom Authorization header. For those, put the
token in the token query parameter:
https://www.bookingsync.com/mcp?token=mcp_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p
A token in a URL leaks more easily than one in a header — URLs end up in browser history, proxy
logs, and crash traces. Smily mitigates this by redacting the token parameter from its own
application logs and error-tracking, but you should still prefer the Authorization header whenever
your client supports it. Treat a URL that contains a token as a secret.
Access scoping
A token can only ever reach the accounts it is authorized for — one account for a single-account token, or its defined set for a multi-account token. Every tool call is scoped to the account it targets:
api_v3_list/api_v3_getonly ever return records belonging to the active account.- A multi-account token cannot reach an account outside its authorized set: pinning an unauthorized
account_idis rejected with anInvalid paramserror.
Combined with the read-only nature of the tools, this keeps the blast radius tightly bounded.
Rate limiting
Each token is limited to 1,000 requests per hour. The server returns standard rate-limit headers on every response:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | The hourly request ceiling (1000). |
X-RateLimit-Remaining | Requests left in the current window. |
X-RateLimit-Reset | Unix timestamp when the window resets. |
Retry-After | Seconds to wait before retrying (only when throttled). |
When the limit is exceeded, the server responds with HTTP 429 Too Many Requests and a JSON-RPC
error with code -32029:
{
"jsonrpc": "2.0",
"id": null,
"error": { "code": -32029, "message": "Rate limit exceeded. Retry after 1543s." }
}
Revoking access
To cut off an agent immediately, revoke the token (or let it expire). Any active MCP session created with that token stops working on its next request, because the session re-checks the token's validity. See Protocol & transport → Sessions for session lifecycle details.