nexus-ai-pro 2.20.2 → 2.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API_STABILITY.md +93 -0
- package/CHANGELOG.md +208 -1
- package/README.md +11 -6
- package/SECURITY.md +16 -2
- package/dist/adapter-kit/gather.d.ts +76 -0
- package/dist/adapter-kit/gather.js +147 -0
- package/dist/adapter-kit/index.d.ts +1 -0
- package/dist/adapter-kit/index.js +1 -0
- package/dist/adapter-kit/record.d.ts +3 -1
- package/dist/adapter-kit/record.js +20 -5
- package/dist/agent/openapi.d.ts +94 -8
- package/dist/agent/openapi.js +528 -32
- package/dist/cli/adapters.d.ts +4 -3
- package/dist/cli/adapters.js +71 -2
- package/dist/cli/doctor.js +3 -0
- package/dist/cli.js +3 -1
- package/dist/core/config-builder.d.ts +1 -0
- package/dist/core/config-builder.js +1 -0
- package/dist/core/defaults.d.ts +34 -0
- package/dist/core/defaults.js +39 -0
- package/dist/core/secure-stream.js +4 -1
- package/dist/decisions/completion.d.ts +10 -7
- package/dist/decisions/completion.js +82 -8
- package/dist/decisions/core.d.ts +88 -43
- package/dist/decisions/core.js +115 -28
- package/dist/decisions/errors.d.ts +25 -0
- package/dist/decisions/errors.js +12 -0
- package/dist/decisions/index.d.ts +6 -5
- package/dist/decisions/index.js +2 -1
- package/dist/decisions/integrations.d.ts +14 -5
- package/dist/decisions/integrations.js +16 -1
- package/dist/decisions/mock.d.ts +5 -3
- package/dist/decisions/mock.js +4 -1
- package/dist/decisions/pictures.d.ts +43 -0
- package/dist/decisions/pictures.js +103 -0
- package/dist/decisions/typesafe.d.ts +33 -5
- package/dist/decisions/typesafe.js +121 -8
- package/dist/doctor/index.d.ts +6 -9
- package/dist/doctor/index.js +41 -0
- package/dist/embeddings/adapters.d.ts +1 -1
- package/dist/embeddings/adapters.js +3 -3
- package/dist/embeddings/batch-google.d.ts +27 -8
- package/dist/embeddings/batch-google.js +112 -36
- package/dist/embeddings/batch-mock.js +1 -1
- package/dist/embeddings/batch.js +10 -4
- package/dist/embeddings/engine.js +14 -13
- package/dist/embeddings/index.d.ts +1 -1
- package/dist/embeddings/inputs.d.ts +26 -3
- package/dist/embeddings/inputs.js +84 -5
- package/dist/embeddings/mock.js +1 -1
- package/dist/embeddings/models.js +39 -4
- package/dist/loaders/csv.d.ts +23 -1
- package/dist/loaders/csv.js +125 -72
- package/dist/loaders/index.d.ts +7 -2
- package/dist/loaders/input.d.ts +6 -0
- package/dist/loaders/input.js +42 -1
- package/dist/loaders/json.d.ts +14 -3
- package/dist/loaders/json.js +171 -20
- package/dist/loaders/web.d.ts +55 -0
- package/dist/loaders/web.js +20 -1
- package/dist/mcp/client.d.ts +54 -5
- package/dist/mcp/client.js +171 -20
- package/dist/mcp/http.d.ts +45 -0
- package/dist/mcp/http.js +233 -0
- package/dist/mcp/index.d.ts +4 -2
- package/dist/mcp/index.js +3 -1
- package/dist/mcp/protocol.d.ts +107 -0
- package/dist/mcp/sampling.d.ts +41 -0
- package/dist/mcp/sampling.js +52 -0
- package/dist/mcp/server.d.ts +96 -14
- package/dist/mcp/server.js +274 -59
- package/dist/models/data.js +20 -1
- package/dist/operations/adapters.d.ts +1 -0
- package/dist/operations/adapters.js +3 -1
- package/dist/protocols/a2a-grpc.js +10 -3
- package/dist/protocols/a2a-signing.d.ts +65 -0
- package/dist/protocols/a2a-signing.js +133 -0
- package/dist/protocols/a2a.d.ts +14 -0
- package/dist/protocols/a2a.js +60 -5
- package/dist/providers/cohere.js +16 -2
- package/dist/providers/google.js +7 -1
- package/dist/providers/ollama.d.ts +1 -1
- package/dist/providers/ollama.js +35 -27
- package/dist/providers/openai.js +19 -2
- package/dist/rag/pinecone.d.ts +63 -2
- package/dist/rag/pinecone.js +80 -0
- package/dist/realtime/conversation.js +18 -0
- package/dist/realtime/gemini-live.transport.d.ts +28 -3
- package/dist/realtime/gemini-live.transport.js +170 -32
- package/dist/realtime/session.d.ts +2 -0
- package/dist/realtime/session.js +19 -4
- package/dist/realtime/types.d.ts +35 -3
- package/dist/security/output-guard.js +4 -1
- package/dist/server/auth.d.ts +263 -2
- package/dist/server/auth.js +432 -5
- package/dist/server/deployments.d.ts +3 -2
- package/dist/server/deployments.js +6 -1
- package/dist/telephony/index.d.ts +1 -1
- package/dist/telephony/manager.d.ts +8 -1
- package/dist/telephony/manager.js +13 -0
- package/dist/telephony/providers/telnyx.d.ts +18 -5
- package/dist/telephony/providers/telnyx.js +44 -7
- package/dist/telephony/providers/twilio.d.ts +3 -1
- package/dist/telephony/providers/twilio.js +16 -0
- package/dist/tracing/stores.d.ts +2 -0
- package/dist/tracing/stores.js +1 -0
- package/dist/tracing/tracer.d.ts +5 -2
- package/dist/tracing/tracer.js +6 -3
- package/dist/types/embeddings.d.ts +47 -5
- package/dist/types/messages.d.ts +7 -0
- package/dist/types/principal.d.ts +1 -1
- package/dist/types/response.d.ts +5 -0
- package/dist/types/telephony.d.ts +38 -0
- package/dist/types/tracing.d.ts +6 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/voice/providers/google.d.ts +44 -0
- package/dist/voice/providers/google.js +215 -0
- package/dist-cjs/adapter-kit/gather.d.ts +76 -0
- package/dist-cjs/adapter-kit/gather.js +152 -0
- package/dist-cjs/adapter-kit/index.d.ts +1 -0
- package/dist-cjs/adapter-kit/index.js +4 -1
- package/dist-cjs/adapter-kit/record.d.ts +3 -1
- package/dist-cjs/adapter-kit/record.js +20 -5
- package/dist-cjs/agent/openapi.d.ts +94 -8
- package/dist-cjs/agent/openapi.js +530 -32
- package/dist-cjs/cli/adapters.d.ts +4 -3
- package/dist-cjs/cli/adapters.js +70 -1
- package/dist-cjs/cli/doctor.js +3 -0
- package/dist-cjs/core/config-builder.d.ts +1 -0
- package/dist-cjs/core/config-builder.js +5 -1
- package/dist-cjs/core/defaults.d.ts +34 -0
- package/dist-cjs/core/defaults.js +44 -0
- package/dist-cjs/core/secure-stream.js +4 -1
- package/dist-cjs/decisions/completion.d.ts +10 -7
- package/dist-cjs/decisions/completion.js +81 -7
- package/dist-cjs/decisions/core.d.ts +88 -43
- package/dist-cjs/decisions/core.js +134 -46
- package/dist-cjs/decisions/errors.d.ts +25 -0
- package/dist-cjs/decisions/errors.js +16 -0
- package/dist-cjs/decisions/index.d.ts +6 -5
- package/dist-cjs/decisions/index.js +5 -1
- package/dist-cjs/decisions/integrations.d.ts +14 -5
- package/dist-cjs/decisions/integrations.js +16 -1
- package/dist-cjs/decisions/mock.d.ts +5 -3
- package/dist-cjs/decisions/mock.js +4 -1
- package/dist-cjs/decisions/pictures.d.ts +43 -0
- package/dist-cjs/decisions/pictures.js +109 -0
- package/dist-cjs/decisions/typesafe.d.ts +33 -5
- package/dist-cjs/decisions/typesafe.js +126 -13
- package/dist-cjs/doctor/index.d.ts +6 -9
- package/dist-cjs/doctor/index.js +41 -0
- package/dist-cjs/embeddings/adapters.d.ts +1 -1
- package/dist-cjs/embeddings/adapters.js +3 -3
- package/dist-cjs/embeddings/batch-google.d.ts +27 -8
- package/dist-cjs/embeddings/batch-google.js +112 -36
- package/dist-cjs/embeddings/batch-mock.js +1 -1
- package/dist-cjs/embeddings/batch.js +9 -3
- package/dist-cjs/embeddings/engine.js +13 -12
- package/dist-cjs/embeddings/index.d.ts +1 -1
- package/dist-cjs/embeddings/inputs.d.ts +26 -3
- package/dist-cjs/embeddings/inputs.js +89 -5
- package/dist-cjs/embeddings/mock.js +1 -1
- package/dist-cjs/embeddings/models.js +39 -4
- package/dist-cjs/loaders/csv.d.ts +23 -1
- package/dist-cjs/loaders/csv.js +126 -71
- package/dist-cjs/loaders/index.d.ts +7 -2
- package/dist-cjs/loaders/input.d.ts +6 -0
- package/dist-cjs/loaders/input.js +43 -1
- package/dist-cjs/loaders/json.d.ts +14 -3
- package/dist-cjs/loaders/json.js +170 -19
- package/dist-cjs/loaders/web.d.ts +55 -0
- package/dist-cjs/loaders/web.js +21 -1
- package/dist-cjs/mcp/client.d.ts +54 -5
- package/dist-cjs/mcp/client.js +171 -20
- package/dist-cjs/mcp/http.d.ts +45 -0
- package/dist-cjs/mcp/http.js +236 -0
- package/dist-cjs/mcp/index.d.ts +4 -2
- package/dist-cjs/mcp/index.js +5 -1
- package/dist-cjs/mcp/protocol.d.ts +107 -0
- package/dist-cjs/mcp/sampling.d.ts +41 -0
- package/dist-cjs/mcp/sampling.js +55 -0
- package/dist-cjs/mcp/server.d.ts +96 -14
- package/dist-cjs/mcp/server.js +273 -58
- package/dist-cjs/models/data.js +20 -1
- package/dist-cjs/operations/adapters.d.ts +1 -0
- package/dist-cjs/operations/adapters.js +3 -1
- package/dist-cjs/protocols/a2a-grpc.js +10 -3
- package/dist-cjs/protocols/a2a-signing.d.ts +65 -0
- package/dist-cjs/protocols/a2a-signing.js +140 -0
- package/dist-cjs/protocols/a2a.d.ts +14 -0
- package/dist-cjs/protocols/a2a.js +65 -6
- package/dist-cjs/providers/cohere.js +16 -2
- package/dist-cjs/providers/google.js +7 -1
- package/dist-cjs/providers/ollama.d.ts +1 -1
- package/dist-cjs/providers/ollama.js +35 -27
- package/dist-cjs/providers/openai.js +19 -2
- package/dist-cjs/rag/pinecone.d.ts +63 -2
- package/dist-cjs/rag/pinecone.js +81 -0
- package/dist-cjs/realtime/conversation.js +18 -0
- package/dist-cjs/realtime/gemini-live.transport.d.ts +28 -3
- package/dist-cjs/realtime/gemini-live.transport.js +170 -32
- package/dist-cjs/realtime/session.d.ts +2 -0
- package/dist-cjs/realtime/session.js +19 -4
- package/dist-cjs/realtime/types.d.ts +35 -3
- package/dist-cjs/security/output-guard.js +4 -1
- package/dist-cjs/server/auth.d.ts +263 -2
- package/dist-cjs/server/auth.js +437 -5
- package/dist-cjs/server/deployments.d.ts +3 -2
- package/dist-cjs/server/deployments.js +6 -1
- package/dist-cjs/telephony/index.d.ts +1 -1
- package/dist-cjs/telephony/manager.d.ts +8 -1
- package/dist-cjs/telephony/manager.js +13 -0
- package/dist-cjs/telephony/providers/telnyx.d.ts +18 -5
- package/dist-cjs/telephony/providers/telnyx.js +44 -7
- package/dist-cjs/telephony/providers/twilio.d.ts +3 -1
- package/dist-cjs/telephony/providers/twilio.js +16 -0
- package/dist-cjs/tracing/stores.d.ts +2 -0
- package/dist-cjs/tracing/stores.js +1 -0
- package/dist-cjs/tracing/tracer.d.ts +5 -2
- package/dist-cjs/tracing/tracer.js +6 -3
- package/dist-cjs/types/embeddings.d.ts +47 -5
- package/dist-cjs/types/messages.d.ts +7 -0
- package/dist-cjs/types/principal.d.ts +1 -1
- package/dist-cjs/types/response.d.ts +5 -0
- package/dist-cjs/types/telephony.d.ts +38 -0
- package/dist-cjs/types/tracing.d.ts +6 -0
- package/dist-cjs/version.d.ts +1 -1
- package/dist-cjs/version.js +1 -1
- package/dist-cjs/voice/providers/google.d.ts +44 -0
- package/dist-cjs/voice/providers/google.js +252 -0
- package/llms.txt +1 -1
- package/package.json +17 -1
package/dist/loaders/web.d.ts
CHANGED
|
@@ -28,7 +28,62 @@ export interface WebLoaderOptions extends SafeFetchPolicy {
|
|
|
28
28
|
onError?: 'throw' | 'skip';
|
|
29
29
|
/** Called for each page skipped, with the reason. */
|
|
30
30
|
onSkip?: (url: string, reason: Error) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Renders a page whose content a script builds, with a browser of the application's own, such as
|
|
33
|
+
* `browserRenderer()` over Playwright's: given the page fetched, it returns the HTML the browser ends
|
|
34
|
+
* with. Called for an HTML page that runs a script and whose text, as fetched, is shorter than
|
|
35
|
+
* `renderBelow`. The fetch has checked the page's URL first; the browser fetches what the page
|
|
36
|
+
* loads under its own policy.
|
|
37
|
+
*/
|
|
38
|
+
render?: WebPageRenderer;
|
|
39
|
+
/** Renders a page whose fetched text is shorter than this many characters. Defaults to 200; `Infinity` renders every page that runs a script. */
|
|
40
|
+
renderBelow?: number;
|
|
41
|
+
}
|
|
42
|
+
/** A page as fetched, which a renderer is given. */
|
|
43
|
+
export interface WebPageToRender {
|
|
44
|
+
/** Its URL, after redirects. */
|
|
45
|
+
url: string;
|
|
46
|
+
/** The HTML the server sent. */
|
|
47
|
+
html: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Renders a page with a browser: the HTML it ends with once the page's scripts have run, which is
|
|
51
|
+
* what a page built by script holds.
|
|
52
|
+
*/
|
|
53
|
+
export type WebPageRenderer = (page: WebPageToRender, signal: AbortSignal) => Promise<string> | string;
|
|
54
|
+
/** What `browserRenderer()` drives: a Playwright or Puppeteer browser, or anything shaped like one. */
|
|
55
|
+
export interface RenderingBrowser {
|
|
56
|
+
/** Opens a page. */
|
|
57
|
+
newPage(): Promise<{
|
|
58
|
+
/** Goes to a URL and waits as told. */
|
|
59
|
+
goto(url: string, options?: {
|
|
60
|
+
waitUntil?: string;
|
|
61
|
+
timeout?: number;
|
|
62
|
+
}): Promise<unknown>;
|
|
63
|
+
/** The HTML the page holds now. */
|
|
64
|
+
content(): Promise<string>;
|
|
65
|
+
/** Closes it. */
|
|
66
|
+
close(): Promise<unknown>;
|
|
67
|
+
}>;
|
|
68
|
+
}
|
|
69
|
+
/** Options for `browserRenderer()`. */
|
|
70
|
+
export interface BrowserRendererOptions {
|
|
71
|
+
/** When the page counts as rendered. Defaults to `networkidle`, as Playwright names it. */
|
|
72
|
+
waitUntil?: string;
|
|
73
|
+
/** Time allowed per page, in milliseconds. Defaults to 30 seconds. */
|
|
74
|
+
timeoutMs?: number;
|
|
31
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* A renderer over a browser of the application's own, such as Playwright's `chromium.launch()`: each
|
|
78
|
+
* page is opened, waited on, read, and closed. The package depends on no browser; the browser fetches
|
|
79
|
+
* the page and what it loads under its own network policy, not the loader's.
|
|
80
|
+
*
|
|
81
|
+
* ```ts
|
|
82
|
+
* const browser = await chromium.launch();
|
|
83
|
+
* for await (const page of loadWebPages(urls, { render: browserRenderer(browser) })) store(page);
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
export declare function browserRenderer(browser: RenderingBrowser, options?: BrowserRendererOptions): WebPageRenderer;
|
|
32
87
|
/** Raised when a page cannot be loaded: a status that is not 2xx, or a type that is not text. */
|
|
33
88
|
export declare class WebLoaderError extends Error {
|
|
34
89
|
/** The page. */
|
package/dist/loaders/web.js
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import { parseUrl, safeFetch } from '../utils/safe-fetch.js';
|
|
2
2
|
import { htmlToText } from './html.js';
|
|
3
|
+
export function browserRenderer(browser, options = {}) {
|
|
4
|
+
return async (page, signal) => {
|
|
5
|
+
signal.throwIfAborted();
|
|
6
|
+
const tab = await browser.newPage();
|
|
7
|
+
try {
|
|
8
|
+
await tab.goto(page.url, { waitUntil: options.waitUntil ?? 'networkidle', timeout: options.timeoutMs ?? 30_000 });
|
|
9
|
+
signal.throwIfAborted();
|
|
10
|
+
return await tab.content();
|
|
11
|
+
}
|
|
12
|
+
finally {
|
|
13
|
+
await tab.close().catch(() => undefined);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
3
17
|
const MAX_SITEMAP_BYTES = 50 * 1024 * 1024;
|
|
4
18
|
export class WebLoaderError extends Error {
|
|
5
19
|
url;
|
|
@@ -84,7 +98,12 @@ async function loadPage(url, options) {
|
|
|
84
98
|
const body = new TextDecoder().decode(response.bytes);
|
|
85
99
|
const metadata = { ...options.metadata, url: response.url };
|
|
86
100
|
if (type === 'text/html' || type === 'application/xhtml+xml' || (!type && /^\s*</.test(body))) {
|
|
87
|
-
|
|
101
|
+
let page = htmlToText(body, { baseUrl: response.url, mainContent: options.mainContent });
|
|
102
|
+
if (options.render && page.text.length < (options.renderBelow ?? 200) && /<script\b/i.test(body)) {
|
|
103
|
+
const html = await options.render({ url: response.url, html: body }, options.signal ?? new AbortController().signal);
|
|
104
|
+
page = htmlToText(html, { baseUrl: response.url, mainContent: options.mainContent });
|
|
105
|
+
metadata.rendered = true;
|
|
106
|
+
}
|
|
88
107
|
if (page.title)
|
|
89
108
|
metadata.title = page.title;
|
|
90
109
|
if (page.description)
|
package/dist/mcp/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ToolDefinition } from '../types/messages.js';
|
|
2
|
-
import { type McpTransport } from './protocol.js';
|
|
2
|
+
import { type McpElicitationRequest, type McpElicitationResult, type McpRoot, type McpSamplingRequest, type McpSamplingResult, type McpTransport } from './protocol.js';
|
|
3
3
|
/**
|
|
4
4
|
* What a server says a tool does, as MCP's tool annotations: hints, which a client trusts only as far
|
|
5
5
|
* as it trusts the server. A hint left out takes the specification's default.
|
|
@@ -99,6 +99,26 @@ export interface McpClientOptions {
|
|
|
99
99
|
* `reopen` a new stream.
|
|
100
100
|
*/
|
|
101
101
|
reconnect?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Answers a server's `sampling/createMessage` with this client's model, so a server's tool can ask
|
|
104
|
+
* for a completion: `samplingFrom(ai, { model })` is one. Declared to the server when given;
|
|
105
|
+
* without it, a server's request for one is refused.
|
|
106
|
+
*/
|
|
107
|
+
sampling?: (request: McpSamplingRequest, context: {
|
|
108
|
+
signal: AbortSignal;
|
|
109
|
+
}) => McpSamplingResult | Promise<McpSamplingResult>;
|
|
110
|
+
/**
|
|
111
|
+
* Answers a server's `elicitation/create`, a question for the person using this client, with the
|
|
112
|
+
* form of its answer. Declared to the server when given; without it, a request is refused.
|
|
113
|
+
*/
|
|
114
|
+
elicitation?: (request: McpElicitationRequest, context: {
|
|
115
|
+
signal: AbortSignal;
|
|
116
|
+
}) => McpElicitationResult | Promise<McpElicitationResult>;
|
|
117
|
+
/**
|
|
118
|
+
* The roots a server may work within, answered to its `roots/list`. Declared to the server when
|
|
119
|
+
* given; `rootsChanged()` tells it they changed.
|
|
120
|
+
*/
|
|
121
|
+
roots?: () => McpRoot[] | Promise<McpRoot[]>;
|
|
102
122
|
}
|
|
103
123
|
/**
|
|
104
124
|
* Talks to an MCP server.
|
|
@@ -119,6 +139,10 @@ export declare class McpClient {
|
|
|
119
139
|
private serverInfo;
|
|
120
140
|
/** Who hears that the server's tools changed. */
|
|
121
141
|
private readonly toolsChanged;
|
|
142
|
+
/** Who hears each of the server's notifications, by method. */
|
|
143
|
+
private readonly listeners;
|
|
144
|
+
/** Requests the server is waiting on this client for, by id, so a cancellation stops them. */
|
|
145
|
+
private readonly answering;
|
|
122
146
|
private stopped;
|
|
123
147
|
constructor(transport: McpTransport, options?: McpClientOptions);
|
|
124
148
|
/**
|
|
@@ -126,6 +150,22 @@ export declare class McpClient {
|
|
|
126
150
|
* `listTools()` returned. Returns a function that stops hearing.
|
|
127
151
|
*/
|
|
128
152
|
onToolsChanged(handler: () => void): () => void;
|
|
153
|
+
/** Hears each `notifications/prompts/list_changed`: the server's prompts changed. Returns a function that stops hearing. */
|
|
154
|
+
onPromptsChanged(handler: () => void): () => void;
|
|
155
|
+
/** Hears each `notifications/resources/list_changed`: the server's resources changed. Returns a function that stops hearing. */
|
|
156
|
+
onResourcesChanged(handler: () => void): () => void;
|
|
157
|
+
/**
|
|
158
|
+
* Hears each `notifications/resources/updated`, for a resource this client subscribed to with
|
|
159
|
+
* `subscribeResource()`: its URI. Returns a function that stops hearing.
|
|
160
|
+
*/
|
|
161
|
+
onResourceUpdated(handler: (uri: string) => void): () => void;
|
|
162
|
+
/** Asks the server to say when a resource changes, by `onResourceUpdated()`. */
|
|
163
|
+
subscribeResource(uri: string): Promise<void>;
|
|
164
|
+
/** Stops hearing that a resource changed. */
|
|
165
|
+
unsubscribeResource(uri: string): Promise<void>;
|
|
166
|
+
/** Tells the server this client's roots changed, so it lists them again. */
|
|
167
|
+
rootsChanged(): Promise<void>;
|
|
168
|
+
private listen;
|
|
129
169
|
/**
|
|
130
170
|
* Performs the handshake and returns the server's name and version. Called automatically by the
|
|
131
171
|
* first request that needs it; requests made together share one handshake.
|
|
@@ -174,6 +214,8 @@ export declare class McpClient {
|
|
|
174
214
|
private request;
|
|
175
215
|
private notify;
|
|
176
216
|
private receive;
|
|
217
|
+
/** Answers one request the server sent, with its result or why not. */
|
|
218
|
+
private answer;
|
|
177
219
|
private settle;
|
|
178
220
|
private failAll;
|
|
179
221
|
}
|
|
@@ -218,12 +260,19 @@ export interface HttpClientOptions {
|
|
|
218
260
|
headers?: Record<string, string>;
|
|
219
261
|
/** Replaces the global `fetch`. */
|
|
220
262
|
fetch?: typeof globalThis.fetch;
|
|
263
|
+
/**
|
|
264
|
+
* Holds a `GET` stream open once the server names a session, for what the server sends of its own
|
|
265
|
+
* accord: notifications that its tools or resources changed, and requests outside any call. A server
|
|
266
|
+
* that answers it with 405 does not offer one, and none is opened. Off by default.
|
|
267
|
+
*/
|
|
268
|
+
listen?: boolean;
|
|
221
269
|
}
|
|
222
270
|
/**
|
|
223
|
-
* Speaks to an MCP server over HTTP,
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
271
|
+
* Speaks to an MCP server over streamable HTTP, MCP's transport since 2025-03-26: a `POST` per
|
|
272
|
+
* message, answered as JSON or as a stream of events the transport reads as they come, so a server
|
|
273
|
+
* may report progress and ask this client for something in the middle of a call. With `listen`, a
|
|
274
|
+
* `GET` stream carries what the server sends of its own accord. It keeps the session the server
|
|
275
|
+
* names, sends the protocol version on every request, and ends the session when it closes.
|
|
227
276
|
*/
|
|
228
277
|
export declare function createHttpTransport(options: HttpClientOptions): McpTransport;
|
|
229
278
|
/** Connects to a remote MCP server over HTTP with Server-Sent Events, the transport before streamable HTTP. */
|
package/dist/mcp/client.js
CHANGED
|
@@ -16,6 +16,8 @@ export class McpClient {
|
|
|
16
16
|
connecting;
|
|
17
17
|
serverInfo = {};
|
|
18
18
|
toolsChanged = new Set();
|
|
19
|
+
listeners = new Map();
|
|
20
|
+
answering = new Map();
|
|
19
21
|
stopped = false;
|
|
20
22
|
constructor(transport, options = {}) {
|
|
21
23
|
this.transport = transport;
|
|
@@ -33,6 +35,38 @@ export class McpClient {
|
|
|
33
35
|
this.toolsChanged.delete(handler);
|
|
34
36
|
};
|
|
35
37
|
}
|
|
38
|
+
onPromptsChanged(handler) {
|
|
39
|
+
return this.listen('notifications/prompts/list_changed', () => handler());
|
|
40
|
+
}
|
|
41
|
+
onResourcesChanged(handler) {
|
|
42
|
+
return this.listen('notifications/resources/list_changed', () => handler());
|
|
43
|
+
}
|
|
44
|
+
onResourceUpdated(handler) {
|
|
45
|
+
return this.listen('notifications/resources/updated', (params) => handler(String(params.uri ?? '')));
|
|
46
|
+
}
|
|
47
|
+
async subscribeResource(uri) {
|
|
48
|
+
await this.connect();
|
|
49
|
+
await this.request('resources/subscribe', { uri });
|
|
50
|
+
}
|
|
51
|
+
async unsubscribeResource(uri) {
|
|
52
|
+
await this.connect();
|
|
53
|
+
await this.request('resources/unsubscribe', { uri });
|
|
54
|
+
}
|
|
55
|
+
async rootsChanged() {
|
|
56
|
+
await this.connect();
|
|
57
|
+
await this.notify('notifications/roots/list_changed');
|
|
58
|
+
}
|
|
59
|
+
listen(method, handler) {
|
|
60
|
+
let handlers = this.listeners.get(method);
|
|
61
|
+
if (!handlers) {
|
|
62
|
+
handlers = new Set();
|
|
63
|
+
this.listeners.set(method, handlers);
|
|
64
|
+
}
|
|
65
|
+
handlers.add(handler);
|
|
66
|
+
return () => {
|
|
67
|
+
handlers.delete(handler);
|
|
68
|
+
};
|
|
69
|
+
}
|
|
36
70
|
async connect() {
|
|
37
71
|
if (this.initialized)
|
|
38
72
|
return this.serverInfo;
|
|
@@ -45,7 +79,14 @@ export class McpClient {
|
|
|
45
79
|
await this.transport.start?.();
|
|
46
80
|
const result = (await this.request('initialize', {
|
|
47
81
|
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
48
|
-
capabilities: {
|
|
82
|
+
capabilities: {
|
|
83
|
+
tools: {},
|
|
84
|
+
resources: {},
|
|
85
|
+
prompts: {},
|
|
86
|
+
...(this.options.sampling ? { sampling: {} } : {}),
|
|
87
|
+
...(this.options.elicitation ? { elicitation: {} } : {}),
|
|
88
|
+
...(this.options.roots ? { roots: { listChanged: true } } : {}),
|
|
89
|
+
},
|
|
49
90
|
clientInfo: this.options.clientInfo ?? { name: 'nexus-ai-pro', version: '1.x' },
|
|
50
91
|
}));
|
|
51
92
|
this.initialized = true;
|
|
@@ -164,6 +205,22 @@ export class McpClient {
|
|
|
164
205
|
}
|
|
165
206
|
return;
|
|
166
207
|
}
|
|
208
|
+
if (isNotification(message) && message.method === 'notifications/cancelled') {
|
|
209
|
+
const requestId = message.params?.requestId;
|
|
210
|
+
if (requestId !== undefined)
|
|
211
|
+
this.answering.get(requestId)?.abort(new McpError('The server cancelled its request'));
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (isNotification(message) && this.listeners.has(message.method)) {
|
|
215
|
+
for (const handler of this.listeners.get(message.method) ?? []) {
|
|
216
|
+
try {
|
|
217
|
+
handler((message.params ?? {}));
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
167
224
|
if (isNotification(message) && message.method === 'notifications/progress') {
|
|
168
225
|
const params = (message.params ?? {});
|
|
169
226
|
const report = this.progress.get(String(params.progressToken));
|
|
@@ -174,12 +231,49 @@ export class McpClient {
|
|
|
174
231
|
});
|
|
175
232
|
return;
|
|
176
233
|
}
|
|
177
|
-
if (isRequest(message))
|
|
178
|
-
void this.
|
|
234
|
+
if (isRequest(message))
|
|
235
|
+
void this.answer(message.id, message.method, message.params);
|
|
236
|
+
}
|
|
237
|
+
async answer(id, method, params) {
|
|
238
|
+
const controller = new AbortController();
|
|
239
|
+
this.answering.set(id, controller);
|
|
240
|
+
const handlers = {
|
|
241
|
+
ping: () => ({}),
|
|
242
|
+
'sampling/createMessage': this.options.sampling
|
|
243
|
+
? () => this.options.sampling(params, {
|
|
244
|
+
signal: controller.signal,
|
|
245
|
+
})
|
|
246
|
+
: undefined,
|
|
247
|
+
'elicitation/create': this.options.elicitation
|
|
248
|
+
? () => this.options.elicitation(params, { signal: controller.signal })
|
|
249
|
+
: undefined,
|
|
250
|
+
'roots/list': this.options.roots
|
|
251
|
+
? async () => ({ roots: await this.options.roots() })
|
|
252
|
+
: undefined,
|
|
253
|
+
};
|
|
254
|
+
const handler = Object.hasOwn(handlers, method) ? handlers[method] : undefined;
|
|
255
|
+
try {
|
|
256
|
+
if (!handler)
|
|
257
|
+
throw new McpError(`This client does not implement "${method}"`, -32_601);
|
|
258
|
+
const result = await handler();
|
|
259
|
+
if (controller.signal.aborted)
|
|
260
|
+
return;
|
|
261
|
+
await this.transport.send({ jsonrpc: '2.0', id, result });
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
if (controller.signal.aborted)
|
|
265
|
+
return;
|
|
266
|
+
await Promise.resolve(this.transport.send({
|
|
179
267
|
jsonrpc: '2.0',
|
|
180
|
-
id
|
|
181
|
-
error: {
|
|
182
|
-
|
|
268
|
+
id,
|
|
269
|
+
error: {
|
|
270
|
+
code: error instanceof McpError ? error.code : -32_603,
|
|
271
|
+
message: error instanceof Error ? error.message : String(error),
|
|
272
|
+
},
|
|
273
|
+
})).catch(() => undefined);
|
|
274
|
+
}
|
|
275
|
+
finally {
|
|
276
|
+
this.answering.delete(id);
|
|
183
277
|
}
|
|
184
278
|
}
|
|
185
279
|
settle(id, result, error) {
|
|
@@ -303,39 +397,96 @@ export function createHttpTransport(options) {
|
|
|
303
397
|
const fetchImplementation = options.fetch ?? globalThis.fetch;
|
|
304
398
|
let onMessage = () => undefined;
|
|
305
399
|
let sessionId;
|
|
400
|
+
let listening;
|
|
401
|
+
let refused = false;
|
|
402
|
+
const deliver = (data) => {
|
|
403
|
+
try {
|
|
404
|
+
onMessage(JSON.parse(data));
|
|
405
|
+
}
|
|
406
|
+
catch {
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
const headers = () => ({
|
|
410
|
+
'mcp-protocol-version': MCP_PROTOCOL_VERSION,
|
|
411
|
+
...(sessionId ? { 'mcp-session-id': sessionId } : {}),
|
|
412
|
+
...options.headers,
|
|
413
|
+
});
|
|
414
|
+
const listen = () => {
|
|
415
|
+
if (!options.listen || !sessionId || listening || refused)
|
|
416
|
+
return;
|
|
417
|
+
const own = new AbortController();
|
|
418
|
+
listening = own;
|
|
419
|
+
void (async () => {
|
|
420
|
+
try {
|
|
421
|
+
const response = await fetchImplementation(options.url, {
|
|
422
|
+
method: 'GET',
|
|
423
|
+
headers: { accept: 'text/event-stream', ...headers() },
|
|
424
|
+
signal: own.signal,
|
|
425
|
+
});
|
|
426
|
+
if (response.status === 405)
|
|
427
|
+
refused = true;
|
|
428
|
+
if (!response.ok || !response.body) {
|
|
429
|
+
await response.body?.cancel().catch(() => undefined);
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
await readEvents(response.body.getReader(), (_name, data) => deliver(data));
|
|
433
|
+
}
|
|
434
|
+
catch {
|
|
435
|
+
}
|
|
436
|
+
finally {
|
|
437
|
+
if (listening === own)
|
|
438
|
+
listening = undefined;
|
|
439
|
+
}
|
|
440
|
+
})();
|
|
441
|
+
};
|
|
306
442
|
return {
|
|
307
443
|
async send(message) {
|
|
308
444
|
const response = await fetchImplementation(options.url, {
|
|
309
445
|
method: 'POST',
|
|
310
|
-
headers: {
|
|
311
|
-
'content-type': 'application/json',
|
|
312
|
-
accept: 'application/json, text/event-stream',
|
|
313
|
-
...(sessionId ? { 'mcp-session-id': sessionId } : {}),
|
|
314
|
-
...options.headers,
|
|
315
|
-
},
|
|
446
|
+
headers: { 'content-type': 'application/json', accept: 'application/json, text/event-stream', ...headers() },
|
|
316
447
|
body: JSON.stringify(message),
|
|
317
448
|
});
|
|
318
449
|
sessionId = response.headers.get('mcp-session-id') ?? sessionId;
|
|
319
|
-
if (
|
|
450
|
+
if (response.status === 404 && sessionId) {
|
|
451
|
+
sessionId = undefined;
|
|
452
|
+
await response.body?.cancel().catch(() => undefined);
|
|
453
|
+
throw new McpError('The MCP server ended the session');
|
|
454
|
+
}
|
|
455
|
+
if (!response.ok) {
|
|
456
|
+
await response.body?.cancel().catch(() => undefined);
|
|
320
457
|
throw new McpError(`MCP HTTP transport failed with ${response.status}`);
|
|
321
|
-
|
|
458
|
+
}
|
|
459
|
+
listen();
|
|
460
|
+
if (response.status === 202 || !response.body)
|
|
461
|
+
return;
|
|
462
|
+
if ((response.headers.get('content-type') ?? '').includes('text/event-stream')) {
|
|
463
|
+
void readEvents(response.body.getReader(), (_name, data) => deliver(data)).catch(() => undefined);
|
|
322
464
|
return;
|
|
465
|
+
}
|
|
323
466
|
const body = await response.text();
|
|
324
467
|
if (!body.trim())
|
|
325
468
|
return;
|
|
326
469
|
for (const payload of body.startsWith('event:') || body.startsWith('data:') ? sseData(body) : [body]) {
|
|
327
|
-
|
|
328
|
-
onMessage(JSON.parse(payload));
|
|
329
|
-
}
|
|
330
|
-
catch {
|
|
331
|
-
}
|
|
470
|
+
deliver(payload);
|
|
332
471
|
}
|
|
333
472
|
},
|
|
334
473
|
onMessage(handler) {
|
|
335
474
|
onMessage = handler;
|
|
336
475
|
},
|
|
337
|
-
close() {
|
|
476
|
+
async close() {
|
|
477
|
+
listening?.abort();
|
|
478
|
+
listening = undefined;
|
|
479
|
+
const ending = sessionId;
|
|
338
480
|
sessionId = undefined;
|
|
481
|
+
refused = false;
|
|
482
|
+
if (ending) {
|
|
483
|
+
await fetchImplementation(options.url, {
|
|
484
|
+
method: 'DELETE',
|
|
485
|
+
headers: { ...options.headers, 'mcp-protocol-version': MCP_PROTOCOL_VERSION, 'mcp-session-id': ending },
|
|
486
|
+
})
|
|
487
|
+
.then((response) => response.body?.cancel())
|
|
488
|
+
.catch(() => undefined);
|
|
489
|
+
}
|
|
339
490
|
},
|
|
340
491
|
};
|
|
341
492
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { McpServer } from './server.js';
|
|
2
|
+
/** Options for `mcpHttpHandler()`. */
|
|
3
|
+
export interface McpHttpOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Origins allowed to call it from a browser, beside the endpoint's own: a request whose `Origin`
|
|
6
|
+
* header names any other is refused with 403, so a web page cannot reach a server on this machine
|
|
7
|
+
* through the person's browser.
|
|
8
|
+
*/
|
|
9
|
+
allowedOrigins?: readonly string[];
|
|
10
|
+
/**
|
|
11
|
+
* Answers each request as JSON, after the server finishes, rather than as a stream of events. What
|
|
12
|
+
* the server sends meanwhile then waits for the session's `GET` stream.
|
|
13
|
+
*/
|
|
14
|
+
json?: boolean;
|
|
15
|
+
/** How long a session lasts without a request, in milliseconds. Defaults to 30 minutes. */
|
|
16
|
+
sessionTtlMs?: number;
|
|
17
|
+
/** The most sessions held at once: a new one past it is refused with 503. Defaults to 1,000. */
|
|
18
|
+
maxSessions?: number;
|
|
19
|
+
/** Makes a new session's id. Defaults to a random UUID. */
|
|
20
|
+
sessionId?: () => string;
|
|
21
|
+
}
|
|
22
|
+
/** A Web handler serving an MCP server over streamable HTTP, and what it holds. */
|
|
23
|
+
export interface McpHttpHandler {
|
|
24
|
+
/** Answers one HTTP request: a `POST` of a message, a `GET` stream, or a `DELETE` of a session. */
|
|
25
|
+
(request: Request): Promise<Response>;
|
|
26
|
+
/** How many sessions are open. */
|
|
27
|
+
sessions(): number;
|
|
28
|
+
/** Ends every session. */
|
|
29
|
+
close(): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Serves an MCP server over streamable HTTP, MCP's transport since 2025-03-26: each client that sends
|
|
33
|
+
* `initialize` gets a session, named in the `Mcp-Session-Id` header it sends from then on. A request is
|
|
34
|
+
* answered as a stream of events, which carries the server's progress and its questions for the
|
|
35
|
+
* client, such as a tool's `context.mcp.createMessage()`, before the answer; with `json`, as JSON. A
|
|
36
|
+
* notification or an answer the client sends is taken with 202. A `GET` holds the session's own stream,
|
|
37
|
+
* for what the server sends of its own accord, and a `DELETE` ends the session. A request from a web
|
|
38
|
+
* page on another origin is refused, unless `allowedOrigins` names it.
|
|
39
|
+
*
|
|
40
|
+
* ```ts
|
|
41
|
+
* const handle = mcpHttpHandler(new McpServer({ tools: [search] }));
|
|
42
|
+
* Bun.serve({ fetch: handle }); // or any server that speaks Request and Response
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function mcpHttpHandler(server: McpServer, options?: McpHttpOptions): McpHttpHandler;
|