mcp-chat-ui
v1.0.8
Published
React Chat UI SDK with speech, file upload, and task actions.
Downloads
514
Readme
MCP Chat UI SDK
React UI SDK that bundles a full chat experience with:
- Login/init panel + session management
- HTTP chat (no streaming/WS)
- Speech-to-text and text-to-speech (Azure Speech SDK)
- File uploads (SAS-based)
- Task cards, take-action workflow, and document preview
Requirements
- React 19 (peer dependency) and React DOM.
- Node 18+ for build workflows.
Install
npm install mcp-chat-uiQuick Start
Import styles once (e.g. in App.tsx):
import "mcp-chat-ui/styles.css";Initialize the SDK
Initialize the SDK before rendering ChatUI:
import { Init } from "mcp-chat-ui";
const initConfig = {
baseUrl: "https://apim.octopian.cloud",
apiSubscriptionKey: "<apim-subscription-key>",
loginSubscriptionKey: "<login-subscription-key>",
token: "Bearer <token>",
isDab: false,
initializeChat: false,
showInitPanel: true,
contextWindow: "ComposeRequest",
initializeLanguage: "ar-JO",
initializeMessage: "",
};
Init(initConfig);Render the UI (view config goes here):
import { ChatUI } from "mcp-chat-ui";
export default function App() {
return (
<ChatUI
speechRegion="swedencentral"
speechKey="<your-speech-key>"
theme={{
brand: "#0b1f33",
panelBackground: "#ffffff",
appBackground: "#f7f7f2",
textMain: "#0b1f33",
}}
fonts={{
base: "\"DM Sans\", system-ui, sans-serif",
}}
/>
);
}Finalize a session (same API used by the Logout button):
import { FinalizeSession } from "mcp-chat-ui";
await FinalizeSession({
domain: "dab.ae",
token: "Bearer <token>",
sessionId: "<session-id>",
});If sessionId is omitted, the SDK uses the stored session ID.
Service Base URL
baseUrldrives the RequestStep, TransactionCatalog, Storage, Signature, and login endpoints used by the UI.apiSubscriptionKeyis sent to those service calls.- Chat initialization, chat messaging, and session finalization use the built-in
MCP gateway base URL and API key (not
baseUrl).
Initialize (Login) Flow
- The login endpoint is derived from
baseUrl. apiSubscriptionKeyis sent to the login endpoint (or override withloginSubscriptionKey).tokenis required inInit(use an empty string if you plan to sign in via the panel and let it set the token).initializeChat: truetriggersinitializeChatinChatUIbefore the chat renders (shows a loading state with retry).- The login panel runs
initializeChatClientsfollowed byinitializeChat. - If
initializeChatisfalse, the chat waits until the user initializes from the login panel.
Token & Cache Notes
- Tokens are normalized to the
Bearer <token>format; if you pass a raw token it will be prefixed automatically. - The current auth token is stored in
localStorageunderchat.authToken. - Supplying a new
tokenprop replaces the stored token. - When the token changes (detected during init), the SDK resets local state and clears cached data:
chat.msgs.*(message history per session)chat.initCompleted.*(per-session init flags)chat.serviceBaseUrl,chat.apiSubscriptionKey,chat.loginSubscriptionKeychat.sessionId,chat.authToken,chat.contextWindow,chat.initUsername,chat.domainspeech.lang,speech.ttsLang- A new
sessionIdis generated and stored.
- Logout calls
FinalizeSessionand clears local messages and session state. - Calling
FinalizeSession()directly clears the same local storage keys and prefixes listed above.
Login From The UI
The SDK ships a Login panel (enabled by default). Click Login in
the top bar, fill the fields (domain, username, password, context window, optional
service/request step IDs, languages), then submit. The SDK stores common values
in localStorage (session ID, auth token, domain, username) to keep continuity.
To hide the panel:
Init({ ...initConfig, showInitPanel: false });To auto-initialize on load:
Init({ ...initConfig, initializeChat: true });API Reference
Methods
import {
Init,
GetConfig,
InitializeChatClients,
FinalizeSession,
} from "mcp-chat-ui";Init(config)(required): stores SDK config; must be called before renderingChatUI.GetConfig(): returns the last config passed toInit.InitializeChatClients(options?): runs/api/initializeChatClientsagainst the built-in MCP gateway. Options:{ domain?, token? }.FinalizeSession(options?): calls/api/deleteSessionContextagainst the built-in MCP gateway and clears SDK local storage. Options:{ domain?, token?, sessionId? }.
Configuration
Init config (ChatUISDKConfig):
baseUrl(required): base URL for RequestStep/TransactionCatalog/Storage/Signature/login.apiSubscriptionKey(required): subscription key for the base URL.loginSubscriptionKey(required): login endpoint subscription key.token(required): pre-set auth header value (include scheme).isDab(required): iftrue, default domain isdab.ae, otherwise blank.showInitPanel(optional, defaulttrue)initializeChat(required)contextWindow(required)initializeLanguage(optional): locale sent toinitializeChat(defaults toar-JO).initializeMessage(optional): initial message passed toinitializeChat.
ChatUI props (ChatUIProps):
initServiceId,initRequestStepIdcontextWindow,domain,token,initializeMessageinitPresets: optional{ requester, provider }credentials used to prefill the preset buttons.initialInitPreset:"requester" | "provider" | "custom"(defaultcustom).speechRegion,speechKeyspeechLanguageorspeechLang(transcription)ttsLanguageorttsLangttsVoiceMap: map of locale to Azure voice name.theme: see tokens below.fonts:{ base, heading, mono }.text: UI strings (login panel text is fixed and not configurable).taskCardSize:{ width?: number; height?: number }for task cards in the chat list.onRequestAdded: called whenAddRequestToolResultis a non-empty object.onRequestProcessed: called whenProcessRequestToolResultis a non-empty object.
Theme Tokens
You can override any subset:
appBackground: main page background behind the chat surface.panelBackground: main chat panel surface color.panelBackgroundMuted: muted surface for translucent panels (top bar, composer).panelBackgroundSubtle: lighter surface tint for subtle sections.brand: primary brand color for buttons and accents.brandHover: hover color for brand buttons.brandAlpha30: brand color with ~30% alpha (badges/overlays).brandAlpha40: brand color with ~40% alpha.brandAlpha50: brand color with ~50% alpha.textMain: primary text color.textEmphasis: stronger text emphasis for headings.textSupporting: secondary text color.textMuted: muted body text color.textSubtle: subtle labels and placeholders.textDisabled: disabled or faint text color.textOnBrand: text color used on brand backgrounds.userMessageBackground: background color for user chat bubbles.userMessageText: text color for user chat bubbles.neutralLightest: light neutral background (50).neutralLighter: light neutral background (100).neutralMedium: neutral mid tone (400).neutralDark: dark neutral (800).neutralDarker: darkest neutral (900).neutralDarker80: darkest neutral with ~80% alpha.borderDefault: default border color.accentBackground: accent background for info callouts.accentText: accent text color for info callouts.warningBackground: warning background for alerts.warningText: warning text color for alerts.errorBackground: error background for alerts.errorText: error text color for alerts.focusRing: subtle focus ring color.focusRingStrong: stronger focus ring color.outlineShadow: outline shadow color for buttons.elevatedShadow: elevated shadow color for modals/cards.selectOptionHover: select option hover/selected background color.cardSelectedBackground: selected task card background color.
Legacy theme keys (e.g. primary, background, surface) are still accepted,
but prefer the names above for new work.
Text Tokens
Override any subset of strings (login panel text is fixed):
<ChatUI
text={{
topBar: { clearButton: "Reset" },
emptyState: { title: "Whats on the agenda today?" },
composer: { placeholderDefault: "Ask me anything" },
}}
/>;Top bar:
topBar.sessionLabeltopBar.clearButtontopBar.clearTitletopBar.logoutButtontopBar.logoutTitletopBar.loginButtontopBar.loginTitle
Empty state:
emptyState.title
Composer:
composer.selectedTaskPrefixcomposer.selectionLineTemplate(supports{id})composer.selectedTaskClearTitlecomposer.attachTitlecomposer.placeholderAuthRequiredcomposer.placeholderDefaultcomposer.voiceStartTitlecomposer.voiceStopTitlecomposer.sendTitle
Voice overlay:
voiceOverlay.cancelTitlevoiceOverlay.confirmTitle
Message item:
messageItem.moreButtonmessageItem.selectCardTitlemessageItem.stopReadingTitlemessageItem.readMessageTitlemessageItem.linkButtonLabel
Task cards:
taskCards.modalTitletaskCards.takeActionButtontaskCards.showDocumentButton
Document viewer:
documentViewer.titledocumentViewer.downloadButtondocumentViewer.loadingdocumentViewer.iframeTitledocumentViewer.useGoogleViewerdocumentViewer.useDirectViewerdocumentViewer.errorSuffixdocumentViewer.proceedButton
Take action:
takeAction.backAriaLabeltakeAction.closeAriaLabeltakeAction.actionTypeLabeltakeAction.selectActionPlaceholdertakeAction.approveOptiontakeAction.rejectOptiontakeAction.commentsLabeltakeAction.commentsPlaceholdertakeAction.noEditableAttributestakeAction.selectSignaturePlaceholdertakeAction.selectOptionPlaceholdertakeAction.signaturePlaceholdertakeAction.cancelButtontakeAction.submitButtontakeAction.nextButton
Tool result:
toolResult.title
Alerts:
alerts.clearConfirmalerts.clearFailedTemplate(supports{error})alerts.fetchHistoryFailedalerts.initMissingCredentialsalerts.initMissingBaseUrlalerts.initMissingSubscriptionKeyalerts.initMissingEndpointalerts.initFailedalerts.initNoTokenalerts.initChatFailedTemplate(supports{status},{statusText},{details})alerts.initChatNetworkErroralerts.initChatErrorTemplate(supports{error})alerts.initRequiredalerts.initNetworkErroralerts.initErrorTemplate(supports{error})
Errors:
errors.assistantMessageTemplate(supports{error})errors.microphoneAccesserrors.transcriptionStarterrors.sasRequestFailedTemplate(supports{status},{statusText},{details})errors.noSasEntrieserrors.invalidSasEntryerrors.chatFailedTemplate(supports{status},{statusText},{details})errors.takeActionAuthRequirederrors.takeActionMissingRequestSteperrors.takeActionMissingSignatureerrors.takeActionNoDocument
Text Direction (LTR/RTL)
Chat layout direction is derived from language settings:
- Chat layout direction (message alignment, list layout) is based on the
transcription language. Set
speechLanguageorspeechLangto an RTL locale (for examplear,he,fa,ur,ps,dv,ku,ug,yi) to render the chat in RTL. - Composer input direction is auto-detected per input:
- Uses the first strong RTL/LTR character you type.
- Falls back to keyboard layout detection when available (
navigator.keyboard.getLayoutMap()). - Falls back to the browser locale (
navigator.language) if no direction is detected.
There is no explicit prop to force RTL/LTR; use speechLanguage/speechLang for
chat layout direction and type an RTL character (or switch keyboard/layout) to
flip the composer input direction.
Build
npm run build