Skip to main content

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.

Experimental — tokens available on request

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
Copy it immediately — it is shown only once

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 typeAccounts it can reachHow the active account is chosen
Single-accountexactly one accountImplicit — nothing to specify.
Multi-accounta defined set of accountsSelected 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​

Limited early availability

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:

  1. JSON-RPC _meta on the call's params, under the key bookingsync.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 }
    }
    }
  2. The account_id tool argument on a tools/call (simplest for most clients — it's a normal tool argument, see Tools):

    {
    "name": "api_v3_list",
    "arguments": { "resource": "bookings", "account_id": 1234 }
    }
  3. The X-BookingSync-Account-ID HTTP 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.

Choosing a method

_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:

PrioritySourceHow to send
1Authorization header (preferred)Authorization: Bearer mcp_…
2X-MCP-Token header (legacy)X-MCP-Token: mcp_…
3token URL query parameter (legacy)https://www.bookingsync.com/mcp?token=mcp_…
Clients you cannot configure at all

Claude's custom connectors (Cowork, claude.ai, Claude Desktop, mobile) accept a URL and nothing else — there are no headers to set, and no token belongs in the URL. They obtain the token through a one-time browser sign-in and then present it exactly as row 1. See Connector sign-in below.

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 (legacy)​

The server also accepts the token as a token query parameter:

https://www.bookingsync.com/mcp?token=mcp_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p
Superseded — not the way to connect Claude

This existed for clients that could only be given a URL. Those clients now use the connector sign-in instead, which keeps the token out of the URL altogether — register https://www.bookingsync.com/mcp with no query parameters. The parameter is still accepted so existing setups keep working, but 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 redacts the token parameter from its own application logs and error tracking; still, treat any URL that contains a token as a secret.

Connector sign-in (for URL-only clients)​

Some clients — Claude's custom connectors in Cowork, claude.ai, Claude Desktop and the mobile apps — can only be pointed at a URL. They cannot attach an Authorization header, and they no longer need a token in the URL either: they discover that https://www.bookingsync.com/mcp supports an OAuth-style browser sign-in, and run it when you click Connect.

What happens:

  1. The client sends your browser to a Smily page titled Connect to bookingsync-mcp.
  2. You paste your MCP token there. Smily verifies it on the spot — a wrong, expired, or revoked token is refused on that page rather than failing silently later.
  3. Smily hands the client a single-use code, which it exchanges for the token behind the scenes.
  4. From then on the client sends Authorization: Bearer mcp_… on every call, exactly like a header-configured client.

There is no separate connector password, client ID, or client secret to obtain: the token you paste is the credential, and it keeps its own account scoping, expiry, and revocation. Leave any OAuth Client ID / OAuth Client Secret fields in the client empty.

The click-by-click walkthrough, with a screenshot of the page, is in Connecting clients.

What this is not

This is not a Smily account login. The page never asks for your Smily email or password, and completing it grants nothing beyond what the pasted token already allowed.

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_get only ever return records belonging to the active account.
  • A multi-account token cannot reach an account outside its authorized set: pinning an unauthorized account_id is rejected with an Invalid params error.

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:

HeaderMeaning
X-RateLimit-LimitThe hourly request ceiling (1000).
X-RateLimit-RemainingRequests left in the current window.
X-RateLimit-ResetUnix timestamp when the window resets.
Retry-AfterSeconds 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.

This covers connectors too: one that authenticated through the sign-in page holds that same token and nothing else, so revoking it stops the connector as well. To resume, connect again and paste a new token.