Smileline

MCP server

Connect an AI agent to a practice over the Model Context Protocol, with OAuth discovery, dynamic registration and three generic tools.

Each regional API serves a remote Model Context Protocol server, so an AI agent can operate a practice through the same API the rest of this reference describes. Sign-in is automatic: the agent discovers Smileline's OAuth server, registers itself and sends the person through the usual sign-in, practice picker and consent. For the practice-facing steps, see the AI agents guide.

Endpoint

RegionMCP server URL
Europehttps://api-eu.smileline.io/mcp
United Stateshttps://api-us.smileline.io/mcp

The server speaks stateless Streamable HTTP: POST /mcp only (GET and DELETE answer 405). It accepts OAuth access tokens only — an API key, a session cookie or a session bearer is refused. A request carrying an Origin header is refused with 403 (the MCP rule against DNS rebinding); supported clients call from a server or a native app.

Discovery

A request without a valid token answers 401 with:

WWW-Authenticate: Bearer resource_metadata="https://api-eu.smileline.io/.well-known/oauth-protected-resource/mcp", scope="read write offline_access"
DocumentURL (Europe)
Protected resource metadata (RFC 9728)https://api-eu.smileline.io/.well-known/oauth-protected-resource/mcp
Authorization server metadata (RFC 8414)https://api-eu.smileline.io/.well-known/oauth-authorization-server/auth

The protected resource's resource is the MCP server URL and its authorization_servers names the issuer https://api-eu.smileline.io/auth. Both documents are public and cacheable.

Registration

Clients register with dynamic client registration (RFC 7591) at POST /auth/oauth2/register, without authentication. Smileline registers every such client the same way, whatever the request asks for:

  • a public client (token_endpoint_auth_method: "none") with PKCE S256;
  • grants authorization_code and refresh_token;
  • scopes read, write and offline_access;
  • client_name trimmed to 80 characters; logos, URIs and contacts are dropped, and the consent screen marks the app Unverified app.

A registration names one to three redirect URIs, and each must be one of:

ClientRedirect URI
Claude (web, desktop, mobile)https://claude.ai/api/mcp/auth_callback
ChatGPThttps://chatgpt.com/connector_platform_oauth_redirect, or under https://chatgpt.com/connector/oauth/
Cursorhttps://www.cursor.com/agents/mcp/oauth/callback, cursor://anysphere.cursor-mcp/oauth/callback
VS Codehttps://vscode.dev/redirect
Tools on the user's computerhttp://localhost, http://127.0.0.1 or http://[::1], any port and path

Any other redirect URI is refused with invalid_redirect_uri, so a stranger cannot register a look-alike app that sends the practice's approval to their own site. Registration is limited per client address block, like the other unauthenticated OAuth endpoints (see Rate limits). A registration that nobody approves within 24 hours is removed; a client holding it gets invalid_client and should register again.

Tokens

The authorization code and refresh requests may carry resource (RFC 8707); it must be the MCP server URL, or the request fails with invalid_target. Tokens are the ordinary OAuth tokens described under Authentication: an access token lasts one hour, a refresh token 30 days and rotates on every use. The consent binds the connection to one practice, and only owners and managers can give it.

Agency connections

A partner agency's owner or member can instead consent on the agency, for read, write and offline_access only. Without a practice argument, a call acts on the agency: GET /partner/practices, POST /partner/practices and the rest of its account. Every tool also takes practice: an organizationId from GET /partner/practices. With it, search_operations lists a practice's operations, and read and write act inside that practice with the approving person's current role there. Any customer practice currently linked to the approved, active agency that the person still belongs to can be reached, including an existing practice linked later or moved from another agency. Linking a practice does not grant a membership. read or write with any other id answers 404 PRACTICE_NOT_FOUND. search_operations returns operation metadata only and does not check the id. GET /partner/practices carries ownerJoined for each practice: whether an owner from outside the agency has joined. The link, membership, role and agency standing are checked on every call, so unlinking, moving the practice away or losing membership ends access on the next request.

POST /partner/practices needs the practice owner's ownerEmail, which receives a 48-hour owner invitation. Repeating an identical create answers 200 with the practice it made. An agency's agents can create 100 practices per rolling 24 hours; past that, the create answers 429 PARTNER_CREATE_LIMIT with Retry-After. POST /leads and managed webhook subscriptions are not available through an agency connection.

Until the owner joins, POST /partner/practices/:organizationId/owner-invitation with ownerEmail sends the practice's owner invitation again, or to a corrected address, and DELETE on the same path withdraws it. Both act on the agency: call them without practice and put the id in params. These owner-handover operations reach only practices the agency created that remain linked to it and that the approving person belongs to; any other id answers 404 PRACTICE_NOT_FOUND. The same address renews the invitation for another 48 hours. A new address first cancels every other pending owner invitation, and any other pending invitation to that address, so the old link stops working. The answer carries sent and delivery, the email's state: pending, publishing, published or parked. A repeat within an hour of the last email answers sent: false and emails nobody, and so does a repeat while that email is being handed to the queue. If the last email failed or was parked, the call sends that same email again rather than a new one: the owner receives it at most once. DELETE answers canceled, the number withdrawn. Once the owner has joined, both answer 409 PRACTICE_OWNER_JOINED, and an address that belongs to a member of the practice answers 409 OWNER_ALREADY_MEMBER. One address receives at most three owner invitation emails for the same practice in 24 hours; past that, POST answers 429 OWNER_INVITATION_LIMIT with Retry-After.

Check a practice's setup

With practice set, read on GET /settings/practice/setup-status returns a practice's whole setup in one call. It changes nothing: unlike the website settings page, it never creates the practice's website tracking settings.

FieldHolds
guideThe setup guide: which tasks are done and the practice's answers.
ownerjoined, true once the practice has an owner from outside the agency's team, and the newest owner invitation: email, status (pending, expired, accepted, rejected or canceled), expiresAt and the state of its email (delivery).
teamHow many members the practice has and how many invitations are still open (pendingInvitations).
websiteThe website checklist: tracking script seen, forms found, test lead received, mapping confirmed.
leadAdsEach connected ad platform and its status.
conversionsConversion setup for each ad platform.
emailDomainsThe practice's sending domains and their verification.
pendingAgreementsDocuments the practice has not accepted in their current version. An owner accepts them in Smileline; no connection can.

For a practice the agency created, while joined is false, send the owner invitation again with POST /partner/practices/:organizationId/owner-invitation when it is expired or its newest email is parked (it may not have gone out). Only owners, managers and Agency members can read the setup status; any other role gets 403.

Tools

ToolDoes
search_operationsFinds API operations by keyword, ten per page with nextOffset. Each result carries its operation id and input JSON Schema.
readRuns a GET operation: { operation, params?, query?, range?, etag? }.
writeRuns a POST, PUT, PATCH or DELETE operation: { operation, params?, query?, body? }.

An operation id is its method and path, for example GET /patients/:id. Each call runs through the regular API route, so it gets the same validation, permission checks, tenant isolation and audit as a direct request; an API error comes back as the tool's error result with the API's error body. One tool call counts as one request against the connection's 300 requests per minute. Send one JSON-RPC message per request: a batch (a JSON array) is refused with error -32600.

A connection granted only read can search and use read; change operations are not listed for it and write refuses them.

A reply is returned whole up to 16 MiB. A stored file — an export download, for example — comes back in parts: the first result carries totalBytes, etag and nextOffset, and the next read of the same operation passes range: { offset, length } with that etag. Each part re-checks permissions, and a changed file answers "start again from offset 0". Text parts always end on a whole character. A write whose reply is too large to return still reports the change as applied, with its status.

Not available to agents

  • Core Practice Transfer (/transfer/core-*).
  • The PMS workspace and clinical referrals, which refuse machine credentials.
  • Calls and recordings, which need the dialer scope no agent holds.
  • Account-wide surfaces such as /user and /organization (BROWSER_SESSION_REQUIRED).

On this page