@mcp-b/webmcp-local-relay 0.0.0-beta-20260225101008
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 +193 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +74 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +314 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/mcpRelayServer-BwF1i7Se.js +583 -0
- package/dist/mcpRelayServer-BwF1i7Se.js.map +1 -0
- package/package.json +73 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 mcp-b contributors
|
|
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,193 @@
|
|
|
1
|
+
# @mcp-b/webmcp-local-relay
|
|
2
|
+
|
|
3
|
+
Local MCP relay for browser WebMCP tools.
|
|
4
|
+
|
|
5
|
+
This package lets an MCP client (Claude Code, Cursor, etc.) call tools from websites you currently have open, via a localhost bridge.
|
|
6
|
+
|
|
7
|
+
## Requirement: WebMCP Runtime On The Page
|
|
8
|
+
|
|
9
|
+
Relay only forwards tools that are registered on `navigator.modelContext`.
|
|
10
|
+
|
|
11
|
+
A connected page must install one of:
|
|
12
|
+
|
|
13
|
+
1. `@mcp-b/global` (recommended).
|
|
14
|
+
2. `@mcp-b/webmcp-polyfill` (strict core), with `navigator.modelContextTesting` available (default in the polyfill).
|
|
15
|
+
|
|
16
|
+
Runtime dispatch behavior:
|
|
17
|
+
|
|
18
|
+
- If `navigator.modelContext.listTools` + `navigator.modelContext.callTool` exist, relay uses that extension path.
|
|
19
|
+
- Otherwise, relay uses `navigator.modelContextTesting.listTools` + `executeTool`.
|
|
20
|
+
|
|
21
|
+
## Users First: Install In Claude Code (Plugin)
|
|
22
|
+
|
|
23
|
+
Recommended path: install the plugin in Claude Code, then use the relayed tools directly.
|
|
24
|
+
|
|
25
|
+
1. Clone this repository locally.
|
|
26
|
+
2. In Claude Code, run:
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
/plugin add /absolute/path/to/npm-packages/packages/webmcp-local-relay/.claude-plugin
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Optional scope flag:
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
/plugin add /absolute/path/to/npm-packages/packages/webmcp-local-relay/.claude-plugin --scope user
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
3. Confirm installation:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
/plugin list
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
4. Start using the relay:
|
|
45
|
+
- Ask Claude to run `webmcp_list_sources`.
|
|
46
|
+
- Ask Claude to run `webmcp_list_tools`.
|
|
47
|
+
- Call the returned `webmcp_*` tools.
|
|
48
|
+
|
|
49
|
+
Plugin manifest:
|
|
50
|
+
- [`./.claude-plugin/plugin.json`](./.claude-plugin/plugin.json)
|
|
51
|
+
|
|
52
|
+
Skill included in the plugin:
|
|
53
|
+
- [`./.claude-plugin/skills/webmcp-local-relay/SKILL.md`](./.claude-plugin/skills/webmcp-local-relay/SKILL.md)
|
|
54
|
+
|
|
55
|
+
## Claude Code Section: Plugin + Skill Behavior
|
|
56
|
+
|
|
57
|
+
The plugin wires two things:
|
|
58
|
+
|
|
59
|
+
1. MCP server registration:
|
|
60
|
+
- Starts `@mcp-b/webmcp-local-relay` via `npx`.
|
|
61
|
+
2. Skill registration:
|
|
62
|
+
- Provides a focused skill that tells the agent how to discover sources/tools and route calls safely.
|
|
63
|
+
|
|
64
|
+
The skill guidance is intentionally operational:
|
|
65
|
+
- list sources first
|
|
66
|
+
- list tools second
|
|
67
|
+
- pick the right domain/tab
|
|
68
|
+
- re-list tools if the browser session changes
|
|
69
|
+
|
|
70
|
+
## Reference Docs (Deep Dive Sources)
|
|
71
|
+
|
|
72
|
+
- Claude Code plugin creation:
|
|
73
|
+
- https://docs.anthropic.com/en/docs/claude-code/plugins/create-plugins
|
|
74
|
+
- Claude Code plugin schema and plugin marketplace reference:
|
|
75
|
+
- https://docs.anthropic.com/en/docs/claude-code/plugins/plugins-reference
|
|
76
|
+
- Claude Code plugin discovery and install commands:
|
|
77
|
+
- https://docs.anthropic.com/en/docs/claude-code/plugins/discover-plugins
|
|
78
|
+
- Claude Code skill system:
|
|
79
|
+
- https://docs.anthropic.com/en/docs/claude-code/skills
|
|
80
|
+
- Agent Skills ecosystem project:
|
|
81
|
+
- https://github.com/agentskills/agent-skills
|
|
82
|
+
|
|
83
|
+
## Website Owner Setup
|
|
84
|
+
|
|
85
|
+
Your page should load an embed script that injects a hidden widget iframe.
|
|
86
|
+
|
|
87
|
+
```html
|
|
88
|
+
<script src="https://yourdomain.example/embed.js"></script>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Minimal `embed.js` pattern:
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
(() => {
|
|
95
|
+
const iframe = document.createElement('iframe');
|
|
96
|
+
iframe.src = 'https://yourdomain.example/widget';
|
|
97
|
+
iframe.style.display = 'none';
|
|
98
|
+
iframe.setAttribute('aria-hidden', 'true');
|
|
99
|
+
document.body.appendChild(iframe);
|
|
100
|
+
})();
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Your page must also register tools using one of the supported WebMCP runtimes.
|
|
104
|
+
|
|
105
|
+
Example (recommended) with `@mcp-b/global`:
|
|
106
|
+
|
|
107
|
+
```html
|
|
108
|
+
<script src="https://cdn.jsdelivr.net/npm/@mcp-b/global@latest/dist/index.iife.js"></script>
|
|
109
|
+
<script>
|
|
110
|
+
navigator.modelContext.registerTool({
|
|
111
|
+
name: 'get_page_title',
|
|
112
|
+
description: 'Get page title',
|
|
113
|
+
inputSchema: { type: 'object', properties: {} },
|
|
114
|
+
execute: async () => ({ content: [{ type: 'text', text: document.title }] }),
|
|
115
|
+
});
|
|
116
|
+
</script>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Example with strict `@mcp-b/webmcp-polyfill`:
|
|
120
|
+
|
|
121
|
+
```html
|
|
122
|
+
<script src="https://cdn.jsdelivr.net/npm/@mcp-b/webmcp-polyfill@latest/dist/index.iife.js"></script>
|
|
123
|
+
<script>
|
|
124
|
+
navigator.modelContext.registerTool({
|
|
125
|
+
name: 'get_page_title',
|
|
126
|
+
description: 'Get page title',
|
|
127
|
+
inputSchema: { type: 'object', properties: {} },
|
|
128
|
+
execute: async () => ({ content: [{ type: 'text', text: document.title }] }),
|
|
129
|
+
});
|
|
130
|
+
</script>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Widget responsibilities:
|
|
134
|
+
- Connect to `ws://127.0.0.1:9333` (or your configured relay port).
|
|
135
|
+
- Send source metadata (`hello`) and current tool list (`tools/list`).
|
|
136
|
+
- Handle `invoke` messages and return `result`.
|
|
137
|
+
- Reconnect automatically when the local relay starts later.
|
|
138
|
+
|
|
139
|
+
Security baseline:
|
|
140
|
+
- Run relay on loopback only (`127.0.0.1`).
|
|
141
|
+
- Restrict `--widget-origin` to your widget origin in production.
|
|
142
|
+
|
|
143
|
+
## User Setup Without Plugin (Fallback)
|
|
144
|
+
|
|
145
|
+
If you do not want plugin install, add the MCP server directly:
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"mcpServers": {
|
|
150
|
+
"webmcp-local-relay": {
|
|
151
|
+
"command": "npx",
|
|
152
|
+
"args": ["-y", "@mcp-b/webmcp-local-relay@latest"]
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Then restart Claude Code and call:
|
|
159
|
+
- `webmcp_list_sources`
|
|
160
|
+
- `webmcp_list_tools`
|
|
161
|
+
|
|
162
|
+
## Developer Setup
|
|
163
|
+
|
|
164
|
+
From repository root:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
pnpm install
|
|
168
|
+
pnpm --filter @mcp-b/webmcp-local-relay build
|
|
169
|
+
pnpm --filter @mcp-b/webmcp-local-relay test
|
|
170
|
+
pnpm --filter @mcp-b/webmcp-local-relay test:e2e
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Run relay locally:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
node packages/webmcp-local-relay/dist/cli.js --host 127.0.0.1 --port 9333
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Lock widget origin while developing:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
node packages/webmcp-local-relay/dist/cli.js --host 127.0.0.1 --port 9333 --widget-origin https://your-widget-domain.example
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Tooling Model
|
|
186
|
+
|
|
187
|
+
Static tools:
|
|
188
|
+
- `webmcp_list_sources`
|
|
189
|
+
- `webmcp_list_tools`
|
|
190
|
+
|
|
191
|
+
Dynamic tools:
|
|
192
|
+
- registered from browser sources
|
|
193
|
+
- deterministic namespaced IDs for de-duping across tabs and domains
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { t as LocalRelayMcpServer } from "./mcpRelayServer-BwF1i7Se.js";
|
|
3
|
+
|
|
4
|
+
//#region src/cli.ts
|
|
5
|
+
function parseCliOptions(argv) {
|
|
6
|
+
const options$1 = {
|
|
7
|
+
host: "127.0.0.1",
|
|
8
|
+
port: 9333,
|
|
9
|
+
allowedOrigins: ["*"]
|
|
10
|
+
};
|
|
11
|
+
for (let i = 0; i < argv.length; i++) {
|
|
12
|
+
const token = argv[i];
|
|
13
|
+
if (!token) continue;
|
|
14
|
+
if ((token === "--host" || token === "-h") && argv[i + 1]) {
|
|
15
|
+
options$1.host = argv[++i];
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if ((token === "--port" || token === "-p") && argv[i + 1]) {
|
|
19
|
+
const value = Number.parseInt(argv[++i], 10);
|
|
20
|
+
if (Number.isFinite(value) && value > 0 && value <= 65535) options$1.port = value;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if ((token === "--widget-origin" || token === "--allowed-origin") && argv[i + 1]) {
|
|
24
|
+
const split = argv[++i].split(",").map((part) => part.trim()).filter(Boolean);
|
|
25
|
+
if (split.length > 0) options$1.allowedOrigins = split;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (token === "--help" || token === "-?") {
|
|
29
|
+
printHelp();
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return options$1;
|
|
34
|
+
}
|
|
35
|
+
function printHelp() {
|
|
36
|
+
process.stderr.write([
|
|
37
|
+
"webmcp-local-relay",
|
|
38
|
+
"",
|
|
39
|
+
"Usage:",
|
|
40
|
+
" webmcp-local-relay [--host 127.0.0.1] [--port 9333] [--widget-origin https://yourdomain.com]",
|
|
41
|
+
"",
|
|
42
|
+
"Options:",
|
|
43
|
+
" --host, -h Bind host for local websocket relay (default: 127.0.0.1)",
|
|
44
|
+
" --port, -p Bind port for local websocket relay (default: 9333)",
|
|
45
|
+
" --widget-origin Allowed browser origin(s), comma-separated (default: *)",
|
|
46
|
+
" --allowed-origin Alias for --widget-origin",
|
|
47
|
+
" --help, -? Show help",
|
|
48
|
+
""
|
|
49
|
+
].join("\n"));
|
|
50
|
+
}
|
|
51
|
+
const options = parseCliOptions(process.argv.slice(2));
|
|
52
|
+
const relay = new LocalRelayMcpServer({ bridgeOptions: {
|
|
53
|
+
host: options.host,
|
|
54
|
+
port: options.port,
|
|
55
|
+
allowedOrigins: options.allowedOrigins
|
|
56
|
+
} });
|
|
57
|
+
await relay.start();
|
|
58
|
+
await relay.startStdio();
|
|
59
|
+
process.stderr.write(`[webmcp-local-relay] listening on ws://${options.host}:${relay.bridge.port} (allowed origins: ${options.allowedOrigins.join(", ")})\n`);
|
|
60
|
+
const shutdown = async (signal) => {
|
|
61
|
+
process.stderr.write(`[webmcp-local-relay] received ${signal}, shutting down\n`);
|
|
62
|
+
await relay.stop();
|
|
63
|
+
process.exit(0);
|
|
64
|
+
};
|
|
65
|
+
process.on("SIGINT", () => {
|
|
66
|
+
shutdown("SIGINT");
|
|
67
|
+
});
|
|
68
|
+
process.on("SIGTERM", () => {
|
|
69
|
+
shutdown("SIGTERM");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
//#endregion
|
|
73
|
+
export { };
|
|
74
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","names":["options: CliOptions","options"],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { LocalRelayMcpServer } from './mcpRelayServer.js';\n\ninterface CliOptions {\n host: string;\n port: number;\n allowedOrigins: string[];\n}\n\nfunction parseCliOptions(argv: string[]): CliOptions {\n const options: CliOptions = {\n host: '127.0.0.1',\n port: 9333,\n allowedOrigins: ['*'],\n };\n\n for (let i = 0; i < argv.length; i++) {\n const token = argv[i];\n if (!token) continue;\n\n if ((token === '--host' || token === '-h') && argv[i + 1]) {\n options.host = argv[++i] as string;\n continue;\n }\n\n if ((token === '--port' || token === '-p') && argv[i + 1]) {\n const value = Number.parseInt(argv[++i] as string, 10);\n if (Number.isFinite(value) && value > 0 && value <= 65535) {\n options.port = value;\n }\n continue;\n }\n\n if ((token === '--widget-origin' || token === '--allowed-origin') && argv[i + 1]) {\n const raw = argv[++i] as string;\n const split = raw\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean);\n\n if (split.length > 0) {\n options.allowedOrigins = split;\n }\n continue;\n }\n\n if (token === '--help' || token === '-?') {\n printHelp();\n process.exit(0);\n }\n }\n\n return options;\n}\n\nfunction printHelp(): void {\n process.stderr.write(\n [\n 'webmcp-local-relay',\n '',\n 'Usage:',\n ' webmcp-local-relay [--host 127.0.0.1] [--port 9333] [--widget-origin https://yourdomain.com]',\n '',\n 'Options:',\n ' --host, -h Bind host for local websocket relay (default: 127.0.0.1)',\n ' --port, -p Bind port for local websocket relay (default: 9333)',\n ' --widget-origin Allowed browser origin(s), comma-separated (default: *)',\n ' --allowed-origin Alias for --widget-origin',\n ' --help, -? Show help',\n '',\n ].join('\\n')\n );\n}\n\nconst options = parseCliOptions(process.argv.slice(2));\n\nconst relay = new LocalRelayMcpServer({\n bridgeOptions: {\n host: options.host,\n port: options.port,\n allowedOrigins: options.allowedOrigins,\n },\n});\n\nawait relay.start();\nawait relay.startStdio();\n\nprocess.stderr.write(\n `[webmcp-local-relay] listening on ws://${options.host}:${relay.bridge.port} (allowed origins: ${options.allowedOrigins.join(', ')})\\n`\n);\n\nconst shutdown = async (signal: string) => {\n process.stderr.write(`[webmcp-local-relay] received ${signal}, shutting down\\n`);\n await relay.stop();\n process.exit(0);\n};\n\nprocess.on('SIGINT', () => {\n void shutdown('SIGINT');\n});\nprocess.on('SIGTERM', () => {\n void shutdown('SIGTERM');\n});\n"],"mappings":";;;;AAUA,SAAS,gBAAgB,MAA4B;CACnD,MAAMA,YAAsB;EAC1B,MAAM;EACN,MAAM;EACN,gBAAgB,CAAC,IAAI;EACtB;AAED,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,QAAQ,KAAK;AACnB,MAAI,CAAC,MAAO;AAEZ,OAAK,UAAU,YAAY,UAAU,SAAS,KAAK,IAAI,IAAI;AACzD,aAAQ,OAAO,KAAK,EAAE;AACtB;;AAGF,OAAK,UAAU,YAAY,UAAU,SAAS,KAAK,IAAI,IAAI;GACzD,MAAM,QAAQ,OAAO,SAAS,KAAK,EAAE,IAAc,GAAG;AACtD,OAAI,OAAO,SAAS,MAAM,IAAI,QAAQ,KAAK,SAAS,MAClD,WAAQ,OAAO;AAEjB;;AAGF,OAAK,UAAU,qBAAqB,UAAU,uBAAuB,KAAK,IAAI,IAAI;GAEhF,MAAM,QADM,KAAK,EAAE,GAEhB,MAAM,IAAI,CACV,KAAK,SAAS,KAAK,MAAM,CAAC,CAC1B,OAAO,QAAQ;AAElB,OAAI,MAAM,SAAS,EACjB,WAAQ,iBAAiB;AAE3B;;AAGF,MAAI,UAAU,YAAY,UAAU,MAAM;AACxC,cAAW;AACX,WAAQ,KAAK,EAAE;;;AAInB,QAAOC;;AAGT,SAAS,YAAkB;AACzB,SAAQ,OAAO,MACb;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,KAAK,KAAK,CACb;;AAGH,MAAM,UAAU,gBAAgB,QAAQ,KAAK,MAAM,EAAE,CAAC;AAEtD,MAAM,QAAQ,IAAI,oBAAoB,EACpC,eAAe;CACb,MAAM,QAAQ;CACd,MAAM,QAAQ;CACd,gBAAgB,QAAQ;CACzB,EACF,CAAC;AAEF,MAAM,MAAM,OAAO;AACnB,MAAM,MAAM,YAAY;AAExB,QAAQ,OAAO,MACb,0CAA0C,QAAQ,KAAK,GAAG,MAAM,OAAO,KAAK,qBAAqB,QAAQ,eAAe,KAAK,KAAK,CAAC,KACpI;AAED,MAAM,WAAW,OAAO,WAAmB;AACzC,SAAQ,OAAO,MAAM,iCAAiC,OAAO,mBAAmB;AAChF,OAAM,MAAM,MAAM;AAClB,SAAQ,KAAK,EAAE;;AAGjB,QAAQ,GAAG,gBAAgB;AACzB,CAAK,SAAS,SAAS;EACvB;AACF,QAAQ,GAAG,iBAAiB;AAC1B,CAAK,SAAS,UAAU;EACxB"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { EventEmitter } from "node:events";
|
|
3
|
+
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
5
|
+
|
|
6
|
+
//#region src/schemas.d.ts
|
|
7
|
+
declare const BrowserToolSchema: z.ZodObject<{
|
|
8
|
+
name: z.ZodString;
|
|
9
|
+
description: z.ZodOptional<z.ZodString>;
|
|
10
|
+
inputSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
11
|
+
outputSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
12
|
+
annotations: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
13
|
+
}, "strip", z.ZodTypeAny, {
|
|
14
|
+
name: string;
|
|
15
|
+
description?: string | undefined;
|
|
16
|
+
inputSchema?: Record<string, unknown> | undefined;
|
|
17
|
+
outputSchema?: Record<string, unknown> | undefined;
|
|
18
|
+
annotations?: Record<string, unknown> | undefined;
|
|
19
|
+
}, {
|
|
20
|
+
name: string;
|
|
21
|
+
description?: string | undefined;
|
|
22
|
+
inputSchema?: Record<string, unknown> | undefined;
|
|
23
|
+
outputSchema?: Record<string, unknown> | undefined;
|
|
24
|
+
annotations?: Record<string, unknown> | undefined;
|
|
25
|
+
}>;
|
|
26
|
+
declare const BrowserHelloMessageSchema: z.ZodObject<{
|
|
27
|
+
type: z.ZodLiteral<"hello">;
|
|
28
|
+
tabId: z.ZodString;
|
|
29
|
+
origin: z.ZodOptional<z.ZodString>;
|
|
30
|
+
url: z.ZodOptional<z.ZodString>;
|
|
31
|
+
title: z.ZodOptional<z.ZodString>;
|
|
32
|
+
iconUrl: z.ZodOptional<z.ZodString>;
|
|
33
|
+
}, "strip", z.ZodTypeAny, {
|
|
34
|
+
type: "hello";
|
|
35
|
+
tabId: string;
|
|
36
|
+
origin?: string | undefined;
|
|
37
|
+
url?: string | undefined;
|
|
38
|
+
title?: string | undefined;
|
|
39
|
+
iconUrl?: string | undefined;
|
|
40
|
+
}, {
|
|
41
|
+
type: "hello";
|
|
42
|
+
tabId: string;
|
|
43
|
+
origin?: string | undefined;
|
|
44
|
+
url?: string | undefined;
|
|
45
|
+
title?: string | undefined;
|
|
46
|
+
iconUrl?: string | undefined;
|
|
47
|
+
}>;
|
|
48
|
+
declare const BrowserToRelayMessageSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
49
|
+
type: z.ZodLiteral<"hello">;
|
|
50
|
+
tabId: z.ZodString;
|
|
51
|
+
origin: z.ZodOptional<z.ZodString>;
|
|
52
|
+
url: z.ZodOptional<z.ZodString>;
|
|
53
|
+
title: z.ZodOptional<z.ZodString>;
|
|
54
|
+
iconUrl: z.ZodOptional<z.ZodString>;
|
|
55
|
+
}, "strip", z.ZodTypeAny, {
|
|
56
|
+
type: "hello";
|
|
57
|
+
tabId: string;
|
|
58
|
+
origin?: string | undefined;
|
|
59
|
+
url?: string | undefined;
|
|
60
|
+
title?: string | undefined;
|
|
61
|
+
iconUrl?: string | undefined;
|
|
62
|
+
}, {
|
|
63
|
+
type: "hello";
|
|
64
|
+
tabId: string;
|
|
65
|
+
origin?: string | undefined;
|
|
66
|
+
url?: string | undefined;
|
|
67
|
+
title?: string | undefined;
|
|
68
|
+
iconUrl?: string | undefined;
|
|
69
|
+
}>, z.ZodObject<{
|
|
70
|
+
type: z.ZodLiteral<"tools/list">;
|
|
71
|
+
tools: z.ZodArray<z.ZodObject<{
|
|
72
|
+
name: z.ZodString;
|
|
73
|
+
description: z.ZodOptional<z.ZodString>;
|
|
74
|
+
inputSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
75
|
+
outputSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
76
|
+
annotations: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
77
|
+
}, "strip", z.ZodTypeAny, {
|
|
78
|
+
name: string;
|
|
79
|
+
description?: string | undefined;
|
|
80
|
+
inputSchema?: Record<string, unknown> | undefined;
|
|
81
|
+
outputSchema?: Record<string, unknown> | undefined;
|
|
82
|
+
annotations?: Record<string, unknown> | undefined;
|
|
83
|
+
}, {
|
|
84
|
+
name: string;
|
|
85
|
+
description?: string | undefined;
|
|
86
|
+
inputSchema?: Record<string, unknown> | undefined;
|
|
87
|
+
outputSchema?: Record<string, unknown> | undefined;
|
|
88
|
+
annotations?: Record<string, unknown> | undefined;
|
|
89
|
+
}>, "many">;
|
|
90
|
+
}, "strip", z.ZodTypeAny, {
|
|
91
|
+
type: "tools/list";
|
|
92
|
+
tools: {
|
|
93
|
+
name: string;
|
|
94
|
+
description?: string | undefined;
|
|
95
|
+
inputSchema?: Record<string, unknown> | undefined;
|
|
96
|
+
outputSchema?: Record<string, unknown> | undefined;
|
|
97
|
+
annotations?: Record<string, unknown> | undefined;
|
|
98
|
+
}[];
|
|
99
|
+
}, {
|
|
100
|
+
type: "tools/list";
|
|
101
|
+
tools: {
|
|
102
|
+
name: string;
|
|
103
|
+
description?: string | undefined;
|
|
104
|
+
inputSchema?: Record<string, unknown> | undefined;
|
|
105
|
+
outputSchema?: Record<string, unknown> | undefined;
|
|
106
|
+
annotations?: Record<string, unknown> | undefined;
|
|
107
|
+
}[];
|
|
108
|
+
}>, z.ZodObject<{
|
|
109
|
+
type: z.ZodLiteral<"tools/changed">;
|
|
110
|
+
tools: z.ZodArray<z.ZodObject<{
|
|
111
|
+
name: z.ZodString;
|
|
112
|
+
description: z.ZodOptional<z.ZodString>;
|
|
113
|
+
inputSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
114
|
+
outputSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
115
|
+
annotations: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
116
|
+
}, "strip", z.ZodTypeAny, {
|
|
117
|
+
name: string;
|
|
118
|
+
description?: string | undefined;
|
|
119
|
+
inputSchema?: Record<string, unknown> | undefined;
|
|
120
|
+
outputSchema?: Record<string, unknown> | undefined;
|
|
121
|
+
annotations?: Record<string, unknown> | undefined;
|
|
122
|
+
}, {
|
|
123
|
+
name: string;
|
|
124
|
+
description?: string | undefined;
|
|
125
|
+
inputSchema?: Record<string, unknown> | undefined;
|
|
126
|
+
outputSchema?: Record<string, unknown> | undefined;
|
|
127
|
+
annotations?: Record<string, unknown> | undefined;
|
|
128
|
+
}>, "many">;
|
|
129
|
+
}, "strip", z.ZodTypeAny, {
|
|
130
|
+
type: "tools/changed";
|
|
131
|
+
tools: {
|
|
132
|
+
name: string;
|
|
133
|
+
description?: string | undefined;
|
|
134
|
+
inputSchema?: Record<string, unknown> | undefined;
|
|
135
|
+
outputSchema?: Record<string, unknown> | undefined;
|
|
136
|
+
annotations?: Record<string, unknown> | undefined;
|
|
137
|
+
}[];
|
|
138
|
+
}, {
|
|
139
|
+
type: "tools/changed";
|
|
140
|
+
tools: {
|
|
141
|
+
name: string;
|
|
142
|
+
description?: string | undefined;
|
|
143
|
+
inputSchema?: Record<string, unknown> | undefined;
|
|
144
|
+
outputSchema?: Record<string, unknown> | undefined;
|
|
145
|
+
annotations?: Record<string, unknown> | undefined;
|
|
146
|
+
}[];
|
|
147
|
+
}>, z.ZodObject<{
|
|
148
|
+
type: z.ZodLiteral<"result">;
|
|
149
|
+
callId: z.ZodString;
|
|
150
|
+
result: z.ZodUnknown;
|
|
151
|
+
}, "strip", z.ZodTypeAny, {
|
|
152
|
+
type: "result";
|
|
153
|
+
callId: string;
|
|
154
|
+
result?: unknown;
|
|
155
|
+
}, {
|
|
156
|
+
type: "result";
|
|
157
|
+
callId: string;
|
|
158
|
+
result?: unknown;
|
|
159
|
+
}>, z.ZodObject<{
|
|
160
|
+
type: z.ZodLiteral<"pong">;
|
|
161
|
+
}, "strip", z.ZodTypeAny, {
|
|
162
|
+
type: "pong";
|
|
163
|
+
}, {
|
|
164
|
+
type: "pong";
|
|
165
|
+
}>]>;
|
|
166
|
+
type BrowserToRelayMessage = z.infer<typeof BrowserToRelayMessageSchema>;
|
|
167
|
+
type BrowserTool = z.infer<typeof BrowserToolSchema>;
|
|
168
|
+
type BrowserHelloMessage = z.infer<typeof BrowserHelloMessageSchema>;
|
|
169
|
+
declare const RelayToBrowserMessageSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
170
|
+
type: z.ZodLiteral<"invoke">;
|
|
171
|
+
callId: z.ZodString;
|
|
172
|
+
toolName: z.ZodString;
|
|
173
|
+
args: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
174
|
+
}, "strip", z.ZodTypeAny, {
|
|
175
|
+
type: "invoke";
|
|
176
|
+
callId: string;
|
|
177
|
+
toolName: string;
|
|
178
|
+
args?: Record<string, unknown> | undefined;
|
|
179
|
+
}, {
|
|
180
|
+
type: "invoke";
|
|
181
|
+
callId: string;
|
|
182
|
+
toolName: string;
|
|
183
|
+
args?: Record<string, unknown> | undefined;
|
|
184
|
+
}>, z.ZodObject<{
|
|
185
|
+
type: z.ZodLiteral<"ping">;
|
|
186
|
+
}, "strip", z.ZodTypeAny, {
|
|
187
|
+
type: "ping";
|
|
188
|
+
}, {
|
|
189
|
+
type: "ping";
|
|
190
|
+
}>]>;
|
|
191
|
+
type RelayToBrowserMessage = z.infer<typeof RelayToBrowserMessageSchema>;
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/registry.d.ts
|
|
194
|
+
interface SourceInfo {
|
|
195
|
+
sourceId: string;
|
|
196
|
+
tabId: string;
|
|
197
|
+
origin: string | undefined;
|
|
198
|
+
url: string | undefined;
|
|
199
|
+
title: string | undefined;
|
|
200
|
+
iconUrl: string | undefined;
|
|
201
|
+
connectedAt: number;
|
|
202
|
+
lastSeenAt: number;
|
|
203
|
+
toolCount: number;
|
|
204
|
+
}
|
|
205
|
+
interface AggregatedTool {
|
|
206
|
+
name: string;
|
|
207
|
+
originalName: string;
|
|
208
|
+
description: string | undefined;
|
|
209
|
+
inputSchema: Record<string, unknown> | undefined;
|
|
210
|
+
outputSchema: Record<string, unknown> | undefined;
|
|
211
|
+
annotations: Record<string, unknown> | undefined;
|
|
212
|
+
sources: SourceInfo[];
|
|
213
|
+
}
|
|
214
|
+
interface ResolvedInvocation {
|
|
215
|
+
connectionId: string;
|
|
216
|
+
tool: BrowserTool;
|
|
217
|
+
publicToolName: string;
|
|
218
|
+
}
|
|
219
|
+
declare class RelayRegistry {
|
|
220
|
+
private readonly now;
|
|
221
|
+
private readonly sourceByConnectionId;
|
|
222
|
+
private readonly toolsByConnectionId;
|
|
223
|
+
private readonly providersByPublicToolName;
|
|
224
|
+
constructor(now?: () => number);
|
|
225
|
+
upsertSource(connectionId: string, hello: BrowserHelloMessage): void;
|
|
226
|
+
registerTools(connectionId: string, tools: BrowserTool[]): void;
|
|
227
|
+
removeConnection(connectionId: string): void;
|
|
228
|
+
touchConnection(connectionId: string): void;
|
|
229
|
+
listSources(): SourceInfo[];
|
|
230
|
+
listTools(): AggregatedTool[];
|
|
231
|
+
resolveInvocation(options: {
|
|
232
|
+
toolName: string;
|
|
233
|
+
sourceId?: string;
|
|
234
|
+
requestTabId?: string;
|
|
235
|
+
}): ResolvedInvocation | null;
|
|
236
|
+
private removeConnectionTools;
|
|
237
|
+
private sortProvidersByRecency;
|
|
238
|
+
private compareRecency;
|
|
239
|
+
}
|
|
240
|
+
//#endregion
|
|
241
|
+
//#region src/bridgeServer.d.ts
|
|
242
|
+
interface RelayBridgeServerOptions {
|
|
243
|
+
host?: string;
|
|
244
|
+
port?: number;
|
|
245
|
+
allowedOrigins?: string[];
|
|
246
|
+
maxPayloadBytes?: number;
|
|
247
|
+
invokeTimeoutMs?: number;
|
|
248
|
+
}
|
|
249
|
+
declare class RelayBridgeServer extends EventEmitter {
|
|
250
|
+
readonly registry: RelayRegistry;
|
|
251
|
+
private readonly host;
|
|
252
|
+
private desiredPort;
|
|
253
|
+
private readonly allowedOrigins;
|
|
254
|
+
private readonly maxPayloadBytes;
|
|
255
|
+
private readonly invokeTimeoutMs;
|
|
256
|
+
private wss;
|
|
257
|
+
private readonly socketByConnectionId;
|
|
258
|
+
private readonly connectionIdBySocket;
|
|
259
|
+
private readonly pendingInvocations;
|
|
260
|
+
constructor(options?: RelayBridgeServerOptions, registry?: RelayRegistry);
|
|
261
|
+
get port(): number;
|
|
262
|
+
start(): Promise<void>;
|
|
263
|
+
stop(): Promise<void>;
|
|
264
|
+
invokeTool(toolName: string, args: Record<string, unknown>, options?: {
|
|
265
|
+
sourceId?: string;
|
|
266
|
+
requestTabId?: string;
|
|
267
|
+
}): Promise<CallToolResult>;
|
|
268
|
+
private onSocketMessage;
|
|
269
|
+
private onSocketClose;
|
|
270
|
+
private isOriginAllowed;
|
|
271
|
+
private normalizeCallToolResult;
|
|
272
|
+
}
|
|
273
|
+
//#endregion
|
|
274
|
+
//#region src/mcpRelayServer.d.ts
|
|
275
|
+
interface LocalRelayMcpServerOptions {
|
|
276
|
+
bridge?: RelayBridgeServer;
|
|
277
|
+
bridgeOptions?: RelayBridgeServerOptions;
|
|
278
|
+
serverName?: string;
|
|
279
|
+
serverVersion?: string;
|
|
280
|
+
}
|
|
281
|
+
declare class LocalRelayMcpServer {
|
|
282
|
+
readonly bridge: RelayBridgeServer;
|
|
283
|
+
private readonly mcpServer;
|
|
284
|
+
private readonly dynamicToolHandles;
|
|
285
|
+
private readonly dynamicToolSignature;
|
|
286
|
+
private syncing;
|
|
287
|
+
private syncRequested;
|
|
288
|
+
private connected;
|
|
289
|
+
constructor(options?: LocalRelayMcpServerOptions);
|
|
290
|
+
start(): Promise<void>;
|
|
291
|
+
connect(transport: Transport): Promise<void>;
|
|
292
|
+
startStdio(): Promise<void>;
|
|
293
|
+
stop(): Promise<void>;
|
|
294
|
+
listDynamicToolNames(): string[];
|
|
295
|
+
private registerStaticTools;
|
|
296
|
+
private syncDynamicTools;
|
|
297
|
+
private applyDynamicTools;
|
|
298
|
+
private registerDynamicTool;
|
|
299
|
+
private dynamicToolDescription;
|
|
300
|
+
private normalizeAnnotations;
|
|
301
|
+
private toolSignature;
|
|
302
|
+
}
|
|
303
|
+
//#endregion
|
|
304
|
+
//#region src/naming.d.ts
|
|
305
|
+
declare function sanitizeName(value: string): string;
|
|
306
|
+
declare function extractSanitizedDomain(originOrUrl?: string): string;
|
|
307
|
+
declare function buildPublicToolName(options: {
|
|
308
|
+
domain: string;
|
|
309
|
+
tabId: string;
|
|
310
|
+
originalToolName: string;
|
|
311
|
+
}): string;
|
|
312
|
+
//#endregion
|
|
313
|
+
export { type AggregatedTool, type BrowserToRelayMessage, BrowserToRelayMessageSchema, type BrowserTool, LocalRelayMcpServer, type LocalRelayMcpServerOptions, RelayBridgeServer, type RelayBridgeServerOptions, RelayRegistry, type RelayToBrowserMessage, RelayToBrowserMessageSchema, type ResolvedInvocation, type SourceInfo, buildPublicToolName, extractSanitizedDomain, sanitizeName };
|
|
314
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/schemas.ts","../src/registry.ts","../src/bridgeServer.ts","../src/mcpRelayServer.ts","../src/naming.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { a as RelayRegistry, c as sanitizeName, i as RelayToBrowserMessageSchema, n as RelayBridgeServer, o as buildPublicToolName, r as BrowserToRelayMessageSchema, s as extractSanitizedDomain, t as LocalRelayMcpServer } from "./mcpRelayServer-BwF1i7Se.js";
|
|
2
|
+
|
|
3
|
+
export { BrowserToRelayMessageSchema, LocalRelayMcpServer, RelayBridgeServer, RelayRegistry, RelayToBrowserMessageSchema, buildPublicToolName, extractSanitizedDomain, sanitizeName };
|