@webmcp-auto-ui/core 0.5.0 → 2.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +3 -1
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/multi-client.d.ts +7 -3
- package/dist/multi-client.d.ts.map +1 -1
- package/dist/multi-client.js +49 -4
- package/dist/multi-client.js.map +1 -1
- package/dist/utils.d.ts +27 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +136 -3
- package/dist/utils.js.map +1 -1
- package/dist/webmcp-helpers.d.ts +0 -16
- package/dist/webmcp-helpers.d.ts.map +1 -1
- package/dist/webmcp-helpers.js +5 -47
- package/dist/webmcp-helpers.js.map +1 -1
- package/dist/webmcp-server.d.ts +54 -0
- package/dist/webmcp-server.d.ts.map +1 -0
- package/dist/webmcp-server.js +425 -0
- package/dist/webmcp-server.js.map +1 -0
- package/package.json +1 -1
- package/src/client.d.ts +26 -0
- package/src/client.ts +3 -1
- package/src/events.d.ts +16 -0
- package/src/index.d.ts +13 -0
- package/src/index.ts +9 -7
- package/src/multi-client.d.ts +55 -0
- package/src/multi-client.ts +53 -4
- package/src/polyfill.d.ts +51 -0
- package/src/types.d.ts +331 -0
- package/src/utils.d.ts +81 -0
- package/src/utils.ts +163 -0
- package/src/validate.d.ts +13 -0
- package/src/webmcp-helpers.d.ts +3 -0
- package/src/webmcp-helpers.ts +6 -63
- package/src/webmcp-server.d.ts +53 -0
- package/src/webmcp-server.ts +538 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { McpTool, McpToolResult } from './types.js';
|
|
2
|
+
export interface ConnectedServer {
|
|
3
|
+
url: string;
|
|
4
|
+
name: string;
|
|
5
|
+
tools: McpTool[];
|
|
6
|
+
}
|
|
7
|
+
export type AggregatedTool = McpTool & {
|
|
8
|
+
serverUrl: string;
|
|
9
|
+
serverName: string;
|
|
10
|
+
};
|
|
11
|
+
export declare class McpMultiClient {
|
|
12
|
+
/** Ordered map — insertion order determines first-match priority */
|
|
13
|
+
private servers;
|
|
14
|
+
/**
|
|
15
|
+
* Add (or reconnect) an MCP server and return its name + tools.
|
|
16
|
+
* If the URL is already registered, the old connection is removed first.
|
|
17
|
+
*/
|
|
18
|
+
addServer(url: string, options?: {
|
|
19
|
+
headers?: Record<string, string>;
|
|
20
|
+
}): Promise<{
|
|
21
|
+
name: string;
|
|
22
|
+
tools: McpTool[];
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* Remove a server and disconnect its client.
|
|
26
|
+
*/
|
|
27
|
+
removeServer(url: string): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* List all connected servers with their metadata.
|
|
30
|
+
*/
|
|
31
|
+
listServers(): ConnectedServer[];
|
|
32
|
+
/**
|
|
33
|
+
* List ALL tools from ALL connected servers.
|
|
34
|
+
* Each tool is augmented with its origin server URL and name.
|
|
35
|
+
* Duplicate tool names across servers are prefixed with the server name
|
|
36
|
+
* (e.g. "wikipedia__search") to satisfy the Claude API uniqueness constraint.
|
|
37
|
+
*/
|
|
38
|
+
listAllTools(): AggregatedTool[];
|
|
39
|
+
/**
|
|
40
|
+
* Call a tool by name. Automatically routes to the correct server.
|
|
41
|
+
* Supports both plain names ("search") and prefixed names ("wikipedia__search")
|
|
42
|
+
* for disambiguated duplicates.
|
|
43
|
+
*/
|
|
44
|
+
callTool(name: string, args?: Record<string, unknown>): Promise<McpToolResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Disconnect from all servers.
|
|
47
|
+
*/
|
|
48
|
+
disconnectAll(): Promise<void>;
|
|
49
|
+
/** Convert a server name to a snake_case prefix for tool name disambiguation. */
|
|
50
|
+
private normalizeServerName;
|
|
51
|
+
/** Number of connected servers. */
|
|
52
|
+
get serverCount(): number;
|
|
53
|
+
/** True if at least one server is connected. */
|
|
54
|
+
get hasConnections(): boolean;
|
|
55
|
+
}
|
package/src/multi-client.ts
CHANGED
|
@@ -86,29 +86,69 @@ export class McpMultiClient {
|
|
|
86
86
|
/**
|
|
87
87
|
* List ALL tools from ALL connected servers.
|
|
88
88
|
* Each tool is augmented with its origin server URL and name.
|
|
89
|
-
*
|
|
89
|
+
* Duplicate tool names across servers are prefixed with the server name
|
|
90
|
+
* (e.g. "wikipedia__search") to satisfy the Claude API uniqueness constraint.
|
|
90
91
|
*/
|
|
91
92
|
listAllTools(): AggregatedTool[] {
|
|
93
|
+
// First pass: count occurrences of each tool name across all servers
|
|
94
|
+
const nameCounts = new Map<string, number>();
|
|
95
|
+
for (const [, entry] of this.servers) {
|
|
96
|
+
for (const tool of entry.tools) {
|
|
97
|
+
nameCounts.set(tool.name, (nameCounts.get(tool.name) ?? 0) + 1);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Second pass: build result, prefixing duplicates with serverName
|
|
92
102
|
const result: AggregatedTool[] = [];
|
|
93
103
|
for (const [url, entry] of this.servers) {
|
|
94
104
|
for (const tool of entry.tools) {
|
|
95
|
-
|
|
105
|
+
const isDuplicate = (nameCounts.get(tool.name) ?? 0) > 1;
|
|
106
|
+
if (isDuplicate) {
|
|
107
|
+
const prefix = this.normalizeServerName(entry.name);
|
|
108
|
+
result.push({
|
|
109
|
+
...tool,
|
|
110
|
+
name: `${prefix}__${tool.name}`,
|
|
111
|
+
description: `[${entry.name}] ${tool.description ?? ''}`,
|
|
112
|
+
serverUrl: url,
|
|
113
|
+
serverName: entry.name,
|
|
114
|
+
});
|
|
115
|
+
} else {
|
|
116
|
+
result.push({ ...tool, serverUrl: url, serverName: entry.name });
|
|
117
|
+
}
|
|
96
118
|
}
|
|
97
119
|
}
|
|
98
120
|
return result;
|
|
99
121
|
}
|
|
100
122
|
|
|
101
123
|
/**
|
|
102
|
-
* Call a tool by name. Automatically routes to the
|
|
103
|
-
*
|
|
124
|
+
* Call a tool by name. Automatically routes to the correct server.
|
|
125
|
+
* Supports both plain names ("search") and prefixed names ("wikipedia__search")
|
|
126
|
+
* for disambiguated duplicates.
|
|
104
127
|
*/
|
|
105
128
|
async callTool(name: string, args?: Record<string, unknown>): Promise<McpToolResult> {
|
|
129
|
+
// 1. Exact match on original tool name (unprefixed)
|
|
106
130
|
for (const [, entry] of this.servers) {
|
|
107
131
|
const match = entry.tools.find((t) => t.name === name);
|
|
108
132
|
if (match) {
|
|
109
133
|
return entry.client.callTool(name, args);
|
|
110
134
|
}
|
|
111
135
|
}
|
|
136
|
+
|
|
137
|
+
// 2. Prefixed name: "serverprefix__realToolName"
|
|
138
|
+
const separatorIdx = name.indexOf('__');
|
|
139
|
+
if (separatorIdx !== -1) {
|
|
140
|
+
const prefix = name.slice(0, separatorIdx);
|
|
141
|
+
const realName = name.slice(separatorIdx + 2);
|
|
142
|
+
for (const [, entry] of this.servers) {
|
|
143
|
+
if (this.normalizeServerName(entry.name) === prefix) {
|
|
144
|
+
const match = entry.tools.find((t) => t.name === realName);
|
|
145
|
+
if (match) {
|
|
146
|
+
return entry.client.callTool(realName, args);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
112
152
|
throw new Error(`McpMultiClient: no server exposes tool "${name}"`);
|
|
113
153
|
}
|
|
114
154
|
|
|
@@ -124,6 +164,15 @@ export class McpMultiClient {
|
|
|
124
164
|
this.servers.clear();
|
|
125
165
|
}
|
|
126
166
|
|
|
167
|
+
// -------------------------------------------------------------------------
|
|
168
|
+
// Private helpers
|
|
169
|
+
// -------------------------------------------------------------------------
|
|
170
|
+
|
|
171
|
+
/** Convert a server name to a snake_case prefix for tool name disambiguation. */
|
|
172
|
+
private normalizeServerName(name: string): string {
|
|
173
|
+
return name.toLowerCase().replace(/[^a-z0-9_-]+/g, '_').replace(/_{2,}/g, '_').replace(/^_|_$/g, '');
|
|
174
|
+
}
|
|
175
|
+
|
|
127
176
|
// -------------------------------------------------------------------------
|
|
128
177
|
// Getters
|
|
129
178
|
// -------------------------------------------------------------------------
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @webmcp-auto-ui/core — WebMCP Polyfill
|
|
3
|
+
*
|
|
4
|
+
* Implements the 17 MUST HAVE features of the W3C WebMCP Draft CG Report
|
|
5
|
+
* (2026-03-27) plus ecosystem extras.
|
|
6
|
+
*
|
|
7
|
+
* Architecture: module-level state (no class) for tree-shakability.
|
|
8
|
+
* Zero external dependencies.
|
|
9
|
+
*
|
|
10
|
+
* @license AGPL-3.0-or-later
|
|
11
|
+
*/
|
|
12
|
+
import type { ToolExecuteResult, WebMCPPolyfillOptions } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Execute a registered tool by name.
|
|
15
|
+
* Steps:
|
|
16
|
+
* 1. Look up tool in map
|
|
17
|
+
* 2. Validate input against inputSchema (Feature 8)
|
|
18
|
+
* 3. Inject authContext if configured (Extra)
|
|
19
|
+
* 4. Apply confirmation policy if applicable (Extra)
|
|
20
|
+
* 5. Create a ModelContextClient (Feature 6)
|
|
21
|
+
* 6. Call execute(input, client)
|
|
22
|
+
* 7. Normalize and return the result (Fix 8)
|
|
23
|
+
*/
|
|
24
|
+
export declare function executeToolInternal(name: string, input: Record<string, unknown>): Promise<ToolExecuteResult>;
|
|
25
|
+
/**
|
|
26
|
+
* Returns true when the browser exposes a native WebMCP implementation
|
|
27
|
+
* (Chrome 146+ or a compatible browser) — no polyfill needed in that case.
|
|
28
|
+
*/
|
|
29
|
+
export declare function hasNativeWebMCP(): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Install the WebMCP polyfill on `navigator.modelContext`.
|
|
32
|
+
*
|
|
33
|
+
* Behavior:
|
|
34
|
+
* - If native WebMCP is present and `forcePolyfill` is not set, skip install
|
|
35
|
+
* - If already installed by us, call cleanupWebMCPPolyfill first then re-install
|
|
36
|
+
* - Saves previous property descriptors for restore on cleanup (Fix 7)
|
|
37
|
+
* - Installs testing shim per installTestingShim option (Fix 14)
|
|
38
|
+
*
|
|
39
|
+
* Throws a SecurityError if called from a non-secure context (HTTP)
|
|
40
|
+
* unless `options.allowInsecureContext` is true.
|
|
41
|
+
*/
|
|
42
|
+
export declare function initializeWebMCPPolyfill(options?: WebMCPPolyfillOptions): void;
|
|
43
|
+
/**
|
|
44
|
+
* Remove the WebMCP polyfill from navigator and reset all module state.
|
|
45
|
+
*
|
|
46
|
+
* Restores previous property descriptors if they existed (Fix 7).
|
|
47
|
+
* Call this in your framework's cleanup / onDestroy hook to support
|
|
48
|
+
* Vite/Svelte HMR without tool duplication on reload.
|
|
49
|
+
*/
|
|
50
|
+
export declare function cleanupWebMCPPolyfill(): void;
|
|
51
|
+
export { initializeWebMCPPolyfill as default };
|
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
export type JsonSchemaType = 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null';
|
|
2
|
+
export interface JsonSchemaObject {
|
|
3
|
+
type?: JsonSchemaType | JsonSchemaType[];
|
|
4
|
+
title?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
default?: unknown;
|
|
7
|
+
examples?: unknown[];
|
|
8
|
+
minLength?: number;
|
|
9
|
+
maxLength?: number;
|
|
10
|
+
pattern?: string;
|
|
11
|
+
format?: string;
|
|
12
|
+
enum?: unknown[];
|
|
13
|
+
const?: unknown;
|
|
14
|
+
minimum?: number;
|
|
15
|
+
maximum?: number;
|
|
16
|
+
exclusiveMinimum?: number | boolean;
|
|
17
|
+
exclusiveMaximum?: number | boolean;
|
|
18
|
+
multipleOf?: number;
|
|
19
|
+
properties?: Record<string, JsonSchema>;
|
|
20
|
+
required?: string[];
|
|
21
|
+
additionalProperties?: boolean | JsonSchema;
|
|
22
|
+
patternProperties?: Record<string, JsonSchema>;
|
|
23
|
+
items?: JsonSchema | JsonSchema[];
|
|
24
|
+
minItems?: number;
|
|
25
|
+
maxItems?: number;
|
|
26
|
+
uniqueItems?: boolean;
|
|
27
|
+
allOf?: JsonSchema[];
|
|
28
|
+
anyOf?: JsonSchema[];
|
|
29
|
+
oneOf?: JsonSchema[];
|
|
30
|
+
not?: JsonSchema;
|
|
31
|
+
$ref?: string;
|
|
32
|
+
$schema?: string;
|
|
33
|
+
$id?: string;
|
|
34
|
+
$defs?: Record<string, JsonSchema>;
|
|
35
|
+
definitions?: Record<string, JsonSchema>;
|
|
36
|
+
if?: JsonSchema;
|
|
37
|
+
then?: JsonSchema;
|
|
38
|
+
else?: JsonSchema;
|
|
39
|
+
nullable?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export type JsonSchema = boolean | JsonSchemaObject;
|
|
42
|
+
export interface ToolAnnotations {
|
|
43
|
+
/** Hint: tool does not modify any state */
|
|
44
|
+
readOnlyHint?: boolean;
|
|
45
|
+
/** Hint: tool may modify state in a destructive/irreversible way */
|
|
46
|
+
destructiveHint?: boolean;
|
|
47
|
+
/** Hint: calling the tool multiple times with the same args has same effect */
|
|
48
|
+
idempotentHint?: boolean;
|
|
49
|
+
/** Hint: tool may interact with external systems (network, disk, etc.) */
|
|
50
|
+
openWorldHint?: boolean;
|
|
51
|
+
/** Hint: tool should be used with caution */
|
|
52
|
+
cautionHint?: boolean;
|
|
53
|
+
/** Human-readable title (MCP SDK) */
|
|
54
|
+
title?: string;
|
|
55
|
+
}
|
|
56
|
+
export interface ModelContextTool {
|
|
57
|
+
/** Unique name, must not be empty */
|
|
58
|
+
name: string;
|
|
59
|
+
/** Human-readable description, must not be empty */
|
|
60
|
+
description: string;
|
|
61
|
+
/** JSON Schema describing the tool's input parameters */
|
|
62
|
+
inputSchema?: JsonSchema;
|
|
63
|
+
/** JSON Schema describing the tool's structured output */
|
|
64
|
+
outputSchema?: JsonSchema;
|
|
65
|
+
/** Annotations about tool behavior */
|
|
66
|
+
annotations?: ToolAnnotations;
|
|
67
|
+
}
|
|
68
|
+
/** Content types returned by a tool */
|
|
69
|
+
export type ToolContentType = 'text' | 'image' | 'resource' | 'error';
|
|
70
|
+
export interface ToolContentText {
|
|
71
|
+
type: 'text';
|
|
72
|
+
text: string;
|
|
73
|
+
}
|
|
74
|
+
export interface ToolContentImage {
|
|
75
|
+
type: 'image';
|
|
76
|
+
data: string;
|
|
77
|
+
mimeType: string;
|
|
78
|
+
}
|
|
79
|
+
export interface ToolContentResource {
|
|
80
|
+
type: 'resource';
|
|
81
|
+
resource: {
|
|
82
|
+
uri: string;
|
|
83
|
+
mimeType?: string;
|
|
84
|
+
text?: string;
|
|
85
|
+
blob?: string;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
export interface ToolContentError {
|
|
89
|
+
type: 'error';
|
|
90
|
+
error: string;
|
|
91
|
+
}
|
|
92
|
+
export type ToolContent = ToolContentText | ToolContentImage | ToolContentResource | ToolContentError;
|
|
93
|
+
/** Extensible metadata for tool results */
|
|
94
|
+
export interface ToolResultMetadata {
|
|
95
|
+
willNavigate?: boolean;
|
|
96
|
+
[key: string]: unknown;
|
|
97
|
+
}
|
|
98
|
+
export interface ToolExecuteResult {
|
|
99
|
+
content: ToolContent[];
|
|
100
|
+
isError?: boolean;
|
|
101
|
+
/** JSON-serializable structured data (MCP structured output) */
|
|
102
|
+
structuredContent?: Record<string, unknown>;
|
|
103
|
+
/** Extensible metadata */
|
|
104
|
+
_meta?: ToolResultMetadata;
|
|
105
|
+
}
|
|
106
|
+
export interface UserInteractionOptions {
|
|
107
|
+
/** Human-readable prompt to show the user */
|
|
108
|
+
prompt?: string;
|
|
109
|
+
/** Interaction type hint */
|
|
110
|
+
kind?: 'confirmation' | 'input' | 'choice';
|
|
111
|
+
/** For 'choice' kind */
|
|
112
|
+
choices?: string[];
|
|
113
|
+
}
|
|
114
|
+
export interface UserInteractionResult {
|
|
115
|
+
accepted: boolean;
|
|
116
|
+
value?: string;
|
|
117
|
+
}
|
|
118
|
+
export interface ModelContextClient {
|
|
119
|
+
/**
|
|
120
|
+
* Request user interaction before the tool proceeds.
|
|
121
|
+
* W3C spec marks this as TODO — placeholder implementation.
|
|
122
|
+
*/
|
|
123
|
+
requestUserInteraction(options?: UserInteractionOptions): Promise<UserInteractionResult>;
|
|
124
|
+
}
|
|
125
|
+
export type ToolExecuteCallback = (input: Record<string, unknown>, client: ModelContextClient) => Promise<ToolExecuteResult> | ToolExecuteResult;
|
|
126
|
+
export interface ToolRegistrationOptions {
|
|
127
|
+
/** AbortSignal to auto-unregister the tool when aborted */
|
|
128
|
+
signal?: AbortSignal;
|
|
129
|
+
}
|
|
130
|
+
export interface RegisteredTool {
|
|
131
|
+
tool: ModelContextTool;
|
|
132
|
+
execute: ToolExecuteCallback;
|
|
133
|
+
/** JSON.stringify'd input schema for fast serialization */
|
|
134
|
+
serializedInputSchema?: string;
|
|
135
|
+
registeredAt: number;
|
|
136
|
+
}
|
|
137
|
+
export interface ContextRegistration {
|
|
138
|
+
tool: ModelContextTool & {
|
|
139
|
+
execute: ToolExecuteCallback;
|
|
140
|
+
};
|
|
141
|
+
options?: ToolRegistrationOptions;
|
|
142
|
+
}
|
|
143
|
+
/** Called with no arguments when the tool set changes (MCP-B spec). */
|
|
144
|
+
export type ToolsChangedCallback = () => void;
|
|
145
|
+
export interface ModelContext {
|
|
146
|
+
registerTool(tool: ModelContextTool & {
|
|
147
|
+
execute: ToolExecuteCallback;
|
|
148
|
+
}, options?: ToolRegistrationOptions): void;
|
|
149
|
+
unregisterTool(nameOrTool: string | {
|
|
150
|
+
name: string;
|
|
151
|
+
}): void;
|
|
152
|
+
provideContext(registrations: ContextRegistration[]): void;
|
|
153
|
+
clearContext(): void;
|
|
154
|
+
registerToolsChangedCallback(callback: ToolsChangedCallback): void;
|
|
155
|
+
}
|
|
156
|
+
/** Info shape returned by modelContextTesting.listTools() */
|
|
157
|
+
export interface ModelContextTestingToolInfo {
|
|
158
|
+
name: string;
|
|
159
|
+
description: string;
|
|
160
|
+
/** Serialized JSON Schema string */
|
|
161
|
+
inputSchema?: string;
|
|
162
|
+
}
|
|
163
|
+
export interface ModelContextTesting {
|
|
164
|
+
listTools(): ModelContextTestingToolInfo[];
|
|
165
|
+
executeTool(toolName: string, inputArgsJson: string, options?: {
|
|
166
|
+
signal?: AbortSignal;
|
|
167
|
+
}): Promise<string | null>;
|
|
168
|
+
getCrossDocumentScriptToolResult(): Promise<string>;
|
|
169
|
+
}
|
|
170
|
+
export interface AuthContext {
|
|
171
|
+
userId?: string;
|
|
172
|
+
tenantId?: string;
|
|
173
|
+
workspaceId?: string;
|
|
174
|
+
roles?: string[];
|
|
175
|
+
[key: string]: unknown;
|
|
176
|
+
}
|
|
177
|
+
export type ConfirmationTier = 'none' | 'warn' | 'block';
|
|
178
|
+
export interface ConfirmationPolicy {
|
|
179
|
+
/** Require confirmation for destructive tools */
|
|
180
|
+
destructive?: ConfirmationTier;
|
|
181
|
+
/** Require confirmation for tools without readOnlyHint */
|
|
182
|
+
mutating?: ConfirmationTier;
|
|
183
|
+
/** Require confirmation for all tools */
|
|
184
|
+
all?: ConfirmationTier;
|
|
185
|
+
}
|
|
186
|
+
export interface WebMCPPolyfillOptions {
|
|
187
|
+
/**
|
|
188
|
+
* Force installing the polyfill even when native WebMCP is detected.
|
|
189
|
+
* Useful for testing.
|
|
190
|
+
*/
|
|
191
|
+
forcePolyfill?: boolean;
|
|
192
|
+
/**
|
|
193
|
+
* Allow running in non-secure contexts (HTTP).
|
|
194
|
+
* Should only be set to true during development.
|
|
195
|
+
*/
|
|
196
|
+
allowInsecureContext?: boolean;
|
|
197
|
+
/**
|
|
198
|
+
* If true and the environment has no window (SSR/Node),
|
|
199
|
+
* all polyfill functions become silent no-ops.
|
|
200
|
+
*/
|
|
201
|
+
degradeGracefully?: boolean;
|
|
202
|
+
/**
|
|
203
|
+
* Auth context injected into every tool's input as `_authContext`.
|
|
204
|
+
*/
|
|
205
|
+
authContext?: AuthContext;
|
|
206
|
+
/**
|
|
207
|
+
* Confirmation policy applied before executing tools.
|
|
208
|
+
*/
|
|
209
|
+
confirmationPolicy?: ConfirmationPolicy;
|
|
210
|
+
/**
|
|
211
|
+
* Controls when the testing shim (navigator.modelContextTesting) is installed.
|
|
212
|
+
* - 'if-missing' (default): install only if navigator.modelContextTesting is not already set
|
|
213
|
+
* - 'always': always install (overwrite native)
|
|
214
|
+
* - false: never install
|
|
215
|
+
*/
|
|
216
|
+
installTestingShim?: 'if-missing' | 'always' | false;
|
|
217
|
+
/**
|
|
218
|
+
* If false, skip IIFE auto-initialization even when window.__webMCPPolyfillOptions is set.
|
|
219
|
+
* Default: true
|
|
220
|
+
*/
|
|
221
|
+
autoInitialize?: boolean;
|
|
222
|
+
}
|
|
223
|
+
export interface JsonRpcRequest {
|
|
224
|
+
jsonrpc: '2.0';
|
|
225
|
+
id: number | string;
|
|
226
|
+
method: string;
|
|
227
|
+
params?: Record<string, unknown>;
|
|
228
|
+
}
|
|
229
|
+
export interface JsonRpcError {
|
|
230
|
+
code: number;
|
|
231
|
+
message: string;
|
|
232
|
+
data?: unknown;
|
|
233
|
+
}
|
|
234
|
+
export interface JsonRpcResponse<T = unknown> {
|
|
235
|
+
jsonrpc: '2.0';
|
|
236
|
+
id: number | string | null;
|
|
237
|
+
result?: T;
|
|
238
|
+
error?: JsonRpcError;
|
|
239
|
+
}
|
|
240
|
+
export interface McpServerInfo {
|
|
241
|
+
name: string;
|
|
242
|
+
version: string;
|
|
243
|
+
}
|
|
244
|
+
export interface McpCapabilities {
|
|
245
|
+
tools?: {
|
|
246
|
+
listChanged?: boolean;
|
|
247
|
+
};
|
|
248
|
+
resources?: {
|
|
249
|
+
listChanged?: boolean;
|
|
250
|
+
subscribe?: boolean;
|
|
251
|
+
};
|
|
252
|
+
prompts?: {
|
|
253
|
+
listChanged?: boolean;
|
|
254
|
+
};
|
|
255
|
+
logging?: Record<string, unknown>;
|
|
256
|
+
[key: string]: unknown;
|
|
257
|
+
}
|
|
258
|
+
export interface McpInitializeResult {
|
|
259
|
+
protocolVersion: string;
|
|
260
|
+
capabilities: McpCapabilities;
|
|
261
|
+
serverInfo: McpServerInfo;
|
|
262
|
+
}
|
|
263
|
+
export interface McpTool {
|
|
264
|
+
name: string;
|
|
265
|
+
description?: string;
|
|
266
|
+
inputSchema?: JsonSchema;
|
|
267
|
+
outputSchema?: JsonSchema;
|
|
268
|
+
annotations?: ToolAnnotations;
|
|
269
|
+
}
|
|
270
|
+
export interface McpToolResultContent {
|
|
271
|
+
type: 'text' | 'image' | 'resource';
|
|
272
|
+
text?: string;
|
|
273
|
+
data?: string;
|
|
274
|
+
mimeType?: string;
|
|
275
|
+
resource?: {
|
|
276
|
+
uri: string;
|
|
277
|
+
mimeType?: string;
|
|
278
|
+
text?: string;
|
|
279
|
+
blob?: string;
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
export interface McpToolResult {
|
|
283
|
+
content: McpToolResultContent[];
|
|
284
|
+
isError?: boolean;
|
|
285
|
+
}
|
|
286
|
+
export interface McpListToolsResult {
|
|
287
|
+
tools: McpTool[];
|
|
288
|
+
nextCursor?: string;
|
|
289
|
+
}
|
|
290
|
+
export interface McpClientOptions {
|
|
291
|
+
/** Client name sent during initialize */
|
|
292
|
+
clientName?: string;
|
|
293
|
+
/** Client version sent during initialize */
|
|
294
|
+
clientVersion?: string;
|
|
295
|
+
/** Request timeout in ms (default: 30000) */
|
|
296
|
+
timeout?: number;
|
|
297
|
+
/** Extra headers attached to every request */
|
|
298
|
+
headers?: Record<string, string>;
|
|
299
|
+
/** Auto-reconnect on 404 session-expired */
|
|
300
|
+
autoReconnect?: boolean;
|
|
301
|
+
/** Max reconnect attempts (default: 3) */
|
|
302
|
+
maxReconnectAttempts?: number;
|
|
303
|
+
}
|
|
304
|
+
export interface PostMessageBridgeOptions {
|
|
305
|
+
/** Target origin for postMessage calls (default: '*') */
|
|
306
|
+
targetOrigin?: string;
|
|
307
|
+
/** Origins to accept messages from; empty array = accept all */
|
|
308
|
+
allowedOrigins?: string[];
|
|
309
|
+
}
|
|
310
|
+
export interface WebMCPCallToolEvent {
|
|
311
|
+
type: 'webmcp:call-tool';
|
|
312
|
+
callId: string;
|
|
313
|
+
name: string;
|
|
314
|
+
args?: Record<string, unknown>;
|
|
315
|
+
}
|
|
316
|
+
export interface WebMCPToolResultEvent {
|
|
317
|
+
type: 'webmcp:tool-result';
|
|
318
|
+
callId: string;
|
|
319
|
+
result: ToolExecuteResult;
|
|
320
|
+
}
|
|
321
|
+
export interface WebMCPToolErrorEvent {
|
|
322
|
+
type: 'webmcp:tool-error';
|
|
323
|
+
callId: string;
|
|
324
|
+
error: string;
|
|
325
|
+
}
|
|
326
|
+
declare global {
|
|
327
|
+
interface Navigator {
|
|
328
|
+
modelContext?: ModelContext;
|
|
329
|
+
modelContextTesting?: ModelContextTesting;
|
|
330
|
+
}
|
|
331
|
+
}
|
package/src/utils.d.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { JsonSchema } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Dispatch a CustomEvent and wait for a completion event.
|
|
4
|
+
* Solves the "execute must return after UI updates" requirement.
|
|
5
|
+
*
|
|
6
|
+
* Pattern: dispatch "tool-action" → UI handles it → UI dispatches "tool-completion-{requestId}"
|
|
7
|
+
*
|
|
8
|
+
* @param eventName - Name of the event to dispatch
|
|
9
|
+
* @param detail - Event detail payload
|
|
10
|
+
* @param options - Timeout and target
|
|
11
|
+
* @returns Promise that resolves when the completion event fires
|
|
12
|
+
*/
|
|
13
|
+
export declare function dispatchAndWait<T = unknown>(eventName: string, detail?: Record<string, unknown>, options?: {
|
|
14
|
+
timeout?: number;
|
|
15
|
+
successValue?: T;
|
|
16
|
+
target?: EventTarget;
|
|
17
|
+
}): Promise<T>;
|
|
18
|
+
/**
|
|
19
|
+
* Helper to signal completion of a dispatchAndWait request.
|
|
20
|
+
* Call this from your UI handler after the update is done.
|
|
21
|
+
*/
|
|
22
|
+
export declare function signalCompletion(completionEventName: string, detail?: unknown): void;
|
|
23
|
+
export interface SchemaPatch {
|
|
24
|
+
path: string;
|
|
25
|
+
type: 'additionalProperties';
|
|
26
|
+
value: false;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Sanitize schema AND report patches applied for strict tool use.
|
|
30
|
+
* Use this when you need visibility into what was changed.
|
|
31
|
+
*/
|
|
32
|
+
export declare function sanitizeSchemaWithReport(schema: JsonSchema): {
|
|
33
|
+
schema: JsonSchema;
|
|
34
|
+
patches: SchemaPatch[];
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Strip JSON Schema keywords that cause errors in AI SDKs
|
|
38
|
+
* (e.g., Vercel AI SDK rejects oneOf/anyOf on non-STRING types).
|
|
39
|
+
*
|
|
40
|
+
* Use this before passing tool schemas to LLM providers.
|
|
41
|
+
*/
|
|
42
|
+
export declare function sanitizeSchema(schema: JsonSchema): JsonSchema;
|
|
43
|
+
/**
|
|
44
|
+
* Flatten nested object schemas into flat key__subkey properties.
|
|
45
|
+
* Returns { schema, pathMap } where pathMap maps flat keys to nested paths.
|
|
46
|
+
* Only flattens properties of type "object" with their own properties.
|
|
47
|
+
*/
|
|
48
|
+
export declare function flattenSchema(schema: JsonSchema): {
|
|
49
|
+
schema: JsonSchema;
|
|
50
|
+
pathMap: Record<string, string[]>;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Unflatten params using a pathMap from flattenSchema.
|
|
54
|
+
* Converts { a__b: 1, a__c: 2, d: 3 } back to { a: { b: 1, c: 2 }, d: 3 }
|
|
55
|
+
*/
|
|
56
|
+
export declare function unflattenParams(params: Record<string, unknown>, pathMap: Record<string, string[]>): Record<string, unknown>;
|
|
57
|
+
/**
|
|
58
|
+
* Create a named tool group backed by a shared AbortController.
|
|
59
|
+
* Ergonomic helper for SPA route-based tool registration.
|
|
60
|
+
*
|
|
61
|
+
* Usage:
|
|
62
|
+
* const group = createToolGroup('search-page');
|
|
63
|
+
* group.register(tool1, registerFn);
|
|
64
|
+
* group.register(tool2, registerFn);
|
|
65
|
+
* // On route change:
|
|
66
|
+
* group.abort(); // unregisters all tools in the group
|
|
67
|
+
*/
|
|
68
|
+
export declare function createToolGroup(name: string): {
|
|
69
|
+
name: string;
|
|
70
|
+
register: (tool: {
|
|
71
|
+
name: string;
|
|
72
|
+
description: string;
|
|
73
|
+
inputSchema?: JsonSchema;
|
|
74
|
+
execute: (...args: any[]) => any;
|
|
75
|
+
annotations?: Record<string, unknown>;
|
|
76
|
+
}, registerFn: (tool: any, options: {
|
|
77
|
+
signal: AbortSignal;
|
|
78
|
+
}) => void) => void;
|
|
79
|
+
abort: () => void;
|
|
80
|
+
isAborted: () => boolean;
|
|
81
|
+
};
|