@iqai/adk 0.0.2 → 0.0.3
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/CHANGELOG.md +6 -0
- package/dist/index.d.mts +178 -2
- package/dist/index.d.ts +178 -2
- package/dist/index.js +805 -93
- package/dist/index.mjs +713 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2023,11 +2023,19 @@ __export(tools_exports, {
|
|
|
2023
2023
|
GoogleSearch: () => GoogleSearch,
|
|
2024
2024
|
HttpRequestTool: () => HttpRequestTool,
|
|
2025
2025
|
LoadMemoryTool: () => LoadMemoryTool,
|
|
2026
|
+
McpError: () => McpError,
|
|
2027
|
+
McpErrorType: () => McpErrorType,
|
|
2028
|
+
McpToolset: () => McpToolset,
|
|
2026
2029
|
ToolContext: () => ToolContext,
|
|
2027
2030
|
TransferToAgentTool: () => TransferToAgentTool,
|
|
2028
2031
|
UserInteractionTool: () => UserInteractionTool,
|
|
2032
|
+
adkToMcpToolType: () => adkToMcpToolType,
|
|
2029
2033
|
buildFunctionDeclaration: () => buildFunctionDeclaration,
|
|
2030
|
-
createFunctionTool: () => createFunctionTool
|
|
2034
|
+
createFunctionTool: () => createFunctionTool,
|
|
2035
|
+
getMcpTools: () => getMcpTools,
|
|
2036
|
+
jsonSchemaToDeclaration: () => jsonSchemaToDeclaration,
|
|
2037
|
+
mcpSchemaToParameters: () => mcpSchemaToParameters,
|
|
2038
|
+
normalizeJsonSchema: () => normalizeJsonSchema
|
|
2031
2039
|
});
|
|
2032
2040
|
init_base_tool();
|
|
2033
2041
|
init_function_tool();
|
|
@@ -2768,6 +2776,702 @@ var LoadMemoryTool = class extends BaseTool {
|
|
|
2768
2776
|
}
|
|
2769
2777
|
};
|
|
2770
2778
|
|
|
2779
|
+
// src/tools/mcp/client.ts
|
|
2780
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2781
|
+
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
2782
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
2783
|
+
|
|
2784
|
+
// src/tools/mcp/types.ts
|
|
2785
|
+
var McpErrorType = /* @__PURE__ */ ((McpErrorType2) => {
|
|
2786
|
+
McpErrorType2["CONNECTION_ERROR"] = "connection_error";
|
|
2787
|
+
McpErrorType2["TOOL_EXECUTION_ERROR"] = "tool_execution_error";
|
|
2788
|
+
McpErrorType2["RESOURCE_CLOSED_ERROR"] = "resource_closed_error";
|
|
2789
|
+
McpErrorType2["TIMEOUT_ERROR"] = "timeout_error";
|
|
2790
|
+
McpErrorType2["INVALID_SCHEMA_ERROR"] = "invalid_schema_error";
|
|
2791
|
+
return McpErrorType2;
|
|
2792
|
+
})(McpErrorType || {});
|
|
2793
|
+
var McpError = class extends Error {
|
|
2794
|
+
constructor(message, type, originalError) {
|
|
2795
|
+
super(message);
|
|
2796
|
+
this.name = "McpError";
|
|
2797
|
+
this.type = type;
|
|
2798
|
+
this.originalError = originalError;
|
|
2799
|
+
}
|
|
2800
|
+
};
|
|
2801
|
+
|
|
2802
|
+
// src/tools/mcp/utils.ts
|
|
2803
|
+
function withRetry(fn, instance, reinitMethod, maxRetries = 1) {
|
|
2804
|
+
return async (...args) => {
|
|
2805
|
+
let attempt = 0;
|
|
2806
|
+
while (attempt <= maxRetries) {
|
|
2807
|
+
try {
|
|
2808
|
+
return await fn.apply(instance, args);
|
|
2809
|
+
} catch (error) {
|
|
2810
|
+
const isClosedResourceError = error instanceof Error && (error.message.includes("closed") || error.message.includes("ECONNRESET") || error.message.includes("socket hang up"));
|
|
2811
|
+
if (!isClosedResourceError || attempt >= maxRetries) {
|
|
2812
|
+
throw error;
|
|
2813
|
+
}
|
|
2814
|
+
console.warn(
|
|
2815
|
+
`Resource closed, reinitializing (attempt ${attempt + 1}/${maxRetries + 1})...`
|
|
2816
|
+
);
|
|
2817
|
+
try {
|
|
2818
|
+
await reinitMethod(instance);
|
|
2819
|
+
} catch (reinitError) {
|
|
2820
|
+
console.error("Error reinitializing resources:", reinitError);
|
|
2821
|
+
throw new Error(`Failed to reinitialize resources: ${reinitError}`);
|
|
2822
|
+
}
|
|
2823
|
+
attempt++;
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
throw new Error("Unexpected end of retry loop");
|
|
2827
|
+
};
|
|
2828
|
+
}
|
|
2829
|
+
|
|
2830
|
+
// src/tools/mcp/client.ts
|
|
2831
|
+
var McpClientService = class {
|
|
2832
|
+
constructor(config) {
|
|
2833
|
+
this.client = null;
|
|
2834
|
+
this.transport = null;
|
|
2835
|
+
this.isClosing = false;
|
|
2836
|
+
this.config = config;
|
|
2837
|
+
}
|
|
2838
|
+
/**
|
|
2839
|
+
* Initializes and returns an MCP client based on configuration.
|
|
2840
|
+
* Will create a new client if one doesn't exist yet.
|
|
2841
|
+
*/
|
|
2842
|
+
async initialize() {
|
|
2843
|
+
if (this.isClosing) {
|
|
2844
|
+
throw new McpError(
|
|
2845
|
+
"Cannot initialize a client that is being closed",
|
|
2846
|
+
"resource_closed_error" /* RESOURCE_CLOSED_ERROR */
|
|
2847
|
+
);
|
|
2848
|
+
}
|
|
2849
|
+
if (this.client) {
|
|
2850
|
+
return this.client;
|
|
2851
|
+
}
|
|
2852
|
+
try {
|
|
2853
|
+
if (!this.transport) {
|
|
2854
|
+
this.transport = await this.createTransport();
|
|
2855
|
+
}
|
|
2856
|
+
const client = new Client(
|
|
2857
|
+
{
|
|
2858
|
+
name: this.config.name,
|
|
2859
|
+
version: "0.0.1"
|
|
2860
|
+
},
|
|
2861
|
+
{
|
|
2862
|
+
capabilities: {
|
|
2863
|
+
prompts: {},
|
|
2864
|
+
resources: {},
|
|
2865
|
+
tools: {}
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
2868
|
+
);
|
|
2869
|
+
const connectPromise = client.connect(this.transport);
|
|
2870
|
+
if (this.config.timeout) {
|
|
2871
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
2872
|
+
setTimeout(() => {
|
|
2873
|
+
reject(
|
|
2874
|
+
new McpError(
|
|
2875
|
+
`MCP client connection timed out after ${this.config.timeout}ms`,
|
|
2876
|
+
"timeout_error" /* TIMEOUT_ERROR */
|
|
2877
|
+
)
|
|
2878
|
+
);
|
|
2879
|
+
}, this.config.timeout);
|
|
2880
|
+
});
|
|
2881
|
+
await Promise.race([connectPromise, timeoutPromise]);
|
|
2882
|
+
} else {
|
|
2883
|
+
await connectPromise;
|
|
2884
|
+
}
|
|
2885
|
+
if (this.config.debug) {
|
|
2886
|
+
console.log("\u2705 MCP client connected successfully");
|
|
2887
|
+
}
|
|
2888
|
+
this.client = client;
|
|
2889
|
+
return client;
|
|
2890
|
+
} catch (error) {
|
|
2891
|
+
await this.cleanupResources();
|
|
2892
|
+
if (!(error instanceof McpError)) {
|
|
2893
|
+
console.error("Failed to initialize MCP client:", error);
|
|
2894
|
+
throw new McpError(
|
|
2895
|
+
`Failed to initialize MCP client: ${error instanceof Error ? error.message : String(error)}`,
|
|
2896
|
+
"connection_error" /* CONNECTION_ERROR */,
|
|
2897
|
+
error instanceof Error ? error : void 0
|
|
2898
|
+
);
|
|
2899
|
+
}
|
|
2900
|
+
throw error;
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
/**
|
|
2904
|
+
* Creates a transport based on the configuration.
|
|
2905
|
+
*/
|
|
2906
|
+
async createTransport() {
|
|
2907
|
+
try {
|
|
2908
|
+
if (this.config.transport.mode === "sse") {
|
|
2909
|
+
if (this.config.debug) {
|
|
2910
|
+
console.log(
|
|
2911
|
+
"\u{1F680} Initializing MCP client in SSE mode",
|
|
2912
|
+
this.config.transport.serverUrl
|
|
2913
|
+
);
|
|
2914
|
+
}
|
|
2915
|
+
const headers = {
|
|
2916
|
+
...this.config.transport.headers || {},
|
|
2917
|
+
...this.config.headers || {}
|
|
2918
|
+
};
|
|
2919
|
+
return new SSEClientTransport(
|
|
2920
|
+
new URL(this.config.transport.serverUrl),
|
|
2921
|
+
{
|
|
2922
|
+
requestInit: {
|
|
2923
|
+
headers,
|
|
2924
|
+
...this.config.timeout ? { timeout: this.config.timeout } : {}
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
);
|
|
2928
|
+
}
|
|
2929
|
+
if (this.config.debug) {
|
|
2930
|
+
console.log(
|
|
2931
|
+
"\u{1F680} Initializing MCP client in STDIO mode",
|
|
2932
|
+
this.config.transport.command
|
|
2933
|
+
);
|
|
2934
|
+
}
|
|
2935
|
+
return new StdioClientTransport({
|
|
2936
|
+
command: this.config.transport.command,
|
|
2937
|
+
args: this.config.transport.args,
|
|
2938
|
+
env: this.config.transport.env
|
|
2939
|
+
});
|
|
2940
|
+
} catch (error) {
|
|
2941
|
+
throw new McpError(
|
|
2942
|
+
`Failed to create transport: ${error instanceof Error ? error.message : String(error)}`,
|
|
2943
|
+
"connection_error" /* CONNECTION_ERROR */,
|
|
2944
|
+
error instanceof Error ? error : void 0
|
|
2945
|
+
);
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2948
|
+
/**
|
|
2949
|
+
* Re-initializes the MCP client when a session is closed.
|
|
2950
|
+
* Used by the retry mechanism.
|
|
2951
|
+
*/
|
|
2952
|
+
async reinitialize() {
|
|
2953
|
+
if (this.config.debug) {
|
|
2954
|
+
console.log("\u{1F504} Reinitializing MCP client after closed connection");
|
|
2955
|
+
}
|
|
2956
|
+
await this.cleanupResources();
|
|
2957
|
+
this.client = null;
|
|
2958
|
+
this.transport = null;
|
|
2959
|
+
await this.initialize();
|
|
2960
|
+
}
|
|
2961
|
+
/**
|
|
2962
|
+
* Cleans up resources associated with this client service.
|
|
2963
|
+
* Similar to Python's AsyncExitStack.aclose() functionality.
|
|
2964
|
+
*/
|
|
2965
|
+
async cleanupResources() {
|
|
2966
|
+
try {
|
|
2967
|
+
this.isClosing = true;
|
|
2968
|
+
if (this.client) {
|
|
2969
|
+
try {
|
|
2970
|
+
if (typeof this.client.close === "function") {
|
|
2971
|
+
await this.client.close();
|
|
2972
|
+
}
|
|
2973
|
+
} catch (err) {
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
if (this.transport && typeof this.transport.close === "function") {
|
|
2977
|
+
await this.transport.close();
|
|
2978
|
+
}
|
|
2979
|
+
if (this.config.debug) {
|
|
2980
|
+
console.log("\u{1F9F9} Cleaned up MCP client resources");
|
|
2981
|
+
}
|
|
2982
|
+
} catch (error) {
|
|
2983
|
+
console.error("Error cleaning up MCP resources:", error);
|
|
2984
|
+
} finally {
|
|
2985
|
+
this.client = null;
|
|
2986
|
+
this.transport = null;
|
|
2987
|
+
this.isClosing = false;
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
/**
|
|
2991
|
+
* Call an MCP tool with retry capability if the session is closed.
|
|
2992
|
+
*/
|
|
2993
|
+
async callTool(name, args) {
|
|
2994
|
+
try {
|
|
2995
|
+
const wrappedCall = withRetry(
|
|
2996
|
+
async function() {
|
|
2997
|
+
const client = await this.initialize();
|
|
2998
|
+
return client.callTool({
|
|
2999
|
+
name,
|
|
3000
|
+
arguments: args
|
|
3001
|
+
});
|
|
3002
|
+
},
|
|
3003
|
+
this,
|
|
3004
|
+
async (instance) => await instance.reinitialize(),
|
|
3005
|
+
this.config.retryOptions?.maxRetries || 2
|
|
3006
|
+
);
|
|
3007
|
+
return await wrappedCall();
|
|
3008
|
+
} catch (error) {
|
|
3009
|
+
if (!(error instanceof McpError)) {
|
|
3010
|
+
throw new McpError(
|
|
3011
|
+
`Error calling tool "${name}": ${error instanceof Error ? error.message : String(error)}`,
|
|
3012
|
+
"tool_execution_error" /* TOOL_EXECUTION_ERROR */,
|
|
3013
|
+
error instanceof Error ? error : void 0
|
|
3014
|
+
);
|
|
3015
|
+
}
|
|
3016
|
+
throw error;
|
|
3017
|
+
}
|
|
3018
|
+
}
|
|
3019
|
+
/**
|
|
3020
|
+
* Closes and cleans up all resources.
|
|
3021
|
+
* Should be called when the service is no longer needed.
|
|
3022
|
+
* Similar to Python's close() method.
|
|
3023
|
+
*/
|
|
3024
|
+
async close() {
|
|
3025
|
+
if (this.config.debug) {
|
|
3026
|
+
console.log("\u{1F51A} Closing MCP client service");
|
|
3027
|
+
}
|
|
3028
|
+
await this.cleanupResources();
|
|
3029
|
+
}
|
|
3030
|
+
/**
|
|
3031
|
+
* Checks if the client is currently connected
|
|
3032
|
+
*/
|
|
3033
|
+
isConnected() {
|
|
3034
|
+
return !!this.client && !this.isClosing;
|
|
3035
|
+
}
|
|
3036
|
+
};
|
|
3037
|
+
|
|
3038
|
+
// src/tools/mcp/create-tool.ts
|
|
3039
|
+
init_base_tool();
|
|
3040
|
+
|
|
3041
|
+
// src/tools/mcp/schema-conversion.ts
|
|
3042
|
+
function adkToMcpToolType(tool) {
|
|
3043
|
+
const declaration = tool.getDeclaration();
|
|
3044
|
+
const params = declarationToJsonSchema(declaration);
|
|
3045
|
+
return {
|
|
3046
|
+
name: tool.name,
|
|
3047
|
+
description: tool.description || "",
|
|
3048
|
+
inputSchema: {
|
|
3049
|
+
type: "object",
|
|
3050
|
+
properties: params
|
|
3051
|
+
}
|
|
3052
|
+
};
|
|
3053
|
+
}
|
|
3054
|
+
function declarationToJsonSchema(declaration) {
|
|
3055
|
+
if (!declaration.parameters) {
|
|
3056
|
+
return {};
|
|
3057
|
+
}
|
|
3058
|
+
if (declaration.parameters.properties) {
|
|
3059
|
+
return declaration.parameters.properties;
|
|
3060
|
+
}
|
|
3061
|
+
return declaration.parameters;
|
|
3062
|
+
}
|
|
3063
|
+
function jsonSchemaToDeclaration(name, description, schema) {
|
|
3064
|
+
let parameters;
|
|
3065
|
+
if (schema) {
|
|
3066
|
+
if (typeof schema === "object" && "type" in schema && typeof schema.type === "string") {
|
|
3067
|
+
parameters = schema;
|
|
3068
|
+
} else {
|
|
3069
|
+
parameters = {
|
|
3070
|
+
type: "object",
|
|
3071
|
+
properties: schema
|
|
3072
|
+
};
|
|
3073
|
+
}
|
|
3074
|
+
} else {
|
|
3075
|
+
parameters = {
|
|
3076
|
+
type: "object",
|
|
3077
|
+
properties: {}
|
|
3078
|
+
};
|
|
3079
|
+
}
|
|
3080
|
+
return {
|
|
3081
|
+
name,
|
|
3082
|
+
description,
|
|
3083
|
+
parameters
|
|
3084
|
+
};
|
|
3085
|
+
}
|
|
3086
|
+
function normalizeJsonSchema(schema) {
|
|
3087
|
+
if (!schema) {
|
|
3088
|
+
return { type: "object", properties: {} };
|
|
3089
|
+
}
|
|
3090
|
+
const normalizedSchema = { ...schema };
|
|
3091
|
+
if (!normalizedSchema.type) {
|
|
3092
|
+
normalizedSchema.type = determineSchemaType(normalizedSchema);
|
|
3093
|
+
}
|
|
3094
|
+
switch (normalizedSchema.type) {
|
|
3095
|
+
case "object":
|
|
3096
|
+
return normalizeObjectSchema(normalizedSchema);
|
|
3097
|
+
case "array":
|
|
3098
|
+
return normalizeArraySchema(normalizedSchema);
|
|
3099
|
+
case "string":
|
|
3100
|
+
return normalizeStringSchema(normalizedSchema);
|
|
3101
|
+
case "number":
|
|
3102
|
+
case "integer":
|
|
3103
|
+
return normalizeNumberSchema(normalizedSchema);
|
|
3104
|
+
case "boolean":
|
|
3105
|
+
return { type: "boolean" };
|
|
3106
|
+
case "null":
|
|
3107
|
+
return { type: "null" };
|
|
3108
|
+
default:
|
|
3109
|
+
return normalizedSchema;
|
|
3110
|
+
}
|
|
3111
|
+
}
|
|
3112
|
+
function determineSchemaType(schema) {
|
|
3113
|
+
if (schema.properties || schema.required || schema.additionalProperties !== void 0) {
|
|
3114
|
+
return "object";
|
|
3115
|
+
}
|
|
3116
|
+
if (schema.items) {
|
|
3117
|
+
return "array";
|
|
3118
|
+
}
|
|
3119
|
+
if (schema.enum !== void 0) {
|
|
3120
|
+
if (schema.enum.length === 0) return "string";
|
|
3121
|
+
const firstItem = schema.enum[0];
|
|
3122
|
+
if (typeof firstItem === "string") return "string";
|
|
3123
|
+
if (typeof firstItem === "number") return "number";
|
|
3124
|
+
if (typeof firstItem === "boolean") return "boolean";
|
|
3125
|
+
return "string";
|
|
3126
|
+
}
|
|
3127
|
+
if (schema.minLength !== void 0 || schema.maxLength !== void 0 || schema.pattern) {
|
|
3128
|
+
return "string";
|
|
3129
|
+
}
|
|
3130
|
+
if (schema.minimum !== void 0 || schema.maximum !== void 0 || schema.exclusiveMinimum !== void 0 || schema.exclusiveMaximum !== void 0) {
|
|
3131
|
+
return schema.multipleOf === void 0 || schema.multipleOf % 1 === 0 ? "integer" : "number";
|
|
3132
|
+
}
|
|
3133
|
+
return "object";
|
|
3134
|
+
}
|
|
3135
|
+
function normalizeObjectSchema(schema) {
|
|
3136
|
+
const normalizedSchema = {
|
|
3137
|
+
type: "object",
|
|
3138
|
+
properties: {}
|
|
3139
|
+
};
|
|
3140
|
+
if (schema.properties) {
|
|
3141
|
+
normalizedSchema.properties = {};
|
|
3142
|
+
for (const [key, value] of Object.entries(schema.properties)) {
|
|
3143
|
+
normalizedSchema.properties[key] = normalizeJsonSchema(
|
|
3144
|
+
value
|
|
3145
|
+
);
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
if (schema.required) normalizedSchema.required = schema.required;
|
|
3149
|
+
if (schema.additionalProperties !== void 0)
|
|
3150
|
+
normalizedSchema.additionalProperties = schema.additionalProperties;
|
|
3151
|
+
if (schema.title) normalizedSchema.title = schema.title;
|
|
3152
|
+
if (schema.description) normalizedSchema.description = schema.description;
|
|
3153
|
+
return normalizedSchema;
|
|
3154
|
+
}
|
|
3155
|
+
function normalizeArraySchema(schema) {
|
|
3156
|
+
const normalizedSchema = {
|
|
3157
|
+
type: "array"
|
|
3158
|
+
};
|
|
3159
|
+
if (schema.items) {
|
|
3160
|
+
normalizedSchema.items = normalizeJsonSchema(
|
|
3161
|
+
schema.items
|
|
3162
|
+
);
|
|
3163
|
+
}
|
|
3164
|
+
if (schema.minItems !== void 0)
|
|
3165
|
+
normalizedSchema.minItems = schema.minItems;
|
|
3166
|
+
if (schema.maxItems !== void 0)
|
|
3167
|
+
normalizedSchema.maxItems = schema.maxItems;
|
|
3168
|
+
if (schema.uniqueItems !== void 0)
|
|
3169
|
+
normalizedSchema.uniqueItems = schema.uniqueItems;
|
|
3170
|
+
if (schema.title) normalizedSchema.title = schema.title;
|
|
3171
|
+
if (schema.description) normalizedSchema.description = schema.description;
|
|
3172
|
+
return normalizedSchema;
|
|
3173
|
+
}
|
|
3174
|
+
function normalizeStringSchema(schema) {
|
|
3175
|
+
const normalizedSchema = {
|
|
3176
|
+
type: "string"
|
|
3177
|
+
};
|
|
3178
|
+
if (schema.minLength !== void 0)
|
|
3179
|
+
normalizedSchema.minLength = schema.minLength;
|
|
3180
|
+
if (schema.maxLength !== void 0)
|
|
3181
|
+
normalizedSchema.maxLength = schema.maxLength;
|
|
3182
|
+
if (schema.pattern) normalizedSchema.pattern = schema.pattern;
|
|
3183
|
+
if (schema.format) normalizedSchema.format = schema.format;
|
|
3184
|
+
if (schema.enum) normalizedSchema.enum = schema.enum;
|
|
3185
|
+
if (schema.title) normalizedSchema.title = schema.title;
|
|
3186
|
+
if (schema.description) normalizedSchema.description = schema.description;
|
|
3187
|
+
return normalizedSchema;
|
|
3188
|
+
}
|
|
3189
|
+
function normalizeNumberSchema(schema) {
|
|
3190
|
+
const normalizedSchema = {
|
|
3191
|
+
type: schema.type
|
|
3192
|
+
};
|
|
3193
|
+
if (schema.minimum !== void 0) normalizedSchema.minimum = schema.minimum;
|
|
3194
|
+
if (schema.maximum !== void 0) normalizedSchema.maximum = schema.maximum;
|
|
3195
|
+
if (schema.exclusiveMinimum !== void 0)
|
|
3196
|
+
normalizedSchema.exclusiveMinimum = schema.exclusiveMinimum;
|
|
3197
|
+
if (schema.exclusiveMaximum !== void 0)
|
|
3198
|
+
normalizedSchema.exclusiveMaximum = schema.exclusiveMaximum;
|
|
3199
|
+
if (schema.multipleOf !== void 0)
|
|
3200
|
+
normalizedSchema.multipleOf = schema.multipleOf;
|
|
3201
|
+
if (schema.enum) normalizedSchema.enum = schema.enum;
|
|
3202
|
+
if (schema.title) normalizedSchema.title = schema.title;
|
|
3203
|
+
if (schema.description) normalizedSchema.description = schema.description;
|
|
3204
|
+
return normalizedSchema;
|
|
3205
|
+
}
|
|
3206
|
+
function mcpSchemaToParameters(mcpTool) {
|
|
3207
|
+
let schema;
|
|
3208
|
+
if (mcpTool.inputSchema) {
|
|
3209
|
+
schema = mcpTool.inputSchema;
|
|
3210
|
+
} else if (mcpTool.parameters) {
|
|
3211
|
+
schema = mcpTool.parameters;
|
|
3212
|
+
}
|
|
3213
|
+
if (!schema) {
|
|
3214
|
+
return {
|
|
3215
|
+
type: "object",
|
|
3216
|
+
properties: {}
|
|
3217
|
+
};
|
|
3218
|
+
}
|
|
3219
|
+
return normalizeJsonSchema(schema);
|
|
3220
|
+
}
|
|
3221
|
+
|
|
3222
|
+
// src/tools/mcp/create-tool.ts
|
|
3223
|
+
async function createTool(mcpTool, client) {
|
|
3224
|
+
try {
|
|
3225
|
+
return new McpToolAdapter(mcpTool, client);
|
|
3226
|
+
} catch (error) {
|
|
3227
|
+
if (!(error instanceof McpError)) {
|
|
3228
|
+
throw new McpError(
|
|
3229
|
+
`Failed to create tool from MCP tool: ${error instanceof Error ? error.message : String(error)}`,
|
|
3230
|
+
"invalid_schema_error" /* INVALID_SCHEMA_ERROR */,
|
|
3231
|
+
error instanceof Error ? error : void 0
|
|
3232
|
+
);
|
|
3233
|
+
}
|
|
3234
|
+
throw error;
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
var McpToolAdapter = class extends BaseTool {
|
|
3238
|
+
constructor(mcpTool, client) {
|
|
3239
|
+
const metadata = mcpTool.metadata || {};
|
|
3240
|
+
super({
|
|
3241
|
+
name: mcpTool.name || `mcp_${Date.now()}`,
|
|
3242
|
+
description: mcpTool.description || "MCP Tool",
|
|
3243
|
+
isLongRunning: metadata.isLongRunning ?? false,
|
|
3244
|
+
shouldRetryOnFailure: metadata.shouldRetryOnFailure ?? false,
|
|
3245
|
+
maxRetryAttempts: metadata.maxRetryAttempts ?? 3
|
|
3246
|
+
});
|
|
3247
|
+
this.clientService = null;
|
|
3248
|
+
this.mcpTool = mcpTool;
|
|
3249
|
+
this.client = client;
|
|
3250
|
+
if (client.reinitialize && typeof client.reinitialize === "function") {
|
|
3251
|
+
this.clientService = client;
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
getDeclaration() {
|
|
3255
|
+
try {
|
|
3256
|
+
const parameters = mcpSchemaToParameters(this.mcpTool);
|
|
3257
|
+
return {
|
|
3258
|
+
name: this.name,
|
|
3259
|
+
description: this.description,
|
|
3260
|
+
parameters
|
|
3261
|
+
};
|
|
3262
|
+
} catch (error) {
|
|
3263
|
+
throw new McpError(
|
|
3264
|
+
`Failed to convert schema for tool ${this.name}: ${error instanceof Error ? error.message : String(error)}`,
|
|
3265
|
+
"invalid_schema_error" /* INVALID_SCHEMA_ERROR */,
|
|
3266
|
+
error instanceof Error ? error : void 0
|
|
3267
|
+
);
|
|
3268
|
+
}
|
|
3269
|
+
}
|
|
3270
|
+
async runAsync(args, _context) {
|
|
3271
|
+
if (process.env.DEBUG === "true") {
|
|
3272
|
+
console.log(`Executing MCP tool ${this.name} with args:`, args);
|
|
3273
|
+
}
|
|
3274
|
+
try {
|
|
3275
|
+
if (typeof this.mcpTool.execute === "function") {
|
|
3276
|
+
return await this.mcpTool.execute(args);
|
|
3277
|
+
}
|
|
3278
|
+
if (this.clientService) {
|
|
3279
|
+
return await this.clientService.callTool(this.name, args);
|
|
3280
|
+
}
|
|
3281
|
+
if (this.client && typeof this.client.callTool === "function") {
|
|
3282
|
+
if (this.shouldRetryOnFailure) {
|
|
3283
|
+
const executeWithRetry = withRetry(
|
|
3284
|
+
async () => {
|
|
3285
|
+
return await this.client.callTool({
|
|
3286
|
+
name: this.name,
|
|
3287
|
+
arguments: args
|
|
3288
|
+
});
|
|
3289
|
+
},
|
|
3290
|
+
this,
|
|
3291
|
+
async () => {
|
|
3292
|
+
console.warn(
|
|
3293
|
+
`MCP tool ${this.name} encountered a closed resource, but cannot reinitialize client.`
|
|
3294
|
+
);
|
|
3295
|
+
},
|
|
3296
|
+
this.maxRetryAttempts
|
|
3297
|
+
);
|
|
3298
|
+
return await executeWithRetry();
|
|
3299
|
+
}
|
|
3300
|
+
const result = await this.client.callTool({
|
|
3301
|
+
name: this.name,
|
|
3302
|
+
arguments: args
|
|
3303
|
+
});
|
|
3304
|
+
return result;
|
|
3305
|
+
}
|
|
3306
|
+
throw new McpError(
|
|
3307
|
+
`Cannot execute MCP tool ${this.name}: No execution method found`,
|
|
3308
|
+
"tool_execution_error" /* TOOL_EXECUTION_ERROR */
|
|
3309
|
+
);
|
|
3310
|
+
} catch (error) {
|
|
3311
|
+
if (!(error instanceof McpError)) {
|
|
3312
|
+
console.error(`Error executing MCP tool ${this.name}:`, error);
|
|
3313
|
+
throw new McpError(
|
|
3314
|
+
`Error executing MCP tool ${this.name}: ${error instanceof Error ? error.message : String(error)}`,
|
|
3315
|
+
"tool_execution_error" /* TOOL_EXECUTION_ERROR */,
|
|
3316
|
+
error instanceof Error ? error : void 0
|
|
3317
|
+
);
|
|
3318
|
+
}
|
|
3319
|
+
throw error;
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3322
|
+
};
|
|
3323
|
+
|
|
3324
|
+
// src/tools/mcp/index.ts
|
|
3325
|
+
var McpToolset = class {
|
|
3326
|
+
constructor(config, toolFilter = null) {
|
|
3327
|
+
this.clientService = null;
|
|
3328
|
+
this.toolFilter = null;
|
|
3329
|
+
this.tools = [];
|
|
3330
|
+
this.isClosing = false;
|
|
3331
|
+
this.config = config;
|
|
3332
|
+
this.toolFilter = toolFilter;
|
|
3333
|
+
this.clientService = new McpClientService(config);
|
|
3334
|
+
}
|
|
3335
|
+
/**
|
|
3336
|
+
* Checks if a tool should be included based on the tool filter.
|
|
3337
|
+
* Similar to Python's _is_selected method.
|
|
3338
|
+
*/
|
|
3339
|
+
isSelected(tool, context) {
|
|
3340
|
+
if (!this.toolFilter) {
|
|
3341
|
+
return true;
|
|
3342
|
+
}
|
|
3343
|
+
if (typeof this.toolFilter === "function") {
|
|
3344
|
+
return this.toolFilter(tool, context);
|
|
3345
|
+
}
|
|
3346
|
+
if (Array.isArray(this.toolFilter)) {
|
|
3347
|
+
return this.toolFilter.includes(tool.name);
|
|
3348
|
+
}
|
|
3349
|
+
return true;
|
|
3350
|
+
}
|
|
3351
|
+
/**
|
|
3352
|
+
* Initializes the client service and establishes a connection.
|
|
3353
|
+
*/
|
|
3354
|
+
async initialize() {
|
|
3355
|
+
if (this.isClosing) {
|
|
3356
|
+
throw new McpError(
|
|
3357
|
+
"Cannot initialize a toolset that is being closed",
|
|
3358
|
+
"resource_closed_error" /* RESOURCE_CLOSED_ERROR */
|
|
3359
|
+
);
|
|
3360
|
+
}
|
|
3361
|
+
if (!this.clientService) {
|
|
3362
|
+
this.clientService = new McpClientService(this.config);
|
|
3363
|
+
}
|
|
3364
|
+
await this.clientService.initialize();
|
|
3365
|
+
return this.clientService;
|
|
3366
|
+
}
|
|
3367
|
+
/**
|
|
3368
|
+
* Retrieves tools from the MCP server and converts them to BaseTool instances.
|
|
3369
|
+
* Similar to Python's get_tools method.
|
|
3370
|
+
*/
|
|
3371
|
+
async getTools(context) {
|
|
3372
|
+
try {
|
|
3373
|
+
if (this.isClosing) {
|
|
3374
|
+
throw new McpError(
|
|
3375
|
+
"Cannot get tools from a toolset that is being closed",
|
|
3376
|
+
"resource_closed_error" /* RESOURCE_CLOSED_ERROR */
|
|
3377
|
+
);
|
|
3378
|
+
}
|
|
3379
|
+
if (this.tools.length > 0 && !this.config.cacheConfig?.enabled === false) {
|
|
3380
|
+
return this.tools;
|
|
3381
|
+
}
|
|
3382
|
+
if (!this.clientService) {
|
|
3383
|
+
await this.initialize();
|
|
3384
|
+
}
|
|
3385
|
+
const client = await this.clientService.initialize();
|
|
3386
|
+
const toolsResponse = await client.listTools();
|
|
3387
|
+
if (!toolsResponse.tools || !Array.isArray(toolsResponse.tools)) {
|
|
3388
|
+
console.warn("MCP server returned no tools or invalid tools array");
|
|
3389
|
+
return [];
|
|
3390
|
+
}
|
|
3391
|
+
const tools = [];
|
|
3392
|
+
for (const mcpTool of toolsResponse.tools) {
|
|
3393
|
+
if (this.isSelected(mcpTool, context)) {
|
|
3394
|
+
try {
|
|
3395
|
+
const tool = await createTool(mcpTool, client);
|
|
3396
|
+
tools.push(tool);
|
|
3397
|
+
} catch (toolError) {
|
|
3398
|
+
console.error(
|
|
3399
|
+
`Failed to create tool from MCP tool "${mcpTool.name}":`,
|
|
3400
|
+
toolError
|
|
3401
|
+
);
|
|
3402
|
+
}
|
|
3403
|
+
}
|
|
3404
|
+
}
|
|
3405
|
+
if (this.config.cacheConfig?.enabled !== false) {
|
|
3406
|
+
this.tools = tools;
|
|
3407
|
+
}
|
|
3408
|
+
return tools;
|
|
3409
|
+
} catch (error) {
|
|
3410
|
+
if (!(error instanceof McpError)) {
|
|
3411
|
+
console.error("Error retrieving MCP tools:", error);
|
|
3412
|
+
throw new McpError(
|
|
3413
|
+
`Error retrieving MCP tools: ${error instanceof Error ? error.message : String(error)}`,
|
|
3414
|
+
"connection_error" /* CONNECTION_ERROR */,
|
|
3415
|
+
error instanceof Error ? error : void 0
|
|
3416
|
+
);
|
|
3417
|
+
}
|
|
3418
|
+
throw error;
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
/**
|
|
3422
|
+
* Converts ADK tools to MCP tool format for bidirectional support
|
|
3423
|
+
*/
|
|
3424
|
+
convertADKToolsToMCP(tools) {
|
|
3425
|
+
return tools.map((tool) => adkToMcpToolType(tool));
|
|
3426
|
+
}
|
|
3427
|
+
/**
|
|
3428
|
+
* Refreshes the tool cache by clearing it and fetching tools again
|
|
3429
|
+
*/
|
|
3430
|
+
async refreshTools(context) {
|
|
3431
|
+
this.tools = [];
|
|
3432
|
+
return this.getTools(context);
|
|
3433
|
+
}
|
|
3434
|
+
/**
|
|
3435
|
+
* Closes the connection to the MCP server.
|
|
3436
|
+
* Similar to Python's close method.
|
|
3437
|
+
*/
|
|
3438
|
+
async close() {
|
|
3439
|
+
if (this.isClosing) {
|
|
3440
|
+
return;
|
|
3441
|
+
}
|
|
3442
|
+
try {
|
|
3443
|
+
this.isClosing = true;
|
|
3444
|
+
if (this.clientService) {
|
|
3445
|
+
await this.clientService.close();
|
|
3446
|
+
this.clientService = null;
|
|
3447
|
+
}
|
|
3448
|
+
this.tools = [];
|
|
3449
|
+
if (this.config.debug) {
|
|
3450
|
+
console.log("\u2705 MCP toolset closed successfully");
|
|
3451
|
+
}
|
|
3452
|
+
} catch (error) {
|
|
3453
|
+
console.error("Error closing MCP toolset:", error);
|
|
3454
|
+
} finally {
|
|
3455
|
+
this.isClosing = false;
|
|
3456
|
+
}
|
|
3457
|
+
}
|
|
3458
|
+
/**
|
|
3459
|
+
* Disposes of all resources. This method should be called when the toolset is no longer needed.
|
|
3460
|
+
* Provides alignment with disposal patterns common in TypeScript.
|
|
3461
|
+
*/
|
|
3462
|
+
async dispose() {
|
|
3463
|
+
await this.close();
|
|
3464
|
+
}
|
|
3465
|
+
};
|
|
3466
|
+
async function getMcpTools(config, toolFilter) {
|
|
3467
|
+
const toolset = new McpToolset(config, toolFilter);
|
|
3468
|
+
try {
|
|
3469
|
+
return await toolset.getTools();
|
|
3470
|
+
} finally {
|
|
3471
|
+
await toolset.close().catch((err) => console.error("Error closing toolset:", err));
|
|
3472
|
+
}
|
|
3473
|
+
}
|
|
3474
|
+
|
|
2771
3475
|
// src/models/index.ts
|
|
2772
3476
|
var models_exports = {};
|
|
2773
3477
|
__export(models_exports, {
|
|
@@ -5690,6 +6394,9 @@ export {
|
|
|
5690
6394
|
LangGraphAgent,
|
|
5691
6395
|
LoadMemoryTool,
|
|
5692
6396
|
LoopAgent,
|
|
6397
|
+
McpError,
|
|
6398
|
+
McpErrorType,
|
|
6399
|
+
McpToolset,
|
|
5693
6400
|
memory_exports as Memory,
|
|
5694
6401
|
models_exports as Models,
|
|
5695
6402
|
OAuth2Credential,
|
|
@@ -5712,10 +6419,15 @@ export {
|
|
|
5712
6419
|
TransferToAgentTool,
|
|
5713
6420
|
UserInteractionTool,
|
|
5714
6421
|
VERSION,
|
|
6422
|
+
adkToMcpToolType,
|
|
5715
6423
|
buildFunctionDeclaration,
|
|
5716
6424
|
cloneSession,
|
|
5717
6425
|
createFunctionTool,
|
|
5718
6426
|
generateSessionId,
|
|
6427
|
+
getMcpTools,
|
|
6428
|
+
jsonSchemaToDeclaration,
|
|
6429
|
+
mcpSchemaToParameters,
|
|
6430
|
+
normalizeJsonSchema,
|
|
5719
6431
|
registerProviders,
|
|
5720
6432
|
validateSession
|
|
5721
6433
|
};
|