@ivotoby/openapi-mcp-server 1.6.1 → 1.7.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/README.md +291 -226
- package/dist/bundle.js +235 -65
- package/dist/cli.js +235 -65
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -14374,14 +14374,17 @@ var WORD_ABBREVIATIONS = {
|
|
|
14374
14374
|
// src/utils/tool-id.ts
|
|
14375
14375
|
function parseToolId(toolId) {
|
|
14376
14376
|
const [method, pathPart] = toolId.split("::", 2);
|
|
14377
|
-
|
|
14378
|
-
|
|
14377
|
+
if (!pathPart) {
|
|
14378
|
+
return { method, path: "" };
|
|
14379
|
+
}
|
|
14380
|
+
const path = pathPart.replace(/__/g, "/");
|
|
14381
|
+
return { method, path: "/" + path };
|
|
14379
14382
|
}
|
|
14380
14383
|
function sanitizeForToolId(input) {
|
|
14381
|
-
return input.replace(/[^A-Za-z0-9_-]/g, "").replace(
|
|
14384
|
+
return input.replace(/[^A-Za-z0-9_-]/g, "").replace(/_{3,}/g, "__").replace(/^[_-]+|[_-]+$/g, "");
|
|
14382
14385
|
}
|
|
14383
14386
|
function generateToolId(method, path) {
|
|
14384
|
-
const cleanPath = path.replace(/^\//, "").replace(/\{([^}]+)\}/g, "$1").replace(/\//g, "
|
|
14387
|
+
const cleanPath = path.replace(/^\//, "").replace(/\/+/g, "/").replace(/\{([^}]+)\}/g, "$1").replace(/\//g, "__");
|
|
14385
14388
|
const sanitizedPath = sanitizeForToolId(cleanPath);
|
|
14386
14389
|
return `${method.toUpperCase()}::${sanitizedPath}`;
|
|
14387
14390
|
}
|
|
@@ -14509,8 +14512,79 @@ var OpenAPISpecLoader = class {
|
|
|
14509
14512
|
visited.add(name);
|
|
14510
14513
|
return this.inlineSchema(comp, components, visited);
|
|
14511
14514
|
}
|
|
14515
|
+
return {};
|
|
14512
14516
|
}
|
|
14513
14517
|
const schemaObj = schema2;
|
|
14518
|
+
if (schemaObj.allOf) {
|
|
14519
|
+
const mergedSchema = {
|
|
14520
|
+
type: "object",
|
|
14521
|
+
properties: {},
|
|
14522
|
+
required: []
|
|
14523
|
+
};
|
|
14524
|
+
for (const subSchema of schemaObj.allOf) {
|
|
14525
|
+
const inlinedSubSchema = this.inlineSchema(
|
|
14526
|
+
subSchema,
|
|
14527
|
+
components,
|
|
14528
|
+
new Set(visited)
|
|
14529
|
+
);
|
|
14530
|
+
if (inlinedSubSchema.properties) {
|
|
14531
|
+
mergedSchema.properties = {
|
|
14532
|
+
...mergedSchema.properties,
|
|
14533
|
+
...inlinedSubSchema.properties
|
|
14534
|
+
};
|
|
14535
|
+
}
|
|
14536
|
+
if (inlinedSubSchema.required) {
|
|
14537
|
+
mergedSchema.required = [...mergedSchema.required || [], ...inlinedSubSchema.required];
|
|
14538
|
+
}
|
|
14539
|
+
for (const [key, value] of Object.entries(inlinedSubSchema)) {
|
|
14540
|
+
if (key !== "properties" && key !== "required" && !(key in mergedSchema)) {
|
|
14541
|
+
;
|
|
14542
|
+
mergedSchema[key] = value;
|
|
14543
|
+
}
|
|
14544
|
+
}
|
|
14545
|
+
}
|
|
14546
|
+
if (mergedSchema.required && mergedSchema.required.length === 0) {
|
|
14547
|
+
delete mergedSchema.required;
|
|
14548
|
+
}
|
|
14549
|
+
return mergedSchema;
|
|
14550
|
+
}
|
|
14551
|
+
if (schemaObj.oneOf) {
|
|
14552
|
+
const inlinedOneOf = schemaObj.oneOf.map(
|
|
14553
|
+
(subSchema) => this.inlineSchema(
|
|
14554
|
+
subSchema,
|
|
14555
|
+
components,
|
|
14556
|
+
new Set(visited)
|
|
14557
|
+
)
|
|
14558
|
+
);
|
|
14559
|
+
return {
|
|
14560
|
+
...schemaObj,
|
|
14561
|
+
oneOf: inlinedOneOf
|
|
14562
|
+
};
|
|
14563
|
+
}
|
|
14564
|
+
if (schemaObj.anyOf) {
|
|
14565
|
+
const inlinedAnyOf = schemaObj.anyOf.map(
|
|
14566
|
+
(subSchema) => this.inlineSchema(
|
|
14567
|
+
subSchema,
|
|
14568
|
+
components,
|
|
14569
|
+
new Set(visited)
|
|
14570
|
+
)
|
|
14571
|
+
);
|
|
14572
|
+
return {
|
|
14573
|
+
...schemaObj,
|
|
14574
|
+
anyOf: inlinedAnyOf
|
|
14575
|
+
};
|
|
14576
|
+
}
|
|
14577
|
+
if (schemaObj.not) {
|
|
14578
|
+
const inlinedNot = this.inlineSchema(
|
|
14579
|
+
schemaObj.not,
|
|
14580
|
+
components,
|
|
14581
|
+
new Set(visited)
|
|
14582
|
+
);
|
|
14583
|
+
return {
|
|
14584
|
+
...schemaObj,
|
|
14585
|
+
not: inlinedNot
|
|
14586
|
+
};
|
|
14587
|
+
}
|
|
14514
14588
|
if (schemaObj.type === "object" && schemaObj.properties) {
|
|
14515
14589
|
const newProps = {};
|
|
14516
14590
|
for (const [propName, propSchema] of Object.entries(schemaObj.properties)) {
|
|
@@ -14523,14 +14597,12 @@ var OpenAPISpecLoader = class {
|
|
|
14523
14597
|
return { ...schemaObj, properties: newProps };
|
|
14524
14598
|
}
|
|
14525
14599
|
if (schemaObj.type === "array" && schemaObj.items) {
|
|
14526
|
-
|
|
14527
|
-
|
|
14528
|
-
|
|
14529
|
-
|
|
14530
|
-
|
|
14531
|
-
|
|
14532
|
-
)
|
|
14533
|
-
};
|
|
14600
|
+
const inlinedItems = this.inlineSchema(
|
|
14601
|
+
schemaObj.items,
|
|
14602
|
+
components,
|
|
14603
|
+
new Set(visited)
|
|
14604
|
+
);
|
|
14605
|
+
return { ...schemaObj, items: inlinedItems };
|
|
14534
14606
|
}
|
|
14535
14607
|
return schemaObj;
|
|
14536
14608
|
}
|
|
@@ -14561,6 +14633,24 @@ var OpenAPISpecLoader = class {
|
|
|
14561
14633
|
}
|
|
14562
14634
|
return void 0;
|
|
14563
14635
|
}
|
|
14636
|
+
/**
|
|
14637
|
+
* Extract the primary resource name from an OpenAPI path
|
|
14638
|
+
* Examples:
|
|
14639
|
+
* - "/users" -> "users"
|
|
14640
|
+
* - "/users/{id}" -> "users"
|
|
14641
|
+
* - "/api/v1/users/{id}/posts" -> "posts"
|
|
14642
|
+
* - "/health" -> "health"
|
|
14643
|
+
*/
|
|
14644
|
+
extractResourceName(path) {
|
|
14645
|
+
const segments = path.replace(/^\//, "").split("/");
|
|
14646
|
+
for (let i = segments.length - 1; i >= 0; i--) {
|
|
14647
|
+
const segment = segments[i];
|
|
14648
|
+
if (!segment.includes("{") && !segment.includes("}") && segment.length > 0) {
|
|
14649
|
+
return segment;
|
|
14650
|
+
}
|
|
14651
|
+
}
|
|
14652
|
+
return segments[0] || void 0;
|
|
14653
|
+
}
|
|
14564
14654
|
/**
|
|
14565
14655
|
* Parse an OpenAPI specification into a map of tools
|
|
14566
14656
|
*/
|
|
@@ -14568,6 +14658,41 @@ var OpenAPISpecLoader = class {
|
|
|
14568
14658
|
const tools = /* @__PURE__ */ new Map();
|
|
14569
14659
|
for (const [path, pathItem] of Object.entries(spec.paths)) {
|
|
14570
14660
|
if (!pathItem) continue;
|
|
14661
|
+
const pathLevelParameters = [];
|
|
14662
|
+
if (pathItem.parameters) {
|
|
14663
|
+
for (const param of pathItem.parameters) {
|
|
14664
|
+
let paramObj;
|
|
14665
|
+
if ("$ref" in param && typeof param.$ref === "string") {
|
|
14666
|
+
const refMatch = param.$ref.match(/^#\/components\/parameters\/(.+)$/);
|
|
14667
|
+
if (refMatch && spec.components?.parameters) {
|
|
14668
|
+
const paramNameFromRef = refMatch[1];
|
|
14669
|
+
const resolvedParam = spec.components.parameters[paramNameFromRef];
|
|
14670
|
+
if (resolvedParam && "name" in resolvedParam && "in" in resolvedParam) {
|
|
14671
|
+
paramObj = resolvedParam;
|
|
14672
|
+
} else {
|
|
14673
|
+
console.warn(
|
|
14674
|
+
`Could not resolve path-level parameter reference or invalid structure: ${param.$ref}`
|
|
14675
|
+
);
|
|
14676
|
+
continue;
|
|
14677
|
+
}
|
|
14678
|
+
} else {
|
|
14679
|
+
console.warn(`Could not parse path-level parameter reference: ${param.$ref}`);
|
|
14680
|
+
continue;
|
|
14681
|
+
}
|
|
14682
|
+
} else if ("name" in param && "in" in param) {
|
|
14683
|
+
paramObj = param;
|
|
14684
|
+
} else {
|
|
14685
|
+
console.warn(
|
|
14686
|
+
"Skipping path-level parameter due to missing 'name' or 'in' properties and not being a valid $ref:",
|
|
14687
|
+
param
|
|
14688
|
+
);
|
|
14689
|
+
continue;
|
|
14690
|
+
}
|
|
14691
|
+
if (paramObj) {
|
|
14692
|
+
pathLevelParameters.push(paramObj);
|
|
14693
|
+
}
|
|
14694
|
+
}
|
|
14695
|
+
}
|
|
14571
14696
|
for (const [method, operation] of Object.entries(pathItem)) {
|
|
14572
14697
|
if (method === "parameters" || !operation) continue;
|
|
14573
14698
|
if (!["get", "post", "put", "patch", "delete", "options", "head"].includes(
|
|
@@ -14586,10 +14711,20 @@ var OpenAPISpecLoader = class {
|
|
|
14586
14711
|
inputSchema: {
|
|
14587
14712
|
type: "object",
|
|
14588
14713
|
properties: {}
|
|
14589
|
-
}
|
|
14714
|
+
},
|
|
14715
|
+
// Add metadata for filtering
|
|
14716
|
+
tags: op.tags || [],
|
|
14717
|
+
httpMethod: method.toUpperCase(),
|
|
14718
|
+
resourceName: this.extractResourceName(path),
|
|
14719
|
+
originalPath: path
|
|
14590
14720
|
};
|
|
14591
14721
|
tool["x-original-path"] = path;
|
|
14592
14722
|
const requiredParams = [];
|
|
14723
|
+
const parameterMap = /* @__PURE__ */ new Map();
|
|
14724
|
+
for (const pathParam of pathLevelParameters) {
|
|
14725
|
+
const key = `${pathParam.name}::${pathParam.in}`;
|
|
14726
|
+
parameterMap.set(key, pathParam);
|
|
14727
|
+
}
|
|
14593
14728
|
if (op.parameters) {
|
|
14594
14729
|
for (const param of op.parameters) {
|
|
14595
14730
|
let paramObj;
|
|
@@ -14619,37 +14754,39 @@ var OpenAPISpecLoader = class {
|
|
|
14619
14754
|
);
|
|
14620
14755
|
continue;
|
|
14621
14756
|
}
|
|
14622
|
-
if (
|
|
14623
|
-
|
|
14624
|
-
|
|
14757
|
+
if (paramObj) {
|
|
14758
|
+
const key = `${paramObj.name}::${paramObj.in}`;
|
|
14759
|
+
parameterMap.set(key, paramObj);
|
|
14625
14760
|
}
|
|
14626
|
-
|
|
14627
|
-
|
|
14628
|
-
|
|
14629
|
-
|
|
14630
|
-
|
|
14631
|
-
|
|
14632
|
-
|
|
14633
|
-
|
|
14634
|
-
|
|
14635
|
-
|
|
14636
|
-
}
|
|
14637
|
-
|
|
14638
|
-
|
|
14639
|
-
|
|
14640
|
-
|
|
14641
|
-
|
|
14642
|
-
|
|
14643
|
-
|
|
14644
|
-
|
|
14645
|
-
|
|
14646
|
-
|
|
14647
|
-
|
|
14648
|
-
|
|
14649
|
-
if (paramObj.required === true) {
|
|
14650
|
-
requiredParams.push(paramObj.name);
|
|
14761
|
+
}
|
|
14762
|
+
}
|
|
14763
|
+
for (const paramObj of parameterMap.values()) {
|
|
14764
|
+
if (paramObj.schema) {
|
|
14765
|
+
const paramSchema = this.inlineSchema(
|
|
14766
|
+
paramObj.schema,
|
|
14767
|
+
spec.components?.schemas,
|
|
14768
|
+
/* @__PURE__ */ new Set()
|
|
14769
|
+
);
|
|
14770
|
+
const paramDef = {
|
|
14771
|
+
description: paramObj.description || `${paramObj.name} parameter`,
|
|
14772
|
+
"x-parameter-location": paramObj.in
|
|
14773
|
+
// Store parameter location (path, query, etc.)
|
|
14774
|
+
};
|
|
14775
|
+
const paramType = this.determineParameterType(paramSchema, paramObj.name);
|
|
14776
|
+
if (paramType !== void 0) {
|
|
14777
|
+
paramDef.type = paramType;
|
|
14778
|
+
}
|
|
14779
|
+
if (typeof paramSchema === "object" && paramSchema !== null) {
|
|
14780
|
+
for (const [key, value] of Object.entries(paramSchema)) {
|
|
14781
|
+
if (key === "description" && paramDef.description) continue;
|
|
14782
|
+
if (key === "type" && paramDef.type) continue;
|
|
14783
|
+
paramDef[key] = value;
|
|
14651
14784
|
}
|
|
14652
14785
|
}
|
|
14786
|
+
tool.inputSchema.properties[paramObj.name] = paramDef;
|
|
14787
|
+
if (paramObj.required === true) {
|
|
14788
|
+
requiredParams.push(paramObj.name);
|
|
14789
|
+
}
|
|
14653
14790
|
}
|
|
14654
14791
|
}
|
|
14655
14792
|
if (op.requestBody && "content" in op.requestBody) {
|
|
@@ -14667,7 +14804,24 @@ var OpenAPISpecLoader = class {
|
|
|
14667
14804
|
spec.components?.schemas,
|
|
14668
14805
|
/* @__PURE__ */ new Set()
|
|
14669
14806
|
);
|
|
14670
|
-
if (inlinedSchema.
|
|
14807
|
+
if (inlinedSchema.oneOf || inlinedSchema.anyOf) {
|
|
14808
|
+
const existingProperties = tool.inputSchema.properties || {};
|
|
14809
|
+
const hasExistingProperties = Object.keys(existingProperties).length > 0;
|
|
14810
|
+
if (hasExistingProperties) {
|
|
14811
|
+
const objectSchema = {
|
|
14812
|
+
type: "object",
|
|
14813
|
+
properties: existingProperties
|
|
14814
|
+
};
|
|
14815
|
+
if (tool.inputSchema.required) {
|
|
14816
|
+
objectSchema.required = tool.inputSchema.required;
|
|
14817
|
+
}
|
|
14818
|
+
tool.inputSchema = {
|
|
14819
|
+
allOf: [objectSchema, inlinedSchema]
|
|
14820
|
+
};
|
|
14821
|
+
} else {
|
|
14822
|
+
tool.inputSchema = inlinedSchema;
|
|
14823
|
+
}
|
|
14824
|
+
} else if (inlinedSchema.type === "object" && inlinedSchema.properties) {
|
|
14671
14825
|
for (const [propName, propSchema] of Object.entries(inlinedSchema.properties)) {
|
|
14672
14826
|
const paramName = tool.inputSchema.properties[propName] ? `body_${propName}` : propName;
|
|
14673
14827
|
tool.inputSchema.properties[paramName] = propSchema;
|
|
@@ -14875,46 +15029,62 @@ var ToolsManager = class {
|
|
|
14875
15029
|
this.tools = this.createDynamicTools();
|
|
14876
15030
|
return;
|
|
14877
15031
|
}
|
|
15032
|
+
if (this.config.toolsMode === "explicit") {
|
|
15033
|
+
const rawTools2 = this.specLoader.parseOpenAPISpec(spec);
|
|
15034
|
+
const filtered2 = /* @__PURE__ */ new Map();
|
|
15035
|
+
if (this.config.includeTools && this.config.includeTools.length > 0) {
|
|
15036
|
+
const includeToolsLower2 = this.config.includeTools.map((t) => t.toLowerCase());
|
|
15037
|
+
for (const [toolId, tool] of rawTools2.entries()) {
|
|
15038
|
+
const toolIdLower = toolId.toLowerCase();
|
|
15039
|
+
const toolNameLower = tool.name.toLowerCase();
|
|
15040
|
+
if (includeToolsLower2.includes(toolIdLower) || includeToolsLower2.includes(toolNameLower)) {
|
|
15041
|
+
filtered2.set(toolId, tool);
|
|
15042
|
+
}
|
|
15043
|
+
}
|
|
15044
|
+
}
|
|
15045
|
+
this.tools = filtered2;
|
|
15046
|
+
for (const [toolId, tool] of this.tools.entries()) {
|
|
15047
|
+
console.error(`Registered tool: ${toolId} (${tool.name})`);
|
|
15048
|
+
}
|
|
15049
|
+
return;
|
|
15050
|
+
}
|
|
14878
15051
|
const rawTools = this.specLoader.parseOpenAPISpec(spec);
|
|
14879
15052
|
const filtered = /* @__PURE__ */ new Map();
|
|
14880
15053
|
const includeToolsLower = this.config.includeTools?.map((t) => t.toLowerCase()) || [];
|
|
14881
15054
|
const includeOperationsLower = this.config.includeOperations?.map((op) => op.toLowerCase()) || [];
|
|
14882
|
-
const includeResourcesLower = this.config.includeResources || [];
|
|
15055
|
+
const includeResourcesLower = this.config.includeResources?.map((res) => res.toLowerCase()) || [];
|
|
14883
15056
|
const includeTagsLower = this.config.includeTags?.map((tag) => tag.toLowerCase()) || [];
|
|
14884
|
-
const resourcePathsLower = includeResourcesLower.map((res) => ({
|
|
14885
|
-
exact: `/${res}`.toLowerCase(),
|
|
14886
|
-
prefix: `/${res}/`.toLowerCase()
|
|
14887
|
-
}));
|
|
14888
15057
|
for (const [toolId, tool] of rawTools.entries()) {
|
|
15058
|
+
const extendedTool = tool;
|
|
14889
15059
|
if (includeToolsLower.length > 0) {
|
|
14890
15060
|
const toolIdLower = toolId.toLowerCase();
|
|
14891
15061
|
const toolNameLower = tool.name.toLowerCase();
|
|
14892
15062
|
if (!includeToolsLower.includes(toolIdLower) && !includeToolsLower.includes(toolNameLower)) {
|
|
14893
15063
|
continue;
|
|
14894
15064
|
}
|
|
15065
|
+
filtered.set(toolId, tool);
|
|
15066
|
+
continue;
|
|
14895
15067
|
}
|
|
14896
15068
|
if (includeOperationsLower.length > 0) {
|
|
14897
|
-
const
|
|
14898
|
-
if (!includeOperationsLower.includes(
|
|
15069
|
+
const httpMethod = typeof extendedTool.httpMethod === "string" ? extendedTool.httpMethod.toLowerCase() : void 0;
|
|
15070
|
+
if (!httpMethod || !includeOperationsLower.includes(httpMethod)) {
|
|
14899
15071
|
continue;
|
|
14900
15072
|
}
|
|
14901
15073
|
}
|
|
14902
|
-
if (
|
|
14903
|
-
const
|
|
14904
|
-
|
|
14905
|
-
|
|
14906
|
-
|
|
14907
|
-
);
|
|
14908
|
-
if (!match) continue;
|
|
15074
|
+
if (includeResourcesLower.length > 0) {
|
|
15075
|
+
const resourceName = typeof extendedTool.resourceName === "string" ? extendedTool.resourceName.toLowerCase() : void 0;
|
|
15076
|
+
if (!resourceName || !includeResourcesLower.includes(resourceName)) {
|
|
15077
|
+
continue;
|
|
15078
|
+
}
|
|
14909
15079
|
}
|
|
14910
15080
|
if (includeTagsLower.length > 0) {
|
|
14911
|
-
const
|
|
14912
|
-
const
|
|
14913
|
-
|
|
14914
|
-
|
|
14915
|
-
|
|
14916
|
-
|
|
14917
|
-
|
|
15081
|
+
const toolTags = Array.isArray(extendedTool.tags) ? extendedTool.tags : [];
|
|
15082
|
+
const hasMatchingTag = toolTags.some(
|
|
15083
|
+
(tag) => typeof tag === "string" && includeTagsLower.includes(tag.toLowerCase())
|
|
15084
|
+
);
|
|
15085
|
+
if (!hasMatchingTag) {
|
|
15086
|
+
continue;
|
|
15087
|
+
}
|
|
14918
15088
|
}
|
|
14919
15089
|
filtered.set(toolId, tool);
|
|
14920
15090
|
}
|
|
@@ -23443,8 +23613,8 @@ function loadConfig() {
|
|
|
23443
23613
|
description: "Server version"
|
|
23444
23614
|
}).option("tools", {
|
|
23445
23615
|
type: "string",
|
|
23446
|
-
choices: ["all", "dynamic"],
|
|
23447
|
-
description: "Which tools to load: all
|
|
23616
|
+
choices: ["all", "dynamic", "explicit"],
|
|
23617
|
+
description: "Which tools to load: all, dynamic meta-tools, or explicit (only includeTools)"
|
|
23448
23618
|
}).option("tool", {
|
|
23449
23619
|
type: "array",
|
|
23450
23620
|
string: true,
|