@orkestrel/mcp 0.0.30 → 0.0.32
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/dist/src/browser/index.d.ts +786 -0
- package/dist/src/browser/index.js +636 -4
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/core/index.cjs +271 -102
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +144 -32
- package/dist/src/core/index.d.ts +144 -32
- package/dist/src/core/index.js +269 -104
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +1 -1
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.js +2 -2
- package/dist/src/server/index.js.map +1 -1
- package/package.json +15 -15
|
@@ -1,12 +1,70 @@
|
|
|
1
|
+
import type { EmitterErrorHandler } from '@orkestrel/emitter';
|
|
2
|
+
import type { EmitterHooks } from '@orkestrel/emitter';
|
|
1
3
|
import type { EmitterInterface } from '@orkestrel/emitter';
|
|
2
4
|
import type { HTTPClientTransportOptions } from '@orkestrel/mcp';
|
|
3
5
|
import type { JSONRPCMessage } from '@orkestrel/mcp';
|
|
6
|
+
import type { MCPClientInterface } from '@orkestrel/mcp';
|
|
7
|
+
import type { MCPClientOptions } from '@orkestrel/mcp';
|
|
4
8
|
import type { MCPMessageTransportEventMap } from '@orkestrel/mcp';
|
|
5
9
|
import type { MCPMessageTransportInterface } from '@orkestrel/mcp';
|
|
6
10
|
import type { MCPServerInterface } from '@orkestrel/mcp';
|
|
7
11
|
import type { MCPTransportInterface } from '@orkestrel/mcp';
|
|
12
|
+
import type { ToolAnnotations } from '@orkestrel/tool';
|
|
13
|
+
import type { ToolDefinition } from '@orkestrel/tool';
|
|
14
|
+
import type { ToolInterface } from '@orkestrel/tool';
|
|
8
15
|
import type { ToolManagerInterface } from '@orkestrel/tool';
|
|
9
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Builds the WebMCP projection of every tool a registry advertises, or refuses the batch.
|
|
19
|
+
*
|
|
20
|
+
* @remarks
|
|
21
|
+
* The WebMCP twin of `@orkestrel/mcp`'s `buildToolDescriptors`. Each tool is projected through
|
|
22
|
+
* `@orkestrel/tool`'s own `toolToDefinition` — the projection `definitions()` applies — so a
|
|
23
|
+
* tool advertises one description across the MCP wire and the WebMCP registry alike. The tool
|
|
24
|
+
* travels beside its descriptor because a registration records which tool it was made for, and
|
|
25
|
+
* a descriptor cannot report that.
|
|
26
|
+
*
|
|
27
|
+
* It refuses rather than skips. WebMCP requires `description`, and each alternative to
|
|
28
|
+
* refusing is worse: an empty string is an invented value a foreign agent reads as a real one,
|
|
29
|
+
* and silently dropping the tool publishes a registry missing a tool its author asked for.
|
|
30
|
+
* Refusing before any registration happens is also what keeps `publish` atomic — nothing is
|
|
31
|
+
* registered when one tool cannot be.
|
|
32
|
+
*
|
|
33
|
+
* @param manager - The tool registry to project
|
|
34
|
+
* @returns One projection per advertised tool, in registry order
|
|
35
|
+
* @throws Thrown as an `MCPError` carrying `-32602` when a tool advertises no description,
|
|
36
|
+
* naming the tool
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* const tools = createToolManager()
|
|
41
|
+
* tools.add(createTool({ name: 'add', description: 'Adds two numbers', execute: () => 5 }))
|
|
42
|
+
* buildWebMCPProjections(tools).map((projection) => projection.descriptor.name) // ['add']
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function buildWebMCPProjections(manager: ToolManagerInterface): readonly WebMCPProjection[];
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Collects the WebMCP projection of every tool a registry advertises that WebMCP can carry.
|
|
49
|
+
*
|
|
50
|
+
* @remarks
|
|
51
|
+
* The skipping sibling of {@link buildWebMCPProjections}, and the reading a followed change
|
|
52
|
+
* reconciles against: a followed change reaches no caller, so a tool advertising neither a
|
|
53
|
+
* `description` nor a `summary` is left out of the collection rather than refusing a batch
|
|
54
|
+
* nobody asked for.
|
|
55
|
+
*
|
|
56
|
+
* @param manager - The tool registry to project
|
|
57
|
+
* @returns One projection per advertised tool WebMCP can carry, in registry order
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* const tools = createToolManager()
|
|
62
|
+
* tools.add(createTool({ name: 'bare', execute: () => 1 }))
|
|
63
|
+
* collectWebMCPProjections(tools) // []
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function collectWebMCPProjections(manager: ToolManagerInterface): readonly WebMCPProjection[];
|
|
67
|
+
|
|
10
68
|
/**
|
|
11
69
|
* Creates the HTTP client transport for an
|
|
12
70
|
* {@link import('@orkestrel/mcp').MCPClientInterface} — a {@link MCPMessageTransportInterface}
|
|
@@ -82,6 +140,91 @@ export declare function createHTTPClientTransport(options: HTTPClientTransportOp
|
|
|
82
140
|
*/
|
|
83
141
|
export declare function createMessagePortTransport(options: MessagePortTransportOptions): MCPTransportInterface;
|
|
84
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Creates the bridge between a tool registry and a document's WebMCP registry, or reports that
|
|
145
|
+
* the document exposes none.
|
|
146
|
+
*
|
|
147
|
+
* @remarks
|
|
148
|
+
* Feature detection is the return value: `undefined` means this document has no
|
|
149
|
+
* `document.modelContext`, which is the reading every browser gives today — the specification
|
|
150
|
+
* is incubating in a Community Group, and the chromestatus record, read 2026-09-15 and last
|
|
151
|
+
* updated 2026-08-12, reports `Proposed` with `"flag": false` and `"origintrial": false`. There
|
|
152
|
+
* is no `supported` flag to read and no polyfill behind the factory, because a local
|
|
153
|
+
* implementation of an absent platform feature is one a caller mistakes for the platform.
|
|
154
|
+
*
|
|
155
|
+
* The bridge borrows the registry. It aborts only the registrations it made, so a name it
|
|
156
|
+
* never registered is left exactly as it found it. WebMCP keys a registration by tool name per
|
|
157
|
+
* document, so releasing a name releases whatever now stands under it — a same-name
|
|
158
|
+
* registration the page or another bridge made later goes with it.
|
|
159
|
+
*
|
|
160
|
+
* @param options - The document to bridge and the emitter's initial wiring; see
|
|
161
|
+
* {@link ModelContextOptions}
|
|
162
|
+
* @returns A {@link ModelContextInterface}, or `undefined` when the document exposes no
|
|
163
|
+
* WebMCP registry
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```ts
|
|
167
|
+
* import { createModelContext } from '@orkestrel/mcp/browser'
|
|
168
|
+
* import { createToolManager } from '@orkestrel/tool'
|
|
169
|
+
*
|
|
170
|
+
* const bridge = createModelContext()
|
|
171
|
+
* if (bridge !== undefined) {
|
|
172
|
+
* await bridge.publish(createToolManager())
|
|
173
|
+
* const foreign = await bridge.adopt()
|
|
174
|
+
* bridge.destroy()
|
|
175
|
+
* }
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
export declare function createModelContext(options?: ModelContextOptions): ModelContextInterface | undefined;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Creates an `MCPServer` hosted inside the calling page and hands back the client bound to it
|
|
182
|
+
* — the page twin of {@link createScopeServer}, and the in-page MCP pair as one call.
|
|
183
|
+
*
|
|
184
|
+
* @remarks
|
|
185
|
+
* The pair is a native `MessageChannel`: the server binds `port1`, the client drives `port2`,
|
|
186
|
+
* and no byte leaves the page. That is the point of the factory — a consumer assembling it by
|
|
187
|
+
* hand writes the channel, two transports, `bindServer`, `createDuplexClientTransport`,
|
|
188
|
+
* `createMCPClient`, and `bindClient`, in an order {@link MessagePortTransport}'s own doc warns
|
|
189
|
+
* about: a `MessagePort` starts dispatching at construction, so an `await` interleaved between
|
|
190
|
+
* a transport and its binder drops whatever arrived in the gap. This factory never suspends
|
|
191
|
+
* between the two.
|
|
192
|
+
*
|
|
193
|
+
* The returned client is bound but not connected. Connection is a protocol round trip, so it
|
|
194
|
+
* stays the consumer's `await client.connect()` rather than a promise this call hides — and a
|
|
195
|
+
* factory that returned a promise could not return the terminal beside it.
|
|
196
|
+
*
|
|
197
|
+
* `stop` closes the client's port first, so the client observes the close and reports
|
|
198
|
+
* `connected` as `false` with its pending requests rejected, then unbinds both sides and
|
|
199
|
+
* closes the server's port. It is idempotent, and it takes the twin's verb because it is the
|
|
200
|
+
* twin's action: {@link createScopeServer} publishes `stop` for ending a hosted server's
|
|
201
|
+
* bindings, and a consumer who learned one factory reads the other without checking.
|
|
202
|
+
*
|
|
203
|
+
* The published `client` outlives the pair and is inert after `stop`: every session-bound
|
|
204
|
+
* request issued on it — `call`, `tools`, each `tasks/*` method, and a `listen` stream on its
|
|
205
|
+
* first `next()` — rejects at once with an `MCPError` carrying `-32600`, rather than waiting
|
|
206
|
+
* out its request deadline against a channel nothing is listening on.
|
|
207
|
+
*
|
|
208
|
+
* @param options - The tools, the optional server identity, and the optional client settings;
|
|
209
|
+
* see {@link PageServerOptions}
|
|
210
|
+
* @returns A {@link PageServerInterface} holding the bound client and the pair's `stop`
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```ts
|
|
214
|
+
* import { createPageServer } from '@orkestrel/mcp/browser'
|
|
215
|
+
* import { createTool, createToolManager } from '@orkestrel/tool'
|
|
216
|
+
*
|
|
217
|
+
* const tools = createToolManager()
|
|
218
|
+
* tools.add(createTool({ name: 'add', execute: () => 5 }))
|
|
219
|
+
*
|
|
220
|
+
* const page = createPageServer({ tools })
|
|
221
|
+
* await page.client.connect()
|
|
222
|
+
* const value = await page.client.call('add', {}) // { resultType: 'complete', value: 5 }
|
|
223
|
+
* page.stop()
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
export declare function createPageServer(options: PageServerOptions): PageServerInterface;
|
|
227
|
+
|
|
85
228
|
/**
|
|
86
229
|
* Builds {@link createScopeServer}'s `message`-event listener — the unified dispatcher that
|
|
87
230
|
* routes every inbound event on a hostable scope, portless or port-bearing, to the right
|
|
@@ -226,6 +369,96 @@ export declare const DEFAULT_MCP_SERVER_NAME = "@orkestrel/mcp";
|
|
|
226
369
|
/** Supplies the default server version `createScopeServer` reports (`initialize`'s `serverInfo.version`) when `options.version` is omitted. */
|
|
227
370
|
export declare const DEFAULT_MCP_SERVER_VERSION = "1.0.0";
|
|
228
371
|
|
|
372
|
+
/**
|
|
373
|
+
* Projects the descriptor a registry advertises for one tool name, or reports that it has none.
|
|
374
|
+
*
|
|
375
|
+
* @remarks
|
|
376
|
+
* Reads the manager's own `definitions()` rather than a tool instance, so the description here
|
|
377
|
+
* is the one the registry advertises — an authored `summary` in place of the full
|
|
378
|
+
* `description` — and one tool reaches the WebMCP registry and the MCP wire describing itself
|
|
379
|
+
* the same way.
|
|
380
|
+
*
|
|
381
|
+
* `undefined` covers both answers a caller must not conflate with a descriptor: the manager
|
|
382
|
+
* advertises no tool under that name, and the tool it advertises carries no description, which
|
|
383
|
+
* is the member WebMCP requires.
|
|
384
|
+
*
|
|
385
|
+
* @param manager - The tool registry to read
|
|
386
|
+
* @param name - The tool name to describe
|
|
387
|
+
* @returns The WebMCP descriptor, or `undefined` when the registry advertises none
|
|
388
|
+
*
|
|
389
|
+
* @example
|
|
390
|
+
* ```ts
|
|
391
|
+
* const tools = createToolManager()
|
|
392
|
+
* tools.add(createTool({ name: 'add', description: 'Adds two numbers', execute: () => 5 }))
|
|
393
|
+
* describeWebMCPTool(tools, 'add')?.description // 'Adds two numbers'
|
|
394
|
+
* ```
|
|
395
|
+
*/
|
|
396
|
+
export declare function describeWebMCPTool(manager: ToolManagerInterface, name: string): WebMCPDescriptor | undefined;
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Determines whether an unknown value is a document exposing the WebMCP tool registry.
|
|
400
|
+
*
|
|
401
|
+
* @remarks
|
|
402
|
+
* This is the feature detection {@link import('./factories.js').createModelContext} performs,
|
|
403
|
+
* published so a consumer can run it before deciding to build a bridge at all. It reads
|
|
404
|
+
* `modelContext` and checks it with {@link isWebMCPRegistry}; it asserts nothing about the rest
|
|
405
|
+
* of a `Document`, because that member is the whole of what the bridge needs.
|
|
406
|
+
*
|
|
407
|
+
* @param value - The unknown value to inspect
|
|
408
|
+
* @returns True if the value carries a WebMCP registry; false otherwise
|
|
409
|
+
*
|
|
410
|
+
* @example
|
|
411
|
+
* ```ts
|
|
412
|
+
* isWebMCPDocument(globalThis.document) // false in a browser that ships no WebMCP
|
|
413
|
+
* ```
|
|
414
|
+
*/
|
|
415
|
+
export declare function isWebMCPDocument(value: unknown): value is WebMCPDocument;
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Determines whether an unknown value is a WebMCP tool registry.
|
|
419
|
+
*
|
|
420
|
+
* @remarks
|
|
421
|
+
* Reads the members the bridge dereferences — the IDL's `registerTool`, `getTools`, and
|
|
422
|
+
* `executeTool` operations, plus the `EventTarget` pair the `toolchange` subscription needs —
|
|
423
|
+
* and nothing else. A registry carrying extra members is still a registry, and a user agent's
|
|
424
|
+
* own implementation reaches every one of these through its prototype.
|
|
425
|
+
*
|
|
426
|
+
* @param value - The unknown value to inspect
|
|
427
|
+
* @returns True if the value exposes every WebMCP registry operation; false otherwise
|
|
428
|
+
*
|
|
429
|
+
* @example
|
|
430
|
+
* ```ts
|
|
431
|
+
* isWebMCPRegistry({}) // false
|
|
432
|
+
* ```
|
|
433
|
+
*/
|
|
434
|
+
export declare function isWebMCPRegistry(value: unknown): value is WebMCPRegistryInterface;
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Determines whether two WebMCP descriptors advertise the same tool to the registry.
|
|
438
|
+
*
|
|
439
|
+
* @remarks
|
|
440
|
+
* The reading `ModelContextInterface.publish` reconciles a name against once the manager's
|
|
441
|
+
* tool has changed under it: equal descriptors leave the live registration standing, because
|
|
442
|
+
* execution routes through the manager by name, and anything else releases it and registers
|
|
443
|
+
* the new one.
|
|
444
|
+
*
|
|
445
|
+
* Equality is structural and key-order-independent, through `@orkestrel/contract`'s
|
|
446
|
+
* `canonicalStringify`: `inputSchema` is the author's own JSON Schema record, and two
|
|
447
|
+
* authorings of the same schema that differ only in key order describe the same tool. A
|
|
448
|
+
* descriptor JSON cannot encode — a cyclic or unreadable `inputSchema` — is reported as
|
|
449
|
+
* unequal, which re-registers rather than serving a descriptor nothing could compare.
|
|
450
|
+
*
|
|
451
|
+
* @param held - The descriptor the live registration carries
|
|
452
|
+
* @param projected - The descriptor this publication projected
|
|
453
|
+
* @returns True when both describe the same tool; false otherwise
|
|
454
|
+
*
|
|
455
|
+
* @example
|
|
456
|
+
* ```ts
|
|
457
|
+
* matchesDescriptor({ name: 'add', description: 'Adds' }, { description: 'Adds', name: 'add' }) // true
|
|
458
|
+
* ```
|
|
459
|
+
*/
|
|
460
|
+
export declare function matchesDescriptor(held: WebMCPDescriptor, projected: WebMCPDescriptor): boolean;
|
|
461
|
+
|
|
229
462
|
/**
|
|
230
463
|
* Carries the Model Context Protocol over a native `MessagePort` from the browser face — a
|
|
231
464
|
* {@link MCPTransportInterface}, the genuinely new capability this face adds: MCP over
|
|
@@ -312,6 +545,308 @@ export declare interface MessagePortTransportOptions {
|
|
|
312
545
|
readonly port: MessagePort;
|
|
313
546
|
}
|
|
314
547
|
|
|
548
|
+
/**
|
|
549
|
+
* Bridges a `ToolManagerInterface` and a document's WebMCP tool registry — the
|
|
550
|
+
* {@link ModelContextInterface} {@link import('./factories.js').createModelContext} returns.
|
|
551
|
+
*
|
|
552
|
+
* @remarks
|
|
553
|
+
* - **It borrows the registry, it does not own it.** The handle registers tools, retains one
|
|
554
|
+
* `AbortController` per registration, and aborts exactly those on `destroy`. WebMCP's own
|
|
555
|
+
* unregistration path is that abort. Registration identity is the tool name, per document,
|
|
556
|
+
* so releasing a name releases whatever now stands under it — including a same-name
|
|
557
|
+
* registration another handle made later.
|
|
558
|
+
* - **`publish` snapshots at the call, then follows the manager.** The manager is projected
|
|
559
|
+
* when `publish` is called, before the work queues behind an earlier publication, so a
|
|
560
|
+
* registry mutated while this call waits its turn does not decide what this call registers.
|
|
561
|
+
* The same call subscribes to the manager's own `emitter`, so a later `add`, `remove`, or
|
|
562
|
+
* `clear` reaches the document registry without a second `publish`.
|
|
563
|
+
* - **One manager is followed at a time.** A `publish` naming another manager releases the
|
|
564
|
+
* subscription and takes up the new one, and `destroy` releases it outright. An event from a
|
|
565
|
+
* manager this handle no longer follows is ignored, which is what a listener republishing
|
|
566
|
+
* another manager from inside a dispatch produces. A followed change has no caller to refuse
|
|
567
|
+
* to, so a tool advertising neither a `description` nor a `summary` is left unregistered
|
|
568
|
+
* rather than refusing anything; `publish` still refuses such a batch whole. Under a name
|
|
569
|
+
* this handle never registered that skip emits no `change`, because nothing reached the
|
|
570
|
+
* document registry. A synchronisation registers only what it can carry, so such a tool
|
|
571
|
+
* standing under a name this handle already registered releases that registration rather
|
|
572
|
+
* than leaving it advertising a descriptor the manager no longer stands behind, and that
|
|
573
|
+
* release emits the registry's `change` like any other.
|
|
574
|
+
* - **A followed change is a trigger, not a fact.** Each `add`, `remove`, or `clear` queues one
|
|
575
|
+
* synchronisation of this handle's registrations for that manager against what the manager
|
|
576
|
+
* holds when that queued work runs. The event cannot decide the outcome: `remove` and
|
|
577
|
+
* `clear` name tools the manager no longer holds, an earlier listener in the same dispatch
|
|
578
|
+
* may already have put another tool under one of those names, and the manager's `destroy`
|
|
579
|
+
* empties its map after the `clear` it publishes. Reading the manager converges on its state
|
|
580
|
+
* however the change was reached, so a synchronisation queued and not yet started already
|
|
581
|
+
* covers every change that arrives before it runs and a second one is not queued. A
|
|
582
|
+
* publication queued behind that synchronisation ends its cover, because the publication
|
|
583
|
+
* prunes what the synchronisation registered: a change arriving after that call queues a
|
|
584
|
+
* synchronisation of its own, which runs after the publication.
|
|
585
|
+
* - **A later `publish` reconciles, and so does every synchronisation.** Each name is compared
|
|
586
|
+
* with what this handle already registered for it: the same manager holding the same tool
|
|
587
|
+
* leaves the registration alone, another tool of that same manager advertising an equal
|
|
588
|
+
* descriptor leaves it registered and records the tool it now stands for, and anything else
|
|
589
|
+
* releases it and registers the new descriptor bound to the new manager. A name the snapshot
|
|
590
|
+
* dropped, or a name the manager no longer holds, is released — after the batch has
|
|
591
|
+
* reconciled, never before, so no name is withdrawn while the tools replacing it are still
|
|
592
|
+
* being registered. A failed batch releases them too, and still withdraws nothing it
|
|
593
|
+
* carries. Nothing has to be removed from the manager to make the registry agree with it.
|
|
594
|
+
* - **Work serializes.** Registration is asynchronous and `destroy` is not, so overlapping
|
|
595
|
+
* calls would interleave registrations with the aborts meant to end them. Each publication
|
|
596
|
+
* and each synchronisation queues behind the previous one, and every step re-reads the
|
|
597
|
+
* destroyed flag, so a `destroy` issued mid-publish stops the registrations that have not
|
|
598
|
+
* happened yet instead of racing them.
|
|
599
|
+
* - **Nothing is polyfilled.** A document exposing no registry never reaches this class:
|
|
600
|
+
* {@link import('./factories.js').createModelContext} returns `undefined` instead, so feature
|
|
601
|
+
* absence stays absence rather than becoming a local implementation a caller mistakes for
|
|
602
|
+
* the platform.
|
|
603
|
+
* - **The result shape is the registry's.** An adopted tool resolves whatever `executeTool`
|
|
604
|
+
* resolved, unchanged. WebMCP's IDL types that `Promise<DOMString>` while the
|
|
605
|
+
* specification's README sample returns `{ content: [...] }`; the primary source disagrees
|
|
606
|
+
* with itself, and normalizing either way would encode a guess as a contract.
|
|
607
|
+
*
|
|
608
|
+
* @example
|
|
609
|
+
* ```ts
|
|
610
|
+
* import { isWebMCPDocument, ModelContext } from '@orkestrel/mcp/browser'
|
|
611
|
+
*
|
|
612
|
+
* if (isWebMCPDocument(document)) {
|
|
613
|
+
* const bridge = new ModelContext(document)
|
|
614
|
+
* await bridge.publish(tools)
|
|
615
|
+
* }
|
|
616
|
+
* ```
|
|
617
|
+
*/
|
|
618
|
+
export declare class ModelContext implements ModelContextInterface {
|
|
619
|
+
#private;
|
|
620
|
+
/**
|
|
621
|
+
* Binds a narrowed document's registry and arms the `toolchange` subscription.
|
|
622
|
+
*
|
|
623
|
+
* @param document - The document whose `modelContext` this handle bridges
|
|
624
|
+
* @param options - The emitter's initial hooks and listener-error handler; see
|
|
625
|
+
* {@link ModelContextOptions}
|
|
626
|
+
*/
|
|
627
|
+
constructor(document: WebMCPDocument, options?: ModelContextOptions);
|
|
628
|
+
get emitter(): EmitterInterface<ModelContextEventMap>;
|
|
629
|
+
publish(tools: ToolManagerInterface, options?: ModelContextPublishOptions): Promise<void>;
|
|
630
|
+
adopt(options?: ModelContextAdoptOptions): Promise<readonly ToolInterface[]>;
|
|
631
|
+
destroy(): void;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Options for {@link ModelContextInterface.adopt} — the origins whose tools are read.
|
|
636
|
+
*
|
|
637
|
+
* @remarks
|
|
638
|
+
* `origins` is this package's one-word name for WebMCP's `fromOrigins`, forwarded unchanged.
|
|
639
|
+
* Omitting it reads this document's own registrations.
|
|
640
|
+
*/
|
|
641
|
+
export declare interface ModelContextAdoptOptions {
|
|
642
|
+
readonly origins?: readonly string[];
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* Reports the moments a WebMCP registry's contents changed.
|
|
647
|
+
*
|
|
648
|
+
* @remarks
|
|
649
|
+
* Declared as a `type` alias rather than an interface, so the type-literal satisfies
|
|
650
|
+
* `EventMap` structurally. One event, because the registry publishes one: WebMCP's
|
|
651
|
+
* `toolchange` names no tool and carries no payload, so the bridge republishes it as a bare
|
|
652
|
+
* signal and a listener re-reads {@link ModelContextInterface.adopt} to learn what changed.
|
|
653
|
+
*/
|
|
654
|
+
export declare type ModelContextEventMap = {
|
|
655
|
+
/** Reports that the document's registry changed — re-read it to learn how. */
|
|
656
|
+
readonly change: readonly [];
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Represents the bridge between a {@link ToolManagerInterface} and a document's WebMCP
|
|
661
|
+
* registry — what {@link import('./factories.js').createModelContext} returns.
|
|
662
|
+
*
|
|
663
|
+
* @remarks
|
|
664
|
+
* Bidirectional and symmetric: `publish` sends this page's tools out to the registry, `adopt`
|
|
665
|
+
* brings the registry's tools back in as `@orkestrel/tool` `Tool` instances. Both directions
|
|
666
|
+
* run the same annotation projection in opposite directions.
|
|
667
|
+
*
|
|
668
|
+
* The handle aborts exactly the registrations it made. WebMCP registration identity is the
|
|
669
|
+
* tool name, per document, so a later registration of a name replaces the earlier one whichever
|
|
670
|
+
* handle made it, and this handle's release takes whatever now stands under the names it
|
|
671
|
+
* registered — including a same-name registration another handle made later. Names this handle
|
|
672
|
+
* never registered are untouched.
|
|
673
|
+
*/
|
|
674
|
+
export declare interface ModelContextInterface {
|
|
675
|
+
/** Holds the emitter republishing the registry's `toolchange` as `change`. */
|
|
676
|
+
readonly emitter: EmitterInterface<ModelContextEventMap>;
|
|
677
|
+
/**
|
|
678
|
+
* Registers every tool the manager holds at this moment, then follows it.
|
|
679
|
+
*
|
|
680
|
+
* @remarks
|
|
681
|
+
* The snapshot is taken when the call is made, before the work queues behind an earlier
|
|
682
|
+
* `publish`, so a registry mutated while this call waits registers what it held at the call
|
|
683
|
+
* rather than what it holds when the queue reaches it.
|
|
684
|
+
*
|
|
685
|
+
* The same call subscribes to the manager's own `emitter`. Each `add`, `remove`, and
|
|
686
|
+
* `clear` it publishes queues one synchronisation of this handle's registrations against
|
|
687
|
+
* what the manager holds when that queued work runs, so the document registry converges on
|
|
688
|
+
* the tool registry after every change it follows, without a second call. Changes that
|
|
689
|
+
* arrive before that queued work runs are covered by it; a change that arrives after a
|
|
690
|
+
* later `publish` call takes a synchronisation of its own, which runs after that
|
|
691
|
+
* publication rather than before it. The event is the trigger and the manager is the fact:
|
|
692
|
+
* `remove` and `clear` carry tools the manager no longer holds, a listener that ran earlier
|
|
693
|
+
* in the same dispatch may already have put another tool under one of those names, and the
|
|
694
|
+
* manager's own `destroy` empties its map after publishing the `clear` that reports it. One
|
|
695
|
+
* manager is followed at a time: a `publish` naming another manager releases the
|
|
696
|
+
* subscription and takes up the new one, and `destroy` releases it outright. An event from
|
|
697
|
+
* a manager this handle no longer follows is ignored, which is what a listener republishing
|
|
698
|
+
* another manager from inside a dispatch produces. A followed change reaches no caller, so
|
|
699
|
+
* a tool advertising neither a `description` nor a `summary` is left unregistered rather
|
|
700
|
+
* than refusing anything, and a registration the document registry refuses is dropped, so
|
|
701
|
+
* the next call or the next synchronisation registers that name again. That batch still
|
|
702
|
+
* releases the names it dropped, because the prune runs whether or not every registration
|
|
703
|
+
* it asked for was made. A synchronisation registers only what it can carry, so such a tool
|
|
704
|
+
* standing under a name this handle already registered releases that registration instead
|
|
705
|
+
* of leaving it advertising a descriptor the manager no longer stands behind. Under a name
|
|
706
|
+
* this handle never registered the skip emits no `change`, because nothing reached the
|
|
707
|
+
* document registry; releasing a name this handle did register emits the registry's
|
|
708
|
+
* `change` like any other release. Compare the manager's own `definitions()` with what
|
|
709
|
+
* `adopt()` returns to read the mismatch, and
|
|
710
|
+
* {@link import('./helpers.js').describeWebMCPTool} answers `undefined` for a name
|
|
711
|
+
* `definitions()` still lists, which is that mismatch read from the manager's own side.
|
|
712
|
+
*
|
|
713
|
+
* Every name reconciles against what this handle registered for it, whether it arrives in a
|
|
714
|
+
* snapshot or through a synchronisation. The same manager still holding the same tool
|
|
715
|
+
* leaves the registration untouched, so a repeat publishes nothing and fires no
|
|
716
|
+
* `toolchange`. Another tool of that manager advertising an equal descriptor leaves the
|
|
717
|
+
* registration standing too, because execution routes through the manager by name and the
|
|
718
|
+
* replacement's handler is already what a foreign agent reaches. A changed projection, or
|
|
719
|
+
* the same name arriving from a different manager, releases the registration this handle
|
|
720
|
+
* holds and registers the new descriptor bound to the new manager. A name the snapshot
|
|
721
|
+
* dropped, and a name the followed manager no longer holds, is released after everything
|
|
722
|
+
* the batch carries has reconciled, so no name is withdrawn while the tools replacing it
|
|
723
|
+
* are still being registered.
|
|
724
|
+
*
|
|
725
|
+
* Every tool is projected before anything is registered, so a manager holding a tool with
|
|
726
|
+
* neither `description` nor `summary` is refused whole rather than half-registered.
|
|
727
|
+
*
|
|
728
|
+
* @param tools - The registry whose current tools are registered and whose later changes
|
|
729
|
+
* are followed
|
|
730
|
+
* @param options - The optional exposure list; see {@link ModelContextPublishOptions}
|
|
731
|
+
* @returns Resolves after the registry has accepted each added registration
|
|
732
|
+
* @throws Thrown when a tool carries neither a `description` nor a `summary`, because
|
|
733
|
+
* WebMCP requires the member and an empty string would be an invented one
|
|
734
|
+
*/
|
|
735
|
+
publish(tools: ToolManagerInterface, options?: ModelContextPublishOptions): Promise<void>;
|
|
736
|
+
/**
|
|
737
|
+
* Reads the document's registered tools as locally executable tools.
|
|
738
|
+
*
|
|
739
|
+
* @remarks
|
|
740
|
+
* Each returned tool's `execute` runs the registry's `executeTool` and forwards its
|
|
741
|
+
* `ToolContext.signal` as WebMCP's `signal`, so an agent-side abort reaches the foreign
|
|
742
|
+
* tool. The value resolves unchanged: WebMCP's own sources disagree about whether a tool
|
|
743
|
+
* answers with a string or an MCP content record, so the bridge normalizes neither.
|
|
744
|
+
*
|
|
745
|
+
* An adopted tool advertises the foreign `inputSchema` as its `parameters` and validates
|
|
746
|
+
* nothing against it. Compiling that schema into a contract would let one page's
|
|
747
|
+
* unreadable or hostile schema refuse the whole `adopt` call, and the arguments reach a
|
|
748
|
+
* handler in another document that has to validate them anyway.
|
|
749
|
+
*
|
|
750
|
+
* @param options - The optional origin filter; see {@link ModelContextAdoptOptions}
|
|
751
|
+
* @returns The registry's tools, in registry order
|
|
752
|
+
*/
|
|
753
|
+
adopt(options?: ModelContextAdoptOptions): Promise<readonly ToolInterface[]>;
|
|
754
|
+
/**
|
|
755
|
+
* Aborts every registration this handle made, stops following the tool registry, and
|
|
756
|
+
* releases the emitter — idempotent.
|
|
757
|
+
*
|
|
758
|
+
* @remarks
|
|
759
|
+
* The subscription is released before anything is aborted, and a synchronisation already
|
|
760
|
+
* queued reads the destroyed handle and stops, so no registration is made after this call
|
|
761
|
+
* and none is left behind for a later change to release.
|
|
762
|
+
*
|
|
763
|
+
* @returns Nothing
|
|
764
|
+
*/
|
|
765
|
+
destroy(): void;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Options for {@link import('./factories.js').createModelContext} — the document to bridge
|
|
770
|
+
* and the emitter's initial wiring.
|
|
771
|
+
*
|
|
772
|
+
* @remarks
|
|
773
|
+
* - `document` — the document whose registry to bridge, defaulting to `globalThis.document`.
|
|
774
|
+
* A document exposing no `modelContext` makes the factory return `undefined`.
|
|
775
|
+
* - `on` — the reserved initial {@link import('@orkestrel/emitter').EmitterHooks} for
|
|
776
|
+
* {@link ModelContextEventMap}.
|
|
777
|
+
* - `error` — the emitter's listener-error handler; a listener throw routes here rather than
|
|
778
|
+
* to a domain event.
|
|
779
|
+
*/
|
|
780
|
+
export declare interface ModelContextOptions {
|
|
781
|
+
readonly document?: Document;
|
|
782
|
+
readonly on?: EmitterHooks<ModelContextEventMap>;
|
|
783
|
+
readonly error?: EmitterErrorHandler;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* Options for {@link ModelContextInterface.publish} — the origins each registration is
|
|
788
|
+
* exposed to.
|
|
789
|
+
*
|
|
790
|
+
* @remarks
|
|
791
|
+
* `origins` is this package's one-word name for WebMCP's `exposedTo`, forwarded unchanged.
|
|
792
|
+
* Omitting it registers with no exposure list, which is the registry's own default.
|
|
793
|
+
*/
|
|
794
|
+
export declare interface ModelContextPublishOptions {
|
|
795
|
+
readonly origins?: readonly string[];
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* Represents one MCP server hosted inside the calling page — what
|
|
800
|
+
* {@link import('./factories.js').createPageServer} returns.
|
|
801
|
+
*
|
|
802
|
+
* @remarks
|
|
803
|
+
* The page twin of {@link ScopeServerInterface}, and it publishes the client beside the
|
|
804
|
+
* terminal because the pair's whole value is holding both ends. The returned `client` is
|
|
805
|
+
* bound but NOT connected: connection is a protocol round trip over the channel, so it stays
|
|
806
|
+
* the consumer's `await client.connect()` rather than a promise the factory hides.
|
|
807
|
+
*
|
|
808
|
+
* `stop` closes the client's port first, so the client observes the close and reports
|
|
809
|
+
* `connected` as `false`, then unbinds both sides and closes the server's port. It is
|
|
810
|
+
* idempotent, and it ends this handle's lifetime permanently — the same verb, with the same
|
|
811
|
+
* meaning, that {@link ScopeServerInterface} publishes for the same action.
|
|
812
|
+
*
|
|
813
|
+
* The published `client` stays reachable after `stop` and is inert: `call` and `tools` reject
|
|
814
|
+
* at once with an `MCPError` carrying `-32600`, because the pair's channel is closed and no
|
|
815
|
+
* `connect` can reopen it.
|
|
816
|
+
*/
|
|
817
|
+
export declare interface PageServerInterface {
|
|
818
|
+
/** Holds the client bound to the server this page hosts, awaiting its own `connect`. */
|
|
819
|
+
readonly client: MCPClientInterface;
|
|
820
|
+
/** Closes both ports, unbinds both sides, and disconnects the client — idempotent. */
|
|
821
|
+
stop(): void;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* Options for {@link import('./factories.js').createPageServer} — the live
|
|
826
|
+
* {@link ToolManagerInterface} to expose, the optional server identity, and the optional
|
|
827
|
+
* settings for the client half the pair owns.
|
|
828
|
+
*
|
|
829
|
+
* @remarks
|
|
830
|
+
* - `tools` — the registry the hosted `MCPServer` dispatches `tools/call` against. Required.
|
|
831
|
+
* - `name` / `version` — the hosted server's identity, defaulting to
|
|
832
|
+
* {@link import('./constants.js').DEFAULT_MCP_SERVER_NAME} /
|
|
833
|
+
* {@link import('./constants.js').DEFAULT_MCP_SERVER_VERSION} exactly as
|
|
834
|
+
* {@link ScopeServerOptions} does.
|
|
835
|
+
* - `client` — the client half's own settings, grouped because there is more than one, and
|
|
836
|
+
* declared as `MCPClientOptions` (`@orkestrel/mcp`) minus its one omission rather than as a
|
|
837
|
+
* restatement of its members: every member the client accepts reaches this factory, and a
|
|
838
|
+
* member added to that interface later reaches it without an edit here. `transport` is the
|
|
839
|
+
* omission, and the only one: the pair mints the `MessageChannel` and owns both ends of it,
|
|
840
|
+
* which is the whole point of the factory, so a caller-supplied carrier would be a second
|
|
841
|
+
* transport with nothing on the other side of it.
|
|
842
|
+
*/
|
|
843
|
+
export declare interface PageServerOptions {
|
|
844
|
+
readonly tools: ToolManagerInterface;
|
|
845
|
+
readonly name?: string;
|
|
846
|
+
readonly version?: string;
|
|
847
|
+
readonly client?: Omit<MCPClientOptions, 'transport'>;
|
|
848
|
+
}
|
|
849
|
+
|
|
315
850
|
/**
|
|
316
851
|
* Describes the structural shape {@link import('./factories.js').createScopeServer} needs
|
|
317
852
|
* from a
|
|
@@ -327,8 +862,11 @@ export declare interface MessagePortTransportOptions {
|
|
|
327
862
|
* structurally (it exposes far more, which this narrower shape ignores).
|
|
328
863
|
*/
|
|
329
864
|
export declare interface ScopeInterface {
|
|
865
|
+
/** Posts one reply onto the scope's implicit channel. */
|
|
330
866
|
postMessage(message: unknown): void;
|
|
867
|
+
/** Subscribes to the scope's `message` events, portless and port-bearing alike. */
|
|
331
868
|
addEventListener(type: 'message', listener: (event: MessageEvent) => void): void;
|
|
869
|
+
/** Drops a `message` subscription. */
|
|
332
870
|
removeEventListener(type: 'message', listener: (event: MessageEvent) => void): void;
|
|
333
871
|
}
|
|
334
872
|
|
|
@@ -389,6 +927,254 @@ export declare interface ScopeTransportInterface extends MCPTransportInterface {
|
|
|
389
927
|
deliver(message: string): void;
|
|
390
928
|
}
|
|
391
929
|
|
|
930
|
+
/**
|
|
931
|
+
* Projects domain tool annotations onto WebMCP registry hints without inventing defaults.
|
|
932
|
+
*
|
|
933
|
+
* @param annotations - The authored domain annotations
|
|
934
|
+
* @returns The mapped hints; an omitted annotation stays omitted
|
|
935
|
+
*
|
|
936
|
+
* @example
|
|
937
|
+
* ```ts
|
|
938
|
+
* toolAnnotationsToWebMCP({ pure: true, untrusted: true }) // { readOnlyHint: true, untrustedContentHint: true }
|
|
939
|
+
* ```
|
|
940
|
+
*/
|
|
941
|
+
export declare function toolAnnotationsToWebMCP(annotations: ToolAnnotations): WebMCPAnnotations;
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* Projects one advertised tool definition onto the WebMCP descriptor a registration carries.
|
|
945
|
+
*
|
|
946
|
+
* @remarks
|
|
947
|
+
* Takes the definition a `ToolManagerInterface` advertises rather than the tool itself, so the
|
|
948
|
+
* description here is the one the MCP wire advertises too — the registry substitutes an
|
|
949
|
+
* authored `summary` for the full `description`, and reading the same projection keeps one
|
|
950
|
+
* advertised description across both surfaces.
|
|
951
|
+
*
|
|
952
|
+
* WebMCP requires `description`, so a definition carrying none cannot be registered at all.
|
|
953
|
+
* Returning `undefined` is what lets the caller refuse the whole batch before registering any
|
|
954
|
+
* of it; registering an empty string instead would be an invented value a foreign agent reads
|
|
955
|
+
* as a real one.
|
|
956
|
+
*
|
|
957
|
+
* @param definition - The advertised definition to project
|
|
958
|
+
* @returns The WebMCP descriptor, or `undefined` when the definition advertises no description
|
|
959
|
+
*
|
|
960
|
+
* @example
|
|
961
|
+
* ```ts
|
|
962
|
+
* toolToWebMCP({ name: 'add', description: 'Adds two numbers' })?.description // 'Adds two numbers'
|
|
963
|
+
* ```
|
|
964
|
+
*/
|
|
965
|
+
export declare function toolToWebMCP(definition: ToolDefinition): WebMCPDescriptor | undefined;
|
|
966
|
+
|
|
967
|
+
/** Names the WebMCP registry event the bridge republishes as its own `change`. */
|
|
968
|
+
export declare const WEBMCP_CHANGE_EVENT = "toolchange";
|
|
969
|
+
|
|
970
|
+
/**
|
|
971
|
+
* Describes a tool's observable effects as the WebMCP registry declares them.
|
|
972
|
+
*
|
|
973
|
+
* @remarks
|
|
974
|
+
* Transliterates the WebMCP `ToolAnnotations` dictionary. The IDL defaults each member to
|
|
975
|
+
* `false`; this declaration keeps every member optional instead, because the bridge projects
|
|
976
|
+
* from `@orkestrel/tool`'s `ToolAnnotations` and never invents a hint the author omitted. The
|
|
977
|
+
* mapping is `pure` to `readOnlyHint`, `untrusted` to `untrustedContentHint`, and
|
|
978
|
+
* `consequential` to `consequentialHint` — a fuller correspondence than the MCP wire's, which
|
|
979
|
+
* has no counterpart for `untrusted` and spells the consequence `destructiveHint`.
|
|
980
|
+
*/
|
|
981
|
+
export declare interface WebMCPAnnotations {
|
|
982
|
+
readonly readOnlyHint?: boolean;
|
|
983
|
+
readonly untrustedContentHint?: boolean;
|
|
984
|
+
readonly consequentialHint?: boolean;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
/**
|
|
988
|
+
* Projects WebMCP registry hints onto domain tool annotations without inventing defaults.
|
|
989
|
+
*
|
|
990
|
+
* @param annotations - The registry's hints, as the WebMCP dictionary declares them
|
|
991
|
+
* @returns The mapped annotations; an omitted hint stays omitted
|
|
992
|
+
*
|
|
993
|
+
* @example
|
|
994
|
+
* ```ts
|
|
995
|
+
* webMCPAnnotationsToTool({ readOnlyHint: false, consequentialHint: true }) // { pure: false, consequential: true }
|
|
996
|
+
* ```
|
|
997
|
+
*/
|
|
998
|
+
export declare function webMCPAnnotationsToTool(annotations: WebMCPAnnotations): ToolAnnotations;
|
|
999
|
+
|
|
1000
|
+
/**
|
|
1001
|
+
* Describes the members a WebMCP tool carries into the registry and back out of it.
|
|
1002
|
+
*
|
|
1003
|
+
* @remarks
|
|
1004
|
+
* The WebMCP `ModelContextTool` and `RegisteredTool` dictionaries declare the same members —
|
|
1005
|
+
* `name`, `title`, `description`, `inputSchema`, `annotations` — and differ only in what each
|
|
1006
|
+
* adds, so this is the shared body {@link WebMCPTool} and {@link WebMCPRegisteredTool} extend.
|
|
1007
|
+
* `description` is required in the IDL and stays required here, which is why `publish` refuses
|
|
1008
|
+
* a tool that authors neither a description nor a summary rather than registering an empty one.
|
|
1009
|
+
*/
|
|
1010
|
+
export declare interface WebMCPDescriptor {
|
|
1011
|
+
readonly name: string;
|
|
1012
|
+
readonly title?: string;
|
|
1013
|
+
readonly description: string;
|
|
1014
|
+
readonly inputSchema?: Readonly<Record<string, unknown>>;
|
|
1015
|
+
readonly annotations?: WebMCPAnnotations;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
/**
|
|
1019
|
+
* Describes a document that exposes the WebMCP tool registry.
|
|
1020
|
+
*
|
|
1021
|
+
* @remarks
|
|
1022
|
+
* The narrowed shape {@link import('./validators.js').isWebMCPDocument} produces, and the one
|
|
1023
|
+
* value {@link import('./ModelContext.js').ModelContext} needs. It declares the `modelContext`
|
|
1024
|
+
* member alone rather than extending `Document`, because that member is the whole of what the
|
|
1025
|
+
* bridge dereferences — a real `Document` carrying the registry satisfies it structurally, and
|
|
1026
|
+
* so does any other host object that exposes one.
|
|
1027
|
+
*/
|
|
1028
|
+
export declare interface WebMCPDocument {
|
|
1029
|
+
readonly modelContext: WebMCPRegistryInterface;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
/**
|
|
1033
|
+
* Runs one registered WebMCP tool with the caller's input and the registry's signal.
|
|
1034
|
+
*
|
|
1035
|
+
* @remarks
|
|
1036
|
+
* Transliterates the WebMCP `ToolExecuteCallback` callback. The IDL types its return
|
|
1037
|
+
* `Promise<any>` and this declaration narrows that to `Promise<unknown>`, because a caller
|
|
1038
|
+
* must narrow what a foreign tool returned before reading it.
|
|
1039
|
+
*/
|
|
1040
|
+
export declare type WebMCPExecuteHandler = (input: Readonly<Record<string, unknown>>, options: WebMCPHandlerOptions) => Promise<unknown>;
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* Options for the WebMCP registry's `executeTool` — the caller's cancellation signal.
|
|
1044
|
+
*
|
|
1045
|
+
* @remarks
|
|
1046
|
+
* Transliterates the WebMCP `ModelContextExecuteToolOptions` dictionary. The registry
|
|
1047
|
+
* forwards this signal onto the {@link WebMCPHandlerOptions} it hands the tool's callback.
|
|
1048
|
+
*/
|
|
1049
|
+
export declare interface WebMCPExecuteOptions {
|
|
1050
|
+
readonly signal?: AbortSignal;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
/**
|
|
1054
|
+
* Carries the execution signal the WebMCP registry hands a registered tool's callback.
|
|
1055
|
+
*
|
|
1056
|
+
* @remarks
|
|
1057
|
+
* Transliterates the WebMCP `ToolExecuteCallbackOptions` dictionary, whose `signal` is
|
|
1058
|
+
* required: the registry always mints one, and an `executeTool` caller's own signal is
|
|
1059
|
+
* forwarded onto it.
|
|
1060
|
+
*/
|
|
1061
|
+
export declare interface WebMCPHandlerOptions {
|
|
1062
|
+
readonly signal: AbortSignal;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
/**
|
|
1066
|
+
* Pairs one tool with the WebMCP descriptor a registry advertises for it.
|
|
1067
|
+
*
|
|
1068
|
+
* @remarks
|
|
1069
|
+
* The bridge's own pairing rather than a WebMCP dictionary. A registration has to answer later
|
|
1070
|
+
* whether the manager still holds the tool it was made for, and a descriptor alone cannot
|
|
1071
|
+
* answer that: two tools can advertise identical descriptors, and a descriptor JSON cannot
|
|
1072
|
+
* encode — a cyclic `inputSchema` — compares equal to none, its own included.
|
|
1073
|
+
*/
|
|
1074
|
+
export declare interface WebMCPProjection {
|
|
1075
|
+
readonly tool: ToolInterface;
|
|
1076
|
+
readonly descriptor: WebMCPDescriptor;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
/**
|
|
1080
|
+
* Describes one tool as the WebMCP registry reports it back.
|
|
1081
|
+
*
|
|
1082
|
+
* @remarks
|
|
1083
|
+
* Transliterates the WebMCP `RegisteredTool` dictionary: {@link WebMCPDescriptor}'s members
|
|
1084
|
+
* plus the `window` that registered the tool and the `origin` it was registered from. The
|
|
1085
|
+
* bridge carries both unread — `executeTool` takes the whole record back — and reads the
|
|
1086
|
+
* descriptor members alone.
|
|
1087
|
+
*/
|
|
1088
|
+
export declare interface WebMCPRegisteredTool extends WebMCPDescriptor {
|
|
1089
|
+
readonly window: Window;
|
|
1090
|
+
readonly origin: string;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
/**
|
|
1094
|
+
* Options for the WebMCP registry's `registerTool` — the exposure list and the
|
|
1095
|
+
* unregistration signal.
|
|
1096
|
+
*
|
|
1097
|
+
* @remarks
|
|
1098
|
+
* Transliterates the WebMCP `ModelContextRegisterToolOptions` dictionary. `exposedTo` lists
|
|
1099
|
+
* the origins the registration is visible to; `signal` is WebMCP's unregistration path —
|
|
1100
|
+
* aborting it removes the tool, which is why the bridge retains one controller per
|
|
1101
|
+
* registration.
|
|
1102
|
+
*/
|
|
1103
|
+
export declare interface WebMCPRegisterOptions {
|
|
1104
|
+
readonly exposedTo?: readonly string[];
|
|
1105
|
+
readonly signal?: AbortSignal;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
/**
|
|
1109
|
+
* Represents the WebMCP tool registry a document exposes as `document.modelContext`.
|
|
1110
|
+
*
|
|
1111
|
+
* @remarks
|
|
1112
|
+
* Transliterates the WebMCP `ModelContext` interface, which extends `EventTarget`: the
|
|
1113
|
+
* operations plus the `toolchange` subscription the bridge republishes as
|
|
1114
|
+
* {@link ModelContextEventMap}'s `change`. Only the members the bridge touches are declared,
|
|
1115
|
+
* exactly as {@link ScopeInterface} declares only what `createScopeServer` touches, so a real
|
|
1116
|
+
* `ModelContext` satisfies this structurally and an IDL-faithful double satisfies it without
|
|
1117
|
+
* implementing the whole of `EventTarget`.
|
|
1118
|
+
*
|
|
1119
|
+
* `executeTool` resolves `unknown` because the primary source disagrees with itself: the IDL
|
|
1120
|
+
* types it `Promise<DOMString>` while the specification's own README sample returns the MCP
|
|
1121
|
+
* content shape `{ content: [...] }` from a tool's callback. The bridge records that
|
|
1122
|
+
* disagreement rather than resolving it, so it neither parses the answer as text nor projects
|
|
1123
|
+
* it into content blocks.
|
|
1124
|
+
*/
|
|
1125
|
+
export declare interface WebMCPRegistryInterface {
|
|
1126
|
+
/** Registers one tool, resolving when the registry has accepted it. */
|
|
1127
|
+
registerTool(tool: WebMCPTool, options?: WebMCPRegisterOptions): Promise<void>;
|
|
1128
|
+
/** Reads the registered tools this document may see. */
|
|
1129
|
+
getTools(options?: WebMCPToolsOptions): Promise<readonly WebMCPRegisteredTool[]>;
|
|
1130
|
+
/** Runs one registered tool and resolves whatever its callback returned. */
|
|
1131
|
+
executeTool(tool: WebMCPRegisteredTool, input?: Readonly<Record<string, unknown>>, options?: WebMCPExecuteOptions): Promise<unknown>;
|
|
1132
|
+
/** Subscribes to the registry's `toolchange` event. */
|
|
1133
|
+
addEventListener(type: 'toolchange', listener: () => void): void;
|
|
1134
|
+
/** Drops a `toolchange` subscription. */
|
|
1135
|
+
removeEventListener(type: 'toolchange', listener: () => void): void;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
/**
|
|
1139
|
+
* Describes one tool as handed to the WebMCP registry for registration.
|
|
1140
|
+
*
|
|
1141
|
+
* @remarks
|
|
1142
|
+
* Transliterates the WebMCP `ModelContextTool` dictionary: {@link WebMCPDescriptor}'s members
|
|
1143
|
+
* plus the required `execute` callback the registry invokes.
|
|
1144
|
+
*/
|
|
1145
|
+
export declare interface WebMCPTool extends WebMCPDescriptor {
|
|
1146
|
+
readonly execute: WebMCPExecuteHandler;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
/**
|
|
1150
|
+
* Options for the WebMCP registry's `getTools` — the origins whose tools are read.
|
|
1151
|
+
*
|
|
1152
|
+
* @remarks
|
|
1153
|
+
* Transliterates the WebMCP `ModelContextGetToolOptions` dictionary. Omitting `fromOrigins`
|
|
1154
|
+
* reads this document's own registrations.
|
|
1155
|
+
*/
|
|
1156
|
+
export declare interface WebMCPToolsOptions {
|
|
1157
|
+
readonly fromOrigins?: readonly string[];
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
/**
|
|
1161
|
+
* Projects one registered WebMCP tool onto the tool definition an adopted tool advertises.
|
|
1162
|
+
*
|
|
1163
|
+
* @remarks
|
|
1164
|
+
* The inverse of {@link toolToWebMCP}, and deliberately lossy in the other direction: the
|
|
1165
|
+
* registry's `window` and `origin` describe where the tool lives rather than what it does, and
|
|
1166
|
+
* the bridge hands the whole registered record back to `executeTool` instead of rebuilding it.
|
|
1167
|
+
*
|
|
1168
|
+
* @param registered - The registered tool the registry reported
|
|
1169
|
+
* @returns The definition an adopted tool advertises
|
|
1170
|
+
*
|
|
1171
|
+
* @example
|
|
1172
|
+
* ```ts
|
|
1173
|
+
* webMCPToTool({ name: 'add', description: 'Adds', window, origin: 'https://a.example' }).name // 'add'
|
|
1174
|
+
* ```
|
|
1175
|
+
*/
|
|
1176
|
+
export declare function webMCPToTool(registered: WebMCPRegisteredTool): ToolDefinition;
|
|
1177
|
+
|
|
392
1178
|
/**
|
|
393
1179
|
* Drives a remote MCP server over the native `WebSocket` global from the browser face, as a
|
|
394
1180
|
* client {@link MCPMessageTransportInterface}. This class is the browser sibling of the Node
|