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 +74 -58
- package/dist/ChatUI.js +1 -1
- package/dist/components/MessageItem.js +7 -3
- package/dist/styles.css +0 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
# MCP Chat UI SDK
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
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
|
|
9
|
-
- Node 18+ for build
|
|
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
|
-
|
|
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
|
|
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
|
-
-
|
|
127
|
-
|
|
128
|
-
-
|
|
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
|
-
##
|
|
146
|
+
## API Reference
|
|
162
147
|
|
|
163
|
-
|
|
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 (
|
|
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
|
-
##
|
|
354
|
+
## Text Direction (LTR/RTL)
|
|
348
355
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
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
|
|
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
|
|
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:
|
|
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",
|
|
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
|
}
|