@mcp-b/transports 0.0.1
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/LICENSE +21 -0
- package/README.md +147 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/index.d.ts +514 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 mcp-b
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# MCP Browser Transports
|
|
2
|
+
|
|
3
|
+
This library provides MCP `Transport` implementations for use in browser environments, enabling communication between MCP clients and servers within a web page or across a browser extension.
|
|
4
|
+
|
|
5
|
+
### Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @mcp-b/transports
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Tab Transport (In-Page)
|
|
12
|
+
|
|
13
|
+
Use `TabServerTransport` and `TabClientTransport` when your MCP server and client are running in the same browser tab. The transport uses a `MessageChannel` and a global `window.mcp` object for communication.
|
|
14
|
+
|
|
15
|
+
### Quick Start: Tab Transport
|
|
16
|
+
|
|
17
|
+
**1. Server Setup**
|
|
18
|
+
|
|
19
|
+
Create an MCP server and connect it to a `TabServerTransport`. This will expose it on `window.mcp`.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// my-mcp-server.js
|
|
23
|
+
import { TabServerTransport } from '@mcp-b/transports';
|
|
24
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp';
|
|
25
|
+
import { z } from 'zod';
|
|
26
|
+
|
|
27
|
+
// 1. Create an MCP server
|
|
28
|
+
const server = new McpServer({
|
|
29
|
+
name: 'WebAppServer',
|
|
30
|
+
version: '1.0.0',
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// 2. Add a tool
|
|
34
|
+
server.tool('add', { a: z.number(), b: z.number() }, async ({ a, b }) => ({
|
|
35
|
+
content: [{ type: 'text', text: String(a + b) }],
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
// 3. Create the transport and connect it to the server
|
|
39
|
+
const transport = new TabServerTransport();
|
|
40
|
+
await server.connect(transport);
|
|
41
|
+
|
|
42
|
+
console.log('MCP Tab Server is running.');
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**2. Client Setup**
|
|
46
|
+
|
|
47
|
+
In your application code, create a client that connects to the server running on the page.
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
// my-app.js
|
|
51
|
+
import { TabClientTransport } from '@mcp-b/transports';
|
|
52
|
+
import { Client } from '@modelcontextprotocol/sdk/client';
|
|
53
|
+
|
|
54
|
+
// 1. Create a transport that connects to the global 'mcp' namespace
|
|
55
|
+
const transport = new TabClientTransport('mcp', {
|
|
56
|
+
clientInstanceId: 'my-web-app-client',
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// 2. Create the client
|
|
60
|
+
const client = new Client({
|
|
61
|
+
name: 'WebAppClient',
|
|
62
|
+
version: '1.0.0',
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// 3. Connect and use the client
|
|
66
|
+
await client.connect(transport);
|
|
67
|
+
const result = await client.callTool({
|
|
68
|
+
name: 'add',
|
|
69
|
+
arguments: { a: 5, b: 10 },
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
console.log('Result of add(5, 10):', result.content[0].text); // "15"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Extension Transport
|
|
76
|
+
|
|
77
|
+
Use `ExtensionClientTransport` to allow a browser extension's UI (like a popup or sidebar) to communicate with an MCP server running in a page. This works via a relay through the extension's background script.
|
|
78
|
+
|
|
79
|
+
### Architecture
|
|
80
|
+
|
|
81
|
+
`Extension UI <-> Background Script <-> Content Script <-> Page Script`
|
|
82
|
+
|
|
83
|
+
### Quick Start: Extension Transport
|
|
84
|
+
|
|
85
|
+
**1. Background Script Setup (`background.ts`)**
|
|
86
|
+
|
|
87
|
+
Set up the central bridge to route messages between the extension UI and content scripts.
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { setupBackgroundBridge } from '@mcp-b/transports/extension';
|
|
91
|
+
|
|
92
|
+
// This function listens for connections from UI and content scripts
|
|
93
|
+
// and relays messages between them.
|
|
94
|
+
setupBackgroundBridge();
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**2. Content Script Setup (`contentScript.ts`)**
|
|
98
|
+
|
|
99
|
+
Inject a content script into the target page to relay messages between the page's `window` and the background script.
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { mcpRelay } from '@mcp-b/transports/extension';
|
|
103
|
+
|
|
104
|
+
// The relay forwards messages from the page to the background script
|
|
105
|
+
// and vice-versa.
|
|
106
|
+
mcpRelay();
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**3. Page Script Setup**
|
|
110
|
+
|
|
111
|
+
Your web application still needs to run a `TabServerTransport` as shown in the "Tab Transport" example above. The content script will automatically connect to it.
|
|
112
|
+
|
|
113
|
+
**4. Extension UI Client (`popup.tsx` or `sidebar.tsx`)**
|
|
114
|
+
|
|
115
|
+
Finally, your extension's UI can connect to the page's MCP server.
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { ExtensionClientTransport } from '@mcp-b/transports';
|
|
119
|
+
import { Client } from '@modelcontextprotocol/sdk/client';
|
|
120
|
+
|
|
121
|
+
// 1. Use the ExtensionClientTransport in your UI code
|
|
122
|
+
const transport = new ExtensionClientTransport({
|
|
123
|
+
clientInstanceId: 'my-extension-ui-client',
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// 2. Create the MCP client
|
|
127
|
+
const client = new Client({
|
|
128
|
+
name: 'MyExtensionUI',
|
|
129
|
+
version: '1.0.0',
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// 3. Connect and use the client
|
|
133
|
+
async function callPageTool() {
|
|
134
|
+
try {
|
|
135
|
+
await client.connect(transport);
|
|
136
|
+
const result = await client.callTool({
|
|
137
|
+
name: 'add',
|
|
138
|
+
arguments: { a: 20, b: 22 },
|
|
139
|
+
});
|
|
140
|
+
console.log('Result from page tool:', result.content[0].text); // "42"
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error('Failed to call tool via extension bridge:', error);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
callPageTool();
|
|
147
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"fileNames":["../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es5.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2016.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2017.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2018.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2019.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2020.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2021.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2022.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.dom.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2021.string.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2022.array.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2022.error.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2022.object.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2022.string.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.decorators.d.ts","../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../../node_modules/.pnpm/@types+react@19.1.6/node_modules/@types/react/global.d.ts","../../../node_modules/.pnpm/csstype@3.1.3/node_modules/csstype/index.d.ts","../../../node_modules/.pnpm/@types+react@19.1.6/node_modules/@types/react/index.d.ts","../../../node_modules/.pnpm/@types+react@19.1.6/node_modules/@types/react/jsx-runtime.d.ts","../../../node_modules/.pnpm/zod@3.25.56/node_modules/zod/dist/types/v3/helpers/typealiases.d.ts","../../../node_modules/.pnpm/zod@3.25.56/node_modules/zod/dist/types/v3/helpers/util.d.ts","../../../node_modules/.pnpm/zod@3.25.56/node_modules/zod/dist/types/v3/zoderror.d.ts","../../../node_modules/.pnpm/zod@3.25.56/node_modules/zod/dist/types/v3/locales/en.d.ts","../../../node_modules/.pnpm/zod@3.25.56/node_modules/zod/dist/types/v3/errors.d.ts","../../../node_modules/.pnpm/zod@3.25.56/node_modules/zod/dist/types/v3/helpers/parseutil.d.ts","../../../node_modules/.pnpm/zod@3.25.56/node_modules/zod/dist/types/v3/helpers/enumutil.d.ts","../../../node_modules/.pnpm/zod@3.25.56/node_modules/zod/dist/types/v3/helpers/errorutil.d.ts","../../../node_modules/.pnpm/zod@3.25.56/node_modules/zod/dist/types/v3/helpers/partialutil.d.ts","../../../node_modules/.pnpm/zod@3.25.56/node_modules/zod/dist/types/v3/standard-schema.d.ts","../../../node_modules/.pnpm/zod@3.25.56/node_modules/zod/dist/types/v3/types.d.ts","../../../node_modules/.pnpm/zod@3.25.56/node_modules/zod/dist/types/v3/external.d.ts","../../../node_modules/.pnpm/zod@3.25.56/node_modules/zod/dist/types/v3/index.d.ts","../../../node_modules/.pnpm/zod@3.25.56/node_modules/zod/dist/types/index.d.ts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.12.1/node_modules/@modelcontextprotocol/sdk/dist/esm/types.d.ts","../src/browser-types.ts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.12.1/node_modules/@modelcontextprotocol/sdk/dist/esm/server/auth/types.d.ts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.12.1/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/transport.d.ts","../src/tab/tabclienttransport.ts","../src/tab/tabservertransport.ts","../src/tab/index.ts","../src/extension/uiconnector.ts","../src/extension/backgroundbridge.ts","../src/extension/contentscript.ts","../src/extension/extensionclienttransport.ts","../src/extension/index.ts","../src/index.ts","../src/extension/pagebridge.ts","../../../node_modules/.pnpm/@types+har-format@1.2.16/node_modules/@types/har-format/index.d.ts","../../../node_modules/.pnpm/@types+chrome@0.0.326/node_modules/@types/chrome/har-format/index.d.ts","../../../node_modules/.pnpm/@types+chrome@0.0.326/node_modules/@types/chrome/chrome-cast/index.d.ts","../../../node_modules/.pnpm/@types+filewriter@0.0.33/node_modules/@types/filewriter/index.d.ts","../../../node_modules/.pnpm/@types+filesystem@0.0.36/node_modules/@types/filesystem/index.d.ts","../../../node_modules/.pnpm/@types+chrome@0.0.326/node_modules/@types/chrome/index.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/compatibility/disposable.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/compatibility/indexable.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/compatibility/iterators.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/compatibility/index.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/globals.typedarray.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/buffer.buffer.d.ts","../../../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/header.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/readable.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/file.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/fetch.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/formdata.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/connector.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/client.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/errors.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/dispatcher.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/global-dispatcher.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/global-origin.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/pool-stats.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/pool.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/handlers.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/balanced-pool.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-interceptor.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-client.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-pool.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-errors.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/proxy-agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/env-http-proxy-agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/retry-handler.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/retry-agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/api.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/interceptors.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/util.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/cookies.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/patch.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/websocket.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/eventsource.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/filereader.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/diagnostics-channel.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/content-type.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/cache.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/index.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/globals.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/assert.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/assert/strict.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/async_hooks.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/buffer.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/child_process.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/cluster.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/console.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/constants.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/crypto.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/dgram.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/diagnostics_channel.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/dns.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/dns/promises.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/domain.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/dom-events.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/events.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/fs.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/fs/promises.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/http.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/http2.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/https.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/inspector.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/module.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/net.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/os.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/path.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/perf_hooks.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/process.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/punycode.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/querystring.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/readline.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/readline/promises.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/repl.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/sea.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/sqlite.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/stream.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/stream/promises.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/stream/consumers.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/stream/web.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/string_decoder.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/test.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/timers.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/timers/promises.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/tls.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/trace_events.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/tty.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/url.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/util.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/v8.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/vm.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/wasi.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/worker_threads.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/zlib.d.ts","../../../node_modules/.pnpm/@types+node@22.15.29/node_modules/@types/node/index.d.ts"],"fileIdsList":[[103,146],[78,80,103,146],[77,103,146],[92,103,146],[93,94,96,103,146],[95,103,146],[103,143,146],[103,145,146],[146],[103,146,151,181],[103,146,147,152,158,159,166,178,189],[103,146,147,148,158,166],[98,99,100,103,146],[103,146,149,190],[103,146,150,151,159,167],[103,146,151,178,186],[103,146,152,154,158,166],[103,145,146,153],[103,146,154,155],[103,146,156,158],[103,145,146,158],[103,146,158,159,160,178,189],[103,146,158,159,160,173,178,181],[103,141,146],[103,141,146,154,158,161,166,178,189],[103,146,158,159,161,162,166,178,186,189],[103,146,161,163,178,186,189],[101,102,103,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,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],[103,146,158,164],[103,146,165,189],[103,146,154,158,166,178],[103,146,167],[103,146,168],[103,145,146,169],[103,143,144,145,146,147,148,149,150,151,152,153,154,155,156,158,159,160,161,162,163,164,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],[103,146,171],[103,146,172],[103,146,158,173,174],[103,146,173,175,190,192],[103,146,158,178,179,181],[103,146,180,181],[103,146,178,179],[103,146,181],[103,146,182],[103,143,146,178],[103,146,158,184,185],[103,146,184,185],[103,146,151,166,178,186],[103,146,187],[103,146,166,188],[103,146,161,172,189],[103,146,151,190],[103,146,178,191],[103,146,165,192],[103,146,193],[103,146,158,160,169,178,181,189,192,194],[103,146,178,195],[60,61,103,146],[62,103,146],[103,113,117,146,189],[103,113,146,178,189],[103,108,146],[103,110,113,146,186,189],[103,146,166,186],[103,146,196],[103,108,146,196],[103,110,113,146,166,189],[103,105,106,109,112,146,158,178,189],[103,113,120,146],[103,105,111,146],[103,113,134,135,146],[103,109,113,146,181,189,196],[103,134,146,196],[103,107,108,146,196],[103,113,146],[103,107,108,109,110,111,112,113,114,115,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,135,136,137,138,139,140,146],[103,113,128,146],[103,113,120,121,146],[103,111,113,121,122,146],[103,112,146],[103,105,108,113,146],[103,113,117,121,122,146],[103,117,146],[103,111,113,116,146,189],[103,105,110,113,120,146],[103,146,178],[103,108,113,134,146,194,196],[76,103,146],[66,67,103,146],[64,65,66,68,69,74,103,146],[65,66,103,146],[74,103,146],[75,103,146],[66,103,146],[64,65,66,69,70,71,72,73,103,146],[64,65,76,103,146],[63,78,103,146],[63,85,103,146],[63,78,79,81,85,103,146],[63,85,86,87,88,103,146],[63,103,146],[63,78,79,103,146],[63,79,84,89,103,146],[63,82,83,103,146],[63,78,79,81,103,146],[63,78,79,80,81,103,146]],"fileInfos":[{"version":"69684132aeb9b5642cbcd9e22dff7818ff0ee1aa831728af0ecf97d3364d5546","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"092c2bfe125ce69dbb1223c85d68d4d2397d7d8411867b5cc03cec902c233763","affectsGlobalScope":true,"impliedFormat":1},{"version":"07f073f19d67f74d732b1adea08e1dc66b1b58d77cb5b43931dee3d798a2fd53","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"936e80ad36a2ee83fc3caf008e7c4c5afe45b3cf3d5c24408f039c1d47bdc1df","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"fef8cfad2e2dc5f5b3d97a6f4f2e92848eb1b88e897bb7318cef0e2820bceaab","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"b5ce7a470bc3628408429040c4e3a53a27755022a32fd05e2cb694e7015386c7","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"170d4db14678c68178ee8a3d5a990d5afb759ecb6ec44dbd885c50f6da6204f6","affectsGlobalScope":true,"impliedFormat":1},{"version":"8a8eb4ebffd85e589a1cc7c178e291626c359543403d58c9cd22b81fab5b1fb9","impliedFormat":1},{"version":"9e83685e23baf56b50eab5f89bcc46c66ccd709c4a44d32e635040196ad96603","impliedFormat":1},{"version":"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3","impliedFormat":1},{"version":"d3cfde44f8089768ebb08098c96d01ca260b88bccf238d55eee93f1c620ff5a5","impliedFormat":1},{"version":"293eadad9dead44c6fd1db6de552663c33f215c55a1bfa2802a1bceed88ff0ec","impliedFormat":1},{"version":"54f6ec6ea75acea6eb23635617252d249145edbc7bcd9d53f2d70280d2aef953","impliedFormat":1},{"version":"c25ce98cca43a3bfa885862044be0d59557be4ecd06989b2001a83dcf69620fd","impliedFormat":1},{"version":"8e71e53b02c152a38af6aec45e288cc65bede077b92b9b43b3cb54a37978bb33","impliedFormat":1},{"version":"754a9396b14ca3a4241591afb4edc644b293ccc8a3397f49be4dfd520c08acb3","impliedFormat":1},{"version":"f672c876c1a04a223cf2023b3d91e8a52bb1544c576b81bf64a8fec82be9969c","impliedFormat":1},{"version":"e4b03ddcf8563b1c0aee782a185286ed85a255ce8a30df8453aade2188bbc904","impliedFormat":1},{"version":"de2316e90fc6d379d83002f04ad9698bc1e5285b4d52779778f454dd12ce9f44","impliedFormat":1},{"version":"25b3f581e12ede11e5739f57a86e8668fbc0124f6649506def306cad2c59d262","impliedFormat":1},{"version":"2da997a01a6aa5c5c09de5d28f0f4407b597c5e1aecfd32f1815809c532650a2","impliedFormat":1},{"version":"5d26d2e47e2352def36f89a3e8bf8581da22b7f857e07ef3114cd52cf4813445","impliedFormat":1},{"version":"3db2efd285e7328d8014b54a7fce3f4861ebcdc655df40517092ed0050983617","impliedFormat":1},{"version":"d5d39a24c759df40480a4bfc0daffd364489702fdbcbdfc1711cde34f8739995","impliedFormat":1},{"version":"b4cf968abdb59faf21fa8a38457bc6d31cc18eff07c1d5f40df95ad87a0b6e80","impliedFormat":99},"aebb775370916c8afc13c7ea8596dd41d004b4a959ff6210ddd8cb3df24fa543",{"version":"6bbaa172e4398e6562365e7dca6c2639b8a595b55046c6055706dd2923f7d7c2","impliedFormat":99},{"version":"a07daee7d2bf3132c437203f2fb694776a938075b570d339e0d482d85ff3b608","impliedFormat":99},"32edfa5bbcc1f86e2030d4a0a4f2a045d0ab92465613fda12646cbb8c229418f","f2c03cb8adcd76cb65d458d9bdd523e7e841b0f22e6ee6974399d2ffaaf4062c","8ec6d726a560ea129715f5b8bba5cff09f0a38a9e71eb8a2d8580b2f40cd1f2d","44d348c41fc378a077e4a0891b49b901faa97d7d7f65feaf7d256d79e7b81ee7","98f0172a4d4f25cd481cc01fe2e5ca87148d4127df064c165a16a9135ae5bc3b","c223e521987859b8461e47333e5fcbf95bc590cf5eb58c98267733f73bd98928","f4c2a4b0db97d6819d6cf31605df396a0c41b960abc2c9d15ca04cc40a61094a","53e1d5b14449fc61aa992477d084b755ed9caa008379425d31dd5c0d6c1431d9","6a2c412c1c94d0f0e43921b9dcc80f2a6657d17aa771a7101da7151acfe7db94","a57dfc94938f8cdd99ad884384f52fe5e8e2e8d4fcb4092705572e86adb77060",{"version":"5574d520dabc450de6be799f1791d86d71da4fb236f16e6ca21b953788bb5154","impliedFormat":1},{"version":"5f877dfc985d1fd3ac8bf4a75cd77b06c42ca608809b324c44b4151758de7189","affectsGlobalScope":true,"impliedFormat":1},{"version":"4f585cea32567574de0301ed79131a4c3d0bb36bbfea7f66e2f29b5dce1c4293","affectsGlobalScope":true,"impliedFormat":1},{"version":"14c2fd6220654a41c53836a62ba96d4b515ae1413b0ccb31c2445fb1ae1de5de","affectsGlobalScope":true,"impliedFormat":1},{"version":"4f29c38739500cd35a2ce41d15a35e34445ca755ebb991915b5f170985a49d21","affectsGlobalScope":true,"impliedFormat":1},{"version":"16f842a1a38c8bc26dfebd1e3c56a63a2c2a0e1979a4141c8012d2f763c38267","affectsGlobalScope":true,"impliedFormat":1},{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true,"impliedFormat":1},{"version":"030e350db2525514580ed054f712ffb22d273e6bc7eddc1bb7eda1e0ba5d395e","affectsGlobalScope":true,"impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"a79e62f1e20467e11a904399b8b18b18c0c6eea6b50c1168bf215356d5bebfaf","affectsGlobalScope":true,"impliedFormat":1},{"version":"d802f0e6b5188646d307f070d83512e8eb94651858de8a82d1e47f60fb6da4e2","affectsGlobalScope":true,"impliedFormat":1},{"version":"4967529644e391115ca5592184d4b63980569adf60ee685f968fd59ab1557188","impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"a4ef5ccfd69b5bc2a2c29896aa07daaff7c5924a12e70cb3d9819145c06897db","affectsGlobalScope":true,"impliedFormat":1},{"version":"a38efe83ff77c34e0f418a806a01ca3910c02ee7d64212a59d59bca6c2c38fa1","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"3fe4022ba1e738034e38ad9afacbf0f1f16b458ed516326f5bf9e4a31e9be1dc","impliedFormat":1},{"version":"a957197054b074bcdf5555d26286e8461680c7c878040d0f4e2d5509a7524944","affectsGlobalScope":true,"impliedFormat":1},{"version":"4314c7a11517e221f7296b46547dbc4df047115b182f544d072bdccffa57fc72","impliedFormat":1},{"version":"e9b97d69510658d2f4199b7d384326b7c4053b9e6645f5c19e1c2a54ede427fc","impliedFormat":1},{"version":"c2510f124c0293ab80b1777c44d80f812b75612f297b9857406468c0f4dafe29","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"f478f6f5902dc144c0d6d7bdc919c5177cac4d17a8ca8653c2daf6d7dc94317f","affectsGlobalScope":true,"impliedFormat":1},{"version":"19d5f8d3930e9f99aa2c36258bf95abbe5adf7e889e6181872d1cdba7c9a7dd5","impliedFormat":1},{"version":"9855e02d837744303391e5623a531734443a5f8e6e8755e018c41d63ad797db2","impliedFormat":1},{"version":"a6bf63d17324010ca1fbf0389cab83f93389bb0b9a01dc8a346d092f65b3605f","impliedFormat":1},{"version":"e009777bef4b023a999b2e5b9a136ff2cde37dc3f77c744a02840f05b18be8ff","impliedFormat":1},{"version":"1e0d1f8b0adfa0b0330e028c7941b5a98c08b600efe7f14d2d2a00854fb2f393","impliedFormat":1},{"version":"71450bbc2d82821d24ca05699a533e72758964e9852062c53b30f31c36978ab8","affectsGlobalScope":true,"impliedFormat":1},{"version":"88bc59b32d0d5b4e5d9632ac38edea23454057e643684c3c0b94511296f2998c","affectsGlobalScope":true,"impliedFormat":1},{"version":"a0a1dda070290b92da5a50113b73ecc4dd6bcbffad66e3c86503d483eafbadcf","impliedFormat":1},{"version":"59dcad36c4549175a25998f6a8b33c1df8e18df9c12ebad1dfb25af13fd4b1ce","impliedFormat":1},{"version":"206a70e72af3e24688397b81304358526ce70d020e4c2606c4acfd1fa1e81fb2","impliedFormat":1},{"version":"3f3edb8e44e3b9df3b7ca3219ab539710b6a7f4fe16bd884d441af207e03cd57","impliedFormat":1},{"version":"528b62e4272e3ddfb50e8eed9e359dedea0a4d171c3eb8f337f4892aac37b24b","impliedFormat":1},{"version":"d71535813e39c23baa113bc4a29a0e187b87d1105ccc8c5a6ebaca38d9a9bff2","impliedFormat":1},{"version":"4a1c5b43d4d408cb0df0a6cc82ca7be314553d37e432fc1fd801bae1a9ab2cb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"f72bc8fe16da67e4e3268599295797b202b95e54bd215a03f97e925dd1502a36","impliedFormat":1},{"version":"b1b6ee0d012aeebe11d776a155d8979730440082797695fc8e2a5c326285678f","impliedFormat":1},{"version":"45875bcae57270aeb3ebc73a5e3fb4c7b9d91d6b045f107c1d8513c28ece71c0","impliedFormat":1},{"version":"915e18c559321c0afaa8d34674d3eb77e1ded12c3e85bf2a9891ec48b07a1ca5","affectsGlobalScope":true,"impliedFormat":1},{"version":"636302a00dfd1f9fe6e8e91e4e9350c6518dcc8d51a474e4fc3a9ba07135100b","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f16a7e4deafa527ed9995a772bb380eb7d3c2c0fd4ae178c5263ed18394db2c","impliedFormat":1},{"version":"933921f0bb0ec12ef45d1062a1fc0f27635318f4d294e4d99de9a5493e618ca2","impliedFormat":1},{"version":"71a0f3ad612c123b57239a7749770017ecfe6b66411488000aba83e4546fde25","impliedFormat":1},{"version":"8145e07aad6da5f23f2fcd8c8e4c5c13fb26ee986a79d03b0829b8fce152d8b2","impliedFormat":1},{"version":"e1120271ebbc9952fdc7b2dd3e145560e52e06956345e6fdf91d70ca4886464f","impliedFormat":1},{"version":"814118df420c4e38fe5ae1b9a3bafb6e9c2aa40838e528cde908381867be6466","impliedFormat":1},{"version":"e1ce1d622f1e561f6cdf246372ead3bbc07ce0342024d0e9c7caf3136f712698","impliedFormat":1},{"version":"199c8269497136f3a0f4da1d1d90ab033f899f070e0dd801946f2a241c8abba2","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"125d792ec6c0c0f657d758055c494301cc5fdb327d9d9d5960b3f129aff76093","impliedFormat":1},{"version":"27e4532aaaa1665d0dd19023321e4dc12a35a741d6b8e1ca3517fcc2544e0efe","affectsGlobalScope":true,"impliedFormat":1},{"version":"2754d8221d77c7b382096651925eb476f1066b3348da4b73fe71ced7801edada","impliedFormat":1},{"version":"8c2ad42d5d1a2e8e6112625767f8794d9537f1247907378543106f7ba6c7df90","affectsGlobalScope":true,"impliedFormat":1},{"version":"f0be1b8078cd549d91f37c30c222c2a187ac1cf981d994fb476a1adc61387b14","affectsGlobalScope":true,"impliedFormat":1},{"version":"0aaed1d72199b01234152f7a60046bc947f1f37d78d182e9ae09c4289e06a592","impliedFormat":1},{"version":"98ffdf93dfdd206516971d28e3e473f417a5cfd41172e46b4ce45008f640588e","impliedFormat":1},{"version":"66ba1b2c3e3a3644a1011cd530fb444a96b1b2dfe2f5e837a002d41a1a799e60","impliedFormat":1},{"version":"7e514f5b852fdbc166b539fdd1f4e9114f29911592a5eb10a94bb3a13ccac3c4","impliedFormat":1},{"version":"7d6ff413e198d25639f9f01f16673e7df4e4bd2875a42455afd4ecc02ef156da","affectsGlobalScope":true,"impliedFormat":1},{"version":"12e8ce658dd17662d82fb0509d2057afc5e6ee30369a2e9e0957eff725b1f11d","affectsGlobalScope":true,"impliedFormat":1},{"version":"74736930d108365d7bbe740c7154706ccfb1b2a3855a897963ab3e5c07ecbf19","impliedFormat":1},{"version":"3a051941721a7f905544732b0eb819c8d88333a96576b13af08b82c4f17581e4","impliedFormat":1},{"version":"ac5ed35e649cdd8143131964336ab9076937fa91802ec760b3ea63b59175c10a","impliedFormat":1},{"version":"c6ab0dd29bf74b71a54ff2bbce509eb8ae3c4294d57cc54940f443c01cd1baae","affectsGlobalScope":true,"impliedFormat":1},{"version":"3797dd6f4ea3dc15f356f8cdd3128bfa18122213b38a80d6c1f05d8e13cbdad8","impliedFormat":1},{"version":"ad90122e1cb599b3bc06a11710eb5489101be678f2920f2322b0ac3e195af78d","impliedFormat":1}],"root":[79,[82,91]],"options":{"allowImportingTsExtensions":false,"allowSyntheticDefaultImports":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"exactOptionalPropertyTypes":false,"jsx":4,"module":99,"noFallthroughCasesInSwitch":true,"noImplicitReturns":true,"noUncheckedIndexedAccess":false,"noUnusedLocals":true,"noUnusedParameters":true,"outDir":"./","rootDir":"../src","skipLibCheck":true,"sourceMap":true,"strict":true,"target":9,"tsBuildInfoFile":"./.tsbuildinfo","verbatimModuleSyntax":false},"referencedMap":[[80,1],[81,2],[78,3],[94,1],[93,4],[97,5],[96,6],[95,1],[92,1],[143,7],[144,7],[145,8],[103,9],[146,10],[147,11],[148,12],[98,1],[101,13],[99,1],[100,1],[149,14],[150,15],[151,16],[152,17],[153,18],[154,19],[155,19],[157,1],[156,20],[158,21],[159,22],[160,23],[142,24],[102,1],[161,25],[162,26],[163,27],[196,28],[164,29],[165,30],[166,31],[167,32],[168,33],[169,34],[170,35],[171,36],[172,37],[173,38],[174,38],[175,39],[176,1],[177,1],[178,40],[180,41],[179,42],[181,43],[182,44],[183,45],[184,46],[185,47],[186,48],[187,49],[188,50],[189,51],[190,52],[191,53],[192,54],[193,55],[194,56],[195,57],[60,1],[62,58],[63,59],[104,1],[61,1],[58,1],[59,1],[10,1],[11,1],[13,1],[12,1],[2,1],[14,1],[15,1],[16,1],[17,1],[18,1],[19,1],[20,1],[21,1],[3,1],[22,1],[23,1],[4,1],[24,1],[28,1],[25,1],[26,1],[27,1],[29,1],[30,1],[31,1],[5,1],[32,1],[33,1],[34,1],[35,1],[6,1],[39,1],[36,1],[37,1],[38,1],[40,1],[7,1],[41,1],[46,1],[47,1],[42,1],[43,1],[44,1],[45,1],[8,1],[51,1],[48,1],[49,1],[50,1],[52,1],[9,1],[53,1],[54,1],[55,1],[57,1],[56,1],[1,1],[120,60],[130,61],[119,60],[140,62],[111,63],[110,64],[139,65],[133,66],[138,67],[113,68],[127,69],[112,70],[136,71],[108,72],[107,65],[137,73],[109,74],[114,75],[115,1],[118,75],[105,1],[141,76],[131,77],[122,78],[123,79],[125,80],[121,81],[124,82],[134,65],[116,83],[117,84],[126,85],[106,86],[129,77],[128,75],[132,1],[135,87],[77,88],[68,89],[75,90],[70,1],[71,1],[69,91],[72,92],[64,1],[65,1],[76,93],[67,94],[73,1],[74,95],[66,96],[79,97],[86,98],[87,98],[88,99],[89,100],[91,101],[85,102],[90,103],[84,104],[82,105],[83,106]],"affectedFilesPendingEmit":[[79,51],[86,51],[87,51],[88,51],[89,51],[91,51],[85,51],[90,51],[84,51],[82,51],[83,51]],"version":"5.8.3"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { Transport, TransportSendOptions } from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
3
|
+
import { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Unique identifier for an event in the event store
|
|
7
|
+
*/
|
|
8
|
+
type EventId = string;
|
|
9
|
+
/**
|
|
10
|
+
* Unique identifier for a stream of events
|
|
11
|
+
*/
|
|
12
|
+
type StreamId = string;
|
|
13
|
+
/**
|
|
14
|
+
* Options for connecting to an MCP server
|
|
15
|
+
*/
|
|
16
|
+
interface MCPConnectOptions {
|
|
17
|
+
/**
|
|
18
|
+
* The event ID to resume from if reconnecting
|
|
19
|
+
*/
|
|
20
|
+
resumeFrom?: EventId;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Information about the MCP server
|
|
24
|
+
*/
|
|
25
|
+
interface MCPServerInfo {
|
|
26
|
+
/**
|
|
27
|
+
* Unique identifier for this server instance
|
|
28
|
+
*/
|
|
29
|
+
instanceId: string;
|
|
30
|
+
/**
|
|
31
|
+
* Whether the server maintains session state
|
|
32
|
+
*/
|
|
33
|
+
stateful: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Whether the server has event storage enabled
|
|
36
|
+
*/
|
|
37
|
+
hasEventStore: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Event storage interface for accessing stored events
|
|
41
|
+
*/
|
|
42
|
+
interface MCPEventStore {
|
|
43
|
+
/**
|
|
44
|
+
* Get stored events, optionally filtered by client and/or after a specific event
|
|
45
|
+
* @param clientId - Optional client ID to filter events
|
|
46
|
+
* @param afterEventId - Optional event ID to get events after
|
|
47
|
+
* @param limit - Maximum number of events to return (default: 100)
|
|
48
|
+
*/
|
|
49
|
+
getEvents(clientId?: string, afterEventId?: EventId, limit?: number): StoredEvent[];
|
|
50
|
+
/**
|
|
51
|
+
* Get the ID of the last event, optionally for a specific client
|
|
52
|
+
* @param clientId - Optional client ID to filter by
|
|
53
|
+
*/
|
|
54
|
+
getLastEventId(clientId?: string): EventId | null;
|
|
55
|
+
/**
|
|
56
|
+
* Clear stored events, optionally for a specific client
|
|
57
|
+
* @param clientId - Optional client ID to clear events for
|
|
58
|
+
*/
|
|
59
|
+
clearEvents(clientId?: string): void;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The MCP interface exposed on window for browser environments
|
|
63
|
+
*/
|
|
64
|
+
interface MCPBrowserInterface {
|
|
65
|
+
/**
|
|
66
|
+
* Connect a client to the MCP server
|
|
67
|
+
* @param clientId - Unique identifier for the client
|
|
68
|
+
* @param options - Optional connection options
|
|
69
|
+
* @returns MessagePort for communication or null if connection fails
|
|
70
|
+
*/
|
|
71
|
+
connect(clientId: string, options?: MCPConnectOptions): MessagePort | null;
|
|
72
|
+
/**
|
|
73
|
+
* Disconnect a client from the MCP server
|
|
74
|
+
* @param clientId - The client ID to disconnect
|
|
75
|
+
*/
|
|
76
|
+
disconnect(clientId: string): void;
|
|
77
|
+
/**
|
|
78
|
+
* Terminate a client's session and clean up all associated resources
|
|
79
|
+
* @param clientId - The client ID to terminate
|
|
80
|
+
*/
|
|
81
|
+
terminateSession?(clientId: string): void;
|
|
82
|
+
/**
|
|
83
|
+
* Check if the MCP server is available and running
|
|
84
|
+
*/
|
|
85
|
+
isServerAvailable(): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Get information about the MCP server
|
|
88
|
+
*/
|
|
89
|
+
getServerInfo(): MCPServerInfo;
|
|
90
|
+
/**
|
|
91
|
+
* Event storage access (only available in stateful mode with event store)
|
|
92
|
+
*/
|
|
93
|
+
events?: MCPEventStore;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Extended Window interface with MCP support
|
|
97
|
+
*/
|
|
98
|
+
interface MCPWindow extends Window {
|
|
99
|
+
mcp?: MCPBrowserInterface;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Message types for internal MCP communication
|
|
103
|
+
*/
|
|
104
|
+
interface MCPServerInfoMessage {
|
|
105
|
+
type: 'mcp-server-info';
|
|
106
|
+
serverInstanceId: string;
|
|
107
|
+
serverSessionId?: string;
|
|
108
|
+
hasEventStore: boolean;
|
|
109
|
+
streamId: StreamId;
|
|
110
|
+
}
|
|
111
|
+
interface MCPEventMessage {
|
|
112
|
+
type: 'mcp-event';
|
|
113
|
+
eventId: EventId;
|
|
114
|
+
message: JSONRPCMessage;
|
|
115
|
+
}
|
|
116
|
+
interface MCPReplayEventMessage {
|
|
117
|
+
type: 'mcp-replay-event';
|
|
118
|
+
eventId: EventId;
|
|
119
|
+
message: JSONRPCMessage;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Stored event with metadata for event sourcing
|
|
123
|
+
*/
|
|
124
|
+
interface StoredEvent {
|
|
125
|
+
eventId: EventId;
|
|
126
|
+
streamId: StreamId;
|
|
127
|
+
message: JSONRPCMessage;
|
|
128
|
+
timestamp: number;
|
|
129
|
+
clientId: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Browser-specific error class to match StreamableHTTPError
|
|
134
|
+
*/
|
|
135
|
+
declare class BrowserTransportError extends Error {
|
|
136
|
+
readonly code: string | undefined;
|
|
137
|
+
constructor(code: string | undefined, message: string | undefined);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Configuration options for the BrowserClientTransport, matching StreamableHTTPClientTransportOptions style
|
|
141
|
+
*/
|
|
142
|
+
interface TabClientTransportOptions {
|
|
143
|
+
/**
|
|
144
|
+
* A unique identifier for this client instance. If not provided, one will be generated.
|
|
145
|
+
* This is similar to a persistent client identifier.
|
|
146
|
+
*/
|
|
147
|
+
clientInstanceId?: string;
|
|
148
|
+
/**
|
|
149
|
+
* Global namespace to look for MCP server (defaults to 'mcp')
|
|
150
|
+
*/
|
|
151
|
+
globalNamespace?: string;
|
|
152
|
+
/**
|
|
153
|
+
* Options to configure the reconnection behavior.
|
|
154
|
+
*/
|
|
155
|
+
reconnectionOptions?: BrowserReconnectionOptions;
|
|
156
|
+
/**
|
|
157
|
+
* Timeout for initial connection handshake (ms). Default is 30000 (30 seconds).
|
|
158
|
+
*/
|
|
159
|
+
connectionTimeout?: number;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Configuration options for reconnection behavior
|
|
163
|
+
*/
|
|
164
|
+
interface BrowserReconnectionOptions {
|
|
165
|
+
/**
|
|
166
|
+
* Maximum backoff time between reconnection attempts in milliseconds.
|
|
167
|
+
* Default is 30000 (30 seconds).
|
|
168
|
+
*/
|
|
169
|
+
maxReconnectionDelay: number;
|
|
170
|
+
/**
|
|
171
|
+
* Initial backoff time between reconnection attempts in milliseconds.
|
|
172
|
+
* Default is 1000 (1 second).
|
|
173
|
+
*/
|
|
174
|
+
initialReconnectionDelay: number;
|
|
175
|
+
/**
|
|
176
|
+
* The factor by which the reconnection delay increases after each attempt.
|
|
177
|
+
* Default is 1.5.
|
|
178
|
+
*/
|
|
179
|
+
reconnectionDelayGrowFactor: number;
|
|
180
|
+
/**
|
|
181
|
+
* Maximum number of reconnection attempts before giving up.
|
|
182
|
+
* Default is 2.
|
|
183
|
+
*/
|
|
184
|
+
maxRetries: number;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Client transport for browser environments using window.mcp global.
|
|
188
|
+
* This implementation follows the same patterns as StreamableHTTPClientTransport.
|
|
189
|
+
*/
|
|
190
|
+
declare class TabClientTransport implements Transport {
|
|
191
|
+
private _globalNamespace;
|
|
192
|
+
/**
|
|
193
|
+
* The client's persistent instance ID
|
|
194
|
+
*/
|
|
195
|
+
clientInstanceId: string;
|
|
196
|
+
/**
|
|
197
|
+
* The session ID provided by the server during connection
|
|
198
|
+
*/
|
|
199
|
+
sessionId?: string;
|
|
200
|
+
private _reconnectionOptions;
|
|
201
|
+
private _connectionTimeout;
|
|
202
|
+
private _port?;
|
|
203
|
+
/**
|
|
204
|
+
* The server's instance ID, received during handshake.
|
|
205
|
+
*/
|
|
206
|
+
serverInstanceId?: string;
|
|
207
|
+
hasEventStore: boolean;
|
|
208
|
+
streamId?: string;
|
|
209
|
+
/**
|
|
210
|
+
* Indicates whether the transport is currently connected.
|
|
211
|
+
*/
|
|
212
|
+
isConnected: boolean;
|
|
213
|
+
private _abortController?;
|
|
214
|
+
private _connectionPromise?;
|
|
215
|
+
/**
|
|
216
|
+
* The last event ID received from the server.
|
|
217
|
+
*/
|
|
218
|
+
lastEventId?: EventId;
|
|
219
|
+
private _reconnectAttempt;
|
|
220
|
+
onclose?: () => void;
|
|
221
|
+
onerror?: (error: Error) => void;
|
|
222
|
+
onmessage?: (message: JSONRPCMessage) => void;
|
|
223
|
+
constructor(opts?: TabClientTransportOptions);
|
|
224
|
+
/**
|
|
225
|
+
* Start the transport connection
|
|
226
|
+
*/
|
|
227
|
+
start(): Promise<void>;
|
|
228
|
+
/**
|
|
229
|
+
* Internal method to establish connection with retry logic
|
|
230
|
+
*/
|
|
231
|
+
private _connectWithRetry;
|
|
232
|
+
/**
|
|
233
|
+
* Handle incoming messages with error handling
|
|
234
|
+
*/
|
|
235
|
+
private _handleMessage;
|
|
236
|
+
/**
|
|
237
|
+
* Handle connection errors with retry logic
|
|
238
|
+
*/
|
|
239
|
+
private _handleConnectionError;
|
|
240
|
+
/**
|
|
241
|
+
* Calculate the next reconnection delay using exponential backoff
|
|
242
|
+
*/
|
|
243
|
+
private _getNextReconnectionDelay;
|
|
244
|
+
/**
|
|
245
|
+
* Schedule a reconnection attempt with exponential backoff
|
|
246
|
+
*/
|
|
247
|
+
private _scheduleReconnection;
|
|
248
|
+
/**
|
|
249
|
+
* Send a message over the transport
|
|
250
|
+
*/
|
|
251
|
+
send(message: JSONRPCMessage, options?: {
|
|
252
|
+
resumptionToken?: string;
|
|
253
|
+
onresumptiontoken?: (token: string) => void;
|
|
254
|
+
}): Promise<void>;
|
|
255
|
+
/**
|
|
256
|
+
* Close the transport connection
|
|
257
|
+
*/
|
|
258
|
+
close(): Promise<void>;
|
|
259
|
+
/**
|
|
260
|
+
* Terminate the current session explicitly
|
|
261
|
+
* Similar to StreamableHTTP's terminateSession
|
|
262
|
+
*/
|
|
263
|
+
terminateSession(): Promise<void>;
|
|
264
|
+
/**
|
|
265
|
+
* Static helper to check if an MCP server is available
|
|
266
|
+
* Similar to checking server availability before connection
|
|
267
|
+
*/
|
|
268
|
+
static isServerAvailable(namespace?: string): boolean;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Configuration options for BrowserServerTransport
|
|
273
|
+
*/
|
|
274
|
+
interface BrowserServerTransportOptions {
|
|
275
|
+
/**
|
|
276
|
+
* Function that generates a session ID for each client connection.
|
|
277
|
+
* Return undefined to operate in stateless mode.
|
|
278
|
+
* If not provided, defaults to undefined (stateless mode).
|
|
279
|
+
*/
|
|
280
|
+
sessionIdGenerator?: (() => string) | undefined;
|
|
281
|
+
/**
|
|
282
|
+
* Callback for session initialization events
|
|
283
|
+
*/
|
|
284
|
+
onsessioninitialized?: (clientSessionId: string | undefined, clientInstanceId: string) => void;
|
|
285
|
+
/**
|
|
286
|
+
* Optional namespace to use instead of window.mcp
|
|
287
|
+
*/
|
|
288
|
+
globalNamespace?: string;
|
|
289
|
+
/**
|
|
290
|
+
* Enable event storage for resumability (only works in stateful mode)
|
|
291
|
+
* Default is true in stateful mode, false in stateless mode
|
|
292
|
+
*/
|
|
293
|
+
enableEventStore?: boolean;
|
|
294
|
+
/**
|
|
295
|
+
* Maximum number of events to store per client (default: 1000)
|
|
296
|
+
*/
|
|
297
|
+
maxEventsPerClient?: number;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Server transport for browser environments using window.mcp global
|
|
301
|
+
* Supports multiple concurrent client connections via MessageChannel
|
|
302
|
+
*/
|
|
303
|
+
declare class TabServerTransport implements Transport {
|
|
304
|
+
private _serverInstanceId;
|
|
305
|
+
private _sessionIdGenerator;
|
|
306
|
+
private _onsessioninitialized?;
|
|
307
|
+
private _isStarted;
|
|
308
|
+
private _clients;
|
|
309
|
+
private _globalNamespace;
|
|
310
|
+
private _eventStore?;
|
|
311
|
+
private _enableEventStore;
|
|
312
|
+
onclose?: () => void;
|
|
313
|
+
onerror?: (error: Error) => void;
|
|
314
|
+
onmessage?: (message: JSONRPCMessage, extra?: {
|
|
315
|
+
authInfo?: AuthInfo | undefined;
|
|
316
|
+
}) => void;
|
|
317
|
+
constructor(options?: BrowserServerTransportOptions);
|
|
318
|
+
start(): Promise<void>;
|
|
319
|
+
private _setupClientConnection;
|
|
320
|
+
send(message: JSONRPCMessage, options?: TransportSendOptions & {
|
|
321
|
+
targetClientId?: string;
|
|
322
|
+
}): Promise<void>;
|
|
323
|
+
close(): Promise<void>;
|
|
324
|
+
get clientCount(): number;
|
|
325
|
+
get clients(): ReadonlyArray<{
|
|
326
|
+
clientId: string;
|
|
327
|
+
initialized: boolean;
|
|
328
|
+
serverSessionId?: string;
|
|
329
|
+
}>;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* In your background script:
|
|
334
|
+
* import { setupBackgroundBridge } from '@modelcontextprotocol/sdk/extension-bridge/backgroundBridge'
|
|
335
|
+
* // Dynamically inject pageBridge and contentScript into matching pages
|
|
336
|
+
* setupBackgroundBridge({
|
|
337
|
+
* matches: ['https://your-app.com/*'],
|
|
338
|
+
* pageBridgeRunAt: 'document_start',
|
|
339
|
+
* contentScriptRunAt: 'document_idle'
|
|
340
|
+
* });
|
|
341
|
+
*/
|
|
342
|
+
declare function setupBackgroundBridge(_?: {
|
|
343
|
+
/** Host-match patterns for injection, defaults to ['<all_urls>'] */
|
|
344
|
+
matches?: string[];
|
|
345
|
+
/** When to inject the pageBridge (MAIN world) */
|
|
346
|
+
pageBridgeRunAt?: 'document_start' | 'document_end' | 'document_idle';
|
|
347
|
+
/** When to inject the content script (ISOLATED world) */
|
|
348
|
+
contentScriptRunAt?: 'document_start' | 'document_end' | 'document_idle';
|
|
349
|
+
}): Promise<void>;
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Sets up a content script bridge that relays messages between the page context
|
|
353
|
+
* and the extension background script. This enables communication between
|
|
354
|
+
* the injected page bridge and the extension's background script.
|
|
355
|
+
*
|
|
356
|
+
* @param port - Optional Chrome runtime port. If not provided, creates a default port with name 'cs'
|
|
357
|
+
* @returns The Chrome runtime port used for communication
|
|
358
|
+
*/
|
|
359
|
+
declare function mcpRelay(port?: chrome.runtime.Port): chrome.runtime.Port;
|
|
360
|
+
|
|
361
|
+
declare const isJSONRPCMessage: (value: unknown) => value is JSONRPCMessage;
|
|
362
|
+
/**
|
|
363
|
+
* Configuration options for reconnection behavior, mirroring BrowserReconnectionOptions
|
|
364
|
+
*/
|
|
365
|
+
interface ExtensionReconnectionOptions {
|
|
366
|
+
maxReconnectionDelay: number;
|
|
367
|
+
initialReconnectionDelay: number;
|
|
368
|
+
reconnectionDelayGrowFactor: number;
|
|
369
|
+
maxRetries: number;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Configuration options for the ExtensionClientTransport
|
|
373
|
+
*/
|
|
374
|
+
interface ExtensionClientTransportOptions {
|
|
375
|
+
clientInstanceId?: string;
|
|
376
|
+
reconnectionOptions?: ExtensionReconnectionOptions;
|
|
377
|
+
connectionTimeout?: number;
|
|
378
|
+
}
|
|
379
|
+
declare class ExtensionClientTransport implements Transport {
|
|
380
|
+
onclose?: () => void;
|
|
381
|
+
onerror?: (err: Error) => void;
|
|
382
|
+
onmessage?: (message: JSONRPCMessage, extra?: {
|
|
383
|
+
authInfo?: any;
|
|
384
|
+
}) => void;
|
|
385
|
+
isConnected: boolean;
|
|
386
|
+
sessionId?: string;
|
|
387
|
+
lastEventId?: EventId;
|
|
388
|
+
serverInstanceId?: string;
|
|
389
|
+
hasEventStore: boolean;
|
|
390
|
+
streamId?: string;
|
|
391
|
+
private clientId;
|
|
392
|
+
private bridge;
|
|
393
|
+
private _reconnectionOptions;
|
|
394
|
+
private _connectionTimeout;
|
|
395
|
+
private _abortController?;
|
|
396
|
+
private _connectionPromise?;
|
|
397
|
+
private _reconnectAttempt;
|
|
398
|
+
private _startPromise?;
|
|
399
|
+
constructor(options?: ExtensionClientTransportOptions & {
|
|
400
|
+
port?: chrome.runtime.Port;
|
|
401
|
+
});
|
|
402
|
+
private _setupMessageHandler;
|
|
403
|
+
start(): Promise<void>;
|
|
404
|
+
private _connectWithRetry;
|
|
405
|
+
private _handleConnectionError;
|
|
406
|
+
private _getNextReconnectionDelay;
|
|
407
|
+
private _scheduleReconnection;
|
|
408
|
+
send(message: JSONRPCMessage, _?: TransportSendOptions): Promise<void>;
|
|
409
|
+
close(): Promise<void>;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Union type representing all possible message types that can be sent through the page bridge.
|
|
414
|
+
* This includes MCP server information, events, replay events, and JSON-RPC messages.
|
|
415
|
+
*/
|
|
416
|
+
type PageBridgeMessageType = MCPServerInfoMessage | MCPEventMessage | MCPReplayEventMessage | JSONRPCMessage | {
|
|
417
|
+
type: 'mcp-server-disconnected';
|
|
418
|
+
reason: string;
|
|
419
|
+
};
|
|
420
|
+
/**
|
|
421
|
+
* Response structure for messages received from the bridge.
|
|
422
|
+
*/
|
|
423
|
+
interface BridgeResponse {
|
|
424
|
+
/** Unique identifier for the client connection */
|
|
425
|
+
clientId: string;
|
|
426
|
+
/** The actual message payload */
|
|
427
|
+
msg: PageBridgeMessageType;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Message structure for commands sent to the bridge.
|
|
431
|
+
*/
|
|
432
|
+
interface BridgeMessage {
|
|
433
|
+
/** Command type - either 'connect' to establish a connection or 'send' to send a message */
|
|
434
|
+
cmd: 'connect' | 'send' | 'disconnect';
|
|
435
|
+
/** Unique identifier for the client connection */
|
|
436
|
+
clientId: string;
|
|
437
|
+
/** Connection options, required when cmd is 'connect' */
|
|
438
|
+
options?: MCPConnectOptions;
|
|
439
|
+
/** JSON-RPC message to send, required when cmd is 'send' */
|
|
440
|
+
message?: JSONRPCMessage;
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Creates a UI bridge for communicating with MCP servers from browser extension UI components.
|
|
444
|
+
*
|
|
445
|
+
* This function establishes a connection to the extension's background script via Chrome's
|
|
446
|
+
* runtime messaging API, allowing UI components like sidebars and popups to interact with
|
|
447
|
+
* MCP servers.
|
|
448
|
+
*
|
|
449
|
+
* @param port - Optional Chrome runtime port to use for communication. If not provided,
|
|
450
|
+
* a new port will be created with the name 'extensionUI'.
|
|
451
|
+
*
|
|
452
|
+
* The port should be connected to your background script's chrome.runtime.onConnect listener.
|
|
453
|
+
*
|
|
454
|
+
* @returns An object with methods to interact with MCP servers:
|
|
455
|
+
* - connect: Establish a connection to an MCP server
|
|
456
|
+
* - send: Send JSON-RPC messages to a connected server
|
|
457
|
+
* - onMessage: Listen for responses and events from the server
|
|
458
|
+
*
|
|
459
|
+
* @example
|
|
460
|
+
* ```typescript
|
|
461
|
+
* // In your sidebar/popup code:
|
|
462
|
+
* import { createUIBridge } from '@modelcontextprotocol/sdk/extension-bridge/uiConnector';
|
|
463
|
+
*
|
|
464
|
+
* // Using default port
|
|
465
|
+
* const bridge = createUIBridge();
|
|
466
|
+
*
|
|
467
|
+
* // Or using a custom port
|
|
468
|
+
* const customPort = chrome.runtime.connect({ name: 'sidebar' });
|
|
469
|
+
* const bridge = createUIBridge(customPort);
|
|
470
|
+
*
|
|
471
|
+
* // Connect to an MCP server
|
|
472
|
+
* bridge.connect('my-client-id', {
|
|
473
|
+
* serverName: 'my-server',
|
|
474
|
+
* command: 'node',
|
|
475
|
+
* args: ['server.js']
|
|
476
|
+
* });
|
|
477
|
+
*
|
|
478
|
+
* // Listen for messages
|
|
479
|
+
* bridge.onMessage((response) => {
|
|
480
|
+
* console.log('Received:', response.msg);
|
|
481
|
+
* });
|
|
482
|
+
*
|
|
483
|
+
* // Send a message
|
|
484
|
+
* bridge.send('my-client-id', {
|
|
485
|
+
* jsonrpc: '2.0',
|
|
486
|
+
* id: 1,
|
|
487
|
+
* method: 'tools/list'
|
|
488
|
+
* });
|
|
489
|
+
* ```
|
|
490
|
+
*/
|
|
491
|
+
declare function createUIBridge(port?: chrome.runtime.Port): {
|
|
492
|
+
/**
|
|
493
|
+
* Establishes a connection to an MCP server.
|
|
494
|
+
*
|
|
495
|
+
* @param clientId - Unique identifier for this client connection
|
|
496
|
+
* @param options - Configuration options for the MCP server connection
|
|
497
|
+
*/
|
|
498
|
+
connect: (clientId: string, options?: MCPConnectOptions) => void;
|
|
499
|
+
/**
|
|
500
|
+
* Sends a JSON-RPC message to a connected MCP server.
|
|
501
|
+
*
|
|
502
|
+
* @param clientId - The client ID of the connection to send the message through
|
|
503
|
+
* @param message - The JSON-RPC message to send
|
|
504
|
+
*/
|
|
505
|
+
send: (clientId: string, message: JSONRPCMessage) => void;
|
|
506
|
+
/**
|
|
507
|
+
* Registers a handler for incoming messages from MCP servers.
|
|
508
|
+
*
|
|
509
|
+
* @param handler - Function to handle incoming bridge responses
|
|
510
|
+
*/
|
|
511
|
+
onMessage: (handler: (resp: BridgeResponse) => void) => void;
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
export { type BridgeMessage, type BridgeResponse, type BrowserReconnectionOptions, type BrowserServerTransportOptions, BrowserTransportError, type EventId, ExtensionClientTransport, type ExtensionClientTransportOptions, type ExtensionReconnectionOptions, type MCPBrowserInterface, type MCPConnectOptions, type MCPEventMessage, type MCPEventStore, type MCPReplayEventMessage, type MCPServerInfo, type MCPServerInfoMessage, type MCPWindow, type PageBridgeMessageType, type StoredEvent, type StreamId, TabClientTransport, type TabClientTransportOptions, TabServerTransport, createUIBridge, isJSONRPCMessage, mcpRelay, setupBackgroundBridge };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {JSONRPCMessageSchema,isInitializeRequest,isJSONRPCResponse,isJSONRPCError}from'@modelcontextprotocol/sdk/types.js';var m=class extends Error{constructor(t,s){super(`Browser transport error: ${s}`);this.code=t;}},P={initialReconnectionDelay:1e3,maxReconnectionDelay:3e4,reconnectionDelayGrowFactor:1.5,maxRetries:2},f=class{_globalNamespace;clientInstanceId;sessionId;_reconnectionOptions;_connectionTimeout;_port;serverInstanceId;hasEventStore=false;streamId;isConnected=false;_abortController;_connectionPromise;lastEventId;_reconnectAttempt=0;onclose;onerror;onmessage;constructor(e){this._globalNamespace=e?.globalNamespace??"mcp",this._reconnectionOptions=e?.reconnectionOptions??P,this._connectionTimeout=e?.connectionTimeout??3e4,this.clientInstanceId=e?.clientInstanceId||(typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():`client-${Date.now()}-${Math.random().toString(36).substr(2,9)}`);}async start(){if(this._abortController)throw new Error("TabClientTransport already started! If using Client class, note that connect() calls start() automatically.");this._abortController=new AbortController,await this._connectWithRetry();}async _connectWithRetry(e){return new Promise((t,s)=>{this._connectionPromise={resolve:t,reject:s};let n=window,o=this._globalNamespace==="mcp"?n.mcp:n[this._globalNamespace];if(!o?.isServerAvailable?.()){let l=new m("NO_SERVER",`No MCP server found at window.${this._globalNamespace}`);this._handleConnectionError(l,e);return}let r=o.getServerInfo();this.serverInstanceId=r.instanceId;let i=e?{resumeFrom:e}:void 0,c=o.connect(this.clientInstanceId,i);if(!c){let l=new m("CONNECTION_FAILED","Failed to connect to MCP server");this._handleConnectionError(l,e);return}this._port=c;let p=false,g;this._port.onmessage=l=>{let h=l.data;if(!p&&h.type==="mcp-server-info"){let d=h;clearTimeout(g),p=true,this.sessionId=d.serverSessionId,this.hasEventStore=d.hasEventStore||false,this.streamId=d.streamId,this.isConnected=true,this._reconnectAttempt=0,this._connectionPromise&&(this._connectionPromise.resolve(),this._connectionPromise=void 0);return}if(h.type==="mcp-replay-event"){let d=h;this.lastEventId=d.eventId,this._handleMessage(d.message);return}if(h.type==="mcp-event"){let d=h;this.lastEventId=d.eventId,this._handleMessage(d.message);return}p&&this._handleMessage(h);},this._port.onmessageerror=()=>{let l=new m("MESSAGE_ERROR","MessagePort error");this.onerror?.(l),this._connectionPromise&&(this._connectionPromise.reject(l),this._connectionPromise=void 0);},this._port.start(),g=setTimeout(()=>{if(!p){let l=new m("HANDSHAKE_TIMEOUT","Server handshake timeout");this._handleConnectionError(l,e);}},this._connectionTimeout);})}_handleMessage(e){try{let t=JSONRPCMessageSchema.parse(e);this.onmessage?.(t);}catch(t){this.onerror?.(new Error(`Failed to parse message: ${t}`));}}_handleConnectionError(e,t){this.onerror?.(e),this._connectionPromise&&(this._connectionPromise.reject(e),this._connectionPromise=void 0),this._abortController&&!this._abortController.signal.aborted&&t&&this._scheduleReconnection(t);}_getNextReconnectionDelay(e){let t=this._reconnectionOptions.initialReconnectionDelay,s=this._reconnectionOptions.reconnectionDelayGrowFactor,n=this._reconnectionOptions.maxReconnectionDelay;return Math.min(t*Math.pow(s,e),n)}_scheduleReconnection(e){let t=this._reconnectionOptions.maxRetries;if(t>0&&this._reconnectAttempt>=t){this.onerror?.(new Error(`Maximum reconnection attempts (${t}) exceeded.`));return}let s=this._getNextReconnectionDelay(this._reconnectAttempt);setTimeout(()=>{this._reconnectAttempt++,this._connectWithRetry(e).catch(n=>{this.onerror?.(new Error(`Failed to reconnect: ${n instanceof Error?n.message:String(n)}`));});},s);}async send(e,t){if(!this.isConnected||!this._port)if(t?.resumptionToken){if(await this._connectWithRetry(t.resumptionToken).catch(s=>{throw this.onerror?.(new Error(`Failed to reconnect with token: ${s instanceof Error?s.message:String(s)}`)),s}),!this.isConnected||!this._port)throw new Error("Not connected after attempting reconnection with token.")}else if(this._reconnectionOptions.maxRetries>0&&this.lastEventId&&this._abortController&&!this._abortController.signal.aborted){if(await this._connectWithRetry(this.lastEventId).catch(s=>{let n=new Error(`Failed to auto-reconnect: ${s instanceof Error?s.message:String(s)}`);throw this.onerror?.(n),n}),!this.isConnected||!this._port)throw new Error("Not connected after attempting auto-reconnection.")}else throw new Error("Not connected");this._port.postMessage(e);}async close(){this._abortController?.abort(),this._abortController=void 0,this._connectionPromise&&(this._connectionPromise.reject(new Error("Transport closed")),this._connectionPromise=void 0),this._port&&(this._port.close(),this._port=void 0);let e=window,t=this._globalNamespace==="mcp"?e.mcp:e[this._globalNamespace];t?.disconnect&&t.disconnect(this.clientInstanceId),this.isConnected=false,this.onclose?.();}async terminateSession(){if(this.sessionId)try{let e=window,t=this._globalNamespace==="mcp"?e.mcp:e[this._globalNamespace];t?.terminateSession?t.terminateSession(this.clientInstanceId):t?.events?.clearEvents&&t.events.clearEvents(this.clientInstanceId),this.sessionId=void 0,this.lastEventId=void 0;}catch(e){throw this.onerror?.(e),e}}static isServerAvailable(e="mcp"){let t=window;return !!(e==="mcp"?t.mcp:t[e])?.isServerAvailable?.()}};var v=class{_events=[];_eventCounter=0;_maxEventsPerClient;constructor(e=1e3){this._maxEventsPerClient=e;}async storeEvent(e,t,s){let n=`evt_${++this._eventCounter}_${Date.now()}`,o={eventId:n,streamId:e,message:s,timestamp:Date.now(),clientId:t};this._events.push(o);let r=this._events.filter(i=>i.clientId===t);if(r.length>this._maxEventsPerClient){let i=r.slice(0,r.length-this._maxEventsPerClient);this._events=this._events.filter(c=>!i.includes(c));}return n}async replayEventsAfter(e,t,s){let n=this._events.filter(i=>i.clientId===e),o=0;if(t){let i=n.findIndex(c=>c.eventId===t);i>=0&&(o=i+1);}let r=n.slice(o);for(let i of r)await s(i.eventId,i.message);return r.length>0?r[r.length-1].streamId:`stream_${Date.now()}`}getEvents(e,t,s=100){let n=e?this._events.filter(o=>o.clientId===e):this._events;if(t){let o=n.findIndex(r=>r.eventId===t);o>=0&&(n=n.slice(o+1));}return n.slice(0,s)}getLastEventId(e){let t=e?this._events.filter(s=>s.clientId===e):this._events;return t.length>0?t[t.length-1].eventId:null}clearEvents(e){e?this._events=this._events.filter(t=>t.clientId!==e):this._events=[];}removeClientEvents(e){this._events=this._events.filter(t=>t.clientId!==e);}},u=class{_serverInstanceId;_sessionIdGenerator;_onsessioninitialized;_isStarted=false;_clients=new Map;_globalNamespace;_eventStore;_enableEventStore;onclose;onerror;onmessage;constructor(e){this._sessionIdGenerator=e?.sessionIdGenerator,this._onsessioninitialized=e?.onsessioninitialized,this._globalNamespace=e?.globalNamespace||"mcp",this._enableEventStore=e?.enableEventStore??this._sessionIdGenerator!==void 0,this._enableEventStore&&this._sessionIdGenerator&&(this._eventStore=new v(e?.maxEventsPerClient)),this._serverInstanceId=typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():`server-${Date.now()}-${Math.random().toString(36).substr(2,9)}`;}async start(){if(this._isStarted)throw new Error("BrowserServerTransport already started");let e=window;if((this._globalNamespace==="mcp"?e.mcp:e[this._globalNamespace])?.isServerAvailable?.())throw new Error(`Another MCP server is already registered at window.${this._globalNamespace}`);let s={connect:(n,o)=>{if(!this._isStarted)return console.error("MCP server not started"),null;if(this._clients.has(n))return console.error(`Client ${n} already connected`),null;let r=new MessageChannel,i=r.port1,c=r.port2,p=this._sessionIdGenerator?.(),g=`stream_${n}_${Date.now()}`,l={port:i,clientInstanceId:n,serverSessionId:p,streamId:g,initialized:false,requestIds:new Set};return this._setupClientConnection(l,o?.resumeFrom),this._clients.set(n,l),c},disconnect:n=>{let o=this._clients.get(n);o&&(o.port.close(),this._clients.delete(n));},isServerAvailable:()=>this._isStarted,getServerInfo:()=>({instanceId:this._serverInstanceId,stateful:this._sessionIdGenerator!==void 0,hasEventStore:this._eventStore!==void 0}),terminateSession:n=>{let o=this._clients.get(n);o&&(o.port.close(),this._clients.delete(n)),this._eventStore?.removeClientEvents(n);}};this._eventStore&&(s.events={getEvents:(n,o,r)=>this._eventStore.getEvents(n,o,r),getLastEventId:n=>this._eventStore.getLastEventId(n),clearEvents:n=>{this._eventStore.clearEvents(n);}}),this._globalNamespace==="mcp"?window.mcp=s:window[this._globalNamespace]=s,this._isStarted=true;}async _setupClientConnection(e,t){let{port:s,clientInstanceId:n}=e;s.onmessage=r=>{try{let i=JSONRPCMessageSchema.parse(r.data);if("id"in i&&i.id!==void 0&&"method"in i&&e.requestIds.add(i.id),isInitializeRequest(i)){if(e.initialized){this.onerror?.(new Error(`Client ${n} attempted to re-initialize`));return}e.initialized=!0,this._onsessioninitialized?.(e.serverSessionId,n);}else if(!e.initialized){let p=`Client ${n} sent message before initialization`;this.onerror?.(new Error(p));return}this.onmessage?.(i,{authInfo:{clientId:n,token:"N/A",scopes:["browser"]}});}catch(i){this.onerror?.(i instanceof Error?i:new Error(String(i)));}},s.onmessageerror=()=>{this.onerror?.(new Error(`MessagePort error for client ${n}`));},s.start();let o={type:"mcp-server-info",serverInstanceId:this._serverInstanceId,serverSessionId:e.serverSessionId,hasEventStore:this._eventStore!==void 0,streamId:e.streamId};s.postMessage(o),t&&this._eventStore&&await this._eventStore.replayEventsAfter(n,t,async(r,i)=>{let c={type:"mcp-replay-event",eventId:r,message:i};s.postMessage(c);});}async send(e,t){if(!this._isStarted)throw new Error("BrowserServerTransport not started");let s=[];if(t?.relatedRequestId){for(let[n,o]of this._clients)if(o.requestIds.has(t.relatedRequestId)){s=[o],(isJSONRPCResponse(e)||isJSONRPCError(e))&&o.requestIds.delete(t.relatedRequestId);break}}else if(t?.targetClientId){let n=this._clients.get(t.targetClientId);n&&(s=[n]);}else s=Array.from(this._clients.values()).filter(n=>n.initialized);if(s.length===0){this.onerror?.(new Error("No suitable clients found for message"));return}for(let n of s){let o;if(this._eventStore&&(o=await this._eventStore.storeEvent(n.streamId,n.clientInstanceId,e)),o){let r={type:"mcp-event",eventId:o,message:e};n.port.postMessage(r);}else n.port.postMessage(e);}}async close(){if(this._isStarted){for(let e of this._clients.values())e.port.close();this._clients.clear(),this._eventStore?.clearEvents(),this._globalNamespace==="mcp"?delete window.mcp:delete window[this._globalNamespace],this._isStarted=false,this.onclose?.();}}get clientCount(){return this._clients.size}get clients(){return Array.from(this._clients.entries()).map(([e,t])=>({clientId:e,initialized:t.initialized,serverSessionId:t.serverSessionId}))}};async function G(a){let e=null,t=new Map,s=new Map;console.log("BSGW: Background bridge initialized"),chrome.runtime.onConnect.addListener(n=>{if(n.name==="extensionUI")console.log("BSGW: Extension UI connected"),e=n,n.onMessage.addListener(o=>{if(console.log("BSGW: Message from extension",o),o.cmd==="connect"){let r=Array.from(t.keys())[0];if(r!==void 0){s.set(o.clientId,r);let i=t.get(r);i&&(console.log(`BSGW: Routing connect for client ${o.clientId} to tab ${r}`),i.postMessage(o));}else console.error("BSGW: No content script tabs available for connection");}else if(o.cmd==="send"){let r=s.get(o.clientId);if(r!==void 0){let i=t.get(r);i?(console.log(`BSGW: Routing send for client ${o.clientId} to tab ${r}`),i.postMessage(o)):(console.error(`BSGW: Tab ${r} no longer available for client ${o.clientId}`),s.delete(o.clientId));}else console.error(`BSGW: No tab mapping found for client ${o.clientId}`);}}),n.onDisconnect.addListener(()=>{console.log("BSGW: Extension UI disconnected");let o=new Set;for(let[r,i]of s.entries())o.add(r);o.forEach(r=>{let i=s.get(r);if(i!==void 0){let c=t.get(i);c&&(console.log(`BSGW: Relaying disconnect for client ${r} to tab ${i}`),c.postMessage({cmd:"disconnect",clientId:r}));}s.delete(r);}),e=null;});else if(n.name==="cs"){let o=n.sender?.tab?.id;typeof o=="number"&&(console.log(`BSGW: Content script connected from tab ${o}`),t.set(o,n),n.onMessage.addListener(r=>{console.log(`BSGW: Message from tab ${o}`,r);let i=s.get(r.clientId);i===o?e?.postMessage(r):console.warn(`BSGW: Ignoring response from tab ${o} for client ${r.clientId} (expected tab ${i})`);}),n.onDisconnect.addListener(()=>{console.log(`BSGW: Content script disconnected from tab ${o}`),t.delete(o);for(let[r,i]of s.entries())i===o&&(console.log(`BSGW: Removing client ${r} mapping to disconnected tab ${o}`),e&&(console.log(`BSGW: Notifying UI about disconnected client ${r}`),e.postMessage({clientId:r,msg:{type:"mcp-server-disconnected",reason:"The tab hosting the server was refreshed or closed."}})),s.delete(r));}));}});}function U(a){let e=a??chrome.runtime.connect({name:"cs"});return window.addEventListener("message",t=>{if(t.source===window&&t.data?.source==="EXT-PAGE"){console.log("MCP relay: received from tab",t.data.cmd,t.data.clientId);let{clientId:s,msg:n}=t.data;e.postMessage({clientId:s,msg:n});}}),e.onMessage.addListener(t=>{console.log("MCP relay: received from extension",t.cmd,t.clientId),window.postMessage({source:"EXT-CS",...t},"*");}),e}function _(a=chrome.runtime.connect({name:"extensionUI"})){return {connect:(e,t)=>{console.log({clientId:e,options:t}),a.postMessage({cmd:"connect",clientId:e,options:t});},send:(e,t)=>{console.log({clientId:e,message:t}),a.postMessage({cmd:"send",clientId:e,message:t});},onMessage:e=>{a.onMessage.addListener(e);}}}var I=a=>JSONRPCMessageSchema.safeParse(a).success,R={initialReconnectionDelay:1e3,maxReconnectionDelay:3e4,reconnectionDelayGrowFactor:1.5,maxRetries:2},C=class{onclose;onerror;onmessage;isConnected=false;sessionId;lastEventId;serverInstanceId;hasEventStore=false;streamId;clientId;bridge;_reconnectionOptions;_connectionTimeout;_abortController;_connectionPromise;_reconnectAttempt=0;_startPromise;constructor(e){this.clientId=e?.clientInstanceId||(crypto.randomUUID?.()??`ext-${Date.now()}-${Math.random().toString(36).slice(2,8)}`),this._reconnectionOptions=e?.reconnectionOptions??R,this._connectionTimeout=e?.connectionTimeout??3e4,this.bridge=_(e?.port),this._setupMessageHandler();}_setupMessageHandler(){this.bridge.onMessage(e=>{if(console.log(`ExtensionClientTransport: Received message for client ${e.clientId}`,"Expected client:",this.clientId,"Match:",e.clientId===this.clientId,"Message type:",e.msg&&"type"in e.msg?e.msg.type:"unknown"),e.clientId!==this.clientId){console.log(`ExtensionClientTransport: Ignoring message for different client. Expected ${this.clientId}, got ${e.clientId}`);return}let t=e.msg;try{if("type"in t&&t.type==="mcp-server-disconnected"){if(console.warn(`ExtensionClientTransport: Server for client ${this.clientId} disconnected unexpectedly.`),this.isConnected){this.isConnected=!1;let s=new Error("The server-side transport has disconnected.");this._handleConnectionError(s,this.lastEventId);}return}if("type"in t&&t.type==="mcp-server-info"){let s=t;if(console.log(`ExtensionClientTransport: Received server info for client ${this.clientId}`,s),this._connectionPromise){this.sessionId=s.serverSessionId,this.serverInstanceId=s.serverInstanceId,this.hasEventStore=s.hasEventStore||!1,this.streamId=s.streamId,this.isConnected=!0,this._reconnectAttempt=0;let n=this._connectionPromise;this._connectionPromise=void 0,n.resolve();}else console.warn("ExtensionClientTransport: Received server info but no connection promise pending");return}if(!this.isConnected){console.warn("ExtensionClientTransport: Received message while not connected",t);return}if("type"in t&&(t.type==="mcp-replay-event"||t.type==="mcp-event")){let s=t;if(this.lastEventId=s.eventId,I(s.message))this.onmessage?.(s.message);else {let n=JSONRPCMessageSchema.parse(s.message);this.onmessage?.(n);}}else I(t)?this.onmessage?.(t):console.warn("ExtensionClientTransport received unknown message type:",t);}catch(s){let n=s;console.error("Error processing message in ExtensionClientTransport:",n,"Data:",t),this.onerror?.(n);}});}async start(){return this._startPromise?(console.warn("ExtensionClientTransport already started, returning existing connection promise"),this._startPromise):this._abortController&&(console.warn("ExtensionClientTransport already started!"),this.isConnected)?Promise.resolve():(this._abortController=new AbortController,this._startPromise=this._connectWithRetry().finally(()=>{this._startPromise=void 0;}),this._startPromise)}async _connectWithRetry(e){return new Promise((t,s)=>{this._connectionPromise={resolve:t,reject:s};let n,o=this._abortController?.signal;if(o?.aborted)return s(new Error("Connection aborted"));console.log(`ExtensionClientTransport: Starting connection for client ${this.clientId}`,e?`with resumption token ${e}`:"without resumption token");let r=e?{resumeFrom:e}:void 0;console.log(`ExtensionClientTransport: Sending connect command for client ${this.clientId}`,r),this.bridge.connect(this.clientId,r),n=setTimeout(()=>{if(!this.isConnected&&this._connectionPromise){let c=new Error(`ExtensionClientTransport: Server handshake timeout for client ${this.clientId}`);this._handleConnectionError(c,e);}},this._connectionTimeout);let i=this._connectionPromise.resolve;this._connectionPromise.resolve=()=>{n&&clearTimeout(n),i();},o?.addEventListener("abort",()=>{n&&clearTimeout(n),this._connectionPromise&&(this._connectionPromise.reject(new Error("Connection aborted during handshake")),this._connectionPromise=void 0);});})}_handleConnectionError(e,t){this.onerror?.(e),this.isConnected=false,this._connectionPromise&&(this._connectionPromise.reject(e),this._connectionPromise=void 0),this._abortController&&!this._abortController.signal.aborted&&(t||this.lastEventId)&&this._reconnectionOptions.maxRetries>0&&this._reconnectAttempt<this._reconnectionOptions.maxRetries?this._scheduleReconnection(t||this.lastEventId):this._abortController&&(this.onclose?.(),this._abortController=void 0);}_getNextReconnectionDelay(e){let{initialReconnectionDelay:t,maxReconnectionDelay:s,reconnectionDelayGrowFactor:n}=this._reconnectionOptions;return Math.min(t*Math.pow(n,e),s)}_scheduleReconnection(e){let t=this._getNextReconnectionDelay(this._reconnectAttempt);this._reconnectAttempt++,console.log(`ExtensionClientTransport: Scheduling reconnection attempt ${this._reconnectAttempt} in ${t}ms`),setTimeout(()=>{if(this._abortController?.signal.aborted){console.log("ExtensionClientTransport: Reconnection aborted.");return}console.log(`ExtensionClientTransport: Attempting reconnection (attempt ${this._reconnectAttempt})`),this._connectWithRetry(e).catch(s=>{console.error("ExtensionClientTransport: Scheduled reconnection attempt failed:",s);});},t);}async send(e,t){if(this._startPromise){console.log("ExtensionClientTransport: Waiting for initial connection before send.");try{await this._startPromise;}catch(s){let n=new Error(`ExtensionClientTransport: Failed to establish initial connection: ${s instanceof Error?s.message:String(s)}`);throw this.onerror?.(n),n}}if(!this.isConnected)if(this._reconnectionOptions.maxRetries>0&&this.lastEventId&&this._abortController&&!this._abortController.signal.aborted){console.log("ExtensionClientTransport: Not connected. Attempting auto-reconnect before send.");try{await this._connectWithRetry(this.lastEventId);}catch(n){let o=new Error(`ExtensionClientTransport: Failed to auto-reconnect before send: ${n instanceof Error?n.message:String(n)}`);throw this.onerror?.(o),o}if(!this.isConnected)throw new Error("ExtensionClientTransport: Not connected after attempting auto-reconnection.")}else throw new Error("ExtensionClientTransport: Not connected and cannot auto-reconnect.");this.bridge.send(this.clientId,e);}async close(){this._abortController&&(this._abortController.abort(),this._abortController=void 0),this._connectionPromise&&(this._connectionPromise.reject(new Error("ExtensionClientTransport: Transport closed by client.")),this._connectionPromise=void 0),this._startPromise=void 0,this.isConnected=false,this.onclose?.();}};export{m as BrowserTransportError,C as ExtensionClientTransport,f as TabClientTransport,u as TabServerTransport,_ as createUIBridge,I as isJSONRPCMessage,U as mcpRelay,G as setupBackgroundBridge};//# sourceMappingURL=index.js.map
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tab/TabClientTransport.ts","../src/tab/TabServerTransport.ts","../src/extension/backgroundBridge.ts","../src/extension/contentScript.ts","../src/extension/uiConnector.ts","../src/extension/extensionClientTransport.ts"],"names":["BrowserTransportError","code","message","DEFAULT_BROWSER_RECONNECTION_OPTIONS","TabClientTransport","opts","resumptionToken","resolve","reject","windowWithMcp","mcp","error","serverInfo","connectOptions","clientPort","handshakeComplete","handshakeTimer","event","data","replayEvent","eventMessage","JSONRPCMessageSchema","attempt","initialDelay","growFactor","maxDelay","lastEventId","maxRetries","delay","options","err","reconErr","namespace","InMemoryEventStore","maxEventsPerClient","streamId","clientId","eventId","clientEvents","e","eventsToRemove","send","startIndex","lastEventIndex","eventsToReplay","afterEventId","limit","events","afterIndex","TabServerTransport","mcpInterface","channel","serverPort","serverSessionId","connection","client","resumeFromEventId","port","clientInstanceId","isInitializeRequest","errMsg","serverInfoMessage","replayMessage","targetConnections","_","isJSONRPCResponse","isJSONRPCError","c","setupBackgroundBridge","uiPort","csPorts","clientTabMap","msgFromExtension","firstTabId","targetPort","tabId","disconnectedClientIds","msgFromTab","expectedTabId","mappedTabId","mcpRelay","csPort","msg","createUIBridge","handler","isJSONRPCMessage","value","DEFAULT_EXTENSION_RECONNECTION_OPTIONS","ExtensionClientTransport","resp","promise","eventMsg","signal","originalResolve","initialReconnectionDelay","maxReconnectionDelay","reconnectionDelayGrowFactor","tokenToResume"],"mappings":"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","file":"index.js","sourcesContent":["import { type Transport } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport { JSONRPCMessageSchema, type JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';\nimport {\n type EventId,\n type MCPBrowserInterface,\n type MCPConnectOptions,\n type MCPEventMessage,\n type MCPReplayEventMessage,\n type MCPServerInfoMessage,\n type MCPWindow,\n} from '../browser-types.js';\n\n/**\n * Browser-specific error class to match StreamableHTTPError\n */\nexport class BrowserTransportError extends Error {\n constructor(\n public readonly code: string | undefined,\n message: string | undefined\n ) {\n super(`Browser transport error: ${message}`);\n }\n}\n\n/**\n * Configuration options for the BrowserClientTransport, matching StreamableHTTPClientTransportOptions style\n */\nexport interface TabClientTransportOptions {\n /**\n * A unique identifier for this client instance. If not provided, one will be generated.\n * This is similar to a persistent client identifier.\n */\n clientInstanceId?: string;\n\n /**\n * Global namespace to look for MCP server (defaults to 'mcp')\n */\n globalNamespace?: string;\n\n /**\n * Options to configure the reconnection behavior.\n */\n reconnectionOptions?: BrowserReconnectionOptions;\n\n /**\n * Timeout for initial connection handshake (ms). Default is 30000 (30 seconds).\n */\n connectionTimeout?: number;\n}\n\n/**\n * Configuration options for reconnection behavior\n */\nexport interface BrowserReconnectionOptions {\n /**\n * Maximum backoff time between reconnection attempts in milliseconds.\n * Default is 30000 (30 seconds).\n */\n maxReconnectionDelay: number;\n\n /**\n * Initial backoff time between reconnection attempts in milliseconds.\n * Default is 1000 (1 second).\n */\n initialReconnectionDelay: number;\n\n /**\n * The factor by which the reconnection delay increases after each attempt.\n * Default is 1.5.\n */\n reconnectionDelayGrowFactor: number;\n\n /**\n * Maximum number of reconnection attempts before giving up.\n * Default is 2.\n */\n maxRetries: number;\n}\n\n// Default reconnection options matching StreamableHTTP\nconst DEFAULT_BROWSER_RECONNECTION_OPTIONS: BrowserReconnectionOptions = {\n initialReconnectionDelay: 1000,\n maxReconnectionDelay: 30000,\n reconnectionDelayGrowFactor: 1.5,\n maxRetries: 2,\n};\n\n/**\n * Client transport for browser environments using window.mcp global.\n * This implementation follows the same patterns as StreamableHTTPClientTransport.\n */\nexport class TabClientTransport implements Transport {\n private _globalNamespace: string;\n /**\n * The client's persistent instance ID\n */\n public clientInstanceId: string;\n /**\n * The session ID provided by the server during connection\n */\n public sessionId?: string;\n private _reconnectionOptions: BrowserReconnectionOptions;\n private _connectionTimeout: number;\n\n private _port?: MessagePort;\n /**\n * The server's instance ID, received during handshake.\n */\n public serverInstanceId?: string;\n public hasEventStore: boolean = false;\n public streamId?: string;\n /**\n * Indicates whether the transport is currently connected.\n */\n public isConnected: boolean = false;\n private _abortController?: AbortController; // For consistency with StreamableHTTP\n private _connectionPromise?: {\n resolve: () => void;\n reject: (error: Error) => void;\n };\n /**\n * The last event ID received from the server.\n */\n public lastEventId?: EventId;\n private _reconnectAttempt: number = 0;\n\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n\n constructor(opts?: TabClientTransportOptions) {\n this._globalNamespace = opts?.globalNamespace ?? 'mcp';\n this._reconnectionOptions = opts?.reconnectionOptions ?? DEFAULT_BROWSER_RECONNECTION_OPTIONS;\n this._connectionTimeout = opts?.connectionTimeout ?? 30000;\n\n this.clientInstanceId =\n opts?.clientInstanceId ||\n (typeof crypto !== 'undefined' && crypto.randomUUID\n ? crypto.randomUUID()\n : `client-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`);\n }\n\n /**\n * Start the transport connection\n */\n async start(): Promise<void> {\n if (this._abortController) {\n throw new Error(\n 'TabClientTransport already started! If using Client class, note that connect() calls start() automatically.'\n );\n }\n\n this._abortController = new AbortController();\n await this._connectWithRetry();\n }\n\n /**\n * Internal method to establish connection with retry logic\n */\n private async _connectWithRetry(resumptionToken?: EventId): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n this._connectionPromise = { resolve, reject };\n\n const windowWithMcp = window as MCPWindow;\n const mcp: MCPBrowserInterface | undefined =\n this._globalNamespace === 'mcp'\n ? windowWithMcp.mcp\n : (windowWithMcp as any)[this._globalNamespace];\n\n if (!mcp?.isServerAvailable?.()) {\n const error = new BrowserTransportError(\n 'NO_SERVER',\n `No MCP server found at window.${this._globalNamespace}`\n );\n this._handleConnectionError(error, resumptionToken);\n return;\n }\n\n // Get server info\n const serverInfo = mcp.getServerInfo();\n this.serverInstanceId = serverInfo.instanceId;\n\n // Request connection with optional resume\n const connectOptions: MCPConnectOptions | undefined = resumptionToken\n ? { resumeFrom: resumptionToken }\n : undefined;\n\n const clientPort = mcp.connect(this.clientInstanceId, connectOptions);\n if (!clientPort) {\n const error = new BrowserTransportError(\n 'CONNECTION_FAILED',\n 'Failed to connect to MCP server'\n );\n this._handleConnectionError(error, resumptionToken);\n return;\n }\n\n this._port = clientPort;\n let handshakeComplete = false;\n let handshakeTimer: ReturnType<typeof setTimeout>;\n\n // Set up message handling\n this._port.onmessage = (event: MessageEvent) => {\n const data = event.data;\n\n // Handle server info handshake\n if (!handshakeComplete && data.type === 'mcp-server-info') {\n const serverInfo = data as MCPServerInfoMessage;\n clearTimeout(handshakeTimer);\n handshakeComplete = true;\n this.sessionId = serverInfo.serverSessionId;\n this.hasEventStore = serverInfo.hasEventStore || false;\n this.streamId = serverInfo.streamId;\n this.isConnected = true;\n this._reconnectAttempt = 0; // Reset on successful connection\n\n if (this._connectionPromise) {\n this._connectionPromise.resolve();\n this._connectionPromise = undefined;\n }\n return;\n }\n\n // Handle replay events during resumption\n if (data.type === 'mcp-replay-event') {\n const replayEvent = data as MCPReplayEventMessage;\n this.lastEventId = replayEvent.eventId;\n this._handleMessage(replayEvent.message);\n return;\n }\n\n // Handle regular events with event IDs\n if (data.type === 'mcp-event') {\n const eventMessage = data as MCPEventMessage;\n this.lastEventId = eventMessage.eventId;\n this._handleMessage(eventMessage.message);\n return;\n }\n\n // Handle regular JSON-RPC messages (backward compatibility)\n if (handshakeComplete) {\n this._handleMessage(data);\n }\n };\n\n this._port.onmessageerror = () => {\n const error = new BrowserTransportError('MESSAGE_ERROR', 'MessagePort error');\n this.onerror?.(error);\n if (this._connectionPromise) {\n this._connectionPromise.reject(error);\n this._connectionPromise = undefined;\n }\n };\n\n // Note: MessagePort doesn't have an onclose event\n // Connection loss will be detected through other means (e.g., send failures)\n\n // Start the port\n this._port.start();\n\n // Set handshake timeout\n handshakeTimer = setTimeout(() => {\n if (!handshakeComplete) {\n const error = new BrowserTransportError('HANDSHAKE_TIMEOUT', 'Server handshake timeout');\n this._handleConnectionError(error, resumptionToken);\n }\n }, this._connectionTimeout);\n });\n }\n\n /**\n * Handle incoming messages with error handling\n */\n private _handleMessage(data: unknown): void {\n try {\n const message = JSONRPCMessageSchema.parse(data);\n this.onmessage?.(message);\n } catch (error) {\n this.onerror?.(new Error(`Failed to parse message: ${error}`));\n }\n }\n\n /**\n * Handle connection errors with retry logic\n */\n private _handleConnectionError(error: Error, resumptionToken?: EventId): void {\n this.onerror?.(error);\n\n if (this._connectionPromise) {\n this._connectionPromise.reject(error);\n this._connectionPromise = undefined;\n }\n\n // Schedule reconnection if appropriate\n if (this._abortController && !this._abortController.signal.aborted && resumptionToken) {\n this._scheduleReconnection(resumptionToken);\n }\n }\n\n /**\n * Calculate the next reconnection delay using exponential backoff\n */\n private _getNextReconnectionDelay(attempt: number): number {\n const initialDelay = this._reconnectionOptions.initialReconnectionDelay;\n const growFactor = this._reconnectionOptions.reconnectionDelayGrowFactor;\n const maxDelay = this._reconnectionOptions.maxReconnectionDelay;\n\n return Math.min(initialDelay * Math.pow(growFactor, attempt), maxDelay);\n }\n\n /**\n * Schedule a reconnection attempt with exponential backoff\n */\n private _scheduleReconnection(lastEventId: EventId): void {\n const maxRetries = this._reconnectionOptions.maxRetries;\n\n if (maxRetries > 0 && this._reconnectAttempt >= maxRetries) {\n this.onerror?.(new Error(`Maximum reconnection attempts (${maxRetries}) exceeded.`));\n return;\n }\n\n const delay = this._getNextReconnectionDelay(this._reconnectAttempt);\n\n setTimeout(() => {\n this._reconnectAttempt++;\n this._connectWithRetry(lastEventId).catch((error) => {\n this.onerror?.(\n new Error(\n `Failed to reconnect: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n });\n }, delay);\n }\n\n /**\n * Send a message over the transport\n */\n async send(\n message: JSONRPCMessage,\n options?: {\n resumptionToken?: string;\n onresumptiontoken?: (token: string) => void;\n }\n ): Promise<void> {\n if (!this.isConnected || !this._port) {\n // Handle resumption case with explicit token\n if (options?.resumptionToken) {\n await this._connectWithRetry(options.resumptionToken).catch((err) => {\n this.onerror?.(\n new Error(\n `Failed to reconnect with token: ${err instanceof Error ? err.message : String(err)}`\n )\n );\n throw err;\n });\n if (!this.isConnected || !this._port) {\n throw new Error('Not connected after attempting reconnection with token.');\n }\n } else if (\n this._reconnectionOptions.maxRetries > 0 &&\n this.lastEventId &&\n this._abortController &&\n !this._abortController.signal.aborted\n ) {\n // Attempt auto-reconnection if disconnected, retries enabled, and lastEventId known\n await this._connectWithRetry(this.lastEventId).catch((err) => {\n const reconErr = new Error(\n `Failed to auto-reconnect: ${err instanceof Error ? err.message : String(err)}`\n );\n this.onerror?.(reconErr);\n throw reconErr;\n });\n if (!this.isConnected || !this._port) {\n throw new Error('Not connected after attempting auto-reconnection.');\n }\n } else {\n throw new Error('Not connected');\n }\n }\n\n // For browser transport, we just send the message directly\n // The event ID tracking is handled automatically by the server\n this._port.postMessage(message);\n }\n\n /**\n * Close the transport connection\n */\n async close(): Promise<void> {\n // Abort any pending operations\n this._abortController?.abort();\n this._abortController = undefined;\n\n if (this._connectionPromise) {\n this._connectionPromise.reject(new Error('Transport closed'));\n this._connectionPromise = undefined;\n }\n\n if (this._port) {\n this._port.close();\n this._port = undefined;\n }\n\n // Notify server of disconnection\n const windowWithMcp = window as MCPWindow;\n const mcp: MCPBrowserInterface | undefined =\n this._globalNamespace === 'mcp'\n ? windowWithMcp.mcp\n : (windowWithMcp as any)[this._globalNamespace];\n\n if (mcp?.disconnect) {\n mcp.disconnect(this.clientInstanceId);\n }\n\n this.isConnected = false;\n this.onclose?.();\n }\n\n /**\n * Terminate the current session explicitly\n * Similar to StreamableHTTP's terminateSession\n */\n async terminateSession(): Promise<void> {\n if (!this.sessionId) {\n return; // No session to terminate\n }\n\n try {\n // Use the new terminateSession for full cleanup if available\n const windowWithMcp = window as MCPWindow;\n const mcp: MCPBrowserInterface | undefined =\n this._globalNamespace === 'mcp'\n ? windowWithMcp.mcp\n : (windowWithMcp as any)[this._globalNamespace];\n\n if (mcp?.terminateSession) {\n mcp.terminateSession(this.clientInstanceId);\n } else if (mcp?.events?.clearEvents) {\n // Fallback to just clearing events if terminate is not implemented\n mcp.events.clearEvents(this.clientInstanceId);\n }\n\n this.sessionId = undefined;\n this.lastEventId = undefined;\n } catch (error) {\n this.onerror?.(error as Error);\n throw error;\n }\n }\n\n /**\n * Static helper to check if an MCP server is available\n * Similar to checking server availability before connection\n */\n static isServerAvailable(namespace: string = 'mcp'): boolean {\n const windowWithMcp = window as MCPWindow;\n const mcp: MCPBrowserInterface | undefined =\n namespace === 'mcp' ? windowWithMcp.mcp : (windowWithMcp as any)[namespace];\n\n return !!mcp?.isServerAvailable?.();\n }\n}\n","import { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js';\nimport { Transport, TransportSendOptions } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport {\n isInitializeRequest,\n isJSONRPCError,\n isJSONRPCResponse,\n JSONRPCMessage,\n JSONRPCMessageSchema,\n RequestId,\n} from '@modelcontextprotocol/sdk/types.js';\nimport {\n EventId,\n MCPBrowserInterface,\n MCPConnectOptions,\n MCPEventMessage,\n MCPReplayEventMessage,\n MCPServerInfo,\n MCPServerInfoMessage,\n MCPWindow,\n StoredEvent,\n StreamId,\n} from '../browser-types.js';\n\n/**\n * In-memory event store implementation\n */\nclass InMemoryEventStore {\n private _events: StoredEvent[] = [];\n private _eventCounter: number = 0;\n private _maxEventsPerClient: number;\n\n constructor(maxEventsPerClient: number = 1000) {\n this._maxEventsPerClient = maxEventsPerClient;\n }\n\n async storeEvent(\n streamId: StreamId,\n clientId: string,\n message: JSONRPCMessage\n ): Promise<EventId> {\n const eventId = `evt_${++this._eventCounter}_${Date.now()}`;\n const event: StoredEvent = {\n eventId,\n streamId,\n message,\n timestamp: Date.now(),\n clientId,\n };\n\n this._events.push(event);\n\n // Cleanup old events for this client if limit exceeded\n const clientEvents = this._events.filter((e) => e.clientId === clientId);\n if (clientEvents.length > this._maxEventsPerClient) {\n const eventsToRemove = clientEvents.slice(0, clientEvents.length - this._maxEventsPerClient);\n this._events = this._events.filter((e) => !eventsToRemove.includes(e));\n }\n\n return eventId;\n }\n\n async replayEventsAfter(\n clientId: string,\n lastEventId: EventId | undefined,\n send: (eventId: EventId, message: JSONRPCMessage) => Promise<void>\n ): Promise<StreamId> {\n const clientEvents = this._events.filter((e) => e.clientId === clientId);\n\n let startIndex = 0;\n if (lastEventId) {\n const lastEventIndex = clientEvents.findIndex((e) => e.eventId === lastEventId);\n if (lastEventIndex >= 0) {\n startIndex = lastEventIndex + 1;\n }\n }\n\n const eventsToReplay = clientEvents.slice(startIndex);\n for (const event of eventsToReplay) {\n await send(event.eventId, event.message);\n }\n\n // Return the stream ID from the last replayed event, or generate new one\n return eventsToReplay.length > 0\n ? eventsToReplay[eventsToReplay.length - 1].streamId\n : `stream_${Date.now()}`;\n }\n\n getEvents(clientId?: string, afterEventId?: EventId, limit: number = 100): StoredEvent[] {\n let events = clientId ? this._events.filter((e) => e.clientId === clientId) : this._events;\n\n if (afterEventId) {\n const afterIndex = events.findIndex((e) => e.eventId === afterEventId);\n if (afterIndex >= 0) {\n events = events.slice(afterIndex + 1);\n }\n }\n\n return events.slice(0, limit);\n }\n\n getLastEventId(clientId?: string): EventId | null {\n const events = clientId ? this._events.filter((e) => e.clientId === clientId) : this._events;\n\n return events.length > 0 ? events[events.length - 1].eventId : null;\n }\n\n clearEvents(clientId?: string): void {\n if (clientId) {\n this._events = this._events.filter((e) => e.clientId !== clientId);\n } else {\n this._events = [];\n }\n }\n\n removeClientEvents(clientId: string): void {\n this._events = this._events.filter((e) => e.clientId !== clientId);\n }\n}\n\n/**\n * Configuration options for BrowserServerTransport\n */\nexport interface BrowserServerTransportOptions {\n /**\n * Function that generates a session ID for each client connection.\n * Return undefined to operate in stateless mode.\n * If not provided, defaults to undefined (stateless mode).\n */\n sessionIdGenerator?: (() => string) | undefined;\n\n /**\n * Callback for session initialization events\n */\n onsessioninitialized?: (clientSessionId: string | undefined, clientInstanceId: string) => void;\n\n /**\n * Optional namespace to use instead of window.mcp\n */\n globalNamespace?: string;\n\n /**\n * Enable event storage for resumability (only works in stateful mode)\n * Default is true in stateful mode, false in stateless mode\n */\n enableEventStore?: boolean;\n\n /**\n * Maximum number of events to store per client (default: 1000)\n */\n maxEventsPerClient?: number;\n}\n\ninterface ClientConnection {\n port: MessagePort;\n clientInstanceId: string;\n serverSessionId?: string;\n streamId: StreamId;\n initialized: boolean;\n requestIds: Set<RequestId>;\n}\n\n/**\n * Server transport for browser environments using window.mcp global\n * Supports multiple concurrent client connections via MessageChannel\n */\nexport class TabServerTransport implements Transport {\n private _serverInstanceId: string;\n private _sessionIdGenerator: (() => string) | undefined;\n private _onsessioninitialized?: (\n clientSessionId: string | undefined,\n clientInstanceId: string\n ) => void;\n\n private _isStarted: boolean = false;\n private _clients: Map<string, ClientConnection> = new Map();\n private _globalNamespace: string;\n private _eventStore?: InMemoryEventStore;\n private _enableEventStore: boolean;\n\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage, extra?: { authInfo?: AuthInfo | undefined }) => void;\n\n constructor(options?: BrowserServerTransportOptions) {\n this._sessionIdGenerator = options?.sessionIdGenerator;\n this._onsessioninitialized = options?.onsessioninitialized;\n this._globalNamespace = options?.globalNamespace || 'mcp';\n\n // Event store is enabled by default in stateful mode\n this._enableEventStore = options?.enableEventStore ?? this._sessionIdGenerator !== undefined;\n\n if (this._enableEventStore && this._sessionIdGenerator) {\n this._eventStore = new InMemoryEventStore(options?.maxEventsPerClient);\n }\n\n this._serverInstanceId =\n typeof crypto !== 'undefined' && crypto.randomUUID\n ? crypto.randomUUID()\n : `server-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n }\n\n async start(): Promise<void> {\n if (this._isStarted) {\n throw new Error('BrowserServerTransport already started');\n }\n\n // Check if another server is already registered\n const windowWithMcp = window as MCPWindow;\n const existingMcp =\n this._globalNamespace === 'mcp'\n ? windowWithMcp.mcp\n : (windowWithMcp as any)[this._globalNamespace];\n if (existingMcp?.isServerAvailable?.()) {\n throw new Error(\n `Another MCP server is already registered at window.${this._globalNamespace}`\n );\n }\n\n const mcpInterface: MCPBrowserInterface = {\n connect: (clientId: string, options?: MCPConnectOptions): MessagePort | null => {\n if (!this._isStarted) {\n console.error('MCP server not started');\n return null;\n }\n\n if (this._clients.has(clientId)) {\n console.error(`Client ${clientId} already connected`);\n return null;\n }\n\n const channel = new MessageChannel();\n const serverPort = channel.port1;\n const clientPort = channel.port2;\n\n const serverSessionId = this._sessionIdGenerator?.();\n const streamId = `stream_${clientId}_${Date.now()}`;\n\n const connection: ClientConnection = {\n port: serverPort,\n clientInstanceId: clientId,\n serverSessionId,\n streamId,\n initialized: false,\n requestIds: new Set(),\n };\n\n this._setupClientConnection(connection, options?.resumeFrom);\n this._clients.set(clientId, connection);\n\n return clientPort;\n },\n\n disconnect: (clientId: string): void => {\n const client = this._clients.get(clientId);\n if (client) {\n client.port.close();\n this._clients.delete(clientId);\n // Note: We keep events for disconnected clients for resumability\n }\n },\n\n isServerAvailable: (): boolean => {\n return this._isStarted;\n },\n\n getServerInfo: (): MCPServerInfo => ({\n instanceId: this._serverInstanceId,\n stateful: this._sessionIdGenerator !== undefined,\n hasEventStore: this._eventStore !== undefined,\n }),\n\n terminateSession: (clientId: string): void => {\n const client = this._clients.get(clientId);\n if (client) {\n client.port.close();\n this._clients.delete(clientId);\n }\n this._eventStore?.removeClientEvents(clientId);\n },\n };\n\n // Add event storage interface if enabled\n if (this._eventStore) {\n mcpInterface.events = {\n getEvents: (clientId?: string, afterEventId?: EventId, limit?: number) => {\n return this._eventStore!.getEvents(clientId, afterEventId, limit);\n },\n getLastEventId: (clientId?: string) => {\n return this._eventStore!.getLastEventId(clientId);\n },\n clearEvents: (clientId?: string) => {\n this._eventStore!.clearEvents(clientId);\n },\n };\n }\n\n if (this._globalNamespace === 'mcp') {\n (window as MCPWindow).mcp = mcpInterface;\n } else {\n (window as any)[this._globalNamespace] = mcpInterface;\n }\n this._isStarted = true;\n }\n\n private async _setupClientConnection(\n connection: ClientConnection,\n resumeFromEventId?: EventId\n ): Promise<void> {\n const { port, clientInstanceId } = connection;\n\n port.onmessage = (event: MessageEvent) => {\n try {\n const message = JSONRPCMessageSchema.parse(event.data);\n\n // Track request IDs from this client\n if ('id' in message && message.id !== undefined && 'method' in message) {\n connection.requestIds.add(message.id);\n }\n\n const isInitReq = isInitializeRequest(message);\n\n if (isInitReq) {\n if (connection.initialized) {\n this.onerror?.(new Error(`Client ${clientInstanceId} attempted to re-initialize`));\n return;\n }\n connection.initialized = true;\n this._onsessioninitialized?.(connection.serverSessionId, clientInstanceId);\n } else if (!connection.initialized) {\n const errMsg = `Client ${clientInstanceId} sent message before initialization`;\n this.onerror?.(new Error(errMsg));\n return;\n }\n\n this.onmessage?.(message, {\n authInfo: {\n clientId: clientInstanceId,\n token: 'N/A',\n scopes: ['browser'],\n },\n });\n } catch (error) {\n this.onerror?.(error instanceof Error ? error : new Error(String(error)));\n }\n };\n\n port.onmessageerror = () => {\n this.onerror?.(new Error(`MessagePort error for client ${clientInstanceId}`));\n };\n\n port.start();\n\n // Send initial server info\n const serverInfoMessage: MCPServerInfoMessage = {\n type: 'mcp-server-info',\n serverInstanceId: this._serverInstanceId,\n serverSessionId: connection.serverSessionId,\n hasEventStore: this._eventStore !== undefined,\n streamId: connection.streamId,\n };\n port.postMessage(serverInfoMessage);\n\n // Replay events if resuming\n if (resumeFromEventId && this._eventStore) {\n await this._eventStore.replayEventsAfter(\n clientInstanceId,\n resumeFromEventId,\n async (eventId: EventId, message: JSONRPCMessage) => {\n const replayMessage: MCPReplayEventMessage = {\n type: 'mcp-replay-event',\n eventId,\n message,\n };\n port.postMessage(replayMessage);\n }\n );\n }\n }\n\n async send(\n message: JSONRPCMessage,\n options?: TransportSendOptions & { targetClientId?: string }\n ): Promise<void> {\n if (!this._isStarted) {\n throw new Error('BrowserServerTransport not started');\n }\n\n let targetConnections: ClientConnection[] = [];\n\n // Determine target client(s)\n if (options?.relatedRequestId) {\n // Find client that made this request\n for (const [_, connection] of this._clients) {\n if (connection.requestIds.has(options.relatedRequestId)) {\n targetConnections = [connection];\n // Clean up request ID if this is a response\n if (isJSONRPCResponse(message) || isJSONRPCError(message)) {\n connection.requestIds.delete(options.relatedRequestId);\n }\n break;\n }\n }\n } else if (options?.targetClientId) {\n const connection = this._clients.get(options.targetClientId);\n if (connection) {\n targetConnections = [connection];\n }\n } else {\n // Broadcast to all initialized clients\n targetConnections = Array.from(this._clients.values()).filter((c) => c.initialized);\n }\n\n if (targetConnections.length === 0) {\n this.onerror?.(new Error('No suitable clients found for message'));\n return;\n }\n\n for (const connection of targetConnections) {\n // Store event if event store is enabled\n let eventId: EventId | undefined;\n if (this._eventStore) {\n eventId = await this._eventStore.storeEvent(\n connection.streamId,\n connection.clientInstanceId,\n message\n );\n }\n\n // Send message with event ID if available\n if (eventId) {\n const eventMessage: MCPEventMessage = {\n type: 'mcp-event',\n eventId,\n message,\n };\n connection.port.postMessage(eventMessage);\n } else {\n connection.port.postMessage(message);\n }\n }\n }\n\n async close(): Promise<void> {\n if (!this._isStarted) {\n return;\n }\n\n // Close all client connections\n for (const connection of this._clients.values()) {\n connection.port.close();\n }\n this._clients.clear();\n\n // Clear all events\n this._eventStore?.clearEvents();\n\n // Remove global interface\n if (this._globalNamespace === 'mcp') {\n delete (window as MCPWindow).mcp;\n } else {\n delete (window as any)[this._globalNamespace];\n }\n\n this._isStarted = false;\n this.onclose?.();\n }\n\n get clientCount(): number {\n return this._clients.size;\n }\n\n get clients(): ReadonlyArray<{\n clientId: string;\n initialized: boolean;\n serverSessionId?: string;\n }> {\n return Array.from(this._clients.entries()).map(([clientId, connection]) => ({\n clientId,\n initialized: connection.initialized,\n serverSessionId: connection.serverSessionId,\n }));\n }\n}\n","import { type BridgeMessage, type BridgeResponse } from './uiConnector.js';\n\n/**\n * In your background script:\n * import { setupBackgroundBridge } from '@modelcontextprotocol/sdk/extension-bridge/backgroundBridge'\n * // Dynamically inject pageBridge and contentScript into matching pages\n * setupBackgroundBridge({\n * matches: ['https://your-app.com/*'],\n * pageBridgeRunAt: 'document_start',\n * contentScriptRunAt: 'document_idle'\n * });\n */\nexport async function setupBackgroundBridge(_?: {\n /** Host-match patterns for injection, defaults to ['<all_urls>'] */\n matches?: string[];\n /** When to inject the pageBridge (MAIN world) */\n pageBridgeRunAt?: 'document_start' | 'document_end' | 'document_idle';\n /** When to inject the content script (ISOLATED world) */\n contentScriptRunAt?: 'document_start' | 'document_end' | 'document_idle';\n}): Promise<void> {\n // // Dynamically register content scripts if the scripting API is available (MV3+)\n // if (chrome.scripting?.registerContentScripts) {\n // const matches = options?.matches ?? ['<all_urls>'];\n // chrome.scripting.registerContentScripts([{\n // id: 'mcp-page-bridge',\n // js: ['extension-bridge/pageBridge.js'],\n // matches,\n // runAt: options?.pageBridgeRunAt ?? 'document_start',\n // world: 'MAIN',\n // persistAcrossSessions: true\n // }, {\n // id: 'mcp-content-script',\n // js: ['extension-bridge/contentScript.js'],\n // matches,\n // runAt: options?.contentScriptRunAt ?? 'document_idle',\n // world: 'ISOLATED',\n // persistAcrossSessions: true\n // }]);\n // }\n let uiPort: chrome.runtime.Port | null = null;\n const csPorts = new Map<number, chrome.runtime.Port>();\n\n // Map client IDs to specific tab IDs to ensure proper routing\n const clientTabMap = new Map<string, number>();\n\n console.log('BSGW: Background bridge initialized');\n\n chrome.runtime.onConnect.addListener((port) => {\n if (port.name === 'extensionUI') {\n console.log('BSGW: Extension UI connected');\n uiPort = port;\n\n port.onMessage.addListener((msgFromExtension: BridgeMessage) => {\n console.log('BSGW: Message from extension', msgFromExtension);\n\n if (msgFromExtension.cmd === 'connect') {\n // For connect commands, we need to pick a tab to connect to\n // For now, use the first available tab, but this could be made smarter\n const firstTabId = Array.from(csPorts.keys())[0];\n if (firstTabId !== undefined) {\n clientTabMap.set(msgFromExtension.clientId, firstTabId);\n const targetPort = csPorts.get(firstTabId);\n if (targetPort) {\n console.log(\n `BSGW: Routing connect for client ${msgFromExtension.clientId} to tab ${firstTabId}`\n );\n targetPort.postMessage(msgFromExtension);\n }\n } else {\n console.error('BSGW: No content script tabs available for connection');\n }\n } else if (msgFromExtension.cmd === 'send') {\n // For send commands, route to the tab that this client is connected to\n const tabId = clientTabMap.get(msgFromExtension.clientId);\n if (tabId !== undefined) {\n const targetPort = csPorts.get(tabId);\n if (targetPort) {\n console.log(\n `BSGW: Routing send for client ${msgFromExtension.clientId} to tab ${tabId}`\n );\n targetPort.postMessage(msgFromExtension);\n } else {\n console.error(\n `BSGW: Tab ${tabId} no longer available for client ${msgFromExtension.clientId}`\n );\n clientTabMap.delete(msgFromExtension.clientId);\n }\n } else {\n console.error(`BSGW: No tab mapping found for client ${msgFromExtension.clientId}`);\n }\n }\n });\n\n // In backgroundBridge.ts\n\n port.onDisconnect.addListener(() => {\n console.log('BSGW: Extension UI disconnected');\n\n // Find all clients that were connected through this UI port\n const disconnectedClientIds = new Set<string>();\n for (const [clientId, _] of clientTabMap.entries()) {\n // This logic assumes one UI port. If you have multiple, you'll need to\n // map UI ports to clients. For now, let's assume one.\n disconnectedClientIds.add(clientId);\n }\n\n disconnectedClientIds.forEach((clientId) => {\n const tabId = clientTabMap.get(clientId);\n if (tabId !== undefined) {\n const targetPort = csPorts.get(tabId);\n if (targetPort) {\n // Send a new 'disconnect' command to the content script\n console.log(`BSGW: Relaying disconnect for client ${clientId} to tab ${tabId}`);\n targetPort.postMessage({ cmd: 'disconnect', clientId });\n }\n }\n // Clean up the mapping in the background script\n clientTabMap.delete(clientId);\n });\n\n uiPort = null;\n });\n } else if (port.name === 'cs') {\n const tabId = port.sender?.tab?.id;\n if (typeof tabId === 'number') {\n console.log(`BSGW: Content script connected from tab ${tabId}`);\n csPorts.set(tabId, port);\n\n port.onMessage.addListener((msgFromTab: BridgeResponse) => {\n console.log(`BSGW: Message from tab ${tabId}`, msgFromTab);\n\n // Only forward if this response is from the tab we expect for this client\n const expectedTabId = clientTabMap.get(msgFromTab.clientId);\n if (expectedTabId === tabId) {\n uiPort?.postMessage(msgFromTab);\n } else {\n console.warn(\n `BSGW: Ignoring response from tab ${tabId} for client ${msgFromTab.clientId} (expected tab ${expectedTabId})`\n );\n }\n });\n\n port.onDisconnect.addListener(() => {\n console.log(`BSGW: Content script disconnected from tab ${tabId}`);\n csPorts.delete(tabId);\n\n // Clean up any client mappings to this tab\n for (const [clientId, mappedTabId] of clientTabMap.entries()) {\n if (mappedTabId === tabId) {\n console.log(`BSGW: Removing client ${clientId} mapping to disconnected tab ${tabId}`);\n\n // NOTIFY THE UI: Tell the extension UI that the server for this specific\n // client has disappeared.\n if (uiPort) {\n console.log(`BSGW: Notifying UI about disconnected client ${clientId}`);\n uiPort.postMessage({\n clientId: clientId, // Target the specific client instance\n msg: {\n type: 'mcp-server-disconnected',\n reason: `The tab hosting the server was refreshed or closed.`,\n },\n });\n }\n\n clientTabMap.delete(clientId);\n }\n }\n });\n }\n }\n });\n}\n","import { type BridgeMessage, type PageBridgeMessageType } from './uiConnector.js';\n\n/**\n * Sets up a content script bridge that relays messages between the page context\n * and the extension background script. This enables communication between\n * the injected page bridge and the extension's background script.\n *\n * @param port - Optional Chrome runtime port. If not provided, creates a default port with name 'cs'\n * @returns The Chrome runtime port used for communication\n */\nexport function mcpRelay(port?: chrome.runtime.Port): chrome.runtime.Port {\n // Use provided port or create default connection to background script\n const csPort = port ?? chrome.runtime.connect({ name: 'cs' });\n\n // Relay messages from page context to extension background\n // Listen for messages from the injected page bridge (pageBridge.js)\n window.addEventListener('message', (e: MessageEvent) => {\n if (e.source === window && e.data?.source === 'EXT-PAGE') {\n console.log('MCP relay: received from tab', e.data.cmd, e.data.clientId);\n const { clientId, msg } = e.data as {\n clientId: string;\n msg: PageBridgeMessageType;\n };\n csPort.postMessage({ clientId, msg });\n }\n });\n\n // Relay messages from extension background to page context\n // Forward messages from background script to the page bridge\n csPort.onMessage.addListener((data: BridgeMessage) => {\n console.log('MCP relay: received from extension', data.cmd, data.clientId);\n window.postMessage({ source: 'EXT-CS', ...data }, '*');\n });\n\n return csPort;\n}\n","import { type JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';\nimport {\n type MCPConnectOptions,\n type MCPEventMessage,\n type MCPReplayEventMessage,\n type MCPServerInfoMessage,\n} from '../browser-types';\n\n/**\n * Union type representing all possible message types that can be sent through the page bridge.\n * This includes MCP server information, events, replay events, and JSON-RPC messages.\n */\nexport type PageBridgeMessageType =\n | MCPServerInfoMessage\n | MCPEventMessage\n | MCPReplayEventMessage\n | JSONRPCMessage\n | {\n type: 'mcp-server-disconnected';\n reason: string;\n };\n\n/**\n * Response structure for messages received from the bridge.\n */\nexport interface BridgeResponse {\n /** Unique identifier for the client connection */\n clientId: string;\n /** The actual message payload */\n msg: PageBridgeMessageType;\n}\n\n/**\n * Message structure for commands sent to the bridge.\n */\nexport interface BridgeMessage {\n /** Command type - either 'connect' to establish a connection or 'send' to send a message */\n cmd: 'connect' | 'send' | 'disconnect';\n /** Unique identifier for the client connection */\n clientId: string;\n /** Connection options, required when cmd is 'connect' */\n options?: MCPConnectOptions;\n /** JSON-RPC message to send, required when cmd is 'send' */\n message?: JSONRPCMessage;\n}\n\n/**\n * Creates a UI bridge for communicating with MCP servers from browser extension UI components.\n *\n * This function establishes a connection to the extension's background script via Chrome's\n * runtime messaging API, allowing UI components like sidebars and popups to interact with\n * MCP servers.\n *\n * @param port - Optional Chrome runtime port to use for communication. If not provided,\n * a new port will be created with the name 'extensionUI'.\n *\n * The port should be connected to your background script's chrome.runtime.onConnect listener.\n *\n * @returns An object with methods to interact with MCP servers:\n * - connect: Establish a connection to an MCP server\n * - send: Send JSON-RPC messages to a connected server\n * - onMessage: Listen for responses and events from the server\n *\n * @example\n * ```typescript\n * // In your sidebar/popup code:\n * import { createUIBridge } from '@modelcontextprotocol/sdk/extension-bridge/uiConnector';\n *\n * // Using default port\n * const bridge = createUIBridge();\n *\n * // Or using a custom port\n * const customPort = chrome.runtime.connect({ name: 'sidebar' });\n * const bridge = createUIBridge(customPort);\n *\n * // Connect to an MCP server\n * bridge.connect('my-client-id', {\n * serverName: 'my-server',\n * command: 'node',\n * args: ['server.js']\n * });\n *\n * // Listen for messages\n * bridge.onMessage((response) => {\n * console.log('Received:', response.msg);\n * });\n *\n * // Send a message\n * bridge.send('my-client-id', {\n * jsonrpc: '2.0',\n * id: 1,\n * method: 'tools/list'\n * });\n * ```\n */\nexport function createUIBridge(\n port: chrome.runtime.Port = chrome.runtime.connect({ name: 'extensionUI' })\n) {\n return {\n /**\n * Establishes a connection to an MCP server.\n *\n * @param clientId - Unique identifier for this client connection\n * @param options - Configuration options for the MCP server connection\n */\n connect: (clientId: string, options?: MCPConnectOptions) => {\n console.log({ clientId, options });\n port.postMessage({ cmd: 'connect', clientId, options });\n },\n\n /**\n * Sends a JSON-RPC message to a connected MCP server.\n *\n * @param clientId - The client ID of the connection to send the message through\n * @param message - The JSON-RPC message to send\n */\n send: (clientId: string, message: JSONRPCMessage) => {\n console.log({ clientId, message });\n port.postMessage({ cmd: 'send', clientId, message });\n },\n\n /**\n * Registers a handler for incoming messages from MCP servers.\n *\n * @param handler - Function to handle incoming bridge responses\n */\n onMessage: (handler: (resp: BridgeResponse) => void) => {\n port.onMessage.addListener(handler);\n },\n };\n}\n","import {\n type Transport,\n type TransportSendOptions,\n} from '@modelcontextprotocol/sdk/shared/transport.js';\nimport { JSONRPCMessageSchema, type JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';\nimport {\n type EventId,\n type MCPConnectOptions,\n type MCPEventMessage,\n type MCPReplayEventMessage,\n type MCPServerInfoMessage,\n} from '../browser-types';\nimport { createUIBridge, type BridgeResponse, type PageBridgeMessageType } from './uiConnector.js';\n\nexport const isJSONRPCMessage = (value: unknown): value is JSONRPCMessage =>\n JSONRPCMessageSchema.safeParse(value).success;\n\n/**\n * Configuration options for reconnection behavior, mirroring BrowserReconnectionOptions\n */\nexport interface ExtensionReconnectionOptions {\n maxReconnectionDelay: number;\n initialReconnectionDelay: number;\n reconnectionDelayGrowFactor: number;\n maxRetries: number;\n}\n\nconst DEFAULT_EXTENSION_RECONNECTION_OPTIONS: ExtensionReconnectionOptions = {\n initialReconnectionDelay: 1000,\n maxReconnectionDelay: 30000,\n reconnectionDelayGrowFactor: 1.5,\n maxRetries: 2,\n};\n\n/**\n * Configuration options for the ExtensionClientTransport\n */\nexport interface ExtensionClientTransportOptions {\n clientInstanceId?: string;\n reconnectionOptions?: ExtensionReconnectionOptions;\n connectionTimeout?: number;\n}\n\nexport class ExtensionClientTransport implements Transport {\n onclose?: () => void;\n onerror?: (err: Error) => void;\n onmessage?: (message: JSONRPCMessage, extra?: { authInfo?: any }) => void;\n\n public isConnected = false;\n public sessionId?: string;\n public lastEventId?: EventId;\n public serverInstanceId?: string;\n public hasEventStore: boolean = false;\n public streamId?: string;\n\n private clientId: string;\n private bridge: ReturnType<typeof createUIBridge>;\n\n private _reconnectionOptions: ExtensionReconnectionOptions;\n private _connectionTimeout: number;\n private _abortController?: AbortController;\n private _connectionPromise?: {\n resolve: () => void;\n reject: (error: Error) => void;\n };\n private _reconnectAttempt: number = 0;\n private _startPromise?: Promise<void>;\n\n constructor(options?: ExtensionClientTransportOptions & { port?: chrome.runtime.Port }) {\n this.clientId =\n options?.clientInstanceId ||\n (crypto.randomUUID?.() ?? `ext-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);\n\n this._reconnectionOptions =\n options?.reconnectionOptions ?? DEFAULT_EXTENSION_RECONNECTION_OPTIONS;\n this._connectionTimeout = options?.connectionTimeout ?? 30000;\n this.bridge = createUIBridge(options?.port);\n\n // Set up the message handler once for the lifetime of this transport\n this._setupMessageHandler();\n }\n\n private _setupMessageHandler(): void {\n this.bridge.onMessage((resp: BridgeResponse) => {\n console.log(\n `ExtensionClientTransport: Received message for client ${resp.clientId}`,\n 'Expected client:',\n this.clientId,\n 'Match:',\n resp.clientId === this.clientId,\n 'Message type:',\n resp.msg && 'type' in resp.msg ? resp.msg.type : 'unknown'\n );\n\n // Only process messages for our client ID\n if (resp.clientId !== this.clientId) {\n console.log(\n `ExtensionClientTransport: Ignoring message for different client. Expected ${this.clientId}, got ${resp.clientId}`\n );\n return;\n }\n\n const data: PageBridgeMessageType = resp.msg;\n try {\n // HANDLE THE SERVER-SIDE DISCONNECT NOTIFICATION\n if ('type' in data && data.type === 'mcp-server-disconnected') {\n console.warn(\n `ExtensionClientTransport: Server for client ${this.clientId} disconnected unexpectedly.`\n );\n\n // If we thought we were connected, trigger the full close/reconnect cycle.\n if (this.isConnected) {\n this.isConnected = false; // Immediately update state\n const error = new Error('The server-side transport has disconnected.');\n\n // Re-use the existing connection error handler. It contains the logic\n // to attempt reconnection based on your options.\n this._handleConnectionError(error, this.lastEventId);\n }\n return;\n }\n\n if ('type' in data && data.type === 'mcp-server-info') {\n const serverInfo = data as MCPServerInfoMessage;\n console.log(\n `ExtensionClientTransport: Received server info for client ${this.clientId}`,\n serverInfo\n );\n\n // Only process if we're expecting a handshake (have a connection promise)\n if (this._connectionPromise) {\n this.sessionId = serverInfo.serverSessionId;\n this.serverInstanceId = serverInfo.serverInstanceId;\n this.hasEventStore = serverInfo.hasEventStore || false;\n this.streamId = serverInfo.streamId;\n this.isConnected = true;\n this._reconnectAttempt = 0;\n const promise = this._connectionPromise;\n this._connectionPromise = undefined;\n promise.resolve();\n } else {\n console.warn(\n `ExtensionClientTransport: Received server info but no connection promise pending`\n );\n }\n return;\n }\n\n // Only process other messages if we're connected\n if (!this.isConnected) {\n console.warn('ExtensionClientTransport: Received message while not connected', data);\n return;\n }\n\n // Handle messages after connection established\n if ('type' in data && (data.type === 'mcp-replay-event' || data.type === 'mcp-event')) {\n const eventMsg = data as MCPEventMessage | MCPReplayEventMessage;\n this.lastEventId = eventMsg.eventId;\n if (isJSONRPCMessage(eventMsg.message)) {\n this.onmessage?.(eventMsg.message);\n } else {\n const message = JSONRPCMessageSchema.parse(eventMsg.message);\n this.onmessage?.(message);\n }\n } else if (isJSONRPCMessage(data)) {\n // Check if it's a direct JSONRPCMessage\n this.onmessage?.(data);\n } else {\n console.warn('ExtensionClientTransport received unknown message type:', data);\n }\n } catch (err) {\n const error = err as Error;\n console.error(\n 'Error processing message in ExtensionClientTransport:',\n error,\n 'Data:',\n data\n );\n this.onerror?.(error);\n }\n });\n }\n\n async start(): Promise<void> {\n if (this._startPromise) {\n console.warn(\n 'ExtensionClientTransport already started, returning existing connection promise'\n );\n return this._startPromise;\n }\n\n if (this._abortController) {\n console.warn('ExtensionClientTransport already started!');\n // If we have an abort controller but no start promise, we're in an inconsistent state\n // Return a resolved promise if connected, otherwise create a new connection\n if (this.isConnected) {\n return Promise.resolve();\n }\n }\n\n this._abortController = new AbortController();\n this._startPromise = this._connectWithRetry().finally(() => {\n // Clear the start promise once connection attempt completes (success or failure)\n this._startPromise = undefined;\n });\n\n return this._startPromise;\n }\n\n private async _connectWithRetry(resumptionToken?: EventId): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n this._connectionPromise = { resolve, reject };\n let handshakeTimer: ReturnType<typeof setTimeout>;\n\n const signal = this._abortController?.signal;\n if (signal?.aborted) {\n return reject(new Error('Connection aborted'));\n }\n\n console.log(\n `ExtensionClientTransport: Starting connection for client ${this.clientId}`,\n resumptionToken ? `with resumption token ${resumptionToken}` : 'without resumption token'\n );\n\n // Message handler is already set up in constructor\n\n const connectOptions: MCPConnectOptions | undefined = resumptionToken\n ? { resumeFrom: resumptionToken }\n : undefined;\n\n console.log(\n `ExtensionClientTransport: Sending connect command for client ${this.clientId}`,\n connectOptions\n );\n this.bridge.connect(this.clientId, connectOptions);\n\n handshakeTimer = setTimeout(() => {\n if (!this.isConnected && this._connectionPromise) {\n const error = new Error(\n `ExtensionClientTransport: Server handshake timeout for client ${this.clientId}`\n );\n this._handleConnectionError(error, resumptionToken);\n }\n }, this._connectionTimeout);\n\n // Store handshake timer reference so it can be cleared when connection succeeds\n const originalResolve = this._connectionPromise.resolve;\n this._connectionPromise.resolve = () => {\n if (handshakeTimer) clearTimeout(handshakeTimer);\n originalResolve();\n };\n\n signal?.addEventListener('abort', () => {\n if (handshakeTimer) clearTimeout(handshakeTimer);\n // If connectionPromise still exists, it means we haven't resolved/rejected it yet.\n if (this._connectionPromise) {\n this._connectionPromise.reject(new Error('Connection aborted during handshake'));\n this._connectionPromise = undefined;\n }\n });\n });\n }\n\n private _handleConnectionError(error: Error, resumptionToken?: EventId): void {\n this.onerror?.(error);\n this.isConnected = false; // Ensure disconnected state\n\n if (this._connectionPromise) {\n this._connectionPromise.reject(error);\n this._connectionPromise = undefined;\n }\n\n // Attempt reconnection if appropriate (not aborted and lastEventId exists for resumption)\n const shouldRetry =\n this._abortController &&\n !this._abortController.signal.aborted &&\n (resumptionToken || this.lastEventId) && // Need a token to resume\n this._reconnectionOptions.maxRetries > 0 &&\n this._reconnectAttempt < this._reconnectionOptions.maxRetries;\n\n if (shouldRetry) {\n this._scheduleReconnection(resumptionToken || this.lastEventId!);\n } else {\n // If no retry, call onclose if it was previously connected or trying to connect\n // This prevents calling onclose if start() was never called or already closed.\n if (this._abortController) {\n // Check if connection process was initiated\n this.onclose?.();\n // Clean up abort controller as we are fully stopping\n this._abortController = undefined;\n }\n }\n }\n\n private _getNextReconnectionDelay(attempt: number): number {\n const { initialReconnectionDelay, maxReconnectionDelay, reconnectionDelayGrowFactor } =\n this._reconnectionOptions;\n return Math.min(\n initialReconnectionDelay * Math.pow(reconnectionDelayGrowFactor, attempt),\n maxReconnectionDelay\n );\n }\n\n private _scheduleReconnection(tokenToResume: EventId): void {\n const delay = this._getNextReconnectionDelay(this._reconnectAttempt);\n this._reconnectAttempt++;\n\n console.log(\n `ExtensionClientTransport: Scheduling reconnection attempt ${this._reconnectAttempt} in ${delay}ms`\n );\n\n setTimeout(() => {\n if (this._abortController?.signal.aborted) {\n console.log('ExtensionClientTransport: Reconnection aborted.');\n return;\n }\n console.log(\n `ExtensionClientTransport: Attempting reconnection (attempt ${this._reconnectAttempt})`\n );\n this._connectWithRetry(tokenToResume).catch((err) => {\n // Error during a scheduled reconnection attempt is handled by _handleConnectionError within that attempt.\n // We log it here for visibility, but _handleConnectionError will decide on further retries or final close.\n console.error(`ExtensionClientTransport: Scheduled reconnection attempt failed:`, err);\n // If _handleConnectionError doesn't schedule another retry, it will call onclose.\n });\n }, delay);\n }\n\n async send(message: JSONRPCMessage, _?: TransportSendOptions): Promise<void> {\n // options?.resumptionToken and options?.onresumptiontoken are not directly applicable here\n // as the extension bridge manages its own event stream concept via lastEventId internally.\n\n // If there's a start promise pending, wait for it\n if (this._startPromise) {\n console.log('ExtensionClientTransport: Waiting for initial connection before send.');\n try {\n await this._startPromise;\n } catch (err) {\n const error = new Error(\n `ExtensionClientTransport: Failed to establish initial connection: ${err instanceof Error ? err.message : String(err)}`\n );\n this.onerror?.(error);\n throw error;\n }\n }\n\n if (!this.isConnected) {\n const canAttemptReconnect =\n this._reconnectionOptions.maxRetries > 0 &&\n this.lastEventId &&\n this._abortController &&\n !this._abortController.signal.aborted;\n if (canAttemptReconnect) {\n console.log(\n 'ExtensionClientTransport: Not connected. Attempting auto-reconnect before send.'\n );\n try {\n await this._connectWithRetry(this.lastEventId);\n } catch (err) {\n const reconErr = new Error(\n `ExtensionClientTransport: Failed to auto-reconnect before send: ${err instanceof Error ? err.message : String(err)}`\n );\n this.onerror?.(reconErr);\n throw reconErr; // Propagate error if reconnection fails\n }\n if (!this.isConnected) {\n throw new Error(\n 'ExtensionClientTransport: Not connected after attempting auto-reconnection.'\n );\n }\n } else {\n throw new Error('ExtensionClientTransport: Not connected and cannot auto-reconnect.');\n }\n }\n this.bridge.send(this.clientId, message);\n }\n\n async close(): Promise<void> {\n if (this._abortController) {\n this._abortController.abort();\n this._abortController = undefined; // Clear it as we are now closed\n }\n\n if (this._connectionPromise) {\n this._connectionPromise.reject(\n new Error('ExtensionClientTransport: Transport closed by client.')\n );\n this._connectionPromise = undefined;\n }\n\n // Clear any pending start promise\n this._startPromise = undefined;\n\n // Future: If bridge supported explicit disconnect message:\n // if (this.isConnected) { // Or even if not, to clean up server-side if client ID is known\n // this.bridge.disconnect(this.clientId); // This would need to be added to UIBridge and handled by background\n // }\n\n this.isConnected = false;\n // Only call onclose if it hasn't been called by _handleConnectionError already\n // However, a direct call to close() should always trigger onclose if not already closed.\n // The _abortController being undefined (set by _handleConnectionError on final failure or here on direct close)\n // can be a guard. If _handleConnectionError already cleaned up, onclose was called.\n // For simplicity now: always call onclose, assuming it handles multiple calls gracefully or is only set once.\n this.onclose?.();\n }\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mcp-b/transports",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Transports for the in browser transport protocols",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "mcp-b Team",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/alxnahas/mcp-b.git",
|
|
10
|
+
"directory": "packages/mcp-b"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/alxnahas/mcp-b#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/alxnahas/mcp-b/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"mcp",
|
|
18
|
+
"model-context-protocol",
|
|
19
|
+
"browser",
|
|
20
|
+
"transport",
|
|
21
|
+
"browser-extension",
|
|
22
|
+
"tab-transport",
|
|
23
|
+
"chrome-extension"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "./dist/index.js",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"import": "./dist/index.js",
|
|
30
|
+
"types": "./dist/index.d.ts"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsup",
|
|
38
|
+
"dev": "tsup --watch",
|
|
39
|
+
"typecheck": "tsc --noEmit",
|
|
40
|
+
"clean": "rm -rf dist .turbo"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@modelcontextprotocol/sdk": "^1.12.1"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/react": "catalog:",
|
|
48
|
+
"@types/node": "catalog:",
|
|
49
|
+
"tsup": "catalog:",
|
|
50
|
+
"typescript": "catalog:",
|
|
51
|
+
"@types/chrome": "^0.0.326"
|
|
52
|
+
},
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "public",
|
|
55
|
+
"registry": "https://registry.npmjs.org/"
|
|
56
|
+
}
|
|
57
|
+
}
|