@supportbridge/sdk 0.8.1 → 0.9.4
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/CHANGELOG.md +102 -72
- package/README.md +344 -325
- package/dist/client.d.ts +3 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +5 -2
- package/dist/client.js.map +1 -1
- package/dist/control-plane.d.ts +2 -1
- package/dist/control-plane.d.ts.map +1 -1
- package/dist/control-plane.js +10 -0
- package/dist/control-plane.js.map +1 -1
- package/dist/doctor.js +2 -2
- package/dist/doctor.js.map +1 -1
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +2 -1
- package/dist/install.js.map +1 -1
- package/dist/mcp-app.d.ts +1 -1
- package/dist/mcp-app.js +1 -1
- package/dist/mcp.js +14 -3
- package/dist/mcp.js.map +1 -1
- package/package.json +66 -53
- package/dist/offer-app.d.ts +0 -41
- package/dist/offer-app.d.ts.map +0 -1
- package/dist/offer-app.js +0 -21
- package/dist/offer-app.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,326 +1,345 @@
|
|
|
1
|
-
# SupportBridge SDK
|
|
2
|
-
|
|
3
|
-
`@supportbridge/sdk` is the external, production-oriented SDK for adding tool-call telemetry, optional agent telemetry, configurable support triggers, deterministic operational policies, and MCP-compatible support experiences to software-company MCP servers.
|
|
4
|
-
|
|
5
|
-
This package is independent from the internal SupportBridge demo. It does not import the demo server, dashboard, database, or test-user implementation.
|
|
6
|
-
|
|
7
|
-
## What the first release provides
|
|
8
|
-
|
|
9
|
-
- Framework-neutral MCP tool instrumentation
|
|
10
|
-
- Tool name, timing, outcome, request correlation, sanitized arguments, and bounded result summaries
|
|
11
|
-
- Optional agent-run and model-call spans
|
|
12
|
-
- Async-local trace propagation from agent runs into MCP tool events
|
|
13
|
-
- Immediate or non-blocking support-offer triggers
|
|
14
|
-
- Repeated-failure triggers
|
|
15
|
-
- Per-user, per-workspace, per-trace, or always-on trigger scopes
|
|
16
|
-
- Accept, dismiss, and explicit reset decisions
|
|
17
|
-
- Default secret redaction and payload-size limits
|
|
18
|
-
- Batched asynchronous HTTP delivery with bounded retries
|
|
19
|
-
- Queue overflow protection and fail-open behavior
|
|
20
|
-
- Pluggable telemetry transport and trigger-state storage
|
|
21
|
-
- Canonical, versioned policy schema with nested AND/OR/NOT conditions
|
|
22
|
-
- Approved field and action registries with tenant-reference validation
|
|
23
|
-
- Deterministic evaluation, traces, dry runs, conflict detection, and idempotent execution
|
|
24
|
-
- Vendor-neutral natural-language compiler interface and deterministic local fake provider
|
|
25
|
-
- Approval, immutable-version, rollback, and audit lifecycle primitives
|
|
26
|
-
- An interactive MCP policy-builder app for Claude
|
|
27
|
-
|
|
28
|
-
## Install
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
npm install
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
npm install @supportbridge/sdk
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Node.js 20 or newer is required.
|
|
43
|
-
|
|
44
|
-
## Recommended one-call MCP installation
|
|
45
|
-
|
|
46
|
-
For the official TypeScript MCP SDK, one call installs remote policy synchronization, support decisions, the UI-linked `talk_to_support` tool, the embedded chat app, app-only chat handlers, capability reporting, and graceful shutdown behavior:
|
|
47
|
-
|
|
48
|
-
```ts
|
|
49
|
-
import { SupportBridge } from "@supportbridge/sdk";
|
|
50
|
-
|
|
51
|
-
const support = SupportBridge.install(server, {
|
|
52
|
-
source: "acme-mcp",
|
|
53
|
-
apiKey: process.env.SUPPORTBRIDGE_API_KEY!,
|
|
54
|
-
identify: context => ({
|
|
55
|
-
userId: context.authInfo.subject,
|
|
56
|
-
workspaceId: context.authInfo.workspaceId,
|
|
57
|
-
traits: { customer: context.authInfo.organizationName }
|
|
58
|
-
})
|
|
59
|
-
});
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
Use the returned installer to wrap each business tool while keeping the same identity resolver:
|
|
63
|
-
|
|
64
|
-
```ts
|
|
65
|
-
server.tool(
|
|
66
|
-
"search_companies",
|
|
67
|
-
searchSchema,
|
|
68
|
-
support.instrumentTool("search_companies", searchCompanies)
|
|
69
|
-
);
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
The wrapper captures bounded telemetry, enforces downloaded support triggers before execution, and retains recent sanitized failures for automatic ticket context. The installation also registers `open_policy_builder` and its embedded interactive app. No support tools or UI resources need to be registered manually.
|
|
73
|
-
|
|
74
|
-
## Deterministic policy engine
|
|
75
|
-
|
|
76
|
-
Natural language is never executable. A `PolicyNlpProvider` can propose a `CanonicalPolicy`, then deterministic code validates approved fields, operators, events, action parameters, and workspace-scoped references before simulation or publication.
|
|
77
|
-
|
|
78
|
-
```ts
|
|
79
|
-
import {
|
|
80
|
-
FakePolicyNlpProvider,
|
|
81
|
-
PolicyEngine,
|
|
82
|
-
PolicyRegistry,
|
|
83
|
-
validatePolicy
|
|
84
|
-
} from "@supportbridge/sdk";
|
|
85
|
-
|
|
86
|
-
const provider = new FakePolicyNlpProvider();
|
|
87
|
-
const draft = await provider.compile({
|
|
88
|
-
prompt: "Route urgent enterprise billing conversations to Finance.",
|
|
89
|
-
workspaceId: "acme",
|
|
90
|
-
actorId: "admin_123",
|
|
91
|
-
references: { financeTeamId: "team_finance" }
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
const registry = new PolicyRegistry();
|
|
95
|
-
const validation = validatePolicy(draft.policy, { registry });
|
|
96
|
-
if (!validation.valid) throw new Error("Review the validation errors");
|
|
97
|
-
|
|
98
|
-
const decision = new PolicyEngine(registry).evaluate(
|
|
99
|
-
[{ ...draft.policy, enabled: true, state: "dry_run" }],
|
|
100
|
-
{ type: "conversation.created" },
|
|
101
|
-
{ customer: { plan: "enterprise" }, conversation: { priority: "urgent" }, message: { classification: "billing" } },
|
|
102
|
-
{ now: new Date(), eventId: "evt_1", correlationId: "corr_1", workspaceId: "acme" }
|
|
103
|
-
);
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
Evaluation produces a decision plan; it never performs actions. Pass a plan to `executeDecisionPlan` with your authorized executor and durable `IdempotencyStore`. See [the policy engine guide](docs/policy-engine.md) for registries, lifecycle, simulations, and production adapters.
|
|
107
|
-
|
|
108
|
-
If the embedded widget is missing or has scrolled out of view, the model calls `open_support_chat` with the existing `session_id`. Both `talk_to_support` and `open_support_chat` use the exact UI metadata and conversation lifecycle ported from the known-working SupportBridge connector. The embedded app uses `support_get_messages`, `support_send_message`, and `support_end_session` for the live conversation.
|
|
109
|
-
|
|
110
|
-
Availability-gated sales and customer-success policies can assign an offer to a representative in the control plane. Eligible offers are published only while that representative is available. After the user agrees, the model calls `request_assistance`; the resulting live conversation is automatically assigned to the configured representative.
|
|
111
|
-
|
|
112
|
-
Verify an installation with:
|
|
113
|
-
|
|
114
|
-
```bash
|
|
115
|
-
npx supportbridge doctor
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
Set `SUPPORTBRIDGE_URL` and `SUPPORTBRIDGE_API_KEY` first. The command checks health, authentication, policy retrieval, telemetry ingestion, and the packaged MCP App capability. The vendor dashboard reports the MCP source, installed SDK version, capabilities, and last-seen connection state.
|
|
119
|
-
|
|
120
|
-
## Capture an MCP tool
|
|
121
|
-
|
|
122
|
-
```ts
|
|
123
|
-
import { SupportBridgeClient, instrumentMcpTool } from "@supportbridge/sdk";
|
|
124
|
-
|
|
125
|
-
const supportbridge = new SupportBridgeClient({
|
|
126
|
-
source: "acme-mcp",
|
|
127
|
-
endpoint: "https://api.supportbridge.example",
|
|
128
|
-
apiKey: process.env.SUPPORTBRIDGE_API_KEY!,
|
|
129
|
-
triggers: [{
|
|
130
|
-
id: "climate-tech-concierge",
|
|
131
|
-
kind: "argument_match",
|
|
132
|
-
toolName: "list_companies",
|
|
133
|
-
path: "industry",
|
|
134
|
-
operator: "equals",
|
|
135
|
-
value: "Climate Tech",
|
|
136
|
-
action: "block_and_offer",
|
|
137
|
-
oncePer: "user"
|
|
138
|
-
}]
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
const listCompanies = instrumentMcpTool(
|
|
142
|
-
supportbridge,
|
|
143
|
-
"list_companies",
|
|
144
|
-
async args => ({
|
|
145
|
-
content: [{ type: "text", text: "Company results" }],
|
|
146
|
-
structuredContent: { count: 12 }
|
|
147
|
-
}),
|
|
148
|
-
{
|
|
149
|
-
identify: (_args, context) => ({
|
|
150
|
-
userId: context.auth.subject,
|
|
151
|
-
workspaceId: context.auth.workspaceId
|
|
152
|
-
})
|
|
153
|
-
}
|
|
154
|
-
);
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
When the blocking trigger matches, the vendor handler is not executed. The MCP result contains:
|
|
158
|
-
|
|
159
|
-
```json
|
|
160
|
-
{
|
|
161
|
-
"
|
|
162
|
-
|
|
163
|
-
"support_available": true,
|
|
164
|
-
"support_offer_blocking": true,
|
|
165
|
-
"
|
|
166
|
-
"
|
|
167
|
-
"
|
|
168
|
-
"
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
`
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
registerAppTool
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
1
|
+
# SupportBridge SDK
|
|
2
|
+
|
|
3
|
+
`@supportbridge/sdk` is the external, production-oriented SDK for adding tool-call telemetry, optional agent telemetry, configurable support triggers, deterministic operational policies, and MCP-compatible support experiences to software-company MCP servers.
|
|
4
|
+
|
|
5
|
+
This package is independent from the internal SupportBridge demo. It does not import the demo server, dashboard, database, or test-user implementation.
|
|
6
|
+
|
|
7
|
+
## What the first release provides
|
|
8
|
+
|
|
9
|
+
- Framework-neutral MCP tool instrumentation
|
|
10
|
+
- Tool name, timing, outcome, request correlation, sanitized arguments, and bounded result summaries
|
|
11
|
+
- Optional agent-run and model-call spans
|
|
12
|
+
- Async-local trace propagation from agent runs into MCP tool events
|
|
13
|
+
- Immediate or non-blocking support-offer triggers
|
|
14
|
+
- Repeated-failure triggers
|
|
15
|
+
- Per-user, per-workspace, per-trace, or always-on trigger scopes
|
|
16
|
+
- Accept, dismiss, and explicit reset decisions
|
|
17
|
+
- Default secret redaction and payload-size limits
|
|
18
|
+
- Batched asynchronous HTTP delivery with bounded retries
|
|
19
|
+
- Queue overflow protection and fail-open behavior
|
|
20
|
+
- Pluggable telemetry transport and trigger-state storage
|
|
21
|
+
- Canonical, versioned policy schema with nested AND/OR/NOT conditions
|
|
22
|
+
- Approved field and action registries with tenant-reference validation
|
|
23
|
+
- Deterministic evaluation, traces, dry runs, conflict detection, and idempotent execution
|
|
24
|
+
- Vendor-neutral natural-language compiler interface and deterministic local fake provider
|
|
25
|
+
- Approval, immutable-version, rollback, and audit lifecycle primitives
|
|
26
|
+
- An interactive MCP policy-builder app for Claude
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
Install the public package from npm:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install @supportbridge/sdk
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
To pin the current release explicitly:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install @supportbridge/sdk@0.9.4
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Node.js 20 or newer is required.
|
|
43
|
+
|
|
44
|
+
## Recommended one-call MCP installation
|
|
45
|
+
|
|
46
|
+
For the official TypeScript MCP SDK, one call installs remote policy synchronization, support decisions, the UI-linked `talk_to_support` tool, the embedded chat app, app-only chat handlers, capability reporting, and graceful shutdown behavior:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { SupportBridge } from "@supportbridge/sdk";
|
|
50
|
+
|
|
51
|
+
const support = SupportBridge.install(server, {
|
|
52
|
+
source: "acme-mcp",
|
|
53
|
+
apiKey: process.env.SUPPORTBRIDGE_API_KEY!,
|
|
54
|
+
identify: context => ({
|
|
55
|
+
userId: context.authInfo.subject,
|
|
56
|
+
workspaceId: context.authInfo.workspaceId,
|
|
57
|
+
traits: { customer: context.authInfo.organizationName }
|
|
58
|
+
})
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Use the returned installer to wrap each business tool while keeping the same identity resolver:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
server.tool(
|
|
66
|
+
"search_companies",
|
|
67
|
+
searchSchema,
|
|
68
|
+
support.instrumentTool("search_companies", searchCompanies)
|
|
69
|
+
);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The wrapper captures bounded telemetry, enforces downloaded support triggers before execution, and retains recent sanitized failures for automatic ticket context. The installation also registers `open_policy_builder` and its embedded interactive app. No support tools or UI resources need to be registered manually.
|
|
73
|
+
|
|
74
|
+
## Deterministic policy engine
|
|
75
|
+
|
|
76
|
+
Natural language is never executable. A `PolicyNlpProvider` can propose a `CanonicalPolicy`, then deterministic code validates approved fields, operators, events, action parameters, and workspace-scoped references before simulation or publication.
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import {
|
|
80
|
+
FakePolicyNlpProvider,
|
|
81
|
+
PolicyEngine,
|
|
82
|
+
PolicyRegistry,
|
|
83
|
+
validatePolicy
|
|
84
|
+
} from "@supportbridge/sdk";
|
|
85
|
+
|
|
86
|
+
const provider = new FakePolicyNlpProvider();
|
|
87
|
+
const draft = await provider.compile({
|
|
88
|
+
prompt: "Route urgent enterprise billing conversations to Finance.",
|
|
89
|
+
workspaceId: "acme",
|
|
90
|
+
actorId: "admin_123",
|
|
91
|
+
references: { financeTeamId: "team_finance" }
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const registry = new PolicyRegistry();
|
|
95
|
+
const validation = validatePolicy(draft.policy, { registry });
|
|
96
|
+
if (!validation.valid) throw new Error("Review the validation errors");
|
|
97
|
+
|
|
98
|
+
const decision = new PolicyEngine(registry).evaluate(
|
|
99
|
+
[{ ...draft.policy, enabled: true, state: "dry_run" }],
|
|
100
|
+
{ type: "conversation.created" },
|
|
101
|
+
{ customer: { plan: "enterprise" }, conversation: { priority: "urgent" }, message: { classification: "billing" } },
|
|
102
|
+
{ now: new Date(), eventId: "evt_1", correlationId: "corr_1", workspaceId: "acme" }
|
|
103
|
+
);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Evaluation produces a decision plan; it never performs actions. Pass a plan to `executeDecisionPlan` with your authorized executor and durable `IdempotencyStore`. See [the policy engine guide](docs/policy-engine.md) for registries, lifecycle, simulations, and production adapters.
|
|
107
|
+
|
|
108
|
+
If the embedded widget is missing or has scrolled out of view, the model calls `open_support_chat` with the existing `session_id`. Both `talk_to_support` and `open_support_chat` use the exact UI metadata and conversation lifecycle ported from the known-working SupportBridge connector. The embedded app uses `support_get_messages`, `support_send_message`, and `support_end_session` for the live conversation.
|
|
109
|
+
|
|
110
|
+
Availability-gated sales and customer-success policies can assign an offer to a representative in the control plane. Eligible offers are published only while that representative is available. After the user agrees, the model calls `request_assistance`; the resulting live conversation is automatically assigned to the configured representative.
|
|
111
|
+
|
|
112
|
+
Verify an installation with:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
npx supportbridge doctor
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Set `SUPPORTBRIDGE_URL` and `SUPPORTBRIDGE_API_KEY` first. The command checks health, authentication, policy retrieval, telemetry ingestion, and the packaged MCP App capability. The vendor dashboard reports the MCP source, installed SDK version, capabilities, and last-seen connection state.
|
|
119
|
+
|
|
120
|
+
## Capture an MCP tool
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import { SupportBridgeClient, instrumentMcpTool } from "@supportbridge/sdk";
|
|
124
|
+
|
|
125
|
+
const supportbridge = new SupportBridgeClient({
|
|
126
|
+
source: "acme-mcp",
|
|
127
|
+
endpoint: "https://api.supportbridge.example",
|
|
128
|
+
apiKey: process.env.SUPPORTBRIDGE_API_KEY!,
|
|
129
|
+
triggers: [{
|
|
130
|
+
id: "climate-tech-concierge",
|
|
131
|
+
kind: "argument_match",
|
|
132
|
+
toolName: "list_companies",
|
|
133
|
+
path: "industry",
|
|
134
|
+
operator: "equals",
|
|
135
|
+
value: "Climate Tech",
|
|
136
|
+
action: "block_and_offer",
|
|
137
|
+
oncePer: "user"
|
|
138
|
+
}]
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const listCompanies = instrumentMcpTool(
|
|
142
|
+
supportbridge,
|
|
143
|
+
"list_companies",
|
|
144
|
+
async args => ({
|
|
145
|
+
content: [{ type: "text", text: "Company results" }],
|
|
146
|
+
structuredContent: { count: 12 }
|
|
147
|
+
}),
|
|
148
|
+
{
|
|
149
|
+
identify: (_args, context) => ({
|
|
150
|
+
userId: context.auth.subject,
|
|
151
|
+
workspaceId: context.auth.workspaceId
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
When the blocking trigger matches, the vendor handler is not executed. The MCP result contains:
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"structuredContent": {
|
|
162
|
+
"status": "awaiting_user_decision",
|
|
163
|
+
"support_available": true,
|
|
164
|
+
"support_offer_blocking": true,
|
|
165
|
+
"support_offer_status": "pending",
|
|
166
|
+
"support_offer_requires_acknowledgement": true,
|
|
167
|
+
"support_trigger_id": "climate-tech-concierge",
|
|
168
|
+
"accept_tool": "accept_support_offer",
|
|
169
|
+
"decline_tool": "dismiss_support_offer",
|
|
170
|
+
"retry_original_request_after_response": true,
|
|
171
|
+
"do_not_retry_or_bypass": true
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
SupportBridge has three offer modes:
|
|
177
|
+
|
|
178
|
+
- `offer` executes the business handler and attaches structured offer metadata without requiring a visible acknowledgement prompt.
|
|
179
|
+
- `require_acknowledgement` executes the business handler, preserves its original `content` and `structuredContent`, and appends a transparent `LIVE ASSISTANCE AVAILABLE` notice with consent-gated accept and decline tools.
|
|
180
|
+
- `block_and_offer` does not execute the business handler. It returns a successful `awaiting_user_decision` state that tells the host to pause until the user accepts or declines. It is not a tool error; genuine handler failures remain errors.
|
|
181
|
+
|
|
182
|
+
MCP hosts control the visual presentation of these results. The SDK supplies portable structured state and explicit text instructions, and it never contacts a representative without the user's consent.
|
|
183
|
+
|
|
184
|
+
Register the handlers returned by `supportDecisionTools` as MCP tools. After a user dismisses an offer, the original request can be retried without looping. Call `resetSupport` to make that trigger eligible again.
|
|
185
|
+
|
|
186
|
+
## Embedded support chat (MCP App)
|
|
187
|
+
|
|
188
|
+
`accept_support_offer` can create a durable ticket and open an inline chat in hosts that support the MCP Apps extension. Create the app kit and attach its metadata to the registered accept tool:
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
import {
|
|
192
|
+
createSupportChatApp,
|
|
193
|
+
supportDecisionTools
|
|
194
|
+
} from "@supportbridge/sdk";
|
|
195
|
+
|
|
196
|
+
const supportApp = createSupportChatApp(controlPlane);
|
|
197
|
+
const decisions = supportDecisionTools(
|
|
198
|
+
supportbridge,
|
|
199
|
+
context => identifyUser(context),
|
|
200
|
+
{ controlPlane, appMeta: supportApp.toolMeta }
|
|
201
|
+
);
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The MCP server must register these pieces using its framework:
|
|
205
|
+
|
|
206
|
+
- `accept_support_offer`, with `supportApp.toolMeta` on the **tool definition**.
|
|
207
|
+
- `dismiss_support_offer` as a normal model-visible tool.
|
|
208
|
+
- `get_support_chat` and `send_support_message` from `supportApp.tools`, with app-only visibility.
|
|
209
|
+
- A resource at `supportApp.resourceUri` whose read callback returns `supportApp.resourceContents()` and whose MIME type is `supportApp.mimeType`.
|
|
210
|
+
|
|
211
|
+
For the official TypeScript MCP Apps SDK, use `registerAppTool` and `registerAppResource` from `@modelcontextprotocol/ext-apps/server`. The critical registration shape is:
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
registerAppTool(server, "accept_support_offer", {
|
|
215
|
+
description: "Open the human support conversation after the user consents.",
|
|
216
|
+
inputSchema: acceptSchema,
|
|
217
|
+
_meta: supportApp.toolMeta
|
|
218
|
+
}, decisions.accept_support_offer);
|
|
219
|
+
|
|
220
|
+
registerAppTool(server, "get_support_chat", {
|
|
221
|
+
inputSchema: getChatSchema,
|
|
222
|
+
_meta: { ui: { resourceUri: supportApp.resourceUri, visibility: ["app"] } }
|
|
223
|
+
}, supportApp.tools.get_support_chat);
|
|
224
|
+
|
|
225
|
+
registerAppTool(server, "send_support_message", {
|
|
226
|
+
inputSchema: sendMessageSchema,
|
|
227
|
+
_meta: { ui: { resourceUri: supportApp.resourceUri, visibility: ["app"] } }
|
|
228
|
+
}, supportApp.tools.send_support_message);
|
|
229
|
+
|
|
230
|
+
registerAppResource(server, "SupportBridge chat", supportApp.resourceUri, {
|
|
231
|
+
mimeType: supportApp.mimeType,
|
|
232
|
+
_meta: supportApp.resourceMeta
|
|
233
|
+
}, async () => supportApp.resourceContents());
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
The HTML uses the standard `text/html;profile=mcp-app` resource type and MCP Apps JSON-RPC bridge. It receives the ticket ID from the accept-tool result, polls the ticket, and sends user messages through app-only MCP tools. Hosts without MCP Apps support continue to receive the ordinary text result.
|
|
237
|
+
|
|
238
|
+
## Direct tool instrumentation
|
|
239
|
+
|
|
240
|
+
For frameworks with custom middleware:
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
const result = await supportbridge.instrumentTool(
|
|
244
|
+
{
|
|
245
|
+
toolName: "search_companies",
|
|
246
|
+
arguments: { query: "fintech" },
|
|
247
|
+
identity: { userId: "user_34892", workspaceId: "acme" }
|
|
248
|
+
},
|
|
249
|
+
() => searchCompanies("fintech")
|
|
250
|
+
);
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
The return value is discriminated by `kind`:
|
|
254
|
+
|
|
255
|
+
- `result`: the vendor tool executed and `value` contains its result.
|
|
256
|
+
- `support_offer`: execution was paused and `offer` contains the support decision payload.
|
|
257
|
+
|
|
258
|
+
## Agent telemetry
|
|
259
|
+
|
|
260
|
+
```ts
|
|
261
|
+
import { traceAgentRun } from "@supportbridge/sdk";
|
|
262
|
+
|
|
263
|
+
await traceAgentRun(
|
|
264
|
+
supportbridge,
|
|
265
|
+
{
|
|
266
|
+
agentName: "research-agent",
|
|
267
|
+
identity: { userId: "user_34892", workspaceId: "acme" }
|
|
268
|
+
},
|
|
269
|
+
async span => {
|
|
270
|
+
const startedAt = performance.now();
|
|
271
|
+
const response = await callYourModel();
|
|
272
|
+
span.recordModelCall({
|
|
273
|
+
provider: "your-provider",
|
|
274
|
+
model: "your-model",
|
|
275
|
+
startedAt,
|
|
276
|
+
inputTokens: response.usage.input,
|
|
277
|
+
outputTokens: response.usage.output
|
|
278
|
+
});
|
|
279
|
+
return response;
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Tool calls made inside `traceAgentRun` automatically inherit its trace and run identifiers through `AsyncLocalStorage`.
|
|
285
|
+
|
|
286
|
+
## Privacy defaults
|
|
287
|
+
|
|
288
|
+
The SDK captures sanitized tool arguments and bounded result summaries. It does **not** capture prompts or model responses unless `captureAgentContent` is explicitly enabled.
|
|
289
|
+
|
|
290
|
+
Recognized credential fields are replaced with `[REDACTED]`. Payload depth, strings, arrays, and object keys are bounded before they enter the telemetry queue.
|
|
291
|
+
|
|
292
|
+
```ts
|
|
293
|
+
privacy: {
|
|
294
|
+
captureToolArguments: true,
|
|
295
|
+
captureToolResponses: true,
|
|
296
|
+
captureAgentContent: false,
|
|
297
|
+
sensitiveKeys: ["customer_access_code"],
|
|
298
|
+
maxStringLength: 1000
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Software companies should still document telemetry collection, obtain any required consent, and avoid sending regulated or unnecessary data.
|
|
303
|
+
|
|
304
|
+
## Reliability model
|
|
305
|
+
|
|
306
|
+
Telemetry is delivered outside the tool execution path. Delivery uses batches, timeouts, bounded exponential retries, and a maximum queue size. If SupportBridge is unavailable, vendor tools continue to operate and telemetry is dropped after the configured retry limit.
|
|
307
|
+
|
|
308
|
+
Call `flush()` before short-lived processes exit and `close()` during graceful shutdown:
|
|
309
|
+
|
|
310
|
+
```ts
|
|
311
|
+
process.once("SIGTERM", () => void supportbridge.close());
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Trigger-state storage
|
|
315
|
+
|
|
316
|
+
The default `MemoryTriggerStateStore` is appropriate for local development and a single process. Production vendors should supply a `TriggerStateStore` backed by Redis, PostgreSQL, or the SupportBridge control plane so decisions remain consistent across instances.
|
|
317
|
+
|
|
318
|
+
## Development
|
|
319
|
+
|
|
320
|
+
From this directory:
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
npm run check
|
|
324
|
+
npm test
|
|
325
|
+
npm run build
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Publishing releases
|
|
329
|
+
|
|
330
|
+
npm releases are published automatically through GitHub Actions and npm Trusted Publishing. No npm token is stored in GitHub.
|
|
331
|
+
|
|
332
|
+
1. Update the SDK version in `package.json` and update the changelog.
|
|
333
|
+
2. Commit and push the release changes to `main`.
|
|
334
|
+
3. Create and push a tag matching the package version exactly, such as `v0.8.2`.
|
|
335
|
+
|
|
336
|
+
The `Publish SDK to npm` workflow verifies that the tag matches `package.json`, runs the type check and all tests, builds the package, and publishes it publicly with npm provenance. A mismatched tag or failed check stops the release before publication.
|
|
337
|
+
|
|
338
|
+
The package intentionally has no runtime dependency on a particular MCP or agent framework. Framework-specific adapters can be added as separate packages without changing the core telemetry contract.
|
|
339
|
+
|
|
340
|
+
See [the telemetry contract](docs/telemetry-contract.md) for backend ingestion details and [the security guide](SECURITY.md) before a production deployment.
|
|
341
|
+
|
|
342
|
+
## Hosted control plane
|
|
343
|
+
|
|
344
|
+
The repository also contains the first vendor-facing control plane in [`control-plane`](control-plane). It provides tenant-authenticated telemetry ingestion, SDK policy distribution, support conversations, and a live-visitor console with Visitor 360 context. See its [deployment and integration guide](control-plane/README.md).
|
|
326
345
|
|