@better-agent/core 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/agent/constants.mjs +6 -0
- package/dist/agent/constants.mjs.map +1 -0
- package/dist/agent/define-agent.d.mts +29 -0
- package/dist/agent/define-agent.d.mts.map +1 -0
- package/dist/agent/define-agent.mjs +27 -0
- package/dist/agent/define-agent.mjs.map +1 -0
- package/dist/agent/index.d.mts +2 -0
- package/dist/agent/types.d.mts +216 -0
- package/dist/agent/types.d.mts.map +1 -0
- package/dist/agent/validation.mjs +64 -0
- package/dist/agent/validation.mjs.map +1 -0
- package/dist/api.d.mts +8 -0
- package/dist/api.d.mts.map +1 -0
- package/dist/api.mjs +63 -0
- package/dist/api.mjs.map +1 -0
- package/dist/app/config.mjs +43 -0
- package/dist/app/config.mjs.map +1 -0
- package/dist/app/create-app.d.mts +36 -0
- package/dist/app/create-app.d.mts.map +1 -0
- package/dist/app/create-app.mjs +132 -0
- package/dist/app/create-app.mjs.map +1 -0
- package/dist/app/registry.mjs +43 -0
- package/dist/app/registry.mjs.map +1 -0
- package/dist/app/types.d.mts +142 -0
- package/dist/app/types.d.mts.map +1 -0
- package/dist/events/constants.d.mts +49 -0
- package/dist/events/constants.d.mts.map +1 -0
- package/dist/events/constants.mjs +46 -0
- package/dist/events/constants.mjs.map +1 -0
- package/dist/events/index.d.mts +4 -0
- package/dist/events/index.mjs +3 -0
- package/dist/events/types.d.mts +289 -0
- package/dist/events/types.d.mts.map +1 -0
- package/dist/index.d.mts +23 -0
- package/dist/index.mjs +14 -0
- package/dist/internal/id.mjs +21 -0
- package/dist/internal/id.mjs.map +1 -0
- package/dist/internal/types.d.mts +11 -0
- package/dist/internal/types.d.mts.map +1 -0
- package/dist/mcp/error/mcp-client-error.d.mts +36 -0
- package/dist/mcp/error/mcp-client-error.d.mts.map +1 -0
- package/dist/mcp/error/mcp-client-error.mjs +33 -0
- package/dist/mcp/error/mcp-client-error.mjs.map +1 -0
- package/dist/mcp/index.d.mts +8 -0
- package/dist/mcp/index.mjs +9 -0
- package/dist/mcp/tool/json-rpc-message.d.mts +50 -0
- package/dist/mcp/tool/json-rpc-message.d.mts.map +1 -0
- package/dist/mcp/tool/json-rpc-message.mjs +84 -0
- package/dist/mcp/tool/json-rpc-message.mjs.map +1 -0
- package/dist/mcp/tool/mcp-client.d.mts +71 -0
- package/dist/mcp/tool/mcp-client.d.mts.map +1 -0
- package/dist/mcp/tool/mcp-client.mjs +304 -0
- package/dist/mcp/tool/mcp-client.mjs.map +1 -0
- package/dist/mcp/tool/mcp-http-transport.d.mts +62 -0
- package/dist/mcp/tool/mcp-http-transport.d.mts.map +1 -0
- package/dist/mcp/tool/mcp-http-transport.mjs +307 -0
- package/dist/mcp/tool/mcp-http-transport.mjs.map +1 -0
- package/dist/mcp/tool/mcp-tools.d.mts +20 -0
- package/dist/mcp/tool/mcp-tools.d.mts.map +1 -0
- package/dist/mcp/tool/mcp-tools.mjs +73 -0
- package/dist/mcp/tool/mcp-tools.mjs.map +1 -0
- package/dist/mcp/tool/mcp-transport.d.mts +81 -0
- package/dist/mcp/tool/mcp-transport.d.mts.map +1 -0
- package/dist/mcp/tool/mcp-transport.mjs +11 -0
- package/dist/mcp/tool/mcp-transport.mjs.map +1 -0
- package/dist/mcp/tool/types.d.mts +230 -0
- package/dist/mcp/tool/types.d.mts.map +1 -0
- package/dist/mcp/tool/types.mjs +19 -0
- package/dist/mcp/tool/types.mjs.map +1 -0
- package/dist/persistence/index.d.mts +3 -0
- package/dist/persistence/index.mjs +3 -0
- package/dist/persistence/memory.d.mts +21 -0
- package/dist/persistence/memory.d.mts.map +1 -0
- package/dist/persistence/memory.mjs +107 -0
- package/dist/persistence/memory.mjs.map +1 -0
- package/dist/persistence/types.d.mts +124 -0
- package/dist/persistence/types.d.mts.map +1 -0
- package/dist/plugins/index.d.mts +2 -0
- package/dist/plugins/runtime.d.mts +17 -0
- package/dist/plugins/runtime.d.mts.map +1 -0
- package/dist/plugins/runtime.mjs +456 -0
- package/dist/plugins/runtime.mjs.map +1 -0
- package/dist/plugins/types.d.mts +344 -0
- package/dist/plugins/types.d.mts.map +1 -0
- package/dist/providers/index.d.mts +9 -0
- package/dist/providers/index.mjs +0 -0
- package/dist/providers/types/capabilities.d.mts +153 -0
- package/dist/providers/types/capabilities.d.mts.map +1 -0
- package/dist/providers/types/content.d.mts +125 -0
- package/dist/providers/types/content.d.mts.map +1 -0
- package/dist/providers/types/conversation.d.mts +32 -0
- package/dist/providers/types/conversation.d.mts.map +1 -0
- package/dist/providers/types/index.d.mts +8 -0
- package/dist/providers/types/input.d.mts +74 -0
- package/dist/providers/types/input.d.mts.map +1 -0
- package/dist/providers/types/model.d.mts +68 -0
- package/dist/providers/types/model.d.mts.map +1 -0
- package/dist/providers/types/output.d.mts +29 -0
- package/dist/providers/types/output.d.mts.map +1 -0
- package/dist/providers/types/response.d.mts +35 -0
- package/dist/providers/types/response.d.mts.map +1 -0
- package/dist/providers/types/tool-calls.d.mts +51 -0
- package/dist/providers/types/tool-calls.d.mts.map +1 -0
- package/dist/run/agent-loop.mjs +231 -0
- package/dist/run/agent-loop.mjs.map +1 -0
- package/dist/run/event-queue.mjs +67 -0
- package/dist/run/event-queue.mjs.map +1 -0
- package/dist/run/execute-tool-calls.mjs +550 -0
- package/dist/run/execute-tool-calls.mjs.map +1 -0
- package/dist/run/execution.mjs +93 -0
- package/dist/run/execution.mjs.map +1 -0
- package/dist/run/helpers.mjs +466 -0
- package/dist/run/helpers.mjs.map +1 -0
- package/dist/run/hooks.mjs +124 -0
- package/dist/run/hooks.mjs.map +1 -0
- package/dist/run/index.d.mts +4 -0
- package/dist/run/messages.d.mts +8 -0
- package/dist/run/messages.d.mts.map +1 -0
- package/dist/run/messages.mjs +83 -0
- package/dist/run/messages.mjs.map +1 -0
- package/dist/run/model-strategy.mjs +105 -0
- package/dist/run/model-strategy.mjs.map +1 -0
- package/dist/run/output-errors.d.mts +75 -0
- package/dist/run/output-errors.d.mts.map +1 -0
- package/dist/run/pending-tools.d.mts +1 -0
- package/dist/run/pending-tools.mjs +185 -0
- package/dist/run/pending-tools.mjs.map +1 -0
- package/dist/run/registry.mjs +22 -0
- package/dist/run/registry.mjs.map +1 -0
- package/dist/run/runtime.d.mts +19 -0
- package/dist/run/runtime.d.mts.map +1 -0
- package/dist/run/runtime.mjs +491 -0
- package/dist/run/runtime.mjs.map +1 -0
- package/dist/run/stop-conditions.mjs +41 -0
- package/dist/run/stop-conditions.mjs.map +1 -0
- package/dist/run/types.d.mts +348 -0
- package/dist/run/types.d.mts.map +1 -0
- package/dist/schema/index.d.mts +2 -0
- package/dist/schema/resolve-json-schema.d.mts +12 -0
- package/dist/schema/resolve-json-schema.d.mts.map +1 -0
- package/dist/schema/resolve-json-schema.mjs +167 -0
- package/dist/schema/resolve-json-schema.mjs.map +1 -0
- package/dist/schema/types.d.mts +27 -0
- package/dist/schema/types.d.mts.map +1 -0
- package/dist/server/create-server.d.mts +21 -0
- package/dist/server/create-server.d.mts.map +1 -0
- package/dist/server/create-server.mjs +107 -0
- package/dist/server/create-server.mjs.map +1 -0
- package/dist/server/http.mjs +182 -0
- package/dist/server/http.mjs.map +1 -0
- package/dist/server/index.d.mts +3 -0
- package/dist/server/index.mjs +3 -0
- package/dist/server/routes.mjs +399 -0
- package/dist/server/routes.mjs.map +1 -0
- package/dist/server/types.d.mts +31 -0
- package/dist/server/types.d.mts.map +1 -0
- package/dist/tools/constants.d.mts +12 -0
- package/dist/tools/constants.d.mts.map +1 -0
- package/dist/tools/constants.mjs +13 -0
- package/dist/tools/constants.mjs.map +1 -0
- package/dist/tools/define-tool.d.mts +25 -0
- package/dist/tools/define-tool.d.mts.map +1 -0
- package/dist/tools/define-tool.mjs +76 -0
- package/dist/tools/define-tool.mjs.map +1 -0
- package/dist/tools/index.d.mts +5 -0
- package/dist/tools/lazy-tools.d.mts +49 -0
- package/dist/tools/lazy-tools.d.mts.map +1 -0
- package/dist/tools/lazy-tools.mjs +87 -0
- package/dist/tools/lazy-tools.mjs.map +1 -0
- package/dist/tools/resolve-tools.d.mts +12 -0
- package/dist/tools/resolve-tools.d.mts.map +1 -0
- package/dist/tools/resolve-tools.mjs +86 -0
- package/dist/tools/resolve-tools.mjs.map +1 -0
- package/dist/tools/types.d.mts +318 -0
- package/dist/tools/types.d.mts.map +1 -0
- package/dist/tools/validation.mjs +23 -0
- package/dist/tools/validation.mjs.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { MCPClientError } from "../error/mcp-client-error.mjs";
|
|
2
|
+
import { parseJSONRPCMessage, parseJSONRPCMessageArray } from "./json-rpc-message.mjs";
|
|
3
|
+
import { LATEST_PROTOCOL_VERSION } from "./types.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/mcp/tool/mcp-http-transport.ts
|
|
6
|
+
/**
|
|
7
|
+
* HTTP transport for MCP using the Streamable HTTP transport pattern.
|
|
8
|
+
*/
|
|
9
|
+
var HttpMCPTransport = class {
|
|
10
|
+
url;
|
|
11
|
+
abortController;
|
|
12
|
+
headers;
|
|
13
|
+
redirect;
|
|
14
|
+
sessionId;
|
|
15
|
+
inboundSseConnection;
|
|
16
|
+
lastInboundEventId;
|
|
17
|
+
inboundReconnectAttempts = 0;
|
|
18
|
+
reconnectionOptions;
|
|
19
|
+
onclose;
|
|
20
|
+
onerror;
|
|
21
|
+
onmessage;
|
|
22
|
+
validateAdvancedNumber(value, field) {
|
|
23
|
+
if (value === void 0) return;
|
|
24
|
+
if (!Number.isFinite(value) || value < 0) throw new Error(`MCP HTTP Transport Error: '${field}' must be a non-negative number.`);
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
constructor({ url, headers, redirect, sessionId, advanced }) {
|
|
28
|
+
this.url = new URL(url);
|
|
29
|
+
this.headers = headers;
|
|
30
|
+
this.redirect = redirect;
|
|
31
|
+
this.sessionId = sessionId;
|
|
32
|
+
const reconnectInitialDelayMs = this.validateAdvancedNumber(advanced?.reconnectInitialDelayMs, "reconnectInitialDelayMs");
|
|
33
|
+
const reconnectMaxDelayMs = this.validateAdvancedNumber(advanced?.reconnectMaxDelayMs, "reconnectMaxDelayMs");
|
|
34
|
+
const reconnectBackoffFactor = this.validateAdvancedNumber(advanced?.reconnectBackoffFactor, "reconnectBackoffFactor");
|
|
35
|
+
const reconnectMaxRetries = this.validateAdvancedNumber(advanced?.reconnectMaxRetries, "reconnectMaxRetries");
|
|
36
|
+
this.reconnectionOptions = {
|
|
37
|
+
initialReconnectionDelay: reconnectInitialDelayMs ?? 1e3,
|
|
38
|
+
maxReconnectionDelay: reconnectMaxDelayMs ?? 3e4,
|
|
39
|
+
reconnectionDelayGrowFactor: reconnectBackoffFactor ?? 1.5,
|
|
40
|
+
maxRetries: reconnectMaxRetries ?? 2
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Builds common headers for requests.
|
|
45
|
+
*/
|
|
46
|
+
async commonHeaders(base) {
|
|
47
|
+
const headers = {
|
|
48
|
+
...this.headers,
|
|
49
|
+
...base,
|
|
50
|
+
"mcp-protocol-version": LATEST_PROTOCOL_VERSION
|
|
51
|
+
};
|
|
52
|
+
if (this.sessionId) headers["mcp-session-id"] = this.sessionId;
|
|
53
|
+
return headers;
|
|
54
|
+
}
|
|
55
|
+
async start() {
|
|
56
|
+
if (this.abortController) throw new Error("MCP HTTP Transport Error: Transport already started.");
|
|
57
|
+
this.abortController = new AbortController();
|
|
58
|
+
this.openInboundSse();
|
|
59
|
+
}
|
|
60
|
+
async close() {
|
|
61
|
+
this.inboundSseConnection?.close();
|
|
62
|
+
try {
|
|
63
|
+
if (this.sessionId && this.abortController && !this.abortController.signal.aborted) {
|
|
64
|
+
const headers = await this.commonHeaders({});
|
|
65
|
+
await fetch(this.url, {
|
|
66
|
+
method: "DELETE",
|
|
67
|
+
headers,
|
|
68
|
+
...this.redirect ? { redirect: this.redirect } : {},
|
|
69
|
+
signal: this.abortController.signal
|
|
70
|
+
}).catch(() => void 0);
|
|
71
|
+
}
|
|
72
|
+
} catch {}
|
|
73
|
+
this.abortController?.abort();
|
|
74
|
+
this.onclose?.();
|
|
75
|
+
}
|
|
76
|
+
async send(message) {
|
|
77
|
+
const attempt = async (_triedAuth = false) => {
|
|
78
|
+
try {
|
|
79
|
+
const init = {
|
|
80
|
+
method: "POST",
|
|
81
|
+
headers: await this.commonHeaders({
|
|
82
|
+
"Content-Type": "application/json",
|
|
83
|
+
Accept: "application/json, text/event-stream"
|
|
84
|
+
}),
|
|
85
|
+
body: JSON.stringify(message),
|
|
86
|
+
...this.redirect ? { redirect: this.redirect } : {},
|
|
87
|
+
signal: this.abortController?.signal ?? null
|
|
88
|
+
};
|
|
89
|
+
const response = await fetch(this.url, init);
|
|
90
|
+
const sessionId = response.headers.get("mcp-session-id");
|
|
91
|
+
if (sessionId) this.sessionId = sessionId;
|
|
92
|
+
if (response.status === 202) {
|
|
93
|
+
if (!this.inboundSseConnection) this.openInboundSse();
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (!response.ok) {
|
|
97
|
+
const text = await response.text().catch(() => null);
|
|
98
|
+
let errorMessage = `MCP HTTP Transport Error: POSTing to endpoint (HTTP ${response.status})`;
|
|
99
|
+
if (text) errorMessage += `: ${text}`;
|
|
100
|
+
if (response.status === 404) errorMessage += ". This server does not support HTTP transport. Try using `sse` transport instead";
|
|
101
|
+
const error = new MCPClientError({
|
|
102
|
+
message: errorMessage,
|
|
103
|
+
context: {
|
|
104
|
+
status: response.status,
|
|
105
|
+
url: this.url.href
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
this.onerror?.(error);
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
if ("id" in message) {
|
|
112
|
+
const contentType = response.headers.get("content-type") || "";
|
|
113
|
+
if (contentType.includes("application/json")) {
|
|
114
|
+
const messages = parseJSONRPCMessageArray(await response.json());
|
|
115
|
+
for (const msg of messages) this.onmessage?.(msg);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (contentType.includes("text/event-stream")) {
|
|
119
|
+
if (!response.body) {
|
|
120
|
+
const error = new MCPClientError({ message: "MCP HTTP Transport Error: text/event-stream response without body" });
|
|
121
|
+
this.onerror?.(error);
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
await this.processEventStream(response.body);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
} else if ((response.headers.get("content-type") || "").includes("application/json")) await response.json().catch(() => {});
|
|
128
|
+
else await response.text().catch(() => {});
|
|
129
|
+
} catch (error) {
|
|
130
|
+
const mcpError = error instanceof MCPClientError ? error : new MCPClientError({
|
|
131
|
+
message: error instanceof Error ? error.message : "Unknown transport error",
|
|
132
|
+
cause: error
|
|
133
|
+
});
|
|
134
|
+
this.onerror?.(mcpError);
|
|
135
|
+
throw mcpError;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
await attempt();
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Processes an SSE event stream.
|
|
142
|
+
*/
|
|
143
|
+
async processEventStream(body) {
|
|
144
|
+
const reader = body.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream()).getReader();
|
|
145
|
+
try {
|
|
146
|
+
while (true) {
|
|
147
|
+
const { done, value } = await reader.read();
|
|
148
|
+
if (done) return;
|
|
149
|
+
const { event, data, id } = value;
|
|
150
|
+
if (id) this.lastInboundEventId = id;
|
|
151
|
+
if (event === "message") try {
|
|
152
|
+
const msg = parseJSONRPCMessage(JSON.parse(data));
|
|
153
|
+
this.onmessage?.(msg);
|
|
154
|
+
} catch (_error) {
|
|
155
|
+
const e = new MCPClientError({ message: "MCP HTTP Transport Error: Failed to parse message" });
|
|
156
|
+
this.onerror?.(e);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
} catch (error) {
|
|
160
|
+
if (error instanceof Error && error.name === "AbortError") return;
|
|
161
|
+
const mcpError = error instanceof MCPClientError ? error : new MCPClientError({
|
|
162
|
+
message: error instanceof Error ? error.message : "Stream processing error",
|
|
163
|
+
cause: error
|
|
164
|
+
});
|
|
165
|
+
this.onerror?.(mcpError);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Calculate next reconnection delay using exponential backoff.
|
|
170
|
+
*/
|
|
171
|
+
getNextReconnectionDelay(attempt) {
|
|
172
|
+
const { initialReconnectionDelay, reconnectionDelayGrowFactor, maxReconnectionDelay } = this.reconnectionOptions;
|
|
173
|
+
return Math.min(initialReconnectionDelay * reconnectionDelayGrowFactor ** attempt, maxReconnectionDelay);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Schedule SSE reconnection attempt.
|
|
177
|
+
*/
|
|
178
|
+
scheduleInboundSseReconnection() {
|
|
179
|
+
const { maxRetries } = this.reconnectionOptions;
|
|
180
|
+
if (maxRetries > 0 && this.inboundReconnectAttempts >= maxRetries) {
|
|
181
|
+
this.onerror?.(new MCPClientError({ message: `MCP HTTP Transport Error: Maximum reconnection attempts (${maxRetries}) exceeded.` }));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const delay = this.getNextReconnectionDelay(this.inboundReconnectAttempts);
|
|
185
|
+
this.inboundReconnectAttempts += 1;
|
|
186
|
+
setTimeout(async () => {
|
|
187
|
+
if (this.abortController?.signal.aborted) return;
|
|
188
|
+
await this.openInboundSse(false, this.lastInboundEventId);
|
|
189
|
+
}, delay);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Open inbound SSE connection for receiving messages.
|
|
193
|
+
*/
|
|
194
|
+
async openInboundSse(_triedAuth = false, resumeToken) {
|
|
195
|
+
try {
|
|
196
|
+
const headers = await this.commonHeaders({ Accept: "text/event-stream" });
|
|
197
|
+
if (resumeToken) headers["last-event-id"] = resumeToken;
|
|
198
|
+
const response = await fetch(this.url.href, {
|
|
199
|
+
method: "GET",
|
|
200
|
+
headers,
|
|
201
|
+
...this.redirect ? { redirect: this.redirect } : {},
|
|
202
|
+
signal: this.abortController?.signal ?? null
|
|
203
|
+
});
|
|
204
|
+
const sessionId = response.headers.get("mcp-session-id");
|
|
205
|
+
if (sessionId) this.sessionId = sessionId;
|
|
206
|
+
if (response.status === 405) return;
|
|
207
|
+
if (!response.ok || !response.body) {
|
|
208
|
+
const error = new MCPClientError({
|
|
209
|
+
message: `MCP HTTP Transport Error: GET SSE failed: ${response.status} ${response.statusText}`,
|
|
210
|
+
context: {
|
|
211
|
+
status: response.status,
|
|
212
|
+
statusText: response.statusText
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
this.onerror?.(error);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
const reader = response.body.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream()).getReader();
|
|
219
|
+
this.inboundSseConnection = { close: () => reader.cancel() };
|
|
220
|
+
this.inboundReconnectAttempts = 0;
|
|
221
|
+
try {
|
|
222
|
+
while (true) {
|
|
223
|
+
const { done, value } = await reader.read();
|
|
224
|
+
if (done) {
|
|
225
|
+
if (!this.abortController?.signal.aborted) this.scheduleInboundSseReconnection();
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const { event, data, id } = value;
|
|
229
|
+
if (id) this.lastInboundEventId = id;
|
|
230
|
+
if (event === "message") try {
|
|
231
|
+
const msg = parseJSONRPCMessage(JSON.parse(data));
|
|
232
|
+
this.onmessage?.(msg);
|
|
233
|
+
} catch (_error) {
|
|
234
|
+
const e = new MCPClientError({ message: "MCP HTTP Transport Error: Failed to parse message" });
|
|
235
|
+
this.onerror?.(e);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
} catch (error) {
|
|
239
|
+
if (error instanceof Error && error.name === "AbortError") return;
|
|
240
|
+
const mcpError = error instanceof MCPClientError ? error : new MCPClientError({
|
|
241
|
+
message: error instanceof Error ? error.message : "SSE connection error",
|
|
242
|
+
cause: error
|
|
243
|
+
});
|
|
244
|
+
this.onerror?.(mcpError);
|
|
245
|
+
if (!this.abortController?.signal.aborted) this.scheduleInboundSseReconnection();
|
|
246
|
+
}
|
|
247
|
+
} catch (error) {
|
|
248
|
+
if (error instanceof Error && error.name === "AbortError") return;
|
|
249
|
+
const mcpError = error instanceof MCPClientError ? error : new MCPClientError({
|
|
250
|
+
message: error instanceof Error ? error.message : "SSE connection setup error",
|
|
251
|
+
cause: error
|
|
252
|
+
});
|
|
253
|
+
this.onerror?.(mcpError);
|
|
254
|
+
if (!this.abortController?.signal.aborted) this.scheduleInboundSseReconnection();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
/**
|
|
259
|
+
* Parse SSE events from a stream.
|
|
260
|
+
*
|
|
261
|
+
* Implements the EventSource parsing algorithm.
|
|
262
|
+
*/
|
|
263
|
+
var EventSourceParserStream = class extends TransformStream {
|
|
264
|
+
constructor() {
|
|
265
|
+
let buffer = "";
|
|
266
|
+
let data = "";
|
|
267
|
+
let lastEventId = "";
|
|
268
|
+
let eventName = "";
|
|
269
|
+
super({ transform(chunk, controller) {
|
|
270
|
+
buffer += chunk;
|
|
271
|
+
const lines = buffer.split("\n");
|
|
272
|
+
buffer = lines.pop() || "";
|
|
273
|
+
for (const line of lines) {
|
|
274
|
+
if (line === "") {
|
|
275
|
+
if (data !== "") controller.enqueue({
|
|
276
|
+
event: eventName || void 0,
|
|
277
|
+
data: data.slice(0, -1),
|
|
278
|
+
id: lastEventId || void 0
|
|
279
|
+
});
|
|
280
|
+
data = "";
|
|
281
|
+
eventName = "";
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
if (line.startsWith(":")) continue;
|
|
285
|
+
const colonIndex = line.indexOf(":");
|
|
286
|
+
const field = colonIndex === -1 ? line : line.slice(0, colonIndex);
|
|
287
|
+
const value = colonIndex === -1 ? "" : line.slice(colonIndex + 1).startsWith(" ") ? line.slice(colonIndex + 2) : line.slice(colonIndex + 1);
|
|
288
|
+
switch (field) {
|
|
289
|
+
case "event":
|
|
290
|
+
eventName = value;
|
|
291
|
+
break;
|
|
292
|
+
case "data":
|
|
293
|
+
data += `${value}\n`;
|
|
294
|
+
break;
|
|
295
|
+
case "id":
|
|
296
|
+
lastEventId = value;
|
|
297
|
+
break;
|
|
298
|
+
case "retry": break;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
} });
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
//#endregion
|
|
306
|
+
export { HttpMCPTransport };
|
|
307
|
+
//# sourceMappingURL=mcp-http-transport.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-http-transport.mjs","names":[],"sources":["../../../src/mcp/tool/mcp-http-transport.ts"],"sourcesContent":["import { MCPClientError } from \"../error/mcp-client-error\";\nimport {\n type JSONRPCMessage,\n parseJSONRPCMessage,\n parseJSONRPCMessageArray,\n} from \"./json-rpc-message\";\nimport type { MCPTransport, MCPTransportAdvancedConfig } from \"./mcp-transport\";\nimport { LATEST_PROTOCOL_VERSION } from \"./types\";\n\n/**\n * HTTP transport for MCP using the Streamable HTTP transport pattern.\n */\nexport class HttpMCPTransport implements MCPTransport {\n private url: URL;\n private abortController?: AbortController;\n private headers: Record<string, string> | undefined;\n private redirect: RequestRedirect | undefined;\n private sessionId: string | undefined;\n private inboundSseConnection?: { close: () => void };\n\n // Reconnection state for the inbound SSE channel.\n private lastInboundEventId?: string;\n private inboundReconnectAttempts = 0;\n private readonly reconnectionOptions: {\n initialReconnectionDelay: number;\n maxReconnectionDelay: number;\n reconnectionDelayGrowFactor: number;\n maxRetries: number;\n };\n\n onclose: (() => void) | undefined;\n onerror: ((error: MCPClientError) => void) | undefined;\n onmessage: ((message: JSONRPCMessage) => void) | undefined;\n\n private validateAdvancedNumber(\n value: number | undefined,\n field: keyof MCPTransportAdvancedConfig,\n ): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n if (!Number.isFinite(value) || value < 0) {\n throw new Error(`MCP HTTP Transport Error: '${field}' must be a non-negative number.`);\n }\n\n return value;\n }\n\n constructor({\n url,\n headers,\n redirect,\n sessionId,\n advanced,\n }: {\n url: string;\n headers: Record<string, string> | undefined;\n redirect?: RequestRedirect;\n sessionId: string | undefined;\n advanced?: MCPTransportAdvancedConfig;\n }) {\n this.url = new URL(url);\n this.headers = headers;\n this.redirect = redirect;\n this.sessionId = sessionId;\n const reconnectInitialDelayMs = this.validateAdvancedNumber(\n advanced?.reconnectInitialDelayMs,\n \"reconnectInitialDelayMs\",\n );\n const reconnectMaxDelayMs = this.validateAdvancedNumber(\n advanced?.reconnectMaxDelayMs,\n \"reconnectMaxDelayMs\",\n );\n const reconnectBackoffFactor = this.validateAdvancedNumber(\n advanced?.reconnectBackoffFactor,\n \"reconnectBackoffFactor\",\n );\n const reconnectMaxRetries = this.validateAdvancedNumber(\n advanced?.reconnectMaxRetries,\n \"reconnectMaxRetries\",\n );\n this.reconnectionOptions = {\n initialReconnectionDelay: reconnectInitialDelayMs ?? 1000,\n maxReconnectionDelay: reconnectMaxDelayMs ?? 30000,\n reconnectionDelayGrowFactor: reconnectBackoffFactor ?? 1.5,\n maxRetries: reconnectMaxRetries ?? 2,\n };\n }\n\n /**\n * Builds common headers for requests.\n */\n private async commonHeaders(base: Record<string, string>): Promise<Record<string, string>> {\n const headers: Record<string, string> = {\n ...this.headers,\n ...base,\n \"mcp-protocol-version\": LATEST_PROTOCOL_VERSION,\n };\n\n if (this.sessionId) {\n headers[\"mcp-session-id\"] = this.sessionId;\n }\n\n return headers;\n }\n\n async start(): Promise<void> {\n if (this.abortController) {\n throw new Error(\"MCP HTTP Transport Error: Transport already started.\");\n }\n\n this.abortController = new AbortController();\n\n // Start listening for inbound server messages on the side channel.\n void this.openInboundSse();\n }\n\n async close(): Promise<void> {\n this.inboundSseConnection?.close();\n\n try {\n if (this.sessionId && this.abortController && !this.abortController.signal.aborted) {\n const headers = await this.commonHeaders({});\n await fetch(this.url, {\n method: \"DELETE\",\n headers,\n ...(this.redirect ? { redirect: this.redirect } : {}),\n signal: this.abortController.signal,\n }).catch(() => undefined);\n }\n } catch {}\n\n this.abortController?.abort();\n this.onclose?.();\n }\n\n async send(message: JSONRPCMessage): Promise<void> {\n const attempt = async (_triedAuth = false): Promise<void> => {\n try {\n const headers = await this.commonHeaders({\n \"Content-Type\": \"application/json\",\n Accept: \"application/json, text/event-stream\",\n });\n\n const init: RequestInit = {\n method: \"POST\",\n headers,\n body: JSON.stringify(message),\n ...(this.redirect ? { redirect: this.redirect } : {}),\n signal: this.abortController?.signal ?? null,\n };\n\n const response = await fetch(this.url, init);\n\n // Track session id for resumable sessions when the server provides one.\n const sessionId = response.headers.get(\"mcp-session-id\");\n if (sessionId) {\n this.sessionId = sessionId;\n }\n\n // Server accepted the message without an immediate payload.\n if (response.status === 202) {\n // If inbound SSE was not available earlier, try again now.\n if (!this.inboundSseConnection) {\n void this.openInboundSse();\n }\n return;\n }\n\n if (!response.ok) {\n const text = await response.text().catch(() => null);\n let errorMessage = `MCP HTTP Transport Error: POSTing to endpoint (HTTP ${response.status})`;\n if (text) {\n errorMessage += `: ${text}`;\n }\n\n if (response.status === 404) {\n errorMessage +=\n \". This server does not support HTTP transport. Try using `sse` transport instead\";\n }\n\n const error = new MCPClientError({\n message: errorMessage,\n context: { status: response.status, url: this.url.href },\n });\n this.onerror?.(error);\n throw error;\n }\n\n // Only requests with ids expect a direct response payload.\n if (\"id\" in message) {\n const contentType = response.headers.get(\"content-type\") || \"\";\n\n if (contentType.includes(\"application/json\")) {\n const data = await response.json();\n const messages = parseJSONRPCMessageArray(data);\n for (const msg of messages) {\n this.onmessage?.(msg);\n }\n return;\n }\n\n if (contentType.includes(\"text/event-stream\")) {\n if (!response.body) {\n const error = new MCPClientError({\n message:\n \"MCP HTTP Transport Error: text/event-stream response without body\",\n });\n this.onerror?.(error);\n throw error;\n }\n\n await this.processEventStream(\n response.body as ReadableStream<BufferSource>,\n );\n return;\n }\n } else {\n // Notifications still drain the body so connections are not leaked.\n const contentType = response.headers.get(\"content-type\") || \"\";\n if (contentType.includes(\"application/json\")) {\n await response.json().catch(() => {}); // Drain JSON response\n } else {\n await response.text().catch(() => {}); // Drain text response\n }\n }\n } catch (error) {\n const mcpError =\n error instanceof MCPClientError\n ? error\n : new MCPClientError({\n message:\n error instanceof Error\n ? error.message\n : \"Unknown transport error\",\n cause: error,\n });\n this.onerror?.(mcpError);\n throw mcpError;\n }\n };\n\n await attempt();\n }\n\n /**\n * Processes an SSE event stream.\n */\n private async processEventStream(body: ReadableStream<BufferSource>): Promise<void> {\n const reader = body\n .pipeThrough(new TextDecoderStream())\n .pipeThrough(new EventSourceParserStream())\n .getReader();\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) return;\n\n const { event, data, id } = value as {\n event?: string;\n data: string;\n id?: string;\n };\n\n if (id) {\n this.lastInboundEventId = id;\n }\n\n if (event === \"message\") {\n try {\n const msg = parseJSONRPCMessage(JSON.parse(data));\n this.onmessage?.(msg);\n } catch (_error) {\n const e = new MCPClientError({\n message: \"MCP HTTP Transport Error: Failed to parse message\",\n });\n this.onerror?.(e);\n }\n }\n }\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n return;\n }\n const mcpError =\n error instanceof MCPClientError\n ? error\n : new MCPClientError({\n message:\n error instanceof Error ? error.message : \"Stream processing error\",\n cause: error,\n });\n this.onerror?.(mcpError);\n }\n }\n\n /**\n * Calculate next reconnection delay using exponential backoff.\n */\n private getNextReconnectionDelay(attempt: number): number {\n const { initialReconnectionDelay, reconnectionDelayGrowFactor, maxReconnectionDelay } =\n this.reconnectionOptions;\n return Math.min(\n initialReconnectionDelay * reconnectionDelayGrowFactor ** attempt,\n maxReconnectionDelay,\n );\n }\n\n /**\n * Schedule SSE reconnection attempt.\n */\n private scheduleInboundSseReconnection(): void {\n const { maxRetries } = this.reconnectionOptions;\n if (maxRetries > 0 && this.inboundReconnectAttempts >= maxRetries) {\n this.onerror?.(\n new MCPClientError({\n message: `MCP HTTP Transport Error: Maximum reconnection attempts (${maxRetries}) exceeded.`,\n }),\n );\n return;\n }\n\n const delay = this.getNextReconnectionDelay(this.inboundReconnectAttempts);\n this.inboundReconnectAttempts += 1;\n\n setTimeout(async () => {\n if (this.abortController?.signal.aborted) return;\n await this.openInboundSse(false, this.lastInboundEventId);\n }, delay);\n }\n\n /**\n * Open inbound SSE connection for receiving messages.\n */\n private async openInboundSse(_triedAuth = false, resumeToken?: string): Promise<void> {\n try {\n const headers = await this.commonHeaders({\n Accept: \"text/event-stream\",\n });\n\n if (resumeToken) {\n headers[\"last-event-id\"] = resumeToken;\n }\n\n const response = await fetch(this.url.href, {\n method: \"GET\",\n headers,\n ...(this.redirect ? { redirect: this.redirect } : {}),\n signal: this.abortController?.signal ?? null,\n });\n\n // Track session ID\n const sessionId = response.headers.get(\"mcp-session-id\");\n if (sessionId) {\n this.sessionId = sessionId;\n }\n\n // 405 = method not allowed, SSE might not be supported\n if (response.status === 405) {\n return;\n }\n\n if (!response.ok || !response.body) {\n const error = new MCPClientError({\n message: `MCP HTTP Transport Error: GET SSE failed: ${response.status} ${response.statusText}`,\n context: { status: response.status, statusText: response.statusText },\n });\n this.onerror?.(error);\n return;\n }\n\n const reader = (response.body as ReadableStream<BufferSource>)\n .pipeThrough(new TextDecoderStream())\n .pipeThrough(new EventSourceParserStream())\n .getReader();\n\n this.inboundSseConnection = {\n close: () => reader.cancel(),\n };\n this.inboundReconnectAttempts = 0;\n\n // Process events\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n // Connection closed cleanly - attempt reconnection\n if (!this.abortController?.signal.aborted) {\n this.scheduleInboundSseReconnection();\n }\n return;\n }\n\n const { event, data, id } = value as {\n event?: string;\n data: string;\n id?: string;\n };\n\n if (id) {\n this.lastInboundEventId = id;\n }\n\n if (event === \"message\") {\n try {\n const msg = parseJSONRPCMessage(JSON.parse(data));\n this.onmessage?.(msg);\n } catch (_error) {\n const e = new MCPClientError({\n message: \"MCP HTTP Transport Error: Failed to parse message\",\n });\n this.onerror?.(e);\n }\n }\n }\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n return;\n }\n const mcpError =\n error instanceof MCPClientError\n ? error\n : new MCPClientError({\n message:\n error instanceof Error ? error.message : \"SSE connection error\",\n cause: error,\n });\n this.onerror?.(mcpError);\n if (!this.abortController?.signal.aborted) {\n this.scheduleInboundSseReconnection();\n }\n }\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n return;\n }\n const mcpError =\n error instanceof MCPClientError\n ? error\n : new MCPClientError({\n message:\n error instanceof Error ? error.message : \"SSE connection setup error\",\n cause: error,\n });\n this.onerror?.(mcpError);\n if (!this.abortController?.signal.aborted) {\n this.scheduleInboundSseReconnection();\n }\n }\n }\n}\n\n/**\n * Parse SSE events from a stream.\n *\n * Implements the EventSource parsing algorithm.\n */\nclass EventSourceParserStream extends TransformStream<\n string,\n { event: string | undefined; data: string; id: string | undefined }\n> {\n constructor() {\n let buffer = \"\";\n let data = \"\"; // Move data to constructor scope for cross-chunk events\n let lastEventId = \"\";\n let eventName = \"\";\n\n super({\n transform(chunk, controller) {\n buffer += chunk;\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\";\n\n for (const line of lines) {\n if (line === \"\") {\n // Dispatch event\n if (data !== \"\") {\n controller.enqueue({\n event: eventName || undefined,\n data: data.slice(0, -1), // Remove trailing newline\n id: lastEventId || undefined,\n });\n }\n // Reset event state after dispatch\n data = \"\";\n eventName = \"\";\n continue;\n }\n\n if (line.startsWith(\":\")) {\n // Comment line, ignore\n continue;\n }\n\n const colonIndex = line.indexOf(\":\");\n const field = colonIndex === -1 ? line : line.slice(0, colonIndex);\n const value =\n colonIndex === -1\n ? \"\"\n : line.slice(colonIndex + 1).startsWith(\" \")\n ? line.slice(colonIndex + 2)\n : line.slice(colonIndex + 1);\n\n switch (field) {\n case \"event\":\n eventName = value;\n break;\n case \"data\":\n data += `${value}\\n`;\n break;\n case \"id\":\n lastEventId = value;\n break;\n case \"retry\":\n // Retry timing is handled by the transport\n break;\n }\n }\n },\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ServerToolDefinition } from "../../tools/types.mjs";
|
|
2
|
+
import { MCPTool } from "./types.mjs";
|
|
3
|
+
import { MCPClient } from "./mcp-client.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/mcp/tool/mcp-tools.d.ts
|
|
6
|
+
type MCPServerToolDefinition = ServerToolDefinition<any, string, unknown>;
|
|
7
|
+
/**
|
|
8
|
+
* Converts MCP tools into Better Agent server tool definitions.
|
|
9
|
+
*
|
|
10
|
+
* @param client MCP client used for tool calls.
|
|
11
|
+
* @param tools MCP tool definitions from the server.
|
|
12
|
+
* @param options Optional prefix for tool names.
|
|
13
|
+
* @returns Server tool definitions with working handlers.
|
|
14
|
+
*/
|
|
15
|
+
declare function convertMCPTools(client: MCPClient, tools: MCPTool[], options?: {
|
|
16
|
+
/** Optional prefix to add to tool names. */prefix?: string;
|
|
17
|
+
}): MCPServerToolDefinition[];
|
|
18
|
+
//#endregion
|
|
19
|
+
export { convertMCPTools };
|
|
20
|
+
//# sourceMappingURL=mcp-tools.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-tools.d.mts","names":[],"sources":["../../../src/mcp/tool/mcp-tools.ts"],"mappings":";;;;;KAMK,uBAAA,GAA0B,oBAAA;;AAH2B;;;;;AAa1D;;iBAAgB,eAAA,CACZ,MAAA,EAAQ,SAAA,EACR,KAAA,EAAO,OAAA,IACP,OAAA;EAFQ,4CAIJ,MAAA;AAAA,IAEL,uBAAA"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { TOOL_JSON_SCHEMA } from "../../tools/constants.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/mcp/tool/mcp-tools.ts
|
|
4
|
+
/**
|
|
5
|
+
* Converts MCP tools into Better Agent server tool definitions.
|
|
6
|
+
*
|
|
7
|
+
* @param client MCP client used for tool calls.
|
|
8
|
+
* @param tools MCP tool definitions from the server.
|
|
9
|
+
* @param options Optional prefix for tool names.
|
|
10
|
+
* @returns Server tool definitions with working handlers.
|
|
11
|
+
*/
|
|
12
|
+
function convertMCPTools(client, tools, options) {
|
|
13
|
+
return tools.map((tool) => convertMCPTool(client, tool, options?.prefix));
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Converts one MCP tool into a Better Agent server tool definition.
|
|
17
|
+
*/
|
|
18
|
+
function convertMCPTool(client, tool, prefix) {
|
|
19
|
+
const name = prefix ? `${prefix}_${tool.name}` : tool.name;
|
|
20
|
+
const handler = async (input, _ctx) => {
|
|
21
|
+
return convertToolResult(await client.callTool({
|
|
22
|
+
name: tool.name,
|
|
23
|
+
arguments: input
|
|
24
|
+
}));
|
|
25
|
+
};
|
|
26
|
+
const jsonSchema = {
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: tool.inputSchema.properties ?? {},
|
|
29
|
+
required: tool.inputSchema.required ?? [],
|
|
30
|
+
...tool.inputSchema.$schema ? { $schema: tool.inputSchema.$schema } : {}
|
|
31
|
+
};
|
|
32
|
+
return {
|
|
33
|
+
kind: "server",
|
|
34
|
+
name,
|
|
35
|
+
description: tool.description ?? `MCP tool: ${tool.name}`,
|
|
36
|
+
schema: tool.inputSchema,
|
|
37
|
+
handler,
|
|
38
|
+
[TOOL_JSON_SCHEMA]: jsonSchema
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Converts an MCP tool result into a Better Agent tool result value.
|
|
43
|
+
*/
|
|
44
|
+
function convertToolResult(result) {
|
|
45
|
+
if (result.isError === true) {
|
|
46
|
+
const errorMessage = result.content ? result.content.filter((item) => item.type === "text").map((item) => item.text).join("\n") : "Tool execution failed";
|
|
47
|
+
throw new Error(errorMessage);
|
|
48
|
+
}
|
|
49
|
+
if (result.structuredContent !== void 0) return result.structuredContent;
|
|
50
|
+
if (result.content === void 0 || result.content.length === 0) return { success: true };
|
|
51
|
+
const firstItem = result.content[0];
|
|
52
|
+
if (result.content.length === 1 && firstItem !== void 0 && firstItem.type === "text") return firstItem.text;
|
|
53
|
+
return result.content.map((item) => {
|
|
54
|
+
switch (item.type) {
|
|
55
|
+
case "text": return item.text;
|
|
56
|
+
case "image": return {
|
|
57
|
+
type: "image",
|
|
58
|
+
data: item.data,
|
|
59
|
+
mimeType: item.mimeType
|
|
60
|
+
};
|
|
61
|
+
case "resource": return {
|
|
62
|
+
type: "resource",
|
|
63
|
+
uri: item.resource.uri,
|
|
64
|
+
content: item.resource.text ?? item.resource.blob
|
|
65
|
+
};
|
|
66
|
+
default: return item;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
//#endregion
|
|
72
|
+
export { convertMCPTools };
|
|
73
|
+
//# sourceMappingURL=mcp-tools.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-tools.mjs","names":[],"sources":["../../../src/mcp/tool/mcp-tools.ts"],"sourcesContent":["import { TOOL_JSON_SCHEMA } from \"../../tools/constants\";\nimport type { ServerToolDefinition, ToolHandler } from \"../../tools/types\";\nimport type { MCPClient } from \"./mcp-client\";\nimport type { MCPCallToolResult, MCPTool } from \"./types\";\n\n// biome-ignore lint/suspicious/noExplicitAny:\ntype MCPServerToolDefinition = ServerToolDefinition<any, string, unknown>;\n\n/**\n * Converts MCP tools into Better Agent server tool definitions.\n *\n * @param client MCP client used for tool calls.\n * @param tools MCP tool definitions from the server.\n * @param options Optional prefix for tool names.\n * @returns Server tool definitions with working handlers.\n */\nexport function convertMCPTools(\n client: MCPClient,\n tools: MCPTool[],\n options?: {\n /** Optional prefix to add to tool names. */\n prefix?: string;\n },\n): MCPServerToolDefinition[] {\n return tools.map((tool) => convertMCPTool(client, tool, options?.prefix));\n}\n\n/**\n * Converts one MCP tool into a Better Agent server tool definition.\n */\nfunction convertMCPTool(\n client: MCPClient,\n tool: MCPTool,\n prefix?: string,\n): MCPServerToolDefinition {\n const name = prefix ? `${prefix}_${tool.name}` : tool.name;\n\n // The generated handler proxies execution back to the MCP server.\n const handler: ToolHandler<unknown, unknown> = async (\n input: unknown,\n _ctx: { signal: AbortSignal; emit: (event: unknown) => Promise<void> },\n ) => {\n const result = await client.callTool({\n name: tool.name,\n arguments: input as Record<string, unknown>,\n });\n\n // Normalize the MCP result into a Better Agent-friendly value.\n return convertToolResult(result);\n };\n\n // Build a JSON Schema payload that matches Better Agent's tool expectations.\n const jsonSchema: Record<string, unknown> = {\n type: \"object\",\n properties: tool.inputSchema.properties ?? {},\n required: tool.inputSchema.required ?? [],\n ...(tool.inputSchema.$schema ? { $schema: tool.inputSchema.$schema } : {}),\n };\n\n return {\n kind: \"server\",\n name,\n description: tool.description ?? `MCP tool: ${tool.name}`,\n // MCP schemas are discovered at runtime, so the public tool type is intentionally erased.\n schema: tool.inputSchema as Record<string, unknown>,\n handler,\n [TOOL_JSON_SCHEMA]: jsonSchema,\n };\n}\n\n/**\n * Converts an MCP tool result into a Better Agent tool result value.\n */\nfunction convertToolResult(result: MCPCallToolResult): unknown {\n // Text content is used to build a readable thrown error when MCP marks the call as failed.\n if (result.isError === true) {\n const errorMessage = result.content\n ? result.content\n .filter((item) => item.type === \"text\")\n .map((item) => item.text)\n .join(\"\\n\")\n : \"Tool execution failed\";\n\n throw new Error(errorMessage);\n }\n\n // Prefer structured content when the server provides it.\n if (result.structuredContent !== undefined) {\n return result.structuredContent;\n }\n\n if (result.content === undefined || result.content.length === 0) {\n return { success: true };\n }\n\n // Collapse one text item into a plain string for convenience.\n const firstItem = result.content[0];\n if (result.content.length === 1 && firstItem !== undefined && firstItem.type === \"text\") {\n return firstItem.text;\n }\n\n // Preserve multi-item results in a simple array form.\n return result.content.map((item) => {\n switch (item.type) {\n case \"text\":\n return item.text;\n case \"image\":\n return {\n type: \"image\",\n data: item.data,\n mimeType: item.mimeType,\n };\n case \"resource\":\n return {\n type: \"resource\",\n uri: item.resource.uri,\n content: item.resource.text ?? item.resource.blob,\n };\n default:\n return item;\n }\n });\n}\n"],"mappings":";;;;;;;;;;;AAgBA,SAAgB,gBACZ,QACA,OACA,SAIyB;AACzB,QAAO,MAAM,KAAK,SAAS,eAAe,QAAQ,MAAM,SAAS,OAAO,CAAC;;;;;AAM7E,SAAS,eACL,QACA,MACA,QACuB;CACvB,MAAM,OAAO,SAAS,GAAG,OAAO,GAAG,KAAK,SAAS,KAAK;CAGtD,MAAM,UAAyC,OAC3C,OACA,SACC;AAOD,SAAO,kBANQ,MAAM,OAAO,SAAS;GACjC,MAAM,KAAK;GACX,WAAW;GACd,CAAC,CAG8B;;CAIpC,MAAM,aAAsC;EACxC,MAAM;EACN,YAAY,KAAK,YAAY,cAAc,EAAE;EAC7C,UAAU,KAAK,YAAY,YAAY,EAAE;EACzC,GAAI,KAAK,YAAY,UAAU,EAAE,SAAS,KAAK,YAAY,SAAS,GAAG,EAAE;EAC5E;AAED,QAAO;EACH,MAAM;EACN;EACA,aAAa,KAAK,eAAe,aAAa,KAAK;EAEnD,QAAQ,KAAK;EACb;GACC,mBAAmB;EACvB;;;;;AAML,SAAS,kBAAkB,QAAoC;AAE3D,KAAI,OAAO,YAAY,MAAM;EACzB,MAAM,eAAe,OAAO,UACtB,OAAO,QACF,QAAQ,SAAS,KAAK,SAAS,OAAO,CACtC,KAAK,SAAS,KAAK,KAAK,CACxB,KAAK,KAAK,GACf;AAEN,QAAM,IAAI,MAAM,aAAa;;AAIjC,KAAI,OAAO,sBAAsB,OAC7B,QAAO,OAAO;AAGlB,KAAI,OAAO,YAAY,UAAa,OAAO,QAAQ,WAAW,EAC1D,QAAO,EAAE,SAAS,MAAM;CAI5B,MAAM,YAAY,OAAO,QAAQ;AACjC,KAAI,OAAO,QAAQ,WAAW,KAAK,cAAc,UAAa,UAAU,SAAS,OAC7E,QAAO,UAAU;AAIrB,QAAO,OAAO,QAAQ,KAAK,SAAS;AAChC,UAAQ,KAAK,MAAb;GACI,KAAK,OACD,QAAO,KAAK;GAChB,KAAK,QACD,QAAO;IACH,MAAM;IACN,MAAM,KAAK;IACX,UAAU,KAAK;IAClB;GACL,KAAK,WACD,QAAO;IACH,MAAM;IACN,KAAK,KAAK,SAAS;IACnB,SAAS,KAAK,SAAS,QAAQ,KAAK,SAAS;IAChD;GACL,QACI,QAAO;;GAEjB"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { MCPClientError } from "../error/mcp-client-error.mjs";
|
|
2
|
+
import { JSONRPCMessage } from "./json-rpc-message.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/mcp/tool/mcp-transport.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Transport interface for MCP communication.
|
|
7
|
+
*/
|
|
8
|
+
interface MCPTransport {
|
|
9
|
+
/**
|
|
10
|
+
* Starts the transport.
|
|
11
|
+
*/
|
|
12
|
+
start(): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Sends a JSON-RPC message.
|
|
15
|
+
*/
|
|
16
|
+
send(message: JSONRPCMessage): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Closes the transport and releases resources.
|
|
19
|
+
*/
|
|
20
|
+
close(): Promise<void>;
|
|
21
|
+
/** Called when the transport closes. */
|
|
22
|
+
onclose: (() => void) | undefined;
|
|
23
|
+
/** Called when a transport error occurs. */
|
|
24
|
+
onerror: ((error: MCPClientError) => void) | undefined;
|
|
25
|
+
/** Called when a message is received from the server. */
|
|
26
|
+
onmessage: ((message: JSONRPCMessage) => void) | undefined;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Configuration for MCP HTTP transport.
|
|
30
|
+
*/
|
|
31
|
+
interface MCPTransportAdvancedConfig {
|
|
32
|
+
/** Initial delay before the first reconnect attempt. */
|
|
33
|
+
reconnectInitialDelayMs?: number;
|
|
34
|
+
/** Maximum reconnect delay after backoff is applied. */
|
|
35
|
+
reconnectMaxDelayMs?: number;
|
|
36
|
+
/** Exponential backoff multiplier for reconnect attempts. */
|
|
37
|
+
reconnectBackoffFactor?: number;
|
|
38
|
+
/** Maximum number of reconnect attempts. */
|
|
39
|
+
reconnectMaxRetries?: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* HTTP transport config.
|
|
43
|
+
*/
|
|
44
|
+
interface MCPHttpTransportConfig {
|
|
45
|
+
type: "http";
|
|
46
|
+
/** MCP server URL. */
|
|
47
|
+
url: string;
|
|
48
|
+
/** Additional HTTP headers. */
|
|
49
|
+
headers?: Record<string, string>;
|
|
50
|
+
/** How to handle HTTP redirects. */
|
|
51
|
+
redirect?: "follow" | "error";
|
|
52
|
+
/** Session id for resumable connections. */
|
|
53
|
+
sessionId?: string;
|
|
54
|
+
/** Advanced transport controls. */
|
|
55
|
+
advanced?: MCPTransportAdvancedConfig;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* SSE transport config.
|
|
59
|
+
*/
|
|
60
|
+
interface MCPSseTransportConfig {
|
|
61
|
+
type: "sse";
|
|
62
|
+
/** MCP server SSE endpoint URL. */
|
|
63
|
+
url: string;
|
|
64
|
+
/** Additional HTTP headers. */
|
|
65
|
+
headers?: Record<string, string>;
|
|
66
|
+
/** How to handle HTTP redirects. */
|
|
67
|
+
redirect?: "follow" | "error";
|
|
68
|
+
/** Advanced transport controls. */
|
|
69
|
+
advanced?: MCPTransportAdvancedConfig;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* MCP transport config.
|
|
73
|
+
*/
|
|
74
|
+
type MCPTransportConfig = MCPHttpTransportConfig | MCPSseTransportConfig;
|
|
75
|
+
/**
|
|
76
|
+
* Checks whether a transport is a custom implementation.
|
|
77
|
+
*/
|
|
78
|
+
declare function isCustomMCPTransport(transport: MCPTransportConfig | MCPTransport): transport is MCPTransport;
|
|
79
|
+
//#endregion
|
|
80
|
+
export { MCPHttpTransportConfig, MCPSseTransportConfig, MCPTransport, MCPTransportAdvancedConfig, MCPTransportConfig, isCustomMCPTransport };
|
|
81
|
+
//# sourceMappingURL=mcp-transport.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-transport.d.mts","names":[],"sources":["../../../src/mcp/tool/mcp-transport.ts"],"mappings":";;;;;;AAMA;UAAiB,YAAA;;;;EAIb,KAAA,IAAS,OAAA;EAUA;;;EALT,IAAA,CAAK,OAAA,EAAS,cAAA,GAAiB,OAAA;EAcK;;;EATpC,KAAA,IAAS,OAAA;EALK;EAQd,OAAA;EAR+B;EAW/B,OAAA,IAAW,KAAA,EAAO,cAAA;EANT;EAST,SAAA,IAAa,OAAA,EAAS,cAAA;AAAA;;;;UAMT,0BAAA;EANA;EAQb,uBAAA;EARoC;EAUpC,mBAAA;EAJuC;EAMvC,sBAAA;EANuC;EAQvC,mBAAA;AAAA;;;;UAMa,sBAAA;EACb,IAAA;EADmC;EAInC,GAAA;EAYqC;EATrC,OAAA,GAAU,MAAA;EAHV;EAMA,QAAA;EAHU;EAMV,SAAA;EAAA;EAGA,QAAA,GAAW,0BAAA;AAAA;;;AAMf;UAAiB,qBAAA;EACb,IAAA;EAYqC;EATrC,GAAA;EAAA;EAGA,OAAA,GAAU,MAAA;EAAA;EAGV,QAAA;EAGA;EAAA,QAAA,GAAW,0BAAA;AAAA;;AAMf;;KAAY,kBAAA,GAAqB,sBAAA,GAAyB,qBAAA;;;AAK1D;iBAAgB,oBAAA,CACZ,SAAA,EAAW,kBAAA,GAAqB,YAAA,GACjC,SAAA,IAAa,YAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/mcp/tool/mcp-transport.ts
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether a transport is a custom implementation.
|
|
4
|
+
*/
|
|
5
|
+
function isCustomMCPTransport(transport) {
|
|
6
|
+
return "start" in transport && typeof transport.start === "function" && "send" in transport && typeof transport.send === "function" && "close" in transport && typeof transport.close === "function";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
export { isCustomMCPTransport };
|
|
11
|
+
//# sourceMappingURL=mcp-transport.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-transport.mjs","names":[],"sources":["../../../src/mcp/tool/mcp-transport.ts"],"sourcesContent":["import type { MCPClientError } from \"../error/mcp-client-error\";\nimport type { JSONRPCMessage } from \"./json-rpc-message\";\n\n/**\n * Transport interface for MCP communication.\n */\nexport interface MCPTransport {\n /**\n * Starts the transport.\n */\n start(): Promise<void>;\n\n /**\n * Sends a JSON-RPC message.\n */\n send(message: JSONRPCMessage): Promise<void>;\n\n /**\n * Closes the transport and releases resources.\n */\n close(): Promise<void>;\n\n /** Called when the transport closes. */\n onclose: (() => void) | undefined;\n\n /** Called when a transport error occurs. */\n onerror: ((error: MCPClientError) => void) | undefined;\n\n /** Called when a message is received from the server. */\n onmessage: ((message: JSONRPCMessage) => void) | undefined;\n}\n\n/**\n * Configuration for MCP HTTP transport.\n */\nexport interface MCPTransportAdvancedConfig {\n /** Initial delay before the first reconnect attempt. */\n reconnectInitialDelayMs?: number;\n /** Maximum reconnect delay after backoff is applied. */\n reconnectMaxDelayMs?: number;\n /** Exponential backoff multiplier for reconnect attempts. */\n reconnectBackoffFactor?: number;\n /** Maximum number of reconnect attempts. */\n reconnectMaxRetries?: number;\n}\n\n/**\n * HTTP transport config.\n */\nexport interface MCPHttpTransportConfig {\n type: \"http\";\n\n /** MCP server URL. */\n url: string;\n\n /** Additional HTTP headers. */\n headers?: Record<string, string>;\n\n /** How to handle HTTP redirects. */\n redirect?: \"follow\" | \"error\";\n\n /** Session id for resumable connections. */\n sessionId?: string;\n\n /** Advanced transport controls. */\n advanced?: MCPTransportAdvancedConfig;\n}\n\n/**\n * SSE transport config.\n */\nexport interface MCPSseTransportConfig {\n type: \"sse\";\n\n /** MCP server SSE endpoint URL. */\n url: string;\n\n /** Additional HTTP headers. */\n headers?: Record<string, string>;\n\n /** How to handle HTTP redirects. */\n redirect?: \"follow\" | \"error\";\n\n /** Advanced transport controls. */\n advanced?: MCPTransportAdvancedConfig;\n}\n\n/**\n * MCP transport config.\n */\nexport type MCPTransportConfig = MCPHttpTransportConfig | MCPSseTransportConfig;\n\n/**\n * Checks whether a transport is a custom implementation.\n */\nexport function isCustomMCPTransport(\n transport: MCPTransportConfig | MCPTransport,\n): transport is MCPTransport {\n return (\n \"start\" in transport &&\n typeof transport.start === \"function\" &&\n \"send\" in transport &&\n typeof transport.send === \"function\" &&\n \"close\" in transport &&\n typeof transport.close === \"function\"\n );\n}\n"],"mappings":";;;;AA+FA,SAAgB,qBACZ,WACyB;AACzB,QACI,WAAW,aACX,OAAO,UAAU,UAAU,cAC3B,UAAU,aACV,OAAO,UAAU,SAAS,cAC1B,WAAW,aACX,OAAO,UAAU,UAAU"}
|