This commit is contained in:
bipproduction
2025-11-20 16:47:37 +08:00
parent 7466fb1151
commit d8fa7b12ca
2 changed files with 24 additions and 15 deletions

View File

@@ -19,9 +19,11 @@ const toolsCache = new Map<string, CachedTools>();
// ====================================================== // ======================================================
// Load OpenAPI → MCP Tools // Load OpenAPI → MCP Tools
// (preserves original function name loadTools) // (preserves original function name loadTools)
// NOTE: filterTag now supports string | string[] (multi-select)
// ====================================================== // ======================================================
async function loadTools(openapiUrl: string, filterTag: string, forceRefresh = false): Promise<any[]> { async function loadTools(openapiUrl: string, filterTag: string | string[] = "", forceRefresh = false): Promise<any[]> {
const cacheKey = `${openapiUrl}::${filterTag || ""}`; const normalizedFilterKey = Array.isArray(filterTag) ? filterTag.join("|") : (filterTag ?? "");
const cacheKey = `${openapiUrl}::${normalizedFilterKey}`;
try { try {
const cached = toolsCache.get(cacheKey); const cached = toolsCache.get(cacheKey);
@@ -29,8 +31,9 @@ async function loadTools(openapiUrl: string, filterTag: string, forceRefresh = f
return cached.tools; return cached.tools;
} }
console.log(`[MCP] 🔄 Refreshing tools from ${openapiUrl} ...`); console.log(`[MCP] 🔄 Refreshing tools from ${openapiUrl} with filter '${normalizedFilterKey}' ...`);
const fetched = await getMcpTools(openapiUrl, filterTag); // Pass through filterTag in original shape (string | string[]) to getMcpTools.
const fetched = await getMcpTools(openapiUrl, filterTag as any);
console.log(`[MCP] ✅ Loaded ${fetched.length} tools`); console.log(`[MCP] ✅ Loaded ${fetched.length} tools`);
if (fetched.length > 0) { if (fetched.length > 0) {
@@ -369,18 +372,18 @@ export class OpenapiMcpServer implements INodeType {
}, },
// ====================================================== // ======================================================
// ⬇⬇⬇ UPDATED: Default Filter menjadi dropdown tag // ⬇⬇⬇ UPDATED: Default Filter sekarang multi-select (multiOptions)
// ====================================================== // ======================================================
{ {
displayName: 'Default Filter', displayName: 'Default Filter',
name: 'defaultFilter', name: 'defaultFilter',
type: 'options', type: 'multiOptions', // <-- multi-select
typeOptions: { typeOptions: {
loadOptionsMethod: 'loadAvailableTags', loadOptionsMethod: 'loadAvailableTags',
refreshOnOpen: true, refreshOnOpen: true,
}, },
default: 'all', default: [], // empty means no tag filtering (or 'All' in loader)
description: 'Filter berdasarkan tag dari OpenAPI', description: 'Filter berdasarkan tag dari OpenAPI (multi-select supported)',
}, },
// ====================================================== // ======================================================
@@ -393,7 +396,7 @@ export class OpenapiMcpServer implements INodeType {
refreshOnOpen: true, refreshOnOpen: true,
}, },
default: 'all', default: 'all',
description: 'Daftar tools yang berhasil dimuat dari OpenAPI', description: 'Daftar tools yang berhasil dimuat dari OpenAPI (tergantung Default Filter)',
}, },
], ],
}; };
@@ -404,7 +407,7 @@ export class OpenapiMcpServer implements INodeType {
methods = { methods = {
loadOptions: { loadOptions: {
// ======================================================== // ========================================================
// ⬇⬇⬇ NEW: dropdown tag loader // ⬇⬇⬇ NEW: dropdown tag loader (unchanged)
// ======================================================== // ========================================================
async loadAvailableTags(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async loadAvailableTags(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const openapiUrl = this.getNodeParameter("openapiUrl", 0) as string; const openapiUrl = this.getNodeParameter("openapiUrl", 0) as string;
@@ -426,6 +429,7 @@ export class OpenapiMcpServer implements INodeType {
const unique = Array.from(new Set(tags)); const unique = Array.from(new Set(tags));
// include an "All" option; users can still select none (empty array) which we'll treat as "all"
return [ return [
{ name: "All", value: "all" }, { name: "All", value: "all" },
...unique.map((t) => ({ ...unique.map((t) => ({
@@ -440,15 +444,19 @@ export class OpenapiMcpServer implements INodeType {
}, },
// ======================================================== // ========================================================
// ========================================================
// ⬇⬇⬇ UPDATED: refreshToolList now reads multi-select defaultFilter (string | string[])
// ========================================================
async refreshToolList(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async refreshToolList(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const openapiUrl = this.getNodeParameter("openapiUrl", 0) as string; const openapiUrl = this.getNodeParameter("openapiUrl", 0) as string;
const filterTag = this.getNodeParameter("defaultFilter", 0) as string; const filterTag = this.getNodeParameter("defaultFilter", 0) as string | string[]; // may be array
if (!openapiUrl) { if (!openapiUrl) {
return [{ name: "❌ No OpenAPI URL provided", value: "" }]; return [{ name: "❌ No OpenAPI URL provided", value: "" }];
} }
const tools = await loadTools(openapiUrl, filterTag, true); // Pass the filterTag in its native shape to loadTools
const tools = await loadTools(openapiUrl, filterTag as any, true);
return [ return [
{ name: "All Tools", value: "all" }, { name: "All Tools", value: "all" },
@@ -459,6 +467,7 @@ export class OpenapiMcpServer implements INodeType {
})), })),
]; ];
}, },
// ========================================================
}, },
}; };
@@ -467,9 +476,9 @@ export class OpenapiMcpServer implements INodeType {
// ================================================== // ==================================================
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> { async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
const openapiUrl = this.getNodeParameter("openapiUrl", 0) as string; const openapiUrl = this.getNodeParameter("openapiUrl", 0) as string;
const filterTag = this.getNodeParameter("defaultFilter", 0) as string; const filterTag = this.getNodeParameter("defaultFilter", 0) as string | string[]; // multi-select support
const tools = await loadTools(openapiUrl, filterTag, false); const tools = await loadTools(openapiUrl, filterTag as any, false);
const creds = await this.getCredentials("openapiMcpServerCredentials") as { const creds = await this.getCredentials("openapiMcpServerCredentials") as {
baseUrl: string; baseUrl: string;

View File

@@ -1,6 +1,6 @@
{ {
"name": "n8n-nodes-openapi-mcp-server", "name": "n8n-nodes-openapi-mcp-server",
"version": "1.1.31", "version": "1.1.32",
"keywords": [ "keywords": [
"n8n", "n8n",
"n8n-nodes" "n8n-nodes"