@ivotoby/openapi-mcp-server 1.8.0 → 1.8.2
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/bundle.js +264 -6
- package/dist/cli.js +264 -6
- package/package.json +1 -1
package/dist/bundle.js
CHANGED
|
@@ -14989,6 +14989,19 @@ var ToolsManager = class {
|
|
|
14989
14989
|
}
|
|
14990
14990
|
tools = /* @__PURE__ */ new Map();
|
|
14991
14991
|
specLoader;
|
|
14992
|
+
loadedSpec;
|
|
14993
|
+
/**
|
|
14994
|
+
* Get the OpenAPI spec loader instance
|
|
14995
|
+
*/
|
|
14996
|
+
getSpecLoader() {
|
|
14997
|
+
return this.specLoader;
|
|
14998
|
+
}
|
|
14999
|
+
/**
|
|
15000
|
+
* Get the loaded OpenAPI specification
|
|
15001
|
+
*/
|
|
15002
|
+
getOpenApiSpec() {
|
|
15003
|
+
return this.loadedSpec;
|
|
15004
|
+
}
|
|
14992
15005
|
/**
|
|
14993
15006
|
* Create dynamic discovery meta-tools
|
|
14994
15007
|
*/
|
|
@@ -15016,7 +15029,12 @@ var ToolsManager = class {
|
|
|
15016
15029
|
inputSchema: {
|
|
15017
15030
|
type: "object",
|
|
15018
15031
|
properties: {
|
|
15019
|
-
endpoint: { type: "string", description: "Endpoint path to invoke" },
|
|
15032
|
+
endpoint: { type: "string", description: "Endpoint path to invoke (e.g. /users/{id})" },
|
|
15033
|
+
method: {
|
|
15034
|
+
type: "string",
|
|
15035
|
+
description: "HTTP method to use (optional, e.g. GET, POST, PUT, DELETE)",
|
|
15036
|
+
enum: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"]
|
|
15037
|
+
},
|
|
15020
15038
|
params: {
|
|
15021
15039
|
type: "object",
|
|
15022
15040
|
description: "Parameters for the API call",
|
|
@@ -15037,6 +15055,7 @@ var ToolsManager = class {
|
|
|
15037
15055
|
this.config.specInputMethod,
|
|
15038
15056
|
this.config.inlineSpecContent
|
|
15039
15057
|
);
|
|
15058
|
+
this.loadedSpec = spec;
|
|
15040
15059
|
if (this.config.toolsMode === "dynamic") {
|
|
15041
15060
|
this.tools = this.createDynamicTools();
|
|
15042
15061
|
return;
|
|
@@ -18472,18 +18491,39 @@ var StaticAuthProvider = class {
|
|
|
18472
18491
|
}
|
|
18473
18492
|
};
|
|
18474
18493
|
|
|
18494
|
+
// src/utils/http-methods.ts
|
|
18495
|
+
var VALID_HTTP_METHODS = [
|
|
18496
|
+
"get",
|
|
18497
|
+
"post",
|
|
18498
|
+
"put",
|
|
18499
|
+
"patch",
|
|
18500
|
+
"delete",
|
|
18501
|
+
"options",
|
|
18502
|
+
"head"
|
|
18503
|
+
];
|
|
18504
|
+
var GET_LIKE_METHODS = ["get", "delete", "head", "options"];
|
|
18505
|
+
function isValidHttpMethod(method) {
|
|
18506
|
+
return VALID_HTTP_METHODS.includes(method.toLowerCase());
|
|
18507
|
+
}
|
|
18508
|
+
function isGetLikeMethod(method) {
|
|
18509
|
+
return GET_LIKE_METHODS.includes(method.toLowerCase());
|
|
18510
|
+
}
|
|
18511
|
+
|
|
18475
18512
|
// src/api-client.ts
|
|
18476
18513
|
var ApiClient = class {
|
|
18477
18514
|
axiosInstance;
|
|
18478
18515
|
toolsMap = /* @__PURE__ */ new Map();
|
|
18479
18516
|
authProvider;
|
|
18517
|
+
specLoader;
|
|
18518
|
+
openApiSpec;
|
|
18480
18519
|
/**
|
|
18481
18520
|
* Create a new API client
|
|
18482
18521
|
*
|
|
18483
18522
|
* @param baseUrl - Base URL for the API
|
|
18484
18523
|
* @param authProviderOrHeaders - AuthProvider instance or static headers for backward compatibility
|
|
18524
|
+
* @param specLoader - Optional OpenAPI spec loader for dynamic meta-tools
|
|
18485
18525
|
*/
|
|
18486
|
-
constructor(baseUrl, authProviderOrHeaders) {
|
|
18526
|
+
constructor(baseUrl, authProviderOrHeaders, specLoader) {
|
|
18487
18527
|
this.axiosInstance = axios_default.create({
|
|
18488
18528
|
baseURL: baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`
|
|
18489
18529
|
});
|
|
@@ -18494,6 +18534,7 @@ var ApiClient = class {
|
|
|
18494
18534
|
} else {
|
|
18495
18535
|
this.authProvider = authProviderOrHeaders;
|
|
18496
18536
|
}
|
|
18537
|
+
this.specLoader = specLoader;
|
|
18497
18538
|
}
|
|
18498
18539
|
/**
|
|
18499
18540
|
* Set the available tools for the client
|
|
@@ -18503,6 +18544,14 @@ var ApiClient = class {
|
|
|
18503
18544
|
setTools(tools) {
|
|
18504
18545
|
this.toolsMap = tools;
|
|
18505
18546
|
}
|
|
18547
|
+
/**
|
|
18548
|
+
* Set the OpenAPI specification for dynamic meta-tools
|
|
18549
|
+
*
|
|
18550
|
+
* @param spec - The OpenAPI specification document
|
|
18551
|
+
*/
|
|
18552
|
+
setOpenApiSpec(spec) {
|
|
18553
|
+
this.openApiSpec = spec;
|
|
18554
|
+
}
|
|
18506
18555
|
/**
|
|
18507
18556
|
* Get a tool definition by ID
|
|
18508
18557
|
*
|
|
@@ -18532,6 +18581,15 @@ var ApiClient = class {
|
|
|
18532
18581
|
*/
|
|
18533
18582
|
async executeApiCallWithRetry(toolId, params, isRetry) {
|
|
18534
18583
|
try {
|
|
18584
|
+
if (toolId === "LIST-API-ENDPOINTS") {
|
|
18585
|
+
return await this.handleListApiEndpoints();
|
|
18586
|
+
}
|
|
18587
|
+
if (toolId === "GET-API-ENDPOINT-SCHEMA") {
|
|
18588
|
+
return this.handleGetApiEndpointSchema(toolId, params);
|
|
18589
|
+
}
|
|
18590
|
+
if (toolId === "INVOKE-API-ENDPOINT") {
|
|
18591
|
+
return this.handleInvokeApiEndpoint(toolId, params);
|
|
18592
|
+
}
|
|
18535
18593
|
const { method, path } = this.parseToolId(toolId);
|
|
18536
18594
|
const toolDef = this.getToolDefinition(toolId);
|
|
18537
18595
|
const paramsCopy = { ...params };
|
|
@@ -18581,7 +18639,7 @@ var ApiClient = class {
|
|
|
18581
18639
|
url: resolvedPath,
|
|
18582
18640
|
headers: authHeaders
|
|
18583
18641
|
};
|
|
18584
|
-
if (
|
|
18642
|
+
if (isGetLikeMethod(method)) {
|
|
18585
18643
|
config.params = this.processQueryParams(paramsCopy);
|
|
18586
18644
|
} else {
|
|
18587
18645
|
config.data = paramsCopy;
|
|
@@ -18631,6 +18689,194 @@ var ApiClient = class {
|
|
|
18631
18689
|
}
|
|
18632
18690
|
return result;
|
|
18633
18691
|
}
|
|
18692
|
+
/**
|
|
18693
|
+
* Handle the LIST-API-ENDPOINTS meta-tool
|
|
18694
|
+
* Returns a list of all available API endpoints from the loaded tools
|
|
18695
|
+
*/
|
|
18696
|
+
async handleListApiEndpoints() {
|
|
18697
|
+
const endpoints = [];
|
|
18698
|
+
if (this.openApiSpec) {
|
|
18699
|
+
for (const [path, pathItem] of Object.entries(this.openApiSpec.paths)) {
|
|
18700
|
+
if (!pathItem) continue;
|
|
18701
|
+
for (const [method, operation] of Object.entries(pathItem)) {
|
|
18702
|
+
if (method === "parameters" || !operation) continue;
|
|
18703
|
+
if (!isValidHttpMethod(method)) {
|
|
18704
|
+
continue;
|
|
18705
|
+
}
|
|
18706
|
+
const op = operation;
|
|
18707
|
+
endpoints.push({
|
|
18708
|
+
method: method.toUpperCase(),
|
|
18709
|
+
path,
|
|
18710
|
+
summary: op.summary || "",
|
|
18711
|
+
description: op.description || "",
|
|
18712
|
+
operationId: op.operationId || "",
|
|
18713
|
+
tags: op.tags || []
|
|
18714
|
+
});
|
|
18715
|
+
}
|
|
18716
|
+
}
|
|
18717
|
+
} else {
|
|
18718
|
+
for (const [toolId, tool] of this.toolsMap.entries()) {
|
|
18719
|
+
if (toolId.startsWith("LIST-API-ENDPOINTS") || toolId.startsWith("GET-API-ENDPOINT-SCHEMA") || toolId.startsWith("INVOKE-API-ENDPOINT")) {
|
|
18720
|
+
continue;
|
|
18721
|
+
}
|
|
18722
|
+
try {
|
|
18723
|
+
const { method, path } = this.parseToolId(toolId);
|
|
18724
|
+
endpoints.push({
|
|
18725
|
+
toolId,
|
|
18726
|
+
name: tool.name,
|
|
18727
|
+
description: tool.description,
|
|
18728
|
+
method: method.toUpperCase(),
|
|
18729
|
+
path
|
|
18730
|
+
});
|
|
18731
|
+
} catch (error) {
|
|
18732
|
+
continue;
|
|
18733
|
+
}
|
|
18734
|
+
}
|
|
18735
|
+
}
|
|
18736
|
+
return {
|
|
18737
|
+
endpoints,
|
|
18738
|
+
total: endpoints.length,
|
|
18739
|
+
note: this.openApiSpec ? "Use INVOKE-API-ENDPOINT to call specific endpoints with the path parameter" : "Limited endpoint information - OpenAPI spec not available"
|
|
18740
|
+
};
|
|
18741
|
+
}
|
|
18742
|
+
/**
|
|
18743
|
+
* Handle the GET-API-ENDPOINT-SCHEMA meta-tool
|
|
18744
|
+
* Returns the JSON schema for a specified API endpoint
|
|
18745
|
+
*/
|
|
18746
|
+
handleGetApiEndpointSchema(toolId, params) {
|
|
18747
|
+
const { endpoint } = params;
|
|
18748
|
+
if (!endpoint) {
|
|
18749
|
+
throw new Error(`Missing required parameter 'endpoint' for tool '${toolId}'`);
|
|
18750
|
+
}
|
|
18751
|
+
if (this.openApiSpec) {
|
|
18752
|
+
const pathItem = this.openApiSpec.paths[endpoint];
|
|
18753
|
+
if (!pathItem) {
|
|
18754
|
+
throw new Error(`No endpoint found for path '${endpoint}' in tool '${toolId}'`);
|
|
18755
|
+
}
|
|
18756
|
+
const operations = [];
|
|
18757
|
+
for (const [method, operation] of Object.entries(pathItem)) {
|
|
18758
|
+
if (method === "parameters" || !operation) continue;
|
|
18759
|
+
if (!isValidHttpMethod(method)) {
|
|
18760
|
+
continue;
|
|
18761
|
+
}
|
|
18762
|
+
const op = operation;
|
|
18763
|
+
operations.push({
|
|
18764
|
+
method: method.toUpperCase(),
|
|
18765
|
+
operationId: op.operationId || "",
|
|
18766
|
+
summary: op.summary || "",
|
|
18767
|
+
description: op.description || "",
|
|
18768
|
+
parameters: op.parameters || [],
|
|
18769
|
+
requestBody: op.requestBody || null,
|
|
18770
|
+
responses: op.responses || {},
|
|
18771
|
+
tags: op.tags || []
|
|
18772
|
+
});
|
|
18773
|
+
}
|
|
18774
|
+
if (operations.length === 0) {
|
|
18775
|
+
throw new Error(`No valid HTTP operations found for path '${endpoint}' in tool '${toolId}'`);
|
|
18776
|
+
}
|
|
18777
|
+
return {
|
|
18778
|
+
path: endpoint,
|
|
18779
|
+
operations,
|
|
18780
|
+
pathParameters: pathItem.parameters || []
|
|
18781
|
+
};
|
|
18782
|
+
} else {
|
|
18783
|
+
let matchingTool;
|
|
18784
|
+
let matchingToolId;
|
|
18785
|
+
for (const [toolId2, tool] of this.toolsMap.entries()) {
|
|
18786
|
+
try {
|
|
18787
|
+
const { path } = this.parseToolId(toolId2);
|
|
18788
|
+
if (path === endpoint) {
|
|
18789
|
+
matchingTool = tool;
|
|
18790
|
+
matchingToolId = toolId2;
|
|
18791
|
+
break;
|
|
18792
|
+
}
|
|
18793
|
+
} catch (error) {
|
|
18794
|
+
continue;
|
|
18795
|
+
}
|
|
18796
|
+
}
|
|
18797
|
+
if (!matchingTool || !matchingToolId) {
|
|
18798
|
+
throw new Error(`No endpoint found for path: ${endpoint}`);
|
|
18799
|
+
}
|
|
18800
|
+
return {
|
|
18801
|
+
toolId: matchingToolId,
|
|
18802
|
+
name: matchingTool.name,
|
|
18803
|
+
description: matchingTool.description,
|
|
18804
|
+
inputSchema: matchingTool.inputSchema,
|
|
18805
|
+
note: "Limited schema information - using tool definition instead of OpenAPI spec"
|
|
18806
|
+
};
|
|
18807
|
+
}
|
|
18808
|
+
}
|
|
18809
|
+
/**
|
|
18810
|
+
* Handle the INVOKE-API-ENDPOINT meta-tool
|
|
18811
|
+
* Dynamically invokes an API endpoint with the provided parameters
|
|
18812
|
+
*/
|
|
18813
|
+
async handleInvokeApiEndpoint(toolId, params) {
|
|
18814
|
+
const { endpoint, method, params: endpointParams = {} } = params;
|
|
18815
|
+
if (!endpoint) {
|
|
18816
|
+
throw new Error(`Missing required parameter 'endpoint' for tool '${toolId}'`);
|
|
18817
|
+
}
|
|
18818
|
+
if (method) {
|
|
18819
|
+
const toolId2 = generateToolId(method, endpoint);
|
|
18820
|
+
if (this.toolsMap.has(toolId2)) {
|
|
18821
|
+
return this.executeApiCall(toolId2, endpointParams);
|
|
18822
|
+
} else if (this.openApiSpec) {
|
|
18823
|
+
const pathItem = this.openApiSpec.paths[endpoint];
|
|
18824
|
+
if (pathItem && pathItem[method.toLowerCase()]) {
|
|
18825
|
+
const { method: httpMethod, path } = { method: method.toUpperCase(), path: endpoint };
|
|
18826
|
+
return this.makeDirectHttpRequest(httpMethod, path, endpointParams);
|
|
18827
|
+
} else {
|
|
18828
|
+
throw new Error(
|
|
18829
|
+
`No endpoint found for path '${endpoint}' with method '${method}' in tool '${toolId2}'`
|
|
18830
|
+
);
|
|
18831
|
+
}
|
|
18832
|
+
} else {
|
|
18833
|
+
throw new Error(`Tool not found: ${toolId2}`);
|
|
18834
|
+
}
|
|
18835
|
+
}
|
|
18836
|
+
if (this.openApiSpec) {
|
|
18837
|
+
const pathItem = this.openApiSpec.paths[endpoint];
|
|
18838
|
+
if (pathItem) {
|
|
18839
|
+
for (const method2 of VALID_HTTP_METHODS) {
|
|
18840
|
+
if (pathItem[method2]) {
|
|
18841
|
+
return this.makeDirectHttpRequest(method2.toUpperCase(), endpoint, endpointParams);
|
|
18842
|
+
}
|
|
18843
|
+
}
|
|
18844
|
+
throw new Error(`No HTTP operations found for endpoint '${endpoint}' in tool '${toolId}'`);
|
|
18845
|
+
} else {
|
|
18846
|
+
throw new Error(`No endpoint found for path '${endpoint}' in tool '${toolId}'`);
|
|
18847
|
+
}
|
|
18848
|
+
}
|
|
18849
|
+
throw new Error(`No endpoint found for path '${endpoint}' in tool '${toolId}'`);
|
|
18850
|
+
}
|
|
18851
|
+
/**
|
|
18852
|
+
* Make a direct HTTP request without going through the tool system
|
|
18853
|
+
* Used by dynamic meta-tools when we have OpenAPI spec but no corresponding tool
|
|
18854
|
+
*/
|
|
18855
|
+
async makeDirectHttpRequest(method, path, params) {
|
|
18856
|
+
const authHeaders = await this.authProvider.getAuthHeaders();
|
|
18857
|
+
const config = {
|
|
18858
|
+
method: method.toLowerCase(),
|
|
18859
|
+
url: path,
|
|
18860
|
+
headers: authHeaders
|
|
18861
|
+
};
|
|
18862
|
+
if (isGetLikeMethod(method)) {
|
|
18863
|
+
config.params = this.processQueryParams(params);
|
|
18864
|
+
} else {
|
|
18865
|
+
config.data = params;
|
|
18866
|
+
}
|
|
18867
|
+
try {
|
|
18868
|
+
const response = await this.axiosInstance.request(config);
|
|
18869
|
+
return response.data;
|
|
18870
|
+
} catch (error) {
|
|
18871
|
+
if (axios_default.isAxiosError(error)) {
|
|
18872
|
+
const axiosError = error;
|
|
18873
|
+
throw new Error(
|
|
18874
|
+
`API request failed: ${axiosError.message}${axiosError.response ? ` (${axiosError.response.status}: ${typeof axiosError.response.data === "object" ? JSON.stringify(axiosError.response.data) : axiosError.response.data})` : ""}`
|
|
18875
|
+
);
|
|
18876
|
+
}
|
|
18877
|
+
throw error;
|
|
18878
|
+
}
|
|
18879
|
+
}
|
|
18634
18880
|
};
|
|
18635
18881
|
|
|
18636
18882
|
// src/server.ts
|
|
@@ -18652,7 +18898,11 @@ var OpenAPIServer = class {
|
|
|
18652
18898
|
);
|
|
18653
18899
|
this.toolsManager = new ToolsManager(config);
|
|
18654
18900
|
const authProviderOrHeaders = config.authProvider || new StaticAuthProvider(config.headers);
|
|
18655
|
-
this.apiClient = new ApiClient(
|
|
18901
|
+
this.apiClient = new ApiClient(
|
|
18902
|
+
config.apiBaseUrl,
|
|
18903
|
+
authProviderOrHeaders,
|
|
18904
|
+
this.toolsManager.getSpecLoader()
|
|
18905
|
+
);
|
|
18656
18906
|
this.initializeHandlers();
|
|
18657
18907
|
}
|
|
18658
18908
|
/**
|
|
@@ -18717,6 +18967,10 @@ var OpenAPIServer = class {
|
|
|
18717
18967
|
toolsMap.set(toolId, tool);
|
|
18718
18968
|
}
|
|
18719
18969
|
this.apiClient.setTools(toolsMap);
|
|
18970
|
+
const spec = this.toolsManager.getOpenApiSpec();
|
|
18971
|
+
if (spec) {
|
|
18972
|
+
this.apiClient.setOpenApiSpec(spec);
|
|
18973
|
+
}
|
|
18720
18974
|
await this.server.connect(transport);
|
|
18721
18975
|
}
|
|
18722
18976
|
};
|
|
@@ -23575,8 +23829,12 @@ function parseHeaders(headerStr) {
|
|
|
23575
23829
|
const headers = {};
|
|
23576
23830
|
if (headerStr) {
|
|
23577
23831
|
headerStr.split(",").forEach((header) => {
|
|
23578
|
-
const
|
|
23579
|
-
if (
|
|
23832
|
+
const colonIndex = header.indexOf(":");
|
|
23833
|
+
if (colonIndex > 0) {
|
|
23834
|
+
const key = header.substring(0, colonIndex).trim();
|
|
23835
|
+
const value = header.substring(colonIndex + 1).trim();
|
|
23836
|
+
if (key) headers[key] = value;
|
|
23837
|
+
}
|
|
23580
23838
|
});
|
|
23581
23839
|
}
|
|
23582
23840
|
return headers;
|
package/dist/cli.js
CHANGED
|
@@ -14989,6 +14989,19 @@ var ToolsManager = class {
|
|
|
14989
14989
|
}
|
|
14990
14990
|
tools = /* @__PURE__ */ new Map();
|
|
14991
14991
|
specLoader;
|
|
14992
|
+
loadedSpec;
|
|
14993
|
+
/**
|
|
14994
|
+
* Get the OpenAPI spec loader instance
|
|
14995
|
+
*/
|
|
14996
|
+
getSpecLoader() {
|
|
14997
|
+
return this.specLoader;
|
|
14998
|
+
}
|
|
14999
|
+
/**
|
|
15000
|
+
* Get the loaded OpenAPI specification
|
|
15001
|
+
*/
|
|
15002
|
+
getOpenApiSpec() {
|
|
15003
|
+
return this.loadedSpec;
|
|
15004
|
+
}
|
|
14992
15005
|
/**
|
|
14993
15006
|
* Create dynamic discovery meta-tools
|
|
14994
15007
|
*/
|
|
@@ -15016,7 +15029,12 @@ var ToolsManager = class {
|
|
|
15016
15029
|
inputSchema: {
|
|
15017
15030
|
type: "object",
|
|
15018
15031
|
properties: {
|
|
15019
|
-
endpoint: { type: "string", description: "Endpoint path to invoke" },
|
|
15032
|
+
endpoint: { type: "string", description: "Endpoint path to invoke (e.g. /users/{id})" },
|
|
15033
|
+
method: {
|
|
15034
|
+
type: "string",
|
|
15035
|
+
description: "HTTP method to use (optional, e.g. GET, POST, PUT, DELETE)",
|
|
15036
|
+
enum: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"]
|
|
15037
|
+
},
|
|
15020
15038
|
params: {
|
|
15021
15039
|
type: "object",
|
|
15022
15040
|
description: "Parameters for the API call",
|
|
@@ -15037,6 +15055,7 @@ var ToolsManager = class {
|
|
|
15037
15055
|
this.config.specInputMethod,
|
|
15038
15056
|
this.config.inlineSpecContent
|
|
15039
15057
|
);
|
|
15058
|
+
this.loadedSpec = spec;
|
|
15040
15059
|
if (this.config.toolsMode === "dynamic") {
|
|
15041
15060
|
this.tools = this.createDynamicTools();
|
|
15042
15061
|
return;
|
|
@@ -18472,18 +18491,39 @@ var StaticAuthProvider = class {
|
|
|
18472
18491
|
}
|
|
18473
18492
|
};
|
|
18474
18493
|
|
|
18494
|
+
// src/utils/http-methods.ts
|
|
18495
|
+
var VALID_HTTP_METHODS = [
|
|
18496
|
+
"get",
|
|
18497
|
+
"post",
|
|
18498
|
+
"put",
|
|
18499
|
+
"patch",
|
|
18500
|
+
"delete",
|
|
18501
|
+
"options",
|
|
18502
|
+
"head"
|
|
18503
|
+
];
|
|
18504
|
+
var GET_LIKE_METHODS = ["get", "delete", "head", "options"];
|
|
18505
|
+
function isValidHttpMethod(method) {
|
|
18506
|
+
return VALID_HTTP_METHODS.includes(method.toLowerCase());
|
|
18507
|
+
}
|
|
18508
|
+
function isGetLikeMethod(method) {
|
|
18509
|
+
return GET_LIKE_METHODS.includes(method.toLowerCase());
|
|
18510
|
+
}
|
|
18511
|
+
|
|
18475
18512
|
// src/api-client.ts
|
|
18476
18513
|
var ApiClient = class {
|
|
18477
18514
|
axiosInstance;
|
|
18478
18515
|
toolsMap = /* @__PURE__ */ new Map();
|
|
18479
18516
|
authProvider;
|
|
18517
|
+
specLoader;
|
|
18518
|
+
openApiSpec;
|
|
18480
18519
|
/**
|
|
18481
18520
|
* Create a new API client
|
|
18482
18521
|
*
|
|
18483
18522
|
* @param baseUrl - Base URL for the API
|
|
18484
18523
|
* @param authProviderOrHeaders - AuthProvider instance or static headers for backward compatibility
|
|
18524
|
+
* @param specLoader - Optional OpenAPI spec loader for dynamic meta-tools
|
|
18485
18525
|
*/
|
|
18486
|
-
constructor(baseUrl, authProviderOrHeaders) {
|
|
18526
|
+
constructor(baseUrl, authProviderOrHeaders, specLoader) {
|
|
18487
18527
|
this.axiosInstance = axios_default.create({
|
|
18488
18528
|
baseURL: baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`
|
|
18489
18529
|
});
|
|
@@ -18494,6 +18534,7 @@ var ApiClient = class {
|
|
|
18494
18534
|
} else {
|
|
18495
18535
|
this.authProvider = authProviderOrHeaders;
|
|
18496
18536
|
}
|
|
18537
|
+
this.specLoader = specLoader;
|
|
18497
18538
|
}
|
|
18498
18539
|
/**
|
|
18499
18540
|
* Set the available tools for the client
|
|
@@ -18503,6 +18544,14 @@ var ApiClient = class {
|
|
|
18503
18544
|
setTools(tools) {
|
|
18504
18545
|
this.toolsMap = tools;
|
|
18505
18546
|
}
|
|
18547
|
+
/**
|
|
18548
|
+
* Set the OpenAPI specification for dynamic meta-tools
|
|
18549
|
+
*
|
|
18550
|
+
* @param spec - The OpenAPI specification document
|
|
18551
|
+
*/
|
|
18552
|
+
setOpenApiSpec(spec) {
|
|
18553
|
+
this.openApiSpec = spec;
|
|
18554
|
+
}
|
|
18506
18555
|
/**
|
|
18507
18556
|
* Get a tool definition by ID
|
|
18508
18557
|
*
|
|
@@ -18532,6 +18581,15 @@ var ApiClient = class {
|
|
|
18532
18581
|
*/
|
|
18533
18582
|
async executeApiCallWithRetry(toolId, params, isRetry) {
|
|
18534
18583
|
try {
|
|
18584
|
+
if (toolId === "LIST-API-ENDPOINTS") {
|
|
18585
|
+
return await this.handleListApiEndpoints();
|
|
18586
|
+
}
|
|
18587
|
+
if (toolId === "GET-API-ENDPOINT-SCHEMA") {
|
|
18588
|
+
return this.handleGetApiEndpointSchema(toolId, params);
|
|
18589
|
+
}
|
|
18590
|
+
if (toolId === "INVOKE-API-ENDPOINT") {
|
|
18591
|
+
return this.handleInvokeApiEndpoint(toolId, params);
|
|
18592
|
+
}
|
|
18535
18593
|
const { method, path } = this.parseToolId(toolId);
|
|
18536
18594
|
const toolDef = this.getToolDefinition(toolId);
|
|
18537
18595
|
const paramsCopy = { ...params };
|
|
@@ -18581,7 +18639,7 @@ var ApiClient = class {
|
|
|
18581
18639
|
url: resolvedPath,
|
|
18582
18640
|
headers: authHeaders
|
|
18583
18641
|
};
|
|
18584
|
-
if (
|
|
18642
|
+
if (isGetLikeMethod(method)) {
|
|
18585
18643
|
config.params = this.processQueryParams(paramsCopy);
|
|
18586
18644
|
} else {
|
|
18587
18645
|
config.data = paramsCopy;
|
|
@@ -18631,6 +18689,194 @@ var ApiClient = class {
|
|
|
18631
18689
|
}
|
|
18632
18690
|
return result;
|
|
18633
18691
|
}
|
|
18692
|
+
/**
|
|
18693
|
+
* Handle the LIST-API-ENDPOINTS meta-tool
|
|
18694
|
+
* Returns a list of all available API endpoints from the loaded tools
|
|
18695
|
+
*/
|
|
18696
|
+
async handleListApiEndpoints() {
|
|
18697
|
+
const endpoints = [];
|
|
18698
|
+
if (this.openApiSpec) {
|
|
18699
|
+
for (const [path, pathItem] of Object.entries(this.openApiSpec.paths)) {
|
|
18700
|
+
if (!pathItem) continue;
|
|
18701
|
+
for (const [method, operation] of Object.entries(pathItem)) {
|
|
18702
|
+
if (method === "parameters" || !operation) continue;
|
|
18703
|
+
if (!isValidHttpMethod(method)) {
|
|
18704
|
+
continue;
|
|
18705
|
+
}
|
|
18706
|
+
const op = operation;
|
|
18707
|
+
endpoints.push({
|
|
18708
|
+
method: method.toUpperCase(),
|
|
18709
|
+
path,
|
|
18710
|
+
summary: op.summary || "",
|
|
18711
|
+
description: op.description || "",
|
|
18712
|
+
operationId: op.operationId || "",
|
|
18713
|
+
tags: op.tags || []
|
|
18714
|
+
});
|
|
18715
|
+
}
|
|
18716
|
+
}
|
|
18717
|
+
} else {
|
|
18718
|
+
for (const [toolId, tool] of this.toolsMap.entries()) {
|
|
18719
|
+
if (toolId.startsWith("LIST-API-ENDPOINTS") || toolId.startsWith("GET-API-ENDPOINT-SCHEMA") || toolId.startsWith("INVOKE-API-ENDPOINT")) {
|
|
18720
|
+
continue;
|
|
18721
|
+
}
|
|
18722
|
+
try {
|
|
18723
|
+
const { method, path } = this.parseToolId(toolId);
|
|
18724
|
+
endpoints.push({
|
|
18725
|
+
toolId,
|
|
18726
|
+
name: tool.name,
|
|
18727
|
+
description: tool.description,
|
|
18728
|
+
method: method.toUpperCase(),
|
|
18729
|
+
path
|
|
18730
|
+
});
|
|
18731
|
+
} catch (error) {
|
|
18732
|
+
continue;
|
|
18733
|
+
}
|
|
18734
|
+
}
|
|
18735
|
+
}
|
|
18736
|
+
return {
|
|
18737
|
+
endpoints,
|
|
18738
|
+
total: endpoints.length,
|
|
18739
|
+
note: this.openApiSpec ? "Use INVOKE-API-ENDPOINT to call specific endpoints with the path parameter" : "Limited endpoint information - OpenAPI spec not available"
|
|
18740
|
+
};
|
|
18741
|
+
}
|
|
18742
|
+
/**
|
|
18743
|
+
* Handle the GET-API-ENDPOINT-SCHEMA meta-tool
|
|
18744
|
+
* Returns the JSON schema for a specified API endpoint
|
|
18745
|
+
*/
|
|
18746
|
+
handleGetApiEndpointSchema(toolId, params) {
|
|
18747
|
+
const { endpoint } = params;
|
|
18748
|
+
if (!endpoint) {
|
|
18749
|
+
throw new Error(`Missing required parameter 'endpoint' for tool '${toolId}'`);
|
|
18750
|
+
}
|
|
18751
|
+
if (this.openApiSpec) {
|
|
18752
|
+
const pathItem = this.openApiSpec.paths[endpoint];
|
|
18753
|
+
if (!pathItem) {
|
|
18754
|
+
throw new Error(`No endpoint found for path '${endpoint}' in tool '${toolId}'`);
|
|
18755
|
+
}
|
|
18756
|
+
const operations = [];
|
|
18757
|
+
for (const [method, operation] of Object.entries(pathItem)) {
|
|
18758
|
+
if (method === "parameters" || !operation) continue;
|
|
18759
|
+
if (!isValidHttpMethod(method)) {
|
|
18760
|
+
continue;
|
|
18761
|
+
}
|
|
18762
|
+
const op = operation;
|
|
18763
|
+
operations.push({
|
|
18764
|
+
method: method.toUpperCase(),
|
|
18765
|
+
operationId: op.operationId || "",
|
|
18766
|
+
summary: op.summary || "",
|
|
18767
|
+
description: op.description || "",
|
|
18768
|
+
parameters: op.parameters || [],
|
|
18769
|
+
requestBody: op.requestBody || null,
|
|
18770
|
+
responses: op.responses || {},
|
|
18771
|
+
tags: op.tags || []
|
|
18772
|
+
});
|
|
18773
|
+
}
|
|
18774
|
+
if (operations.length === 0) {
|
|
18775
|
+
throw new Error(`No valid HTTP operations found for path '${endpoint}' in tool '${toolId}'`);
|
|
18776
|
+
}
|
|
18777
|
+
return {
|
|
18778
|
+
path: endpoint,
|
|
18779
|
+
operations,
|
|
18780
|
+
pathParameters: pathItem.parameters || []
|
|
18781
|
+
};
|
|
18782
|
+
} else {
|
|
18783
|
+
let matchingTool;
|
|
18784
|
+
let matchingToolId;
|
|
18785
|
+
for (const [toolId2, tool] of this.toolsMap.entries()) {
|
|
18786
|
+
try {
|
|
18787
|
+
const { path } = this.parseToolId(toolId2);
|
|
18788
|
+
if (path === endpoint) {
|
|
18789
|
+
matchingTool = tool;
|
|
18790
|
+
matchingToolId = toolId2;
|
|
18791
|
+
break;
|
|
18792
|
+
}
|
|
18793
|
+
} catch (error) {
|
|
18794
|
+
continue;
|
|
18795
|
+
}
|
|
18796
|
+
}
|
|
18797
|
+
if (!matchingTool || !matchingToolId) {
|
|
18798
|
+
throw new Error(`No endpoint found for path: ${endpoint}`);
|
|
18799
|
+
}
|
|
18800
|
+
return {
|
|
18801
|
+
toolId: matchingToolId,
|
|
18802
|
+
name: matchingTool.name,
|
|
18803
|
+
description: matchingTool.description,
|
|
18804
|
+
inputSchema: matchingTool.inputSchema,
|
|
18805
|
+
note: "Limited schema information - using tool definition instead of OpenAPI spec"
|
|
18806
|
+
};
|
|
18807
|
+
}
|
|
18808
|
+
}
|
|
18809
|
+
/**
|
|
18810
|
+
* Handle the INVOKE-API-ENDPOINT meta-tool
|
|
18811
|
+
* Dynamically invokes an API endpoint with the provided parameters
|
|
18812
|
+
*/
|
|
18813
|
+
async handleInvokeApiEndpoint(toolId, params) {
|
|
18814
|
+
const { endpoint, method, params: endpointParams = {} } = params;
|
|
18815
|
+
if (!endpoint) {
|
|
18816
|
+
throw new Error(`Missing required parameter 'endpoint' for tool '${toolId}'`);
|
|
18817
|
+
}
|
|
18818
|
+
if (method) {
|
|
18819
|
+
const toolId2 = generateToolId(method, endpoint);
|
|
18820
|
+
if (this.toolsMap.has(toolId2)) {
|
|
18821
|
+
return this.executeApiCall(toolId2, endpointParams);
|
|
18822
|
+
} else if (this.openApiSpec) {
|
|
18823
|
+
const pathItem = this.openApiSpec.paths[endpoint];
|
|
18824
|
+
if (pathItem && pathItem[method.toLowerCase()]) {
|
|
18825
|
+
const { method: httpMethod, path } = { method: method.toUpperCase(), path: endpoint };
|
|
18826
|
+
return this.makeDirectHttpRequest(httpMethod, path, endpointParams);
|
|
18827
|
+
} else {
|
|
18828
|
+
throw new Error(
|
|
18829
|
+
`No endpoint found for path '${endpoint}' with method '${method}' in tool '${toolId2}'`
|
|
18830
|
+
);
|
|
18831
|
+
}
|
|
18832
|
+
} else {
|
|
18833
|
+
throw new Error(`Tool not found: ${toolId2}`);
|
|
18834
|
+
}
|
|
18835
|
+
}
|
|
18836
|
+
if (this.openApiSpec) {
|
|
18837
|
+
const pathItem = this.openApiSpec.paths[endpoint];
|
|
18838
|
+
if (pathItem) {
|
|
18839
|
+
for (const method2 of VALID_HTTP_METHODS) {
|
|
18840
|
+
if (pathItem[method2]) {
|
|
18841
|
+
return this.makeDirectHttpRequest(method2.toUpperCase(), endpoint, endpointParams);
|
|
18842
|
+
}
|
|
18843
|
+
}
|
|
18844
|
+
throw new Error(`No HTTP operations found for endpoint '${endpoint}' in tool '${toolId}'`);
|
|
18845
|
+
} else {
|
|
18846
|
+
throw new Error(`No endpoint found for path '${endpoint}' in tool '${toolId}'`);
|
|
18847
|
+
}
|
|
18848
|
+
}
|
|
18849
|
+
throw new Error(`No endpoint found for path '${endpoint}' in tool '${toolId}'`);
|
|
18850
|
+
}
|
|
18851
|
+
/**
|
|
18852
|
+
* Make a direct HTTP request without going through the tool system
|
|
18853
|
+
* Used by dynamic meta-tools when we have OpenAPI spec but no corresponding tool
|
|
18854
|
+
*/
|
|
18855
|
+
async makeDirectHttpRequest(method, path, params) {
|
|
18856
|
+
const authHeaders = await this.authProvider.getAuthHeaders();
|
|
18857
|
+
const config = {
|
|
18858
|
+
method: method.toLowerCase(),
|
|
18859
|
+
url: path,
|
|
18860
|
+
headers: authHeaders
|
|
18861
|
+
};
|
|
18862
|
+
if (isGetLikeMethod(method)) {
|
|
18863
|
+
config.params = this.processQueryParams(params);
|
|
18864
|
+
} else {
|
|
18865
|
+
config.data = params;
|
|
18866
|
+
}
|
|
18867
|
+
try {
|
|
18868
|
+
const response = await this.axiosInstance.request(config);
|
|
18869
|
+
return response.data;
|
|
18870
|
+
} catch (error) {
|
|
18871
|
+
if (axios_default.isAxiosError(error)) {
|
|
18872
|
+
const axiosError = error;
|
|
18873
|
+
throw new Error(
|
|
18874
|
+
`API request failed: ${axiosError.message}${axiosError.response ? ` (${axiosError.response.status}: ${typeof axiosError.response.data === "object" ? JSON.stringify(axiosError.response.data) : axiosError.response.data})` : ""}`
|
|
18875
|
+
);
|
|
18876
|
+
}
|
|
18877
|
+
throw error;
|
|
18878
|
+
}
|
|
18879
|
+
}
|
|
18634
18880
|
};
|
|
18635
18881
|
|
|
18636
18882
|
// src/server.ts
|
|
@@ -18652,7 +18898,11 @@ var OpenAPIServer = class {
|
|
|
18652
18898
|
);
|
|
18653
18899
|
this.toolsManager = new ToolsManager(config);
|
|
18654
18900
|
const authProviderOrHeaders = config.authProvider || new StaticAuthProvider(config.headers);
|
|
18655
|
-
this.apiClient = new ApiClient(
|
|
18901
|
+
this.apiClient = new ApiClient(
|
|
18902
|
+
config.apiBaseUrl,
|
|
18903
|
+
authProviderOrHeaders,
|
|
18904
|
+
this.toolsManager.getSpecLoader()
|
|
18905
|
+
);
|
|
18656
18906
|
this.initializeHandlers();
|
|
18657
18907
|
}
|
|
18658
18908
|
/**
|
|
@@ -18717,6 +18967,10 @@ var OpenAPIServer = class {
|
|
|
18717
18967
|
toolsMap.set(toolId, tool);
|
|
18718
18968
|
}
|
|
18719
18969
|
this.apiClient.setTools(toolsMap);
|
|
18970
|
+
const spec = this.toolsManager.getOpenApiSpec();
|
|
18971
|
+
if (spec) {
|
|
18972
|
+
this.apiClient.setOpenApiSpec(spec);
|
|
18973
|
+
}
|
|
18720
18974
|
await this.server.connect(transport);
|
|
18721
18975
|
}
|
|
18722
18976
|
};
|
|
@@ -23575,8 +23829,12 @@ function parseHeaders(headerStr) {
|
|
|
23575
23829
|
const headers = {};
|
|
23576
23830
|
if (headerStr) {
|
|
23577
23831
|
headerStr.split(",").forEach((header) => {
|
|
23578
|
-
const
|
|
23579
|
-
if (
|
|
23832
|
+
const colonIndex = header.indexOf(":");
|
|
23833
|
+
if (colonIndex > 0) {
|
|
23834
|
+
const key = header.substring(0, colonIndex).trim();
|
|
23835
|
+
const value = header.substring(colonIndex + 1).trim();
|
|
23836
|
+
if (key) headers[key] = value;
|
|
23837
|
+
}
|
|
23580
23838
|
});
|
|
23581
23839
|
}
|
|
23582
23840
|
return headers;
|