Skip to content

MCP integration

Since v0.4.0. Production stable can lag behind new releases. If the version in its manifest is older than v0.4.0, load a pinned vX.Y.Z path (v0.4.0 or later) instead. Use MCP integration when your application already exposes data or operations through a remote MCP server. The chatbot can call an approved set of tools for the user signed in to your page.

The browser calls your MCP endpoint directly. This flow is for user-scoped operations. Keep backend-only credentials out of it; see Security and CSP.

For each server, provide:

  • an absolute HTTPS MCP endpoint that uses Streamable HTTP; URLs must not contain credentials, including query-string credentials;
  • the tools to enable, with each tool classified as read or write;
  • a description and JSON input schema for each enabled tool, or access for Tiketo to create a filtered snapshot;
  • the frontend origins that will host the chatbot;
  • a test account for integration and agent evaluation.

The allowlist denies all tools by default. Tiketo gives each endpoint a short server key. The chatbot can call only the tools configured for that key. Keep real endpoints and customer configuration out of client-side integration code.

Register each server before or after init. The header provider runs for every MCP request, so your application can refresh credentials when needed. This example supplies the signed-in user’s bearer token:

tiketoChat("mcp", "primary", {
headers: async () => ({
Authorization: "Bearer " + await getToken(),
}),
});
tiketoChat("mcp", "analytics", {
headers: async () => await getAnalyticsHeaders(),
});
tiketoChat("mcp", "cookie-session", {
credentials: "include",
});

The object can contain authorization, API-key, tenant, or other headers expected by your server. Header mode is the default because many MCP servers advertise bearer_methods_supported: ["header"] in their OAuth protected-resource metadata and accept bearer credentials only in Authorization. For cookies, set credentials: "include"; the header provider is optional. Calling the command again replaces that server’s registration. On logout, remove it with tiketoChat("mcp", "primary", null) and call reset to discard the conversation and all MCP session IDs.

The embed controls protocol and correlation headers. It accepts Authorization and custom headers, but ignores host values for Content-Type, Accept, mcp-session-id, MCP-Protocol-Version, X-Tiketo-Conversation-Id, and X-Tiketo-Request-Id.

Register MCP access in an effect. Remove it when the signed-in session changes or the component unmounts:

import { useEffect } from "react";
export function ChatMcpAuth({ getToken }: { getToken(): Promise<string> }) {
useEffect(() => {
tiketoChat("mcp", "primary", {
headers: async () => ({ Authorization: `Bearer ${await getToken()}` }),
});
return () => tiketoChat("mcp", "primary", null);
}, [getToken]);
return null;
}

Allow requests from every frontend origin that uses the client ID. Permit POST and list Authorization, Content-Type, Accept, mcp-session-id, MCP-Protocol-Version, X-Tiketo-Conversation-Id, and X-Tiketo-Request-Id, plus every custom host header. Access-Control-Allow-Headers: * does not cover Authorization under the Fetch standard. Expose mcp-session-id so the browser can keep the server’s session identifier. Your page’s Content Security Policy must also list the MCP origin in connect-src; see Security and CSP.

For bearer header mode, a preflight response can be:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type, Accept, mcp-session-id, MCP-Protocol-Version, X-Tiketo-Conversation-Id, X-Tiketo-Request-Id
Access-Control-Expose-Headers: mcp-session-id
Vary: Origin

Cookie mode requires the exact frontend origin, not *, and the credentials flag:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type, Accept, mcp-session-id, MCP-Protocol-Version, X-Tiketo-Conversation-Id, X-Tiketo-Request-Id
Access-Control-Expose-Headers: mcp-session-id
Vary: Origin

Check the deployed preflight from an allowed frontend origin. Add every custom host header to the request and the server allowlist.

Terminal window
curl -X OPTIONS 'https://mcp.example.com/rpc' \
-H 'Origin: https://app.example.com' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: Authorization, Content-Type, Accept, mcp-session-id, MCP-Protocol-Version, X-Tiketo-Conversation-Id, X-Tiketo-Request-Id' \
-i

The embed supports MCP 2025-06-18 and sends MCP-Protocol-Version: 2025-06-18. It does not negotiate another version from the initialize response. The changelog will announce support for a newer version before it is enabled.

The transport is POST only. The embed never opens a GET SSE stream, so a stateless server needs no GET handler. POST responses may use text/event-stream or application/json.

Every MCP HTTP request includes:

  • Content-Type: application/json;
  • Accept: application/json, text/event-stream;
  • MCP-Protocol-Version: 2025-06-18;
  • mcp-session-id after the server establishes a session;
  • X-Tiketo-Conversation-Id, an opaque per-chat-session ID generated by the embed;
  • X-Tiketo-Request-Id on tools/call only; and
  • the headers returned by the host provider.

The embed rotates X-Tiketo-Conversation-Id on reset or logout. It records the same opaque per-chat-session ID generated by the embed in the launch event as tiketoConversationId, so Tiketo can correlate it with transcripts on request. X-Tiketo-Request-Id matches params._meta["tiketo/requestId"].

Authentication headers are read only when an MCP request is about to be sent. Tiketo Chat does not cache, persist, or log their names or values. It does not include them in completion events. They travel from the browser to your configured MCP endpoint and are not sent to Tiketo’s Worker or the conversation service.

Tool arguments and results are part of the chatbot task. The conversation service processes them, and they can appear in transcripts. Enable only tools whose input and output are suitable for that data path.

Ask Tiketo for the retention, region, and subprocessor documentation that applies to your integration.

Write tools always show an explicit confirmation in the chat before the browser makes a network request. Declining returns cancelled and sends nothing to the MCP server.

Treat tool results as untrusted third-party text. The chatbot can call only allowlisted tools, and every write requires fresh user confirmation in the UI. Tool text cannot authorize or execute a write by itself.

The default timeout is 20 seconds per call. It covers authentication header resolution, the network request, response reading, parsing, and retries. The default result limit is 8,000 Unicode characters; Tiketo can change the server default or set a per-tool limit. Only text content items are passed to the chatbot. Other content types become short placeholders, and truncated says whether text was cut. structuredContent is not currently used, so always include a text rendering in content.

Every response also has a byte ceiling. The per-server maxResponseBytes setting defaults to 1 MiB and stops JSON or SSE bodies as soon as they exceed the limit.

Each chatbot tool call gets a new opaque ID in _meta["tiketo/requestId"]. Use it to de-duplicate writes. The embed keeps the same ID if it sends that logical call again:

Condition Embed behavior
401 Calls the header provider again and retries once with the same request id; another 401 or a 403 returns not_authenticated.
403 No retry; returns not_authenticated.
404 with mcp-session-id Re-initializes once and retries once with the same request id. The unknown session means the server did not execute that attempt.
Timeout or network/CORS failure Never retried by the embed.

After timeout or mcp_unavailable, the chatbot is instructed not to repeat a write automatically. It tells the user that the outcome is unknown and asks them to verify it or confirm a retry.

Error Meaning
not_authenticated No header/cookie registration exists, the provider failed, or authentication still failed after one retry.
tool_not_allowed The tool is not in that server’s explicit allowlist. No request was sent.
unknown_server The server key is not configured for this client.
invalid_arguments The MCP server returned JSON-RPC error -32602.
timeout The configured call deadline expired.
tool_error The tool returned isError, or JSON-RPC returned another tool error.
mcp_unavailable The endpoint could not be reached, including network and CORS failures.
cancelled The user declined a write-tool confirmation.

The chatbot’s schema snapshot is generated from the configured allowlist. Tiketo refreshes it in a pull request after your team announces a tool schema change. If a server changes an input schema without notice, the chatbot can send outdated arguments. The server should return JSON-RPC -32602, which becomes invalid_arguments.

Adding or removing a tool requires a client configuration change, a schema snapshot change, and a deploy. It does not require a new embed version because the generic mcpCall@1 browser contract stays the same.

  • The endpoint is absolute HTTPS and implements Streamable HTTP with protocol version 2025-06-18.
  • The enabled tool list and read/write classifications are agreed with Tiketo.
  • The MCP server validates the logged-in user’s authorization and tenant scope for every call.
  • CORS allows each frontend origin and every header the provider can return, and exposes mcp-session-id.
  • The curl -X OPTIONS preflight check succeeds for each frontend origin and auth mode.
  • The bearer token or other credential is available through an async host function and is never hard-coded.
  • Write-tool confirmation, timeout behavior, result limits, token refresh, and logout removal/reset have been tested.
  • Tiketo has a non-production test account for evaluation.