@forestadmin/ai-proxy 1.11.3 → 1.12.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/dist/ai-client.d.ts +5 -0
- package/dist/ai-client.js +14 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -1
- package/dist/mcp-auth-error.d.ts +4 -0
- package/dist/mcp-auth-error.js +53 -0
- package/dist/mcp-client.d.ts +12 -0
- package/dist/mcp-client.js +21 -9
- package/dist/tool-provider.d.ts +5 -0
- package/package.json +1 -1
package/dist/ai-client.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { McpServerLoadFailure } from './mcp-client';
|
|
1
2
|
import type { AiConfiguration } from './provider';
|
|
2
3
|
import type RemoteTool from './remote-tool';
|
|
3
4
|
import type { ToolConfig } from './tool-provider-factory';
|
|
@@ -14,6 +15,10 @@ export declare class AiClient {
|
|
|
14
15
|
});
|
|
15
16
|
getModel(aiName?: string): BaseChatModel;
|
|
16
17
|
loadRemoteTools(configs: Record<string, ToolConfig>): Promise<RemoteTool[]>;
|
|
18
|
+
loadRemoteToolsWithFailures(configs: Record<string, ToolConfig>): Promise<{
|
|
19
|
+
tools: RemoteTool[];
|
|
20
|
+
failures: McpServerLoadFailure[];
|
|
21
|
+
}>;
|
|
17
22
|
closeConnections(): Promise<void>;
|
|
18
23
|
private disposeToolProviders;
|
|
19
24
|
}
|
package/dist/ai-client.js
CHANGED
|
@@ -30,11 +30,22 @@ class AiClient {
|
|
|
30
30
|
return model;
|
|
31
31
|
}
|
|
32
32
|
async loadRemoteTools(configs) {
|
|
33
|
+
return (await this.loadRemoteToolsWithFailures(configs)).tools;
|
|
34
|
+
}
|
|
35
|
+
// Same load as loadRemoteTools, but also returns the classified per-server failures providers
|
|
36
|
+
// surface (only MCP providers do today). The default loadRemoteTools drops them, so existing
|
|
37
|
+
// consumers are unaffected.
|
|
38
|
+
async loadRemoteToolsWithFailures(configs) {
|
|
33
39
|
await this.disposeToolProviders('Error closing previous remote tool connection');
|
|
34
40
|
const providers = (0, tool_provider_factory_1.createToolProviders)(configs, this.logger);
|
|
35
|
-
const
|
|
41
|
+
const resultsByProvider = await Promise.all(providers.map(async (provider) => provider.loadToolsWithFailures
|
|
42
|
+
? provider.loadToolsWithFailures()
|
|
43
|
+
: { tools: await provider.loadTools(), failures: [] }));
|
|
36
44
|
this.toolProviders = providers;
|
|
37
|
-
return
|
|
45
|
+
return {
|
|
46
|
+
tools: resultsByProvider.flatMap(result => result.tools),
|
|
47
|
+
failures: resultsByProvider.flatMap(result => result.failures),
|
|
48
|
+
};
|
|
38
49
|
}
|
|
39
50
|
async closeConnections() {
|
|
40
51
|
await this.disposeToolProviders('Error during remote tool connection cleanup');
|
|
@@ -55,4 +66,4 @@ class AiClient {
|
|
|
55
66
|
}
|
|
56
67
|
}
|
|
57
68
|
exports.AiClient = AiClient;
|
|
58
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
69
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWktY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2FpLWNsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFRQSxxRUFBK0Q7QUFDL0QscUNBQWdEO0FBQ2hELGtGQUF3RDtBQUN4RCxtRUFBOEQ7QUFDOUQsOEZBQW9FO0FBRXBFLHdEQUF3RDtBQUN4RCxNQUFhLFFBQVE7SUFNbkIsWUFBWSxNQUFrRTtRQUg3RCxlQUFVLEdBQUcsSUFBSSxHQUFHLEVBQXlCLENBQUM7UUFDdkQsa0JBQWEsR0FBbUIsRUFBRSxDQUFDO1FBR3pDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxNQUFNLEVBQUUsZ0JBQWdCLElBQUksRUFBRSxDQUFDO1FBQ3ZELElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxFQUFFLE1BQU0sQ0FBQztRQUU3QixJQUFBLG9DQUF3QixFQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBQ2xELENBQUM7SUFFRCxRQUFRLENBQUMsTUFBZTtRQUN0QixNQUFNLE1BQU0sR0FBRyxJQUFBLDhCQUFrQixFQUFDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQzlFLElBQUksQ0FBQyxNQUFNO1lBQUUsTUFBTSxJQUFJLDZCQUFvQixFQUFFLENBQUM7UUFFOUMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2hELElBQUksTUFBTTtZQUFFLE9BQU8sTUFBTSxDQUFDO1FBRTFCLE1BQU0sS0FBSyxHQUFHLElBQUEsNENBQW1CLEVBQUMsTUFBTSxDQUFDLENBQUM7UUFDMUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQztRQUV4QyxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxLQUFL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
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export * from './remote-tools';
|
|
|
10
10
|
export { default as RemoteTool } from './remote-tool';
|
|
11
11
|
export * from './router';
|
|
12
12
|
export * from './mcp-client';
|
|
13
|
+
export * from './mcp-auth-error';
|
|
13
14
|
export * from './oauth-token-injector';
|
|
14
15
|
export * from './errors';
|
|
15
16
|
export * from './tool-provider';
|
package/dist/index.js
CHANGED
|
@@ -35,6 +35,7 @@ var remote_tool_1 = require("./remote-tool");
|
|
|
35
35
|
Object.defineProperty(exports, "RemoteTool", { enumerable: true, get: function () { return __importDefault(remote_tool_1).default; } });
|
|
36
36
|
__exportStar(require("./router"), exports);
|
|
37
37
|
__exportStar(require("./mcp-client"), exports);
|
|
38
|
+
__exportStar(require("./mcp-auth-error"), exports);
|
|
38
39
|
__exportStar(require("./oauth-token-injector"), exports);
|
|
39
40
|
__exportStar(require("./errors"), exports);
|
|
40
41
|
__exportStar(require("./tool-provider"), exports);
|
|
@@ -47,4 +48,4 @@ Object.defineProperty(exports, "HumanMessage", { enumerable: true, get: function
|
|
|
47
48
|
Object.defineProperty(exports, "SystemMessage", { enumerable: true, get: function () { return messages_1.SystemMessage; } });
|
|
48
49
|
var tools_1 = require("@langchain/core/tools");
|
|
49
50
|
Object.defineProperty(exports, "DynamicStructuredTool", { enumerable: true, get: function () { return tools_1.DynamicStructuredTool; } });
|
|
50
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
51
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUE0QkEsc0VBS0M7QUE5QkQsZ0ZBQXNEO0FBRXRELDJEQUF3RDtBQUEvQyxzSEFBQSxnQkFBZ0IsT0FBQTtBQUN6QixtRUFBK0Q7QUFBdEQsNkhBQUEsbUJBQW1CLE9BQUE7QUFDNUIsNkRBQXNFO0FBQTdELDBJQUFBLE9BQU8sT0FBc0I7QUFFdEMseUVBS3FDO0FBSm5DLHFJQUFBLHdCQUF3QixPQUFBO0FBTTFCLHdEQUFzQztBQUN0Qyw4Q0FBNEI7QUFDNUIsaURBQStCO0FBQy9CLDZDQUFzRDtBQUE3QywwSEFBQSxPQUFPLE9BQWM7QUFDOUIsMkNBQXlCO0FBQ3pCLCtDQUE2QjtBQUM3QixtREFBaUM7QUFDakMseURBQXVDO0FBQ3ZDLDJDQUF5QjtBQUN6QixrREFBZ0M7QUFDaEMsMERBQXdDO0FBRXhDLFNBQWdCLDZCQUE2QixDQUMzQyxPQUFtQyxFQUNuQyxNQUFlO0lBRWYsT0FBTyw2QkFBaUIsQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0FBQ2xELENBQUM7QUFJRCxxREFBdUU7QUFBOUQsd0dBQUEsWUFBWSxPQUFBO0FBQUUseUdBQUEsYUFBYSxPQUFBO0FBRXBDLCtDQUE4RDtBQUFyRCw4R0FBQSxxQkFBcUIsT0FBQSJ9
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isMcpAuthError = isMcpAuthError;
|
|
4
|
+
exports.classifyMcpLoadError = classifyMcpLoadError;
|
|
5
|
+
// Classifies errors surfaced while connecting to or calling an MCP server. Only 401 (the token was
|
|
6
|
+
// rejected) is a refreshable auth failure; 403 is a permission/scope problem a token refresh or
|
|
7
|
+
// re-consent cannot resolve, so it is left to surface as an ordinary failure. The MCP SDK / HTTP
|
|
8
|
+
// transport reports failures in several shapes (a numeric status field, or only a message string),
|
|
9
|
+
// so the checks walk the cause chain and inspect both structured status and the message text.
|
|
10
|
+
const AUTH_STATUSES = new Set([401]);
|
|
11
|
+
const AUTH_PATTERN = /\b401\b|unauthorized/i;
|
|
12
|
+
const CONNECTION_PATTERN = /econnrefused|econnreset|etimedout|enotfound|eai_again|fetch failed|network|socket|timeout|connect/i;
|
|
13
|
+
function statusOf(value) {
|
|
14
|
+
const candidate = value;
|
|
15
|
+
for (const field of [candidate?.code, candidate?.status, candidate?.statusCode]) {
|
|
16
|
+
if (typeof field === 'number')
|
|
17
|
+
return field;
|
|
18
|
+
}
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
function messageOf(value) {
|
|
22
|
+
if (value instanceof Error)
|
|
23
|
+
return value.message;
|
|
24
|
+
if (typeof value === 'string')
|
|
25
|
+
return value;
|
|
26
|
+
return '';
|
|
27
|
+
}
|
|
28
|
+
function errorChain(error) {
|
|
29
|
+
const links = [];
|
|
30
|
+
let current = error;
|
|
31
|
+
while (current && links.length < 10 && !links.includes(current)) {
|
|
32
|
+
links.push(current);
|
|
33
|
+
current = current.cause;
|
|
34
|
+
}
|
|
35
|
+
return links;
|
|
36
|
+
}
|
|
37
|
+
function isMcpAuthError(error) {
|
|
38
|
+
return errorChain(error).some(link => {
|
|
39
|
+
const status = statusOf(link);
|
|
40
|
+
// Only an HTTP-range status is authoritative (a 403 isn't refreshable even if its message says
|
|
41
|
+
// "unauthorized"). A JSON-RPC error code like -32603 isn't a status, so fall back to the message.
|
|
42
|
+
if (status !== undefined && status >= 100 && status <= 599)
|
|
43
|
+
return AUTH_STATUSES.has(status);
|
|
44
|
+
return AUTH_PATTERN.test(messageOf(link));
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function classifyMcpLoadError(error) {
|
|
48
|
+
if (isMcpAuthError(error))
|
|
49
|
+
return 'auth';
|
|
50
|
+
const isConnectionFailure = errorChain(error).some(link => CONNECTION_PATTERN.test(messageOf(link)));
|
|
51
|
+
return isConnectionFailure ? 'connection' : 'unknown';
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWNwLWF1dGgtZXJyb3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvbWNwLWF1dGgtZXJyb3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUF5Q0Esd0NBU0M7QUFFRCxvREFRQztBQTVERCxtR0FBbUc7QUFDbkcsZ0dBQWdHO0FBQ2hHLGlHQUFpRztBQUNqRyxtR0FBbUc7QUFDbkcsOEZBQThGO0FBQzlGLE1BQU0sYUFBYSxHQUFHLElBQUksR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztBQUNyQyxNQUFNLFlBQVksR0FBRyx1QkFBdUIsQ0FBQztBQUM3QyxNQUFNLGtCQUFrQixHQUN0QixvR0FBb0csQ0FBQztBQUl2RyxTQUFTLFFBQVEsQ0FBQyxLQUFjO0lBQzlCLE1BQU0sU0FBUyxHQUFHLEtBQW1FLENBQUM7SUFFdEYsS0FBSyxNQUFNLEtBQUssSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUNoRixJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVE7WUFBRSxPQUFPLEtBQUssQ0FBQztJQUM5QyxDQUFDO0lBRUQsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQUVELFNBQVMsU0FBUyxDQUFDLEtBQWM7SUFDL0IsSUFBSSxLQUFLLFlBQVksS0FBSztRQUFFLE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQztJQUNqRCxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVE7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUU1QyxPQUFPLEVBQUUsQ0FBQztBQUNaLENBQUM7QUFFRCxTQUFTLFVBQVUsQ0FBQyxLQUFjO0lBQ2hDLE1BQU0sS0FBSyxHQUFjLEVBQUUsQ0FBQztJQUM1QixJQUFJLE9BQU8sR0FBWSxLQUFLLENBQUM7SUFFN0IsT0FBTyxPQUFPLElBQUksS0FBSyxDQUFDLE1BQU0sR0FBRyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDaEUsS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNwQixPQUFPLEdBQUksT0FBK0IsQ0FBQyxLQUFLLENBQUM7SUFDbkQsQ0FBQztJQUVELE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQztBQUVELFNBQWdCLGNBQWMsQ0FBQyxLQUFjO0lBQzNDLE9BQU8sVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRTtRQUNuQyxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDOUIsK0ZBQStGO1FBQy9GLGtHQUFrRztRQUNsRyxJQUFJLE1BQU0sS0FBSyxTQUFTLElBQUksTUFBTSxJQUFJLEdBQUcsSUFBSSxNQUFNLElBQUksR0FBRztZQUFFLE9BQU8sYUFBYSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUU3RixPQUFPLFlBQVksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDNUMsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsU0FBZ0Isb0JBQW9CLENBQUMsS0FBYztJQUNqRCxJQUFJLGNBQWMsQ0FBQyxLQUFLLENBQUM7UUFBRSxPQUFPLE1BQU0sQ0FBQztJQUV6QyxNQUFNLG1CQUFtQixHQUFHLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FDeEQsa0JBQWtCLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUN6QyxDQUFDO0lBRUYsT0FBTyxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDeEQsQ0FBQyJ9
|
package/dist/mcp-client.d.ts
CHANGED
|
@@ -1,19 +1,31 @@
|
|
|
1
1
|
import type { ToolProvider } from './tool-provider';
|
|
2
2
|
import type { Logger } from '@forestadmin/datasource-toolkit';
|
|
3
3
|
import { MultiServerMCPClient } from '@langchain/mcp-adapters';
|
|
4
|
+
import { type McpLoadFailureKind } from './mcp-auth-error';
|
|
4
5
|
import McpServerRemoteTool from './mcp-server-remote-tool';
|
|
5
6
|
export type McpServers = MultiServerMCPClient['config']['mcpServers'];
|
|
6
7
|
export type McpServerConfig = MultiServerMCPClient['config']['mcpServers'][string] & {
|
|
7
8
|
id?: string;
|
|
9
|
+
authType?: string;
|
|
8
10
|
};
|
|
9
11
|
export type McpConfiguration = {
|
|
10
12
|
configs: Record<string, McpServerConfig>;
|
|
11
13
|
} & Omit<MultiServerMCPClient['config'], 'mcpServers'>;
|
|
14
|
+
export interface McpServerLoadFailure {
|
|
15
|
+
server: string;
|
|
16
|
+
mcpServerId?: string;
|
|
17
|
+
kind: McpLoadFailureKind;
|
|
18
|
+
error: Error;
|
|
19
|
+
}
|
|
12
20
|
export default class McpClient implements ToolProvider {
|
|
13
21
|
private readonly mcpClients;
|
|
14
22
|
private readonly mcpServerIdsByName;
|
|
15
23
|
private readonly logger?;
|
|
16
24
|
constructor(config: McpConfiguration, logger?: Logger);
|
|
25
|
+
loadToolsWithFailures(): Promise<{
|
|
26
|
+
tools: McpServerRemoteTool[];
|
|
27
|
+
failures: McpServerLoadFailure[];
|
|
28
|
+
}>;
|
|
17
29
|
loadTools(): Promise<McpServerRemoteTool[]>;
|
|
18
30
|
checkConnection(): Promise<true>;
|
|
19
31
|
dispose(): Promise<void>;
|
package/dist/mcp-client.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const mcp_adapters_1 = require("@langchain/mcp-adapters");
|
|
7
7
|
const errors_1 = require("./errors");
|
|
8
|
+
const mcp_auth_error_1 = require("./mcp-auth-error");
|
|
8
9
|
const mcp_server_remote_tool_1 = __importDefault(require("./mcp-server-remote-tool"));
|
|
9
10
|
class McpClient {
|
|
10
11
|
constructor(config, logger) {
|
|
@@ -14,7 +15,7 @@ class McpClient {
|
|
|
14
15
|
// split the config into several clients to be more resilient
|
|
15
16
|
// if a mcp server is down, the others will still work
|
|
16
17
|
Object.entries(config.configs).forEach(([name, serverConfig]) => {
|
|
17
|
-
const { id: mcpServerId, ...rest } = serverConfig;
|
|
18
|
+
const { id: mcpServerId, authType, ...rest } = serverConfig;
|
|
18
19
|
this.mcpServerIdsByName[name] = mcpServerId;
|
|
19
20
|
this.mcpClients[name] = new mcp_adapters_1.MultiServerMCPClient({
|
|
20
21
|
mcpServers: { [name]: rest },
|
|
@@ -22,9 +23,12 @@ class McpClient {
|
|
|
22
23
|
});
|
|
23
24
|
});
|
|
24
25
|
}
|
|
25
|
-
|
|
26
|
+
// Exposes per-server failures classified by cause (auth vs connection) alongside the tools that
|
|
27
|
+
// did load, so a caller holding a per-user token can tell a revoked token (retry after refresh)
|
|
28
|
+
// from an unreachable server (genuine failure). loadTools() keeps its tools-only contract.
|
|
29
|
+
async loadToolsWithFailures() {
|
|
26
30
|
const tools = [];
|
|
27
|
-
const
|
|
31
|
+
const failures = [];
|
|
28
32
|
await Promise.all(Object.entries(this.mcpClients).map(async ([name, client]) => {
|
|
29
33
|
try {
|
|
30
34
|
const loadedTools = (await client.getTools()) ?? [];
|
|
@@ -37,16 +41,24 @@ class McpClient {
|
|
|
37
41
|
}
|
|
38
42
|
catch (error) {
|
|
39
43
|
this.logger?.('Error', `Error loading tools for ${name}`, error);
|
|
40
|
-
|
|
44
|
+
failures.push({
|
|
45
|
+
server: name,
|
|
46
|
+
mcpServerId: this.mcpServerIdsByName[name],
|
|
47
|
+
kind: (0, mcp_auth_error_1.classifyMcpLoadError)(error),
|
|
48
|
+
error: error,
|
|
49
|
+
});
|
|
41
50
|
}
|
|
42
51
|
}));
|
|
43
52
|
// Surface partial failures to provide better feedback
|
|
44
|
-
if (
|
|
45
|
-
const errorMessage =
|
|
46
|
-
this.logger?.('Error', `Failed to load tools from ${
|
|
53
|
+
if (failures.length > 0) {
|
|
54
|
+
const errorMessage = failures.map(f => `${f.server}: ${f.error.message}`).join('; ');
|
|
55
|
+
this.logger?.('Error', `Failed to load tools from ${failures.length}/${Object.keys(this.mcpClients).length} ` +
|
|
47
56
|
`MCP server(s): ${errorMessage}`);
|
|
48
57
|
}
|
|
49
|
-
return tools;
|
|
58
|
+
return { tools, failures };
|
|
59
|
+
}
|
|
60
|
+
async loadTools() {
|
|
61
|
+
return (await this.loadToolsWithFailures()).tools;
|
|
50
62
|
}
|
|
51
63
|
async checkConnection() {
|
|
52
64
|
try {
|
|
@@ -83,4 +95,4 @@ class McpClient {
|
|
|
83
95
|
}
|
|
84
96
|
}
|
|
85
97
|
exports.default = McpClient;
|
|
86
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
98
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWNwLWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9tY3AtY2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBR0EsMERBQStEO0FBRS9ELHFDQUE4QztBQUM5QyxxREFBaUY7QUFDakYsc0ZBQTJEO0FBcUIzRCxNQUFxQixTQUFTO0lBSzVCLFlBQVksTUFBd0IsRUFBRSxNQUFlO1FBSnBDLGVBQVUsR0FBeUMsRUFBRSxDQUFDO1FBQ3RELHVCQUFrQixHQUF1QyxFQUFFLENBQUM7UUFJM0UsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsNkRBQTZEO1FBQzdELHNEQUFzRDtRQUN0RCxNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxZQUFZLENBQUMsRUFBRSxFQUFFO1lBQzlELE1BQU0sRUFDSixFQUFFLEVBQUUsV0FBVyxFQUNmLFFBQVEsRUFDUixHQUFHLElBQUksRUFDUixHQUFHLFlBQXlELENBQUM7WUFDOUQsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxHQUFHLFdBQVcsQ0FBQztZQUM1QyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksbUNBQW9CLENBQUM7Z0JBQy9DLFVBQVUsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBdUIsRUFBRTtnQkFDL0MsR0FBRyxNQUFNO2FBQ1YsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsZ0dBQWdHO0lBQ2hHLGdHQUFnRztJQUNoRywyRkFBMkY7SUFDM0YsS0FBSyxDQUFDLHFCQUFxQjtRQUl6QixNQUFNLEtBQUssR0FBMEIsRUFBRSxDQUFDO1FBQ3hDLE1BQU0sUUFBUSxHQUEyQixFQUFFLENBQUM7UUFFNUMsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUNmLE1BQU0sQ0FBQyxP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
|
package/dist/tool-provider.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import type { McpServerLoadFailure } from './mcp-client';
|
|
1
2
|
import type RemoteTool from './remote-tool';
|
|
2
3
|
export interface ToolProvider {
|
|
3
4
|
loadTools(): Promise<RemoteTool[]>;
|
|
5
|
+
loadToolsWithFailures?(): Promise<{
|
|
6
|
+
tools: RemoteTool[];
|
|
7
|
+
failures: McpServerLoadFailure[];
|
|
8
|
+
}>;
|
|
4
9
|
checkConnection(): Promise<true>;
|
|
5
10
|
dispose(): Promise<void>;
|
|
6
11
|
}
|