@ivotoby/openapi-mcp-server 1.2.1 → 1.3.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 +85 -1
- package/dist/bundle.js +258 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -125,6 +125,8 @@ The server can be configured through environment variables or command line argum
|
|
|
125
125
|
- `HTTP_PORT` - Port for HTTP transport (default: 3000)
|
|
126
126
|
- `HTTP_HOST` - Host for HTTP transport (default: "127.0.0.1")
|
|
127
127
|
- `ENDPOINT_PATH` - Endpoint path for HTTP transport (default: "/mcp")
|
|
128
|
+
- `TOOLS_MODE` - Tools loading mode: "all" (load all endpoint-based tools) or "dynamic" (load only meta-tools) (default: "all")
|
|
129
|
+
- `DISABLE_ABBREVIATION` - Disable name optimization (this could throw errors when name is > 64 chars)
|
|
128
130
|
|
|
129
131
|
### Command Line Arguments
|
|
130
132
|
|
|
@@ -138,7 +140,63 @@ npx @ivotoby/openapi-mcp-server \
|
|
|
138
140
|
--transport http \
|
|
139
141
|
--port 3000 \
|
|
140
142
|
--host 127.0.0.1 \
|
|
141
|
-
--path /mcp
|
|
143
|
+
--path /mcp \
|
|
144
|
+
--disable-abbreviation true
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### OpenAPI Schema Processing
|
|
148
|
+
|
|
149
|
+
#### Reference Resolution
|
|
150
|
+
|
|
151
|
+
This MCP server implements robust OpenAPI reference (`$ref`) resolution to ensure accurate representation of API schemas:
|
|
152
|
+
|
|
153
|
+
- **Parameter References**: Fully resolves `$ref` pointers to parameter components in the OpenAPI spec
|
|
154
|
+
- **Schema References**: Handles nested schema references within parameters and request bodies
|
|
155
|
+
- **Recursive References**: Prevents infinite loops by detecting and handling circular references
|
|
156
|
+
- **Nested Properties**: Preserves complex nested object and array structures with all their attributes
|
|
157
|
+
|
|
158
|
+
### Input Schema Composition
|
|
159
|
+
|
|
160
|
+
The server intelligently merges parameters and request bodies into a unified input schema for each tool:
|
|
161
|
+
|
|
162
|
+
- **Parameters + Request Body Merging**: Combines path, query, and body parameters into a single schema
|
|
163
|
+
- **Collision Handling**: Resolves naming conflicts by prefixing body properties that conflict with parameter names
|
|
164
|
+
- **Type Preservation**: Maintains the original type information for all schema elements
|
|
165
|
+
- **Metadata Retention**: Preserves descriptions, formats, defaults, enums, and other schema attributes
|
|
166
|
+
|
|
167
|
+
### Complex Schema Support
|
|
168
|
+
|
|
169
|
+
The MCP server handles various OpenAPI schema complexities:
|
|
170
|
+
|
|
171
|
+
- **Primitive Type Bodies**: Wraps non-object request bodies in a "body" property
|
|
172
|
+
- **Object Bodies**: Flattens object properties into the tool's input schema
|
|
173
|
+
- **Array Bodies**: Properly handles array schemas with their nested item definitions
|
|
174
|
+
- **Required Properties**: Tracks and preserves which parameters and properties are required
|
|
175
|
+
|
|
176
|
+
## Tool Loading & Filtering Options
|
|
177
|
+
|
|
178
|
+
Based on the Stainless article "What We Learned Converting Complex OpenAPI Specs to MCP Servers" (https://www.stainless.com/blog/what-we-learned-converting-complex-openapi-specs-to-mcp-servers), the following flags were added to control which API endpoints (tools) are loaded:
|
|
179
|
+
|
|
180
|
+
- `--tools <all|dynamic>`: Choose to load all tools (default) or only dynamic meta-tools (`list-api-endpoints`, `get-api-endpoint-schema`, `invoke-api-endpoint`).
|
|
181
|
+
- `--tool <toolId>`: Import only specified tool IDs or names. Can be used multiple times.
|
|
182
|
+
- `--tag <tag>`: Import only tools with the specified OpenAPI tag. Can be used multiple times.
|
|
183
|
+
- `--resource <resource>`: Import only tools under the specified resource path prefixes. Can be used multiple times.
|
|
184
|
+
- `--operation <method>`: Import only tools for the specified HTTP methods (get, post, etc). Can be used multiple times.
|
|
185
|
+
|
|
186
|
+
**Examples:**
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# Load only dynamic meta-tools
|
|
190
|
+
npx @ivotoby/openapi-mcp-server --api-base-url https://api.example.com --openapi-spec https://api.example.com/openapi.json --tools dynamic
|
|
191
|
+
|
|
192
|
+
# Load only the GET /users endpoint tool
|
|
193
|
+
npx @ivotoby/openapi-mcp-server --api-base-url https://api.example.com --openapi-spec https://api.example.com/openapi.json --tool GET-users
|
|
194
|
+
|
|
195
|
+
# Load tools tagged with "user" under the "/users" resource
|
|
196
|
+
npx @ivotoby/openapi-mcp-server --api-base-url https://api.example.com --openapi-spec https://api.example.com/openapi.json --tag user --resource users
|
|
197
|
+
|
|
198
|
+
# Load only POST operations
|
|
199
|
+
npx @ivotoby/openapi-mcp-server --api-base-url https://api.example.com --openapi-spec https://api.example.com/openapi.json --operation post
|
|
142
200
|
```
|
|
143
201
|
|
|
144
202
|
## Security Considerations
|
|
@@ -187,6 +245,32 @@ To see debug logs:
|
|
|
187
245
|
4. Run tests and linting: `npm run typecheck && npm run lint`
|
|
188
246
|
5. Submit a pull request
|
|
189
247
|
|
|
248
|
+
## FAQ
|
|
249
|
+
|
|
250
|
+
**Q: What is a "tool"?**
|
|
251
|
+
A: A tool corresponds to a single API endpoint derived from your OpenAPI specification, exposed as an MCP resource.
|
|
252
|
+
|
|
253
|
+
**Q: How do I filter which tools are loaded?**
|
|
254
|
+
A: Use the `--tool`, `--tag`, `--resource`, and `--operation` flags, or set `TOOLS_MODE=dynamic` for meta-tools only.
|
|
255
|
+
|
|
256
|
+
**Q: When should I use dynamic mode?**
|
|
257
|
+
A: Dynamic mode provides meta-tools (`list-api-endpoints`, `get-api-endpoint-schema`, `invoke-api-endpoint`) to inspect and interact with endpoints without preloading all operations, which is useful for large or changing APIs.
|
|
258
|
+
|
|
259
|
+
**Q: How do I specify custom headers for API requests?**
|
|
260
|
+
A: Use the `--headers` flag or `API_HEADERS` environment variable with `key:value` pairs separated by commas.
|
|
261
|
+
|
|
262
|
+
**Q: Which transport methods are supported?**
|
|
263
|
+
A: The server supports stdio transport (default) for integration with AI systems and HTTP transport (with streaming via SSE) for web clients.
|
|
264
|
+
|
|
265
|
+
**Q: How does the server handle complex OpenAPI schemas with references?**
|
|
266
|
+
A: The server fully resolves `$ref` references in parameters and schemas, preserving nested structures, default values, and other attributes. See the "OpenAPI Schema Processing" section for details on reference resolution and schema composition.
|
|
267
|
+
|
|
268
|
+
**Q: What happens when parameter names conflict with request body properties?**
|
|
269
|
+
A: The server detects naming conflicts and automatically prefixes body property names with `body_` to avoid collisions, ensuring all properties are accessible.
|
|
270
|
+
|
|
271
|
+
**Q: Where can I find development and contribution guidelines?**
|
|
272
|
+
A: See the "For Developers" section above for commands (`npm run build`, `npm run dev`, etc) and pull request workflow.
|
|
273
|
+
|
|
190
274
|
## License
|
|
191
275
|
|
|
192
276
|
MIT
|
package/dist/bundle.js
CHANGED
|
@@ -14373,6 +14373,13 @@ var WORD_ABBREVIATIONS = {
|
|
|
14373
14373
|
|
|
14374
14374
|
// src/openapi-loader.ts
|
|
14375
14375
|
var OpenAPISpecLoader = class {
|
|
14376
|
+
/**
|
|
14377
|
+
* Disable name optimization
|
|
14378
|
+
*/
|
|
14379
|
+
disableAbbreviation;
|
|
14380
|
+
constructor(config) {
|
|
14381
|
+
this.disableAbbreviation = config?.disableAbbreviation ?? false;
|
|
14382
|
+
}
|
|
14376
14383
|
/**
|
|
14377
14384
|
* Load an OpenAPI specification from a file path or URL
|
|
14378
14385
|
*/
|
|
@@ -14399,6 +14406,50 @@ var OpenAPISpecLoader = class {
|
|
|
14399
14406
|
}
|
|
14400
14407
|
}
|
|
14401
14408
|
}
|
|
14409
|
+
/**
|
|
14410
|
+
* Inline `$ref` schemas from components and drop recursive cycles
|
|
14411
|
+
*/
|
|
14412
|
+
inlineSchema(schema2, components, visited) {
|
|
14413
|
+
if ("$ref" in schema2 && typeof schema2.$ref === "string") {
|
|
14414
|
+
const ref = schema2.$ref;
|
|
14415
|
+
const match = ref.match(/^#\/components\/schemas\/(.+)$/);
|
|
14416
|
+
if (match && components) {
|
|
14417
|
+
const name = match[1];
|
|
14418
|
+
if (visited.has(name)) {
|
|
14419
|
+
return {};
|
|
14420
|
+
}
|
|
14421
|
+
const comp = components[name];
|
|
14422
|
+
if (!comp) {
|
|
14423
|
+
return {};
|
|
14424
|
+
}
|
|
14425
|
+
visited.add(name);
|
|
14426
|
+
return this.inlineSchema(comp, components, visited);
|
|
14427
|
+
}
|
|
14428
|
+
}
|
|
14429
|
+
const schemaObj = schema2;
|
|
14430
|
+
if (schemaObj.type === "object" && schemaObj.properties) {
|
|
14431
|
+
const newProps = {};
|
|
14432
|
+
for (const [propName, propSchema] of Object.entries(schemaObj.properties)) {
|
|
14433
|
+
newProps[propName] = this.inlineSchema(
|
|
14434
|
+
propSchema,
|
|
14435
|
+
components,
|
|
14436
|
+
new Set(visited)
|
|
14437
|
+
);
|
|
14438
|
+
}
|
|
14439
|
+
return { ...schemaObj, properties: newProps };
|
|
14440
|
+
}
|
|
14441
|
+
if (schemaObj.type === "array" && schemaObj.items) {
|
|
14442
|
+
return {
|
|
14443
|
+
...schemaObj,
|
|
14444
|
+
items: this.inlineSchema(
|
|
14445
|
+
schemaObj.items,
|
|
14446
|
+
components,
|
|
14447
|
+
new Set(visited)
|
|
14448
|
+
)
|
|
14449
|
+
};
|
|
14450
|
+
}
|
|
14451
|
+
return schemaObj;
|
|
14452
|
+
}
|
|
14402
14453
|
/**
|
|
14403
14454
|
* Parse an OpenAPI specification into a map of tools
|
|
14404
14455
|
*/
|
|
@@ -14408,8 +14459,7 @@ var OpenAPISpecLoader = class {
|
|
|
14408
14459
|
if (!pathItem) continue;
|
|
14409
14460
|
for (const [method, operation] of Object.entries(pathItem)) {
|
|
14410
14461
|
if (method === "parameters" || !operation) continue;
|
|
14411
|
-
if (!["get", "post", "
|
|
14412
|
-
console.log(`Skipping non-HTTP method "${method}" for path ${path}`);
|
|
14462
|
+
if (!["get", "put", "post", "delete", "options", "head", "patch", "trace"].includes(method)) {
|
|
14413
14463
|
continue;
|
|
14414
14464
|
}
|
|
14415
14465
|
const op = operation;
|
|
@@ -14425,26 +14475,84 @@ var OpenAPISpecLoader = class {
|
|
|
14425
14475
|
properties: {}
|
|
14426
14476
|
}
|
|
14427
14477
|
};
|
|
14478
|
+
const requiredParams = [];
|
|
14428
14479
|
if (op.parameters) {
|
|
14429
|
-
const requiredParams = [];
|
|
14430
14480
|
for (const param of op.parameters) {
|
|
14431
|
-
|
|
14432
|
-
|
|
14433
|
-
if (
|
|
14434
|
-
|
|
14435
|
-
|
|
14436
|
-
|
|
14437
|
-
|
|
14481
|
+
let paramObj;
|
|
14482
|
+
if (!("name" in param)) {
|
|
14483
|
+
if ("$ref" in param && typeof param.$ref === "string") {
|
|
14484
|
+
const refMatch = param.$ref.match(/^#\/components\/parameters\/(.+)$/);
|
|
14485
|
+
if (refMatch && spec.components?.parameters) {
|
|
14486
|
+
const paramName = refMatch[1];
|
|
14487
|
+
const resolvedParam = spec.components.parameters[paramName];
|
|
14488
|
+
if (!resolvedParam || !("name" in resolvedParam)) continue;
|
|
14489
|
+
paramObj = resolvedParam;
|
|
14490
|
+
} else {
|
|
14491
|
+
continue;
|
|
14492
|
+
}
|
|
14493
|
+
} else {
|
|
14494
|
+
continue;
|
|
14495
|
+
}
|
|
14496
|
+
} else {
|
|
14497
|
+
paramObj = param;
|
|
14498
|
+
}
|
|
14499
|
+
if (paramObj.schema) {
|
|
14500
|
+
const paramSchema = this.inlineSchema(
|
|
14501
|
+
paramObj.schema,
|
|
14502
|
+
spec.components?.schemas,
|
|
14503
|
+
/* @__PURE__ */ new Set()
|
|
14504
|
+
);
|
|
14505
|
+
const paramDef = {
|
|
14506
|
+
description: paramObj.description || `${paramObj.name} parameter`
|
|
14507
|
+
};
|
|
14508
|
+
if (paramSchema.type) {
|
|
14509
|
+
paramDef.type = paramSchema.type;
|
|
14510
|
+
} else {
|
|
14511
|
+
paramDef.type = "string";
|
|
14438
14512
|
}
|
|
14439
|
-
|
|
14440
|
-
|
|
14513
|
+
for (const [key, value] of Object.entries(paramSchema)) {
|
|
14514
|
+
if (key === "type" || key === "description") continue;
|
|
14515
|
+
paramDef[key] = value;
|
|
14516
|
+
}
|
|
14517
|
+
tool.inputSchema.properties[paramObj.name] = paramDef;
|
|
14518
|
+
if (paramObj.required === true) {
|
|
14519
|
+
requiredParams.push(paramObj.name);
|
|
14441
14520
|
}
|
|
14442
14521
|
}
|
|
14443
14522
|
}
|
|
14444
|
-
|
|
14445
|
-
|
|
14523
|
+
}
|
|
14524
|
+
if (op.requestBody && "content" in op.requestBody) {
|
|
14525
|
+
const requestBodyObj = op.requestBody;
|
|
14526
|
+
let mediaTypeObj;
|
|
14527
|
+
if (requestBodyObj.content["application/json"]) {
|
|
14528
|
+
mediaTypeObj = requestBodyObj.content["application/json"];
|
|
14529
|
+
} else if (Object.keys(requestBodyObj.content).length > 0) {
|
|
14530
|
+
const firstContentType = Object.keys(requestBodyObj.content)[0];
|
|
14531
|
+
mediaTypeObj = requestBodyObj.content[firstContentType];
|
|
14532
|
+
}
|
|
14533
|
+
if (mediaTypeObj?.schema) {
|
|
14534
|
+
const inlinedSchema = this.inlineSchema(
|
|
14535
|
+
mediaTypeObj.schema,
|
|
14536
|
+
spec.components?.schemas,
|
|
14537
|
+
/* @__PURE__ */ new Set()
|
|
14538
|
+
);
|
|
14539
|
+
if (inlinedSchema.type === "object" && inlinedSchema.properties) {
|
|
14540
|
+
for (const [propName, propSchema] of Object.entries(inlinedSchema.properties)) {
|
|
14541
|
+
const paramName = tool.inputSchema.properties[propName] ? `body_${propName}` : propName;
|
|
14542
|
+
tool.inputSchema.properties[paramName] = propSchema;
|
|
14543
|
+
if (inlinedSchema.required && inlinedSchema.required.includes(propName)) {
|
|
14544
|
+
requiredParams.push(paramName);
|
|
14545
|
+
}
|
|
14546
|
+
}
|
|
14547
|
+
} else {
|
|
14548
|
+
tool.inputSchema.properties["body"] = inlinedSchema;
|
|
14549
|
+
requiredParams.push("body");
|
|
14550
|
+
}
|
|
14446
14551
|
}
|
|
14447
14552
|
}
|
|
14553
|
+
if (requiredParams.length > 0) {
|
|
14554
|
+
tool.inputSchema.required = requiredParams;
|
|
14555
|
+
}
|
|
14448
14556
|
tools.set(toolId, tool);
|
|
14449
14557
|
}
|
|
14450
14558
|
}
|
|
@@ -14548,14 +14656,20 @@ var OpenAPISpecLoader = class {
|
|
|
14548
14656
|
return finalName;
|
|
14549
14657
|
}
|
|
14550
14658
|
abbreviateOperationId(originalId, maxLength = 64) {
|
|
14659
|
+
maxLength = this.disableAbbreviation ? Number.MAX_SAFE_INTEGER : maxLength;
|
|
14551
14660
|
const {
|
|
14552
14661
|
currentName: sanitizedName,
|
|
14553
14662
|
originalWasLong,
|
|
14554
14663
|
errorName
|
|
14555
14664
|
} = this._initialSanitizeAndValidate(originalId, maxLength);
|
|
14556
14665
|
if (errorName) return errorName;
|
|
14557
|
-
let processedName
|
|
14558
|
-
|
|
14666
|
+
let processedName;
|
|
14667
|
+
if (this.disableAbbreviation) {
|
|
14668
|
+
processedName = this.splitCombined(sanitizedName).join("-");
|
|
14669
|
+
} else {
|
|
14670
|
+
processedName = this._performSemanticAbbreviation(sanitizedName);
|
|
14671
|
+
processedName = this._applyVowelRemovalIfOverLength(processedName, maxLength);
|
|
14672
|
+
}
|
|
14559
14673
|
processedName = this._truncateAndApplyHashIfNeeded(
|
|
14560
14674
|
processedName,
|
|
14561
14675
|
originalId,
|
|
@@ -14571,16 +14685,105 @@ var OpenAPISpecLoader = class {
|
|
|
14571
14685
|
var ToolsManager = class {
|
|
14572
14686
|
constructor(config) {
|
|
14573
14687
|
this.config = config;
|
|
14574
|
-
this.
|
|
14688
|
+
this.config.toolsMode = this.config.toolsMode || "all";
|
|
14689
|
+
this.specLoader = new OpenAPISpecLoader({
|
|
14690
|
+
disableAbbreviation: this.config.disableAbbreviation
|
|
14691
|
+
});
|
|
14575
14692
|
}
|
|
14576
14693
|
tools = /* @__PURE__ */ new Map();
|
|
14577
14694
|
specLoader;
|
|
14695
|
+
/**
|
|
14696
|
+
* Create dynamic discovery meta-tools
|
|
14697
|
+
*/
|
|
14698
|
+
createDynamicTools() {
|
|
14699
|
+
const dynamicTools = /* @__PURE__ */ new Map();
|
|
14700
|
+
dynamicTools.set("LIST-API-ENDPOINTS", {
|
|
14701
|
+
name: "list-api-endpoints",
|
|
14702
|
+
description: "List all available API endpoints",
|
|
14703
|
+
inputSchema: { type: "object", properties: {} }
|
|
14704
|
+
});
|
|
14705
|
+
dynamicTools.set("GET-API-ENDPOINT-SCHEMA", {
|
|
14706
|
+
name: "get-api-endpoint-schema",
|
|
14707
|
+
description: "Get the JSON schema for a specified API endpoint",
|
|
14708
|
+
inputSchema: {
|
|
14709
|
+
type: "object",
|
|
14710
|
+
properties: {
|
|
14711
|
+
endpoint: { type: "string", description: "Endpoint path (e.g. /users/{id})" }
|
|
14712
|
+
},
|
|
14713
|
+
required: ["endpoint"]
|
|
14714
|
+
}
|
|
14715
|
+
});
|
|
14716
|
+
dynamicTools.set("INVOKE-API-ENDPOINT", {
|
|
14717
|
+
name: "invoke-api-endpoint",
|
|
14718
|
+
description: "Invoke an API endpoint with provided parameters",
|
|
14719
|
+
inputSchema: {
|
|
14720
|
+
type: "object",
|
|
14721
|
+
properties: {
|
|
14722
|
+
endpoint: { type: "string", description: "Endpoint path to invoke" },
|
|
14723
|
+
params: {
|
|
14724
|
+
type: "object",
|
|
14725
|
+
description: "Parameters for the API call",
|
|
14726
|
+
properties: {}
|
|
14727
|
+
}
|
|
14728
|
+
},
|
|
14729
|
+
required: ["endpoint"]
|
|
14730
|
+
}
|
|
14731
|
+
});
|
|
14732
|
+
return dynamicTools;
|
|
14733
|
+
}
|
|
14578
14734
|
/**
|
|
14579
14735
|
* Initialize tools from the OpenAPI specification
|
|
14580
14736
|
*/
|
|
14581
14737
|
async initialize() {
|
|
14582
14738
|
const spec = await this.specLoader.loadOpenAPISpec(this.config.openApiSpec);
|
|
14583
|
-
this.
|
|
14739
|
+
if (this.config.toolsMode === "dynamic") {
|
|
14740
|
+
this.tools = this.createDynamicTools();
|
|
14741
|
+
return;
|
|
14742
|
+
}
|
|
14743
|
+
const rawTools = this.specLoader.parseOpenAPISpec(spec);
|
|
14744
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
14745
|
+
const includeToolsLower = this.config.includeTools?.map((t) => t.toLowerCase()) || [];
|
|
14746
|
+
const includeOperationsLower = this.config.includeOperations?.map((op) => op.toLowerCase()) || [];
|
|
14747
|
+
const includeResourcesLower = this.config.includeResources || [];
|
|
14748
|
+
const includeTagsLower = this.config.includeTags?.map((tag) => tag.toLowerCase()) || [];
|
|
14749
|
+
const resourcePathsLower = includeResourcesLower.map((res) => ({
|
|
14750
|
+
exact: `/${res}`.toLowerCase(),
|
|
14751
|
+
prefix: `/${res}/`.toLowerCase()
|
|
14752
|
+
}));
|
|
14753
|
+
for (const [toolId, tool] of rawTools.entries()) {
|
|
14754
|
+
if (includeToolsLower.length > 0) {
|
|
14755
|
+
const toolIdLower = toolId.toLowerCase();
|
|
14756
|
+
const toolNameLower = tool.name.toLowerCase();
|
|
14757
|
+
if (!includeToolsLower.includes(toolIdLower) && !includeToolsLower.includes(toolNameLower)) {
|
|
14758
|
+
continue;
|
|
14759
|
+
}
|
|
14760
|
+
}
|
|
14761
|
+
if (includeOperationsLower.length > 0) {
|
|
14762
|
+
const { method } = this.parseToolId(toolId);
|
|
14763
|
+
if (!includeOperationsLower.includes(method.toLowerCase())) {
|
|
14764
|
+
continue;
|
|
14765
|
+
}
|
|
14766
|
+
}
|
|
14767
|
+
if (resourcePathsLower.length > 0) {
|
|
14768
|
+
const { path } = this.parseToolId(toolId);
|
|
14769
|
+
const pathLower = path.toLowerCase();
|
|
14770
|
+
const match = resourcePathsLower.some(
|
|
14771
|
+
(res) => pathLower === res.exact || pathLower.startsWith(res.prefix)
|
|
14772
|
+
);
|
|
14773
|
+
if (!match) continue;
|
|
14774
|
+
}
|
|
14775
|
+
if (includeTagsLower.length > 0) {
|
|
14776
|
+
const { method, path } = this.parseToolId(toolId);
|
|
14777
|
+
const methodLower = method.toLowerCase();
|
|
14778
|
+
const pathItem = spec.paths[path];
|
|
14779
|
+
if (!pathItem) continue;
|
|
14780
|
+
const opObj = pathItem[methodLower];
|
|
14781
|
+
const tags = Array.isArray(opObj?.tags) ? opObj.tags : [];
|
|
14782
|
+
if (!tags.some((tag) => includeTagsLower.includes(tag.toLowerCase()))) continue;
|
|
14783
|
+
}
|
|
14784
|
+
filtered.set(toolId, tool);
|
|
14785
|
+
}
|
|
14786
|
+
this.tools = filtered;
|
|
14584
14787
|
for (const [toolId, tool] of this.tools.entries()) {
|
|
14585
14788
|
console.error(`Registered tool: ${toolId} (${tool.name})`);
|
|
14586
14789
|
}
|
|
@@ -14595,11 +14798,14 @@ var ToolsManager = class {
|
|
|
14595
14798
|
* Find a tool by ID or name
|
|
14596
14799
|
*/
|
|
14597
14800
|
findTool(idOrName) {
|
|
14598
|
-
|
|
14599
|
-
|
|
14801
|
+
const lowerIdOrName = idOrName.toLowerCase();
|
|
14802
|
+
for (const [toolId, tool] of this.tools.entries()) {
|
|
14803
|
+
if (toolId.toLowerCase() === lowerIdOrName) {
|
|
14804
|
+
return { toolId, tool };
|
|
14805
|
+
}
|
|
14600
14806
|
}
|
|
14601
14807
|
for (const [toolId, tool] of this.tools.entries()) {
|
|
14602
|
-
if (tool.name ===
|
|
14808
|
+
if (tool.name.toLowerCase() === lowerIdOrName) {
|
|
14603
14809
|
return { toolId, tool };
|
|
14604
14810
|
}
|
|
14605
14811
|
}
|
|
@@ -22980,6 +23186,29 @@ function loadConfig() {
|
|
|
22980
23186
|
alias: "v",
|
|
22981
23187
|
type: "string",
|
|
22982
23188
|
description: "Server version"
|
|
23189
|
+
}).option("tools", {
|
|
23190
|
+
type: "string",
|
|
23191
|
+
choices: ["all", "dynamic"],
|
|
23192
|
+
description: "Which tools to load: all or dynamic meta-tools"
|
|
23193
|
+
}).option("tool", {
|
|
23194
|
+
type: "array",
|
|
23195
|
+
string: true,
|
|
23196
|
+
description: "Import only specified tool IDs or names"
|
|
23197
|
+
}).option("tag", {
|
|
23198
|
+
type: "array",
|
|
23199
|
+
string: true,
|
|
23200
|
+
description: "Import only tools with specified OpenAPI tags"
|
|
23201
|
+
}).option("resource", {
|
|
23202
|
+
type: "array",
|
|
23203
|
+
string: true,
|
|
23204
|
+
description: "Import only tools under specified resource path prefixes"
|
|
23205
|
+
}).option("operation", {
|
|
23206
|
+
type: "array",
|
|
23207
|
+
string: true,
|
|
23208
|
+
description: "Import only tools for specified HTTP methods (e.g., get, post)"
|
|
23209
|
+
}).option("disable-abbreviation", {
|
|
23210
|
+
type: "boolean",
|
|
23211
|
+
description: "Disable name optimization"
|
|
22983
23212
|
}).help().parseSync();
|
|
22984
23213
|
let transportType;
|
|
22985
23214
|
if (argv.transport === "http" || process.env.TRANSPORT_TYPE === "http") {
|
|
@@ -22992,6 +23221,7 @@ function loadConfig() {
|
|
|
22992
23221
|
const endpointPath = argv.path || process.env.ENDPOINT_PATH || "/mcp";
|
|
22993
23222
|
const apiBaseUrl = argv["api-base-url"] || process.env.API_BASE_URL;
|
|
22994
23223
|
const openApiSpec = argv["openapi-spec"] || process.env.OPENAPI_SPEC_PATH;
|
|
23224
|
+
const disableAbbreviation = argv["disable-abbreviation"] || (process.env.DISABLE_ABBREVIATION ? process.env.DISABLE_ABBREVIATION === "true" : false);
|
|
22995
23225
|
if (!apiBaseUrl) {
|
|
22996
23226
|
throw new Error("API base URL is required (--api-base-url or API_BASE_URL)");
|
|
22997
23227
|
}
|
|
@@ -23008,7 +23238,13 @@ function loadConfig() {
|
|
|
23008
23238
|
transportType,
|
|
23009
23239
|
httpPort,
|
|
23010
23240
|
httpHost,
|
|
23011
|
-
endpointPath
|
|
23241
|
+
endpointPath,
|
|
23242
|
+
includeTools: argv.tool,
|
|
23243
|
+
includeTags: argv.tag,
|
|
23244
|
+
includeResources: argv.resource,
|
|
23245
|
+
includeOperations: argv.operation,
|
|
23246
|
+
toolsMode: argv.tools || process.env.TOOLS_MODE || "all",
|
|
23247
|
+
disableAbbreviation: disableAbbreviation ? true : void 0
|
|
23012
23248
|
};
|
|
23013
23249
|
}
|
|
23014
23250
|
|