mcp-chat-ui 1.0.6 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,12 +1,16 @@
1
1
  # MCP Chat UI SDK
2
2
 
3
- A React UI SDK that bundles a full chat experience with speech (STT/TTS), file
4
- uploads, document viewing, and task actions.
3
+ React UI SDK that bundles a full chat experience with:
4
+ - Login/init panel + session management
5
+ - HTTP chat (no streaming/WS)
6
+ - Speech-to-text and text-to-speech (Azure Speech SDK)
7
+ - File uploads (SAS-based)
8
+ - Task cards, take-action workflow, and document preview
5
9
 
6
10
  ## Requirements
7
11
 
8
- - React 18+ or 19 and React DOM.
9
- - Node 18+ for build/demo workflows.
12
+ - React 19 (peer dependency) and React DOM.
13
+ - Node 18+ for build workflows.
10
14
 
11
15
 
12
16
 
@@ -19,52 +23,15 @@ npm install mcp-chat-ui
19
23
 
20
24
  ## Quick Start
21
25
 
22
- ### For React Projects
23
-
24
- Import CSS in App.tsx
26
+ Import styles once (e.g. in `App.tsx`):
25
27
 
26
28
  ```App.tsx
27
29
  import "mcp-chat-ui/styles.css";
28
30
  ```
29
31
 
30
- ### For Angular Projects
31
-
32
- **Option 1: Import in global styles.css (Recommended)**
33
-
34
- Open your `src/styles.css` file and add this import at the top:
35
-
36
- ```css
37
- @import "mcp-chat-ui/dist/styles.css";
38
- ```
39
-
40
- **Option 2: Add to angular.json**
41
-
42
- If Option 1 doesn't work, add the CSS file to your `angular.json` configuration:
43
-
44
- ```json
45
- {
46
- "projects": {
47
- "your-app-name": {
48
- "architect": {
49
- "build": {
50
- "options": {
51
- "styles": [
52
- "src/styles.css",
53
- "node_modules/mcp-chat-ui/dist/styles.css"
54
- ]
55
- }
56
- }
57
- }
58
- }
59
- }
60
- }
61
- ```
62
-
63
- **Important:** Do **not** import the CSS in TypeScript/component files for Angular projects. After making changes, restart your Angular dev server (`ng serve`).
64
-
65
32
  ### Initialize the SDK
66
33
 
67
- Initialize the SDK (required):
34
+ Initialize the SDK before rendering `ChatUI`:
68
35
 
69
36
  ```ts
70
37
  import { Init } from "mcp-chat-ui";
@@ -78,6 +45,7 @@ const initConfig = {
78
45
  initializeChat: false,
79
46
  showInitPanel: true,
80
47
  contextWindow: "ComposeRequest",
48
+ initializeLanguage: "ar-JO",
81
49
  initializeMessage: "",
82
50
  };
83
51
 
@@ -123,9 +91,11 @@ If `sessionId` is omitted, the SDK uses the stored session ID.
123
91
 
124
92
  ## Service Base URL
125
93
 
126
- - Provide `baseUrl` and the SDK derives RequestStep, TransactionCatalog, Storage,
127
- Signature, and the login endpoint from it.
128
- - Provide `apiSubscriptionKey` for APIM calls to those services.
94
+ - `baseUrl` drives the RequestStep, TransactionCatalog, Storage, Signature, and
95
+ login endpoints used by the UI.
96
+ - `apiSubscriptionKey` is sent to those service calls.
97
+ - Chat initialization, chat messaging, and session finalization use the built-in
98
+ MCP gateway base URL and API key (not `baseUrl`).
129
99
 
130
100
  ## Initialize (Login) Flow
131
101
 
@@ -139,6 +109,21 @@ If `sessionId` is omitted, the SDK uses the stored session ID.
139
109
  - If `initializeChat` is `false`, the chat waits until the user initializes from
140
110
  the login panel.
141
111
 
112
+ ## Token & Cache Notes
113
+
114
+ - Tokens are normalized to the `Bearer <token>` format; if you pass a raw token it will be prefixed automatically.
115
+ - The current auth token is stored in `localStorage` under `chat.authToken`.
116
+ - Supplying a new `token` prop replaces the stored token.
117
+ - When the token changes (detected during init), the SDK resets local state and clears cached data:
118
+ - `chat.msgs.*` (message history per session)
119
+ - `chat.initCompleted.*` (per-session init flags)
120
+ - `chat.serviceBaseUrl`, `chat.apiSubscriptionKey`, `chat.loginSubscriptionKey`
121
+ - `chat.sessionId`, `chat.authToken`, `chat.contextWindow`, `chat.initUsername`, `chat.domain`
122
+ - `speech.lang`, `speech.ttsLang`
123
+ - A new `sessionId` is generated and stored.
124
+ - Logout calls `FinalizeSession` and clears local messages and session state.
125
+ - Calling `FinalizeSession()` directly clears the same local storage keys and prefixes listed above.
126
+
142
127
  ## Login From The UI
143
128
 
144
129
  The SDK ships a Login panel (enabled by default). Click **Login** in
@@ -158,9 +143,29 @@ To auto-initialize on load:
158
143
  Init({ ...initConfig, initializeChat: true });
159
144
  ```
160
145
 
161
- ## Configuration Reference
146
+ ## API Reference
162
147
 
163
- Init (global):
148
+ ### Methods
149
+
150
+ ```ts
151
+ import {
152
+ Init,
153
+ GetConfig,
154
+ InitializeChatClients,
155
+ FinalizeSession,
156
+ } from "mcp-chat-ui";
157
+ ```
158
+
159
+ - `Init(config)` (required): stores SDK config; must be called before rendering `ChatUI`.
160
+ - `GetConfig()`: returns the last config passed to `Init`.
161
+ - `InitializeChatClients(options?)`: runs `/api/initializeChatClients` against the
162
+ built-in MCP gateway. Options: `{ domain?, token? }`.
163
+ - `FinalizeSession(options?)`: calls `/api/deleteSessionContext` against the
164
+ built-in MCP gateway and clears SDK local storage. Options: `{ domain?, token?, sessionId? }`.
165
+
166
+ ### Configuration
167
+
168
+ Init config (`ChatUISDKConfig`):
164
169
  - `baseUrl` (required): base URL for RequestStep/TransactionCatalog/Storage/Signature/login.
165
170
  - `apiSubscriptionKey` (required): subscription key for the base URL.
166
171
  - `loginSubscriptionKey` (required): login endpoint subscription key.
@@ -169,16 +174,18 @@ Init (global):
169
174
  - `showInitPanel` (optional, default `true`)
170
175
  - `initializeChat` (required)
171
176
  - `contextWindow` (required)
177
+ - `initializeLanguage` (optional): locale sent to `initializeChat` (defaults to `ar-JO`).
172
178
  - `initializeMessage` (optional): initial message passed to `initializeChat`.
173
179
 
174
- ChatUI props (view):
180
+ ChatUI props (`ChatUIProps`):
175
181
  - `initServiceId`, `initRequestStepId`
176
182
  - `contextWindow`, `domain`, `token`, `initializeMessage`
177
183
  - `initPresets`: optional `{ requester, provider }` credentials used to prefill the preset buttons.
184
+ - `initialInitPreset`: `"requester" | "provider" | "custom"` (default `custom`).
178
185
  - `speechRegion`, `speechKey`
179
- - `speechLanguage` (transcription)
180
- - `ttsLanguage`
181
- - `ttsVoiceMap`
186
+ - `speechLanguage` or `speechLang` (transcription)
187
+ - `ttsLanguage` or `ttsLang`
188
+ - `ttsVoiceMap`: map of locale to Azure voice name.
182
189
  - `theme`: see tokens below.
183
190
  - `fonts`: `{ base, heading, mono }`.
184
191
  - `text`: UI strings (login panel text is fixed and not configurable).
@@ -344,13 +351,22 @@ Errors:
344
351
  - `errors.takeActionMissingSignature`
345
352
  - `errors.takeActionNoDocument`
346
353
 
347
- ## Demo App (repo only)
354
+ ## Text Direction (LTR/RTL)
348
355
 
349
- ```bash
350
- cd demo
351
- npm install
352
- npm run dev
353
- ```
356
+ Chat layout direction is derived from language settings:
357
+
358
+ - **Chat layout direction** (message alignment, list layout) is based on the
359
+ transcription language. Set `speechLanguage` or `speechLang` to an RTL locale
360
+ (for example `ar`, `he`, `fa`, `ur`, `ps`, `dv`, `ku`, `ug`, `yi`) to render the
361
+ chat in RTL.
362
+ - **Composer input direction** is auto-detected per input:
363
+ - Uses the first strong RTL/LTR character you type.
364
+ - Falls back to keyboard layout detection when available (`navigator.keyboard.getLayoutMap()`).
365
+ - Falls back to the browser locale (`navigator.language`) if no direction is detected.
366
+
367
+ There is no explicit prop to force RTL/LTR; use `speechLanguage`/`speechLang` for
368
+ chat layout direction and type an RTL character (or switch keyboard/layout) to
369
+ flip the composer input direction.
354
370
 
355
371
  ## Build
356
372
 
package/dist/ChatUI.js CHANGED
@@ -1964,7 +1964,7 @@ function ChatUI(props) {
1964
1964
  ? "Initializing chat..."
1965
1965
  : initGateError || "Initializing chat..." }), !initGateLoading && initGateError && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: `mt-4 inline-flex items-center justify-center rounded-full px-4 py-2 text-sm font-medium ${textButtonTheme}`, onClick: handleInitRetry, children: "Retry" }))] }) })] }));
1966
1966
  }
1967
- return ((0, jsx_runtime_1.jsxs)("div", { className: "chatui-root flex min-h-screen min-h-[100dvh] w-full flex-col", style: themeVars, children: [(0, jsx_runtime_1.jsx)("style", { children: chatDefaults_1.CHATUI_THEME_CSS }), (0, jsx_runtime_1.jsx)(TopBar_1.default, { sessionId: sessionId, authToken: authToken, onClearChat: clearChat, onLogout: doLogout, onInitOpen: () => {
1967
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "chatui-root flex h-full w-full flex-col", style: themeVars, children: [(0, jsx_runtime_1.jsx)("style", { children: chatDefaults_1.CHATUI_THEME_CSS }), (0, jsx_runtime_1.jsx)(TopBar_1.default, { sessionId: sessionId, authToken: authToken, onClearChat: clearChat, onLogout: doLogout, onInitOpen: () => {
1968
1968
  if (initPanelEnabled) {
1969
1969
  setShowInitPanel(true);
1970
1970
  }
@@ -10,17 +10,21 @@ const lu_1 = require("react-icons/lu");
10
10
  const FormattedText_1 = __importDefault(require("./FormattedText"));
11
11
  const classNames_1 = require("../utils/classNames");
12
12
  const format_1 = require("../utils/format");
13
+ const textDirection_1 = require("../utils/textDirection");
13
14
  function MessageItem({ m, openOverlay, isRtl, onOpenTaskCard, onSelectTaskCard, selectedTaskCardId, canSpeak, isSpeaking, onSpeak, onStopSpeak, textButtonTheme, text, taskCardSize, }) {
15
+ var _a, _b;
14
16
  const isUser = m.role === "User";
15
- const alignRight = isUser || isRtl;
17
+ const messageDirection = (_b = (0, textDirection_1.getTextDirection)((_a = m.content) !== null && _a !== void 0 ? _a : "")) !== null && _b !== void 0 ? _b : (isRtl ? "rtl" : "ltr");
18
+ const isMessageRtl = messageDirection === "rtl";
19
+ const alignRight = isUser || isMessageRtl;
16
20
  return ((0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { initial: { opacity: 0, y: 6 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -6 }, transition: { duration: 0.18 }, className: (0, classNames_1.classNames)("flex w-full", alignRight ? "justify-end" : "justify-start"), children: (0, jsx_runtime_1.jsxs)("div", { className: (0, classNames_1.classNames)("max-w-[85%]", isUser ? "" : "w-full"), children: [(0, jsx_runtime_1.jsxs)("div", { className: (0, classNames_1.classNames)(isUser
17
21
  ? "rounded-2xl px-4 py-3 shadow-sm"
18
- : "px-1 py-0"), style: Object.assign({ direction: isRtl ? "rtl" : "ltr", textAlign: isRtl ? "right" : "left" }, (isUser
22
+ : "px-1 py-0"), style: Object.assign({ direction: messageDirection, textAlign: isMessageRtl ? "right" : "left" }, (isUser
19
23
  ? {
20
24
  backgroundColor: "var(--chat-user-message-bg)",
21
25
  color: "var(--chat-user-message-text)",
22
26
  }
23
- : {})), children: [m.attachments && m.attachments.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: (0, classNames_1.classNames)("mb-2 flex flex-wrap gap-2", isRtl ? "justify-end" : "justify-start"), children: m.attachments.map((att, idx) => ((0, jsx_runtime_1.jsxs)("span", { className: "inline-flex items-center gap-1 rounded-full bg-white/70 px-3 py-1 text-xs text-gray-800", children: [(0, jsx_runtime_1.jsx)(lu_1.LuPaperclip, { className: "h-3 w-3" }), " ", att.name] }, idx))) })), (0, jsx_runtime_1.jsx)("div", { className: "space-y-2", children: (0, jsx_runtime_1.jsx)(FormattedText_1.default, { text: m.content, onOpen: openOverlay, isRtl: isRtl, buttonClassName: textButtonTheme, linkButtonLabel: text.linkButtonLabel }) }), !isUser && m.availableTasksCards && m.availableTasksCards.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "mt-3", children: (0, jsx_runtime_1.jsx)("div", { className: "flex snap-x snap-mandatory gap-3 overflow-x-auto pb-2", children: m.availableTasksCards.map((card, idx) => {
27
+ : {})), children: [m.attachments && m.attachments.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: (0, classNames_1.classNames)("mb-2 flex flex-wrap gap-2", isMessageRtl ? "justify-end" : "justify-start"), children: m.attachments.map((att, idx) => ((0, jsx_runtime_1.jsxs)("span", { className: "inline-flex items-center gap-1 rounded-full bg-white/70 px-3 py-1 text-xs text-gray-800", children: [(0, jsx_runtime_1.jsx)(lu_1.LuPaperclip, { className: "h-3 w-3" }), " ", att.name] }, idx))) })), (0, jsx_runtime_1.jsx)("div", { className: "space-y-2", children: (0, jsx_runtime_1.jsx)(FormattedText_1.default, { text: m.content, onOpen: openOverlay, isRtl: isRtl, buttonClassName: textButtonTheme, linkButtonLabel: text.linkButtonLabel }) }), !isUser && m.availableTasksCards && m.availableTasksCards.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "mt-3", children: (0, jsx_runtime_1.jsx)("div", { className: "flex snap-x snap-mandatory gap-3 overflow-x-auto pb-2", children: m.availableTasksCards.map((card, idx) => {
24
28
  var _a, _b, _c, _d, _e, _f, _g;
25
29
  const requestSummary = (_b = (_a = card === null || card === void 0 ? void 0 : card.Details) === null || _a === void 0 ? void 0 : _a.RequestSummary) !== null && _b !== void 0 ? _b : "";
26
30
  const preview = String(requestSummary).slice(0, 125);
package/dist/styles.css CHANGED
@@ -709,15 +709,9 @@ video {
709
709
  .min-h-0 {
710
710
  min-height: 0px;
711
711
  }
712
- .min-h-\[100dvh\] {
713
- min-height: 100dvh;
714
- }
715
712
  .min-h-\[110px\] {
716
713
  min-height: 110px;
717
714
  }
718
- .min-h-screen {
719
- min-height: 100vh;
720
- }
721
715
  .w-1\.5 {
722
716
  width: 0.375rem;
723
717
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-chat-ui",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "React Chat UI SDK with speech, file upload, and task actions.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",