@casys/mcp-bridge 0.2.0

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.
Files changed (131) hide show
  1. package/esm/_dnt.shims.d.ts +2 -0
  2. package/esm/_dnt.shims.d.ts.map +1 -0
  3. package/esm/_dnt.shims.js +57 -0
  4. package/esm/adapters/base-adapter.d.ts +25 -0
  5. package/esm/adapters/base-adapter.d.ts.map +1 -0
  6. package/esm/adapters/base-adapter.js +86 -0
  7. package/esm/adapters/line/adapter.d.ts +11 -0
  8. package/esm/adapters/line/adapter.d.ts.map +1 -0
  9. package/esm/adapters/line/adapter.js +10 -0
  10. package/esm/adapters/line/types.d.ts +25 -0
  11. package/esm/adapters/line/types.d.ts.map +1 -0
  12. package/esm/adapters/line/types.js +4 -0
  13. package/esm/adapters/telegram/adapter.d.ts +11 -0
  14. package/esm/adapters/telegram/adapter.d.ts.map +1 -0
  15. package/esm/adapters/telegram/adapter.js +10 -0
  16. package/esm/adapters/telegram/platform-adapter.d.ts +40 -0
  17. package/esm/adapters/telegram/platform-adapter.d.ts.map +1 -0
  18. package/esm/adapters/telegram/platform-adapter.js +214 -0
  19. package/esm/adapters/telegram/sdk-bridge.d.ts +8 -0
  20. package/esm/adapters/telegram/sdk-bridge.d.ts.map +1 -0
  21. package/esm/adapters/telegram/sdk-bridge.js +22 -0
  22. package/esm/adapters/telegram/types.d.ts +93 -0
  23. package/esm/adapters/telegram/types.d.ts.map +1 -0
  24. package/esm/adapters/telegram/types.js +6 -0
  25. package/esm/client/bridge.js +424 -0
  26. package/esm/core/adapter.d.ts +88 -0
  27. package/esm/core/adapter.d.ts.map +1 -0
  28. package/esm/core/adapter.js +10 -0
  29. package/esm/core/bridge-client.d.ts +77 -0
  30. package/esm/core/bridge-client.d.ts.map +1 -0
  31. package/esm/core/bridge-client.js +275 -0
  32. package/esm/core/message-router.d.ts +71 -0
  33. package/esm/core/message-router.d.ts.map +1 -0
  34. package/esm/core/message-router.js +187 -0
  35. package/esm/core/protocol.d.ts +116 -0
  36. package/esm/core/protocol.d.ts.map +1 -0
  37. package/esm/core/protocol.js +203 -0
  38. package/esm/core/resource-resolver.d.ts +27 -0
  39. package/esm/core/resource-resolver.d.ts.map +1 -0
  40. package/esm/core/resource-resolver.js +85 -0
  41. package/esm/core/transport.d.ts +46 -0
  42. package/esm/core/transport.d.ts.map +1 -0
  43. package/esm/core/transport.js +85 -0
  44. package/esm/core/types.d.ts +187 -0
  45. package/esm/core/types.d.ts.map +1 -0
  46. package/esm/core/types.js +35 -0
  47. package/esm/mod.d.ts +36 -0
  48. package/esm/mod.d.ts.map +1 -0
  49. package/esm/mod.js +33 -0
  50. package/esm/package.json +3 -0
  51. package/esm/resource-server/csp.d.ts +36 -0
  52. package/esm/resource-server/csp.d.ts.map +1 -0
  53. package/esm/resource-server/csp.js +36 -0
  54. package/esm/resource-server/injector.d.ts +18 -0
  55. package/esm/resource-server/injector.d.ts.map +1 -0
  56. package/esm/resource-server/injector.js +39 -0
  57. package/esm/resource-server/server.d.ts +107 -0
  58. package/esm/resource-server/server.d.ts.map +1 -0
  59. package/esm/resource-server/server.js +483 -0
  60. package/esm/resource-server/session.d.ts +60 -0
  61. package/esm/resource-server/session.d.ts.map +1 -0
  62. package/esm/resource-server/session.js +86 -0
  63. package/esm/resource-server/telegram-auth.d.ts +45 -0
  64. package/esm/resource-server/telegram-auth.d.ts.map +1 -0
  65. package/esm/resource-server/telegram-auth.js +161 -0
  66. package/package.json +31 -0
  67. package/script/_dnt.shims.d.ts +2 -0
  68. package/script/_dnt.shims.d.ts.map +1 -0
  69. package/script/_dnt.shims.js +60 -0
  70. package/script/adapters/base-adapter.d.ts +25 -0
  71. package/script/adapters/base-adapter.d.ts.map +1 -0
  72. package/script/adapters/base-adapter.js +113 -0
  73. package/script/adapters/line/adapter.d.ts +11 -0
  74. package/script/adapters/line/adapter.d.ts.map +1 -0
  75. package/script/adapters/line/adapter.js +14 -0
  76. package/script/adapters/line/types.d.ts +25 -0
  77. package/script/adapters/line/types.d.ts.map +1 -0
  78. package/script/adapters/line/types.js +5 -0
  79. package/script/adapters/telegram/adapter.d.ts +11 -0
  80. package/script/adapters/telegram/adapter.d.ts.map +1 -0
  81. package/script/adapters/telegram/adapter.js +14 -0
  82. package/script/adapters/telegram/platform-adapter.d.ts +40 -0
  83. package/script/adapters/telegram/platform-adapter.d.ts.map +1 -0
  84. package/script/adapters/telegram/platform-adapter.js +241 -0
  85. package/script/adapters/telegram/sdk-bridge.d.ts +8 -0
  86. package/script/adapters/telegram/sdk-bridge.d.ts.map +1 -0
  87. package/script/adapters/telegram/sdk-bridge.js +48 -0
  88. package/script/adapters/telegram/types.d.ts +93 -0
  89. package/script/adapters/telegram/types.d.ts.map +1 -0
  90. package/script/adapters/telegram/types.js +7 -0
  91. package/script/client/bridge.js +424 -0
  92. package/script/core/adapter.d.ts +88 -0
  93. package/script/core/adapter.d.ts.map +1 -0
  94. package/script/core/adapter.js +11 -0
  95. package/script/core/bridge-client.d.ts +77 -0
  96. package/script/core/bridge-client.d.ts.map +1 -0
  97. package/script/core/bridge-client.js +302 -0
  98. package/script/core/message-router.d.ts +71 -0
  99. package/script/core/message-router.d.ts.map +1 -0
  100. package/script/core/message-router.js +191 -0
  101. package/script/core/protocol.d.ts +116 -0
  102. package/script/core/protocol.d.ts.map +1 -0
  103. package/script/core/protocol.js +230 -0
  104. package/script/core/resource-resolver.d.ts +27 -0
  105. package/script/core/resource-resolver.d.ts.map +1 -0
  106. package/script/core/resource-resolver.js +89 -0
  107. package/script/core/transport.d.ts +46 -0
  108. package/script/core/transport.d.ts.map +1 -0
  109. package/script/core/transport.js +112 -0
  110. package/script/core/types.d.ts +187 -0
  111. package/script/core/types.d.ts.map +1 -0
  112. package/script/core/types.js +38 -0
  113. package/script/mod.d.ts +36 -0
  114. package/script/mod.d.ts.map +1 -0
  115. package/script/mod.js +76 -0
  116. package/script/package.json +3 -0
  117. package/script/resource-server/csp.d.ts +36 -0
  118. package/script/resource-server/csp.d.ts.map +1 -0
  119. package/script/resource-server/csp.js +39 -0
  120. package/script/resource-server/injector.d.ts +18 -0
  121. package/script/resource-server/injector.d.ts.map +1 -0
  122. package/script/resource-server/injector.js +42 -0
  123. package/script/resource-server/server.d.ts +107 -0
  124. package/script/resource-server/server.d.ts.map +1 -0
  125. package/script/resource-server/server.js +487 -0
  126. package/script/resource-server/session.d.ts +60 -0
  127. package/script/resource-server/session.d.ts.map +1 -0
  128. package/script/resource-server/session.js +90 -0
  129. package/script/resource-server/telegram-auth.d.ts +45 -0
  130. package/script/resource-server/telegram-auth.d.ts.map +1 -0
  131. package/script/resource-server/telegram-auth.js +164 -0
@@ -0,0 +1,424 @@
1
+ /**
2
+ * MCP Apps Bridge — Client-side runtime.
3
+ *
4
+ * Injected by the resource server into MCP App HTML pages.
5
+ * Intercepts postMessage calls from the MCP App class, routes them
6
+ * to the resource server via WebSocket, and dispatches responses
7
+ * back as MessageEvents.
8
+ *
9
+ * Query parameters (set by the resource server on the <script> tag):
10
+ * - platform: "telegram" | "line"
11
+ * - session: session ID (created by the resource server)
12
+ *
13
+ * @module bridge.js
14
+ */
15
+ (function () {
16
+ "use strict";
17
+
18
+ // ---------------------------------------------------------------------------
19
+ // Read configuration from script tag query params
20
+ // ---------------------------------------------------------------------------
21
+
22
+ var currentScript = document.currentScript;
23
+ if (!currentScript) {
24
+ console.error("[bridge.js] Cannot find own <script> element.");
25
+ return;
26
+ }
27
+
28
+ var scriptUrl = new URL(currentScript.src);
29
+ var PLATFORM = scriptUrl.searchParams.get("platform") || "unknown";
30
+ var SESSION_ID = scriptUrl.searchParams.get("session");
31
+ if (!SESSION_ID) {
32
+ console.error("[bridge.js] Missing 'session' query parameter.");
33
+ return;
34
+ }
35
+
36
+ var WS_BASE = scriptUrl.origin;
37
+ var WS_URL = WS_BASE.replace(/^http/, "ws") + "/bridge?session=" + SESSION_ID;
38
+ var DEBUG = scriptUrl.searchParams.get("debug") === "1";
39
+
40
+ function log() {
41
+ if (DEBUG) {
42
+ console.log.apply(console, ["[bridge.js]"].concat(Array.prototype.slice.call(arguments)));
43
+ }
44
+ }
45
+
46
+ log("Platform:", PLATFORM, "Session:", SESSION_ID);
47
+
48
+ // ---------------------------------------------------------------------------
49
+ // JSON-RPC helpers
50
+ // ---------------------------------------------------------------------------
51
+
52
+ function isJsonRpc(msg) {
53
+ return msg && typeof msg === "object" && msg.jsonrpc === "2.0";
54
+ }
55
+
56
+ function isRequest(msg) {
57
+ return "method" in msg && "id" in msg;
58
+ }
59
+
60
+ function isResponse(msg) {
61
+ return ("result" in msg || "error" in msg) && "id" in msg;
62
+ }
63
+
64
+ // ---------------------------------------------------------------------------
65
+ // Platform detection: Telegram theme
66
+ // ---------------------------------------------------------------------------
67
+
68
+ function getTelegramTheme() {
69
+ var tg = window.Telegram && window.Telegram.WebApp;
70
+ if (!tg) {
71
+ return {
72
+ theme: "light",
73
+ styles: { variables: {} },
74
+ platform: "mobile",
75
+ };
76
+ }
77
+
78
+ var isDark = tg.colorScheme === "dark";
79
+ var tp = tg.themeParams || {};
80
+ var variables = {};
81
+ var keys = Object.keys(tp);
82
+ for (var i = 0; i < keys.length; i++) {
83
+ variables["--tg-" + keys[i].replace(/_/g, "-")] = tp[keys[i]];
84
+ }
85
+
86
+ return {
87
+ theme: isDark ? "dark" : "light",
88
+ styles: { variables: variables },
89
+ platform: "mobile",
90
+ locale: tg.initDataUnsafe && tg.initDataUnsafe.user
91
+ ? tg.initDataUnsafe.user.language_code
92
+ : undefined,
93
+ };
94
+ }
95
+
96
+ // ---------------------------------------------------------------------------
97
+ // Request tracking (for matching responses to outgoing requests)
98
+ // ---------------------------------------------------------------------------
99
+
100
+ var pendingRequests = {}; // id -> { resolve, reject, timer }
101
+ var REQUEST_TIMEOUT_MS = 30000;
102
+ var appInitialized = false;
103
+ var earlyNotifications = []; // notifications received before ui/initialize
104
+
105
+ function trackRequest(id) {
106
+ return new Promise(function (resolve, reject) {
107
+ var timer = setTimeout(function () {
108
+ delete pendingRequests[id];
109
+ reject(new Error("Request " + id + " timed out after " + REQUEST_TIMEOUT_MS + "ms"));
110
+ }, REQUEST_TIMEOUT_MS);
111
+
112
+ pendingRequests[id] = { resolve: resolve, reject: reject, timer: timer };
113
+ });
114
+ }
115
+
116
+ function resolveRequest(id, result) {
117
+ var entry = pendingRequests[id];
118
+ if (entry) {
119
+ clearTimeout(entry.timer);
120
+ delete pendingRequests[id];
121
+ entry.resolve(result);
122
+ }
123
+ }
124
+
125
+ function rejectRequest(id, error) {
126
+ var entry = pendingRequests[id];
127
+ if (entry) {
128
+ clearTimeout(entry.timer);
129
+ delete pendingRequests[id];
130
+ entry.reject(error);
131
+ }
132
+ }
133
+
134
+ // ---------------------------------------------------------------------------
135
+ // ui/initialize handler (synthesized locally)
136
+ // ---------------------------------------------------------------------------
137
+
138
+ function handleInitialize(requestId) {
139
+ var hostCtx = getTelegramTheme();
140
+
141
+ var response = {
142
+ jsonrpc: "2.0",
143
+ id: requestId,
144
+ result: {
145
+ protocolVersion: "2025-11-25",
146
+ hostInfo: {
147
+ name: "@casys/mcp-apps-bridge",
148
+ version: "0.1.0",
149
+ },
150
+ hostCapabilities: {
151
+ serverTools: { listChanged: false },
152
+ serverResources: { listChanged: false },
153
+ logging: {},
154
+ openLinks: {},
155
+ },
156
+ hostContext: hostCtx,
157
+ },
158
+ };
159
+
160
+ dispatchToApp(response);
161
+
162
+ // App is now ready — flush any notifications received before init
163
+ appInitialized = true;
164
+ if (earlyNotifications.length > 0) {
165
+ log("Flushing", earlyNotifications.length, "early notification(s)");
166
+ for (var i = 0; i < earlyNotifications.length; i++) {
167
+ dispatchToApp(earlyNotifications[i]);
168
+ }
169
+ earlyNotifications = [];
170
+ }
171
+ }
172
+
173
+ // ---------------------------------------------------------------------------
174
+ // Dispatch to App (via MessageEvent on window)
175
+ // ---------------------------------------------------------------------------
176
+
177
+ function dispatchToApp(message) {
178
+ log("-> App:", message.method || ("id" in message ? "response#" + message.id : "?"));
179
+ // Use real postMessage so event.source === window (=== window.parent in standalone).
180
+ // The MCP Apps SDK checks event.source — dispatchEvent leaves it null.
181
+ // Use the script origin as targetOrigin instead of "*" to prevent message leaking.
182
+ _realPostMessage(message, scriptUrl.origin);
183
+ }
184
+
185
+ // ---------------------------------------------------------------------------
186
+ // WebSocket connection
187
+ // ---------------------------------------------------------------------------
188
+
189
+ var ws = null;
190
+ var reconnectAttempts = 0;
191
+ var MAX_RECONNECT = 5;
192
+ var authenticated = false;
193
+
194
+ function connectWs() {
195
+ log("Connecting to", WS_URL);
196
+ ws = new WebSocket(WS_URL);
197
+
198
+ ws.onopen = function () {
199
+ log("WebSocket connected");
200
+ reconnectAttempts = 0;
201
+
202
+ // Send auth immediately if Telegram SDK is available
203
+ var tg = window.Telegram && window.Telegram.WebApp;
204
+ if (tg && tg.initData) {
205
+ log("Sending Telegram auth...");
206
+ ws.send(JSON.stringify({ type: "auth", initData: tg.initData }));
207
+ } else {
208
+ // No Telegram SDK — server will decide if auth is required
209
+ log("No Telegram SDK, dispatching ready without auth");
210
+ authenticated = true;
211
+ window.dispatchEvent(new CustomEvent("mcp-bridge-ready", {
212
+ detail: { platform: PLATFORM, session: SESSION_ID },
213
+ }));
214
+ }
215
+ };
216
+
217
+ ws.onmessage = function (event) {
218
+ try {
219
+ var msg = JSON.parse(event.data);
220
+ // Handle auth responses (non-JSON-RPC)
221
+ if (msg && msg.type === "auth_ok") {
222
+ log("Authenticated, userId:", msg.userId);
223
+ authenticated = true;
224
+ window.dispatchEvent(new CustomEvent("mcp-bridge-ready", {
225
+ detail: { platform: PLATFORM, session: SESSION_ID, userId: msg.userId },
226
+ }));
227
+ return;
228
+ }
229
+
230
+ if (msg && msg.type === "auth_error") {
231
+ console.error("[bridge.js] Authentication failed:", msg.error);
232
+ window.dispatchEvent(new CustomEvent("mcp-bridge-auth-error", {
233
+ detail: { error: msg.error },
234
+ }));
235
+ return;
236
+ }
237
+
238
+ if (!isJsonRpc(msg)) return;
239
+
240
+ // Responses: resolve tracked requests
241
+ if (isResponse(msg)) {
242
+ if ("error" in msg) {
243
+ rejectRequest(msg.id, msg.error);
244
+ } else {
245
+ resolveRequest(msg.id, msg.result);
246
+ }
247
+ // The trackRequest().then() will call dispatchToApp
248
+ return;
249
+ }
250
+
251
+ // Notifications from server
252
+ if ("method" in msg && !("id" in msg)) {
253
+ if (!appInitialized) {
254
+ log("Queuing early notification:", msg.method);
255
+ earlyNotifications.push(msg);
256
+ } else {
257
+ dispatchToApp(msg);
258
+ }
259
+ }
260
+ } catch (err) {
261
+ console.warn("[bridge.js] Failed to parse WS message:", err);
262
+ }
263
+ };
264
+
265
+ ws.onclose = function () {
266
+ log("WebSocket disconnected");
267
+ ws = null;
268
+ if (reconnectAttempts < MAX_RECONNECT) {
269
+ reconnectAttempts++;
270
+ var delay = Math.min(1000 * Math.pow(2, reconnectAttempts - 1), 10000);
271
+ log("Reconnecting in", delay, "ms (attempt", reconnectAttempts + ")");
272
+ setTimeout(connectWs, delay);
273
+ }
274
+ };
275
+
276
+ ws.onerror = function () {
277
+ log("WebSocket error");
278
+ };
279
+ }
280
+
281
+ function sendToServer(message) {
282
+ if (!ws || ws.readyState !== WebSocket.OPEN) {
283
+ console.warn("[bridge.js] WebSocket not connected. Dropping message:", message);
284
+ return;
285
+ }
286
+ if (!authenticated) {
287
+ console.warn("[bridge.js] Not authenticated yet. Dropping message:", message);
288
+ return;
289
+ }
290
+ ws.send(JSON.stringify(message));
291
+ }
292
+
293
+ // ---------------------------------------------------------------------------
294
+ // Intercept postMessage (App -> Bridge)
295
+ // ---------------------------------------------------------------------------
296
+
297
+ // Save the REAL postMessage before we monkey-patch it.
298
+ // Used by dispatchToApp() so that event.source === window,
299
+ // which the MCP Apps SDK checks (event.source === window.parent).
300
+ var _realPostMessage = window.postMessage.bind(window);
301
+
302
+ var originalPostMessage = window.parent !== window
303
+ ? window.parent.postMessage.bind(window.parent)
304
+ : null;
305
+
306
+ function interceptPostMessage() {
307
+ if (window.parent === window) {
308
+ // Not in a frame — intercept window.postMessage instead for standalone mode
309
+ log("Intercepting window.postMessage (standalone mode)");
310
+ var origSelf = window.postMessage.bind(window);
311
+ window.postMessage = function (message, targetOrigin, transfer) {
312
+ if (isJsonRpc(message)) {
313
+ handleOutgoing(message);
314
+ } else {
315
+ origSelf(message, targetOrigin, transfer);
316
+ }
317
+ };
318
+ return;
319
+ }
320
+
321
+ log("Intercepting window.parent.postMessage (iframe mode)");
322
+ window.parent.postMessage = function (message, targetOrigin, transfer) {
323
+ if (isJsonRpc(message)) {
324
+ handleOutgoing(message);
325
+ } else if (originalPostMessage) {
326
+ originalPostMessage(message, targetOrigin, transfer);
327
+ }
328
+ };
329
+ }
330
+
331
+ function handleOutgoing(message) {
332
+ log("<- App:", message.method || "response");
333
+
334
+ // ui/initialize — handle locally
335
+ if (message.method === "ui/initialize" && "id" in message) {
336
+ handleInitialize(message.id);
337
+ return;
338
+ }
339
+
340
+ // ui/open-link — handle locally via Telegram API or fallback
341
+ if (message.method === "ui/open-link" && "id" in message) {
342
+ var url = message.params && message.params.url;
343
+ if (url) {
344
+ var tg = window.Telegram && window.Telegram.WebApp;
345
+ if (tg && tg.openLink) {
346
+ tg.openLink(url);
347
+ } else {
348
+ window.open(url, "_blank");
349
+ }
350
+ }
351
+ dispatchToApp({ jsonrpc: "2.0", id: message.id, result: {} });
352
+ return;
353
+ }
354
+
355
+ // Forward to resource server via WebSocket
356
+ sendToServer(message);
357
+
358
+ // Track requests for response matching
359
+ if (isRequest(message)) {
360
+ trackRequest(message.id)
361
+ .then(function (result) {
362
+ dispatchToApp({ jsonrpc: "2.0", id: message.id, result: result });
363
+ })
364
+ .catch(function (err) {
365
+ dispatchToApp({
366
+ jsonrpc: "2.0",
367
+ id: message.id,
368
+ error: { code: -32603, message: err.message || String(err) },
369
+ });
370
+ });
371
+ }
372
+ }
373
+
374
+ // ---------------------------------------------------------------------------
375
+ // Telegram lifecycle events
376
+ // ---------------------------------------------------------------------------
377
+
378
+ function setupTelegramEvents() {
379
+ var tg = window.Telegram && window.Telegram.WebApp;
380
+ if (!tg) return;
381
+
382
+ // Tell Telegram we're ready
383
+ tg.ready();
384
+ if (!tg.isExpanded) tg.expand();
385
+
386
+ // Theme changes
387
+ if (typeof tg.onEvent === "function") {
388
+ tg.onEvent("themeChanged", function () {
389
+ var ctx = getTelegramTheme();
390
+ dispatchToApp({
391
+ jsonrpc: "2.0",
392
+ method: "ui/notifications/host-context-changed",
393
+ params: { theme: ctx.theme, styles: ctx.styles },
394
+ });
395
+ });
396
+
397
+ tg.onEvent("viewportChanged", function () {
398
+ dispatchToApp({
399
+ jsonrpc: "2.0",
400
+ method: "ui/notifications/host-context-changed",
401
+ params: {
402
+ containerDimensions: {
403
+ width: window.innerWidth,
404
+ height: tg.viewportStableHeight || window.innerHeight,
405
+ },
406
+ },
407
+ });
408
+ });
409
+ }
410
+ }
411
+
412
+ // ---------------------------------------------------------------------------
413
+ // Boot
414
+ // ---------------------------------------------------------------------------
415
+
416
+ interceptPostMessage();
417
+ connectWs();
418
+
419
+ if (PLATFORM === "telegram") {
420
+ setupTelegramEvents();
421
+ }
422
+
423
+ log("Bridge initialized for", PLATFORM);
424
+ })();
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Abstract adapter interfaces for platform integrations.
3
+ *
4
+ * Two adapter levels:
5
+ * - `McpAppsAdapter`: Low-level message transport (postMessage replacement).
6
+ * - `PlatformAdapter`: High-level platform SDK abstraction (theme, viewport,
7
+ * native UI, auth). Used by BridgeClient to synthesize HostContext and
8
+ * translate platform events into MCP notifications.
9
+ */
10
+ import type { AdapterConfig, ContainerDimensions, HostContext, LifecycleEvent, McpAppsMessage } from "./types.js";
11
+ /** Handler function invoked when the host sends a message to the MCP App. */
12
+ export type MessageHandler = (message: McpAppsMessage) => void;
13
+ /**
14
+ * Low-level transport adapter contract.
15
+ *
16
+ * Replaces the iframe postMessage channel with a platform-specific
17
+ * communication mechanism. Each platform implements this to bridge
18
+ * JSON-RPC messages between the MCP App and the resource server.
19
+ *
20
+ * Lifecycle: `init()` -> use -> `destroy()`.
21
+ */
22
+ export interface McpAppsAdapter {
23
+ /** Unique platform identifier (e.g. `"telegram"`, `"line"`). */
24
+ readonly platform: string;
25
+ /**
26
+ * Initialize the adapter with platform-specific configuration.
27
+ * Must be called before any other method.
28
+ */
29
+ init(config: AdapterConfig): Promise<void>;
30
+ /**
31
+ * Send a JSON-RPC message from the MCP App to the host.
32
+ * Throws if the adapter has not been initialized.
33
+ */
34
+ sendToHost(message: McpAppsMessage): void;
35
+ /**
36
+ * Register a handler that is called when the host sends a message
37
+ * to the MCP App.
38
+ */
39
+ onMessageFromHost(handler: MessageHandler): void;
40
+ /**
41
+ * Tear down the adapter, releasing all resources and listeners.
42
+ * After calling `destroy()`, the adapter must not be reused.
43
+ */
44
+ destroy(): void;
45
+ }
46
+ /** Handler for platform lifecycle events. */
47
+ export type LifecycleEventHandler = (event: LifecycleEvent) => void;
48
+ /**
49
+ * High-level platform adapter contract.
50
+ *
51
+ * Abstracts platform-specific SDK features (theme, viewport, native UI,
52
+ * auth) into a uniform interface that the BridgeClient uses to:
53
+ * - Build the initial `HostContext` for `ui/initialize`
54
+ * - Map platform events to `ui/notifications/host-context-changed`
55
+ * - Execute platform-specific actions (open link, expand viewport)
56
+ */
57
+ export interface PlatformAdapter {
58
+ /** Platform name (e.g. `"telegram"`, `"line"`). */
59
+ readonly name: string;
60
+ /**
61
+ * Initialize the platform SDK and return the initial host context.
62
+ * This is called once during BridgeClient startup.
63
+ */
64
+ initialize(): Promise<HostContext>;
65
+ /** Get the current theme from the platform. */
66
+ getTheme(): "light" | "dark";
67
+ /** Get the current container dimensions from the platform. */
68
+ getContainerDimensions(): ContainerDimensions;
69
+ /**
70
+ * Subscribe to platform lifecycle events (theme change, viewport
71
+ * resize, activation, teardown).
72
+ */
73
+ onLifecycleEvent(handler: LifecycleEventHandler): void;
74
+ /** Open an external link using the platform's native method. */
75
+ openLink(url: string): Promise<void>;
76
+ /**
77
+ * Send a message via the platform's native messaging (if supported).
78
+ *
79
+ * WARNING (Telegram): `sendData()` closes the Mini App. Use with caution.
80
+ */
81
+ sendMessage?(text: string): Promise<void>;
82
+ /**
83
+ * Get platform-specific auth data for forwarding to the MCP server.
84
+ * E.g. Telegram `initData`, LIFF access token.
85
+ */
86
+ getAuthData?(): Record<string, unknown>;
87
+ }
88
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/core/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,aAAa,EACb,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,cAAc,EACf,MAAM,YAAY,CAAC;AAMpB,6EAA6E;AAC7E,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;AAE/D;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B;;;OAGG;IACH,IAAI,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3C;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAE1C;;;OAGG;IACH,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAEjD;;;OAGG;IACH,OAAO,IAAI,IAAI,CAAC;CACjB;AAMD,6CAA6C;AAC7C,MAAM,MAAM,qBAAqB,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;AAEpE;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,UAAU,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IAEnC,+CAA+C;IAC/C,QAAQ,IAAI,OAAO,GAAG,MAAM,CAAC;IAE7B,8DAA8D;IAC9D,sBAAsB,IAAI,mBAAmB,CAAC;IAE9C;;;OAGG;IACH,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAEvD,gEAAgE;IAChE,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAErC;;;;OAIG;IACH,WAAW,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1C;;;OAGG;IACH,WAAW,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ /**
3
+ * Abstract adapter interfaces for platform integrations.
4
+ *
5
+ * Two adapter levels:
6
+ * - `McpAppsAdapter`: Low-level message transport (postMessage replacement).
7
+ * - `PlatformAdapter`: High-level platform SDK abstraction (theme, viewport,
8
+ * native UI, auth). Used by BridgeClient to synthesize HostContext and
9
+ * translate platform events into MCP notifications.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,77 @@
1
+ import type { PlatformAdapter } from "./adapter.js";
2
+ import type { BridgeTransport } from "./transport.js";
3
+ import type { HostContext } from "./types.js";
4
+ /** Options for creating a BridgeClient. */
5
+ export interface BridgeClientOptions {
6
+ /** WebSocket URL of the resource server bridge endpoint. */
7
+ readonly serverUrl: string;
8
+ /** Platform adapter instance (Telegram, LINE, etc.). */
9
+ readonly platform: PlatformAdapter;
10
+ /** Transport implementation. Defaults to WebSocketTransport if not provided. */
11
+ readonly transport: BridgeTransport;
12
+ /** Session ID assigned by the resource server. */
13
+ readonly sessionId: string;
14
+ /** Bridge name/version reported in ui/initialize. */
15
+ readonly bridgeInfo?: {
16
+ readonly name: string;
17
+ readonly version: string;
18
+ };
19
+ /** Request timeout in ms. Defaults to 30_000. */
20
+ readonly requestTimeoutMs?: number;
21
+ }
22
+ /**
23
+ * The MCP Apps Bridge client.
24
+ *
25
+ * Injected into the MCP App HTML by the resource server (`bridge.js`).
26
+ * Intercepts postMessage, routes via WebSocket, translates platform events.
27
+ */
28
+ export declare class BridgeClient {
29
+ private readonly platform;
30
+ private readonly transport;
31
+ private readonly router;
32
+ private readonly options;
33
+ private hostContext;
34
+ private started;
35
+ private originalPostMessage;
36
+ constructor(options: BridgeClientOptions);
37
+ /**
38
+ * Start the bridge:
39
+ * 1. Initialize the platform adapter to get HostContext
40
+ * 2. Connect transport to resource server
41
+ * 3. Intercept postMessage from App class
42
+ * 4. Listen for platform lifecycle events
43
+ * 5. Register ui/initialize handler to synthesize response
44
+ */
45
+ start(): Promise<void>;
46
+ /** Stop the bridge, restore postMessage, disconnect transport. */
47
+ destroy(): void;
48
+ /** Whether the bridge is currently running. */
49
+ get isStarted(): boolean;
50
+ /** The current host context (null before start). */
51
+ get currentHostContext(): HostContext | null;
52
+ private interceptPostMessage;
53
+ private restorePostMessage;
54
+ /**
55
+ * Handle an outgoing message from the MCP App (intercepted from postMessage).
56
+ *
57
+ * Requests that the bridge handles locally (ui/initialize, ui/open-link)
58
+ * are dispatched to the router. All other messages are forwarded to the
59
+ * resource server via transport.
60
+ */
61
+ private handleOutgoingMessage;
62
+ /**
63
+ * Handle an incoming message from the resource server.
64
+ *
65
+ * Responses are routed to the pending request tracker (which resolves the
66
+ * Promise created in handleOutgoingMessage — that Promise already calls
67
+ * dispatchToApp, so we must NOT dispatch responses again here).
68
+ *
69
+ * Notifications are dispatched directly to the App class.
70
+ */
71
+ private handleIncomingMessage;
72
+ /** Dispatch a message to the MCP App class as a MessageEvent. */
73
+ private dispatchToApp;
74
+ private handleInitialize;
75
+ private handleLifecycleEvent;
76
+ }
77
+ //# sourceMappingURL=bridge-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-client.d.ts","sourceRoot":"","sources":["../../src/core/bridge-client.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAOpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAEV,WAAW,EAIZ,MAAM,YAAY,CAAC;AAGpB,2CAA2C;AAC3C,MAAM,WAAW,mBAAmB;IAClC,4DAA4D;IAC5D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,wDAAwD;IACxD,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,gFAAgF;IAChF,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,kDAAkD;IAClD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,qDAAqD;IACrD,QAAQ,CAAC,UAAU,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1E,iDAAiD;IACjD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED;;;;;GAKG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAC3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkB;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAE9C,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,OAAO,CAAS;IAGxB,OAAO,CAAC,mBAAmB,CAA0F;gBAEzG,OAAO,EAAE,mBAAmB;IAOxC;;;;;;;OAOG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA2C5B,kEAAkE;IAClE,OAAO,IAAI,IAAI;IAOf,+CAA+C;IAC/C,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,oDAAoD;IACpD,IAAI,kBAAkB,IAAI,WAAW,GAAG,IAAI,CAE3C;IAMD,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,kBAAkB;IAe1B;;;;;;OAMG;YACW,qBAAqB;IAiDnC;;;;;;;;OAQG;YACW,qBAAqB;IAenC,iEAAiE;IACjE,OAAO,CAAC,aAAa;IAiBrB,OAAO,CAAC,gBAAgB;IAoCxB,OAAO,CAAC,oBAAoB;CA0C7B"}