Skip to main content
Glama
auto-browse

Unbundle OpenAPI Specs MCP

by auto-browse

extract_openapi_endpoints

Extract specific endpoints from a large OpenAPI definition file to create a smaller, focused API specification. Input the path to the original file, list endpoints to keep, and save the condensed output for targeted use.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
endpointsToKeepYesList of exact endpoint paths to keep (e.g., ['/users', '/users/{id}']).
inputApiPathYesAbsolute path to the large input OpenAPI definition file.
outputApiPathYesAbsolute path where the final, smaller bundled OpenAPI file should be saved.

Implementation Reference

  • Handler function for 'extract_openapi_endpoints' tool. Creates temp dir, splits OpenAPI using redocly, parses YAML, filters specified endpoints, rewrites YAML, bundles to output path, cleans up temp dir.
    async ({ inputApiPath, endpointsToKeep, outputApiPath }, extra) => { let tempDir: string | undefined; try { // 1. Create a temporary directory tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openapi-extract-')); // Generic temp prefix console.error(`Created temp directory: ${tempDir}`); // 2. Split the input API into the temporary directory const splitCommand = `npx @redocly/cli@latest split "${inputApiPath}" --outDir="${tempDir}"`; console.error(`Executing split command: ${splitCommand}`); const { stdout: splitStdout, stderr: splitStderr } = await exec(splitCommand); if (splitStderr) { console.error("Split stderr:", splitStderr); } console.error("Split stdout:", splitStdout); // 3. Read the main openapi.yaml from the temporary directory const tempApiFilePath = path.join(tempDir, 'openapi.yaml'); // Default name used by split console.error(`Reading temporary API file: ${tempApiFilePath}`); const tempApiContent = await fs.readFile(tempApiFilePath, 'utf-8'); // 4. Parse the YAML const apiDoc: any = yaml.load(tempApiContent); if (!apiDoc || typeof apiDoc !== 'object' || !apiDoc.paths) { throw new Error('Invalid OpenAPI structure found after split.'); } // 5. Filter the paths console.error(`Filtering paths, keeping: ${endpointsToKeep.join(', ')}`); const originalPaths = apiDoc.paths; const filteredPaths: { [key: string]: any; } = {}; let pathsKept = 0; for (const pathKey in originalPaths) { if (endpointsToKeep.includes(pathKey)) { filteredPaths[pathKey] = originalPaths[pathKey]; pathsKept++; } } if (pathsKept === 0) { console.warn("Warning: No paths matched the endpointsToKeep list. The output file might be empty or invalid."); } else if (pathsKept < endpointsToKeep.length) { console.warn(`Warning: Only ${pathsKept} out of ${endpointsToKeep.length} specified endpoints were found in the original spec.`); } apiDoc.paths = filteredPaths; // 6. Write the modified YAML back const modifiedYamlContent = yaml.dump(apiDoc); console.error(`Writing modified API file back to: ${tempApiFilePath}`); await fs.writeFile(tempApiFilePath, modifiedYamlContent, 'utf-8'); // 7. Bundle the modified API to the final output path // Ensure the output directory exists const outputDir = path.dirname(outputApiPath); await fs.mkdir(outputDir, { recursive: true }); const bundleCommand = `npx @redocly/cli@latest bundle "${tempApiFilePath}" -o "${outputApiPath}"`; console.error(`Executing bundle command: ${bundleCommand}`); const { stdout: bundleStdout, stderr: bundleStderr } = await exec(bundleCommand); if (bundleStderr) { console.error("Bundle stderr:", bundleStderr); } console.error("Bundle stdout:", bundleStdout); return { content: [{ type: "text", text: `Successfully extracted endpoints and saved to ${outputApiPath}\n${bundleStdout}` }] }; } catch (error: any) { console.error("Extraction process failed:", error); const errorMessage = error.stderr || error.stdout || error.message || "Unknown error occurred during extraction"; return { content: [{ type: "text", text: `Error: ${errorMessage}` }], isError: true }; } finally { // 8. Clean up the temporary directory if (tempDir) { try { console.error(`Cleaning up temp directory: ${tempDir}`); await fs.rm(tempDir, { recursive: true, force: true }); } catch (cleanupError) { console.error(`Failed to clean up temp directory ${tempDir}:`, cleanupError); // Log cleanup error but don't let it mask the primary error } } } }
  • Zod schema defining input arguments for the extract_openapi_endpoints tool: inputApiPath, endpointsToKeep array, outputApiPath.
    const ExtractOpenApiEndpointsArgsSchema = z.object({ inputApiPath: z.string().describe("Absolute path to the large input OpenAPI definition file."), endpointsToKeep: z.array(z.string()).describe("List of exact endpoint paths to keep (e.g., ['/users', '/users/{id}'])."), outputApiPath: z.string().describe("Absolute path where the final, smaller bundled OpenAPI file should be saved.") });
  • src/index.ts:80-182 (registration)
    Registration of the 'extract_openapi_endpoints' tool using server.tool(), providing name, input schema, and inline handler function.
    // Register the 'extract_openapi_endpoints' tool server.tool( "extract_openapi_endpoints", // Renamed tool ExtractOpenApiEndpointsArgsSchema.shape, // Use renamed schema variable async ({ inputApiPath, endpointsToKeep, outputApiPath }, extra) => { let tempDir: string | undefined; try { // 1. Create a temporary directory tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openapi-extract-')); // Generic temp prefix console.error(`Created temp directory: ${tempDir}`); // 2. Split the input API into the temporary directory const splitCommand = `npx @redocly/cli@latest split "${inputApiPath}" --outDir="${tempDir}"`; console.error(`Executing split command: ${splitCommand}`); const { stdout: splitStdout, stderr: splitStderr } = await exec(splitCommand); if (splitStderr) { console.error("Split stderr:", splitStderr); } console.error("Split stdout:", splitStdout); // 3. Read the main openapi.yaml from the temporary directory const tempApiFilePath = path.join(tempDir, 'openapi.yaml'); // Default name used by split console.error(`Reading temporary API file: ${tempApiFilePath}`); const tempApiContent = await fs.readFile(tempApiFilePath, 'utf-8'); // 4. Parse the YAML const apiDoc: any = yaml.load(tempApiContent); if (!apiDoc || typeof apiDoc !== 'object' || !apiDoc.paths) { throw new Error('Invalid OpenAPI structure found after split.'); } // 5. Filter the paths console.error(`Filtering paths, keeping: ${endpointsToKeep.join(', ')}`); const originalPaths = apiDoc.paths; const filteredPaths: { [key: string]: any; } = {}; let pathsKept = 0; for (const pathKey in originalPaths) { if (endpointsToKeep.includes(pathKey)) { filteredPaths[pathKey] = originalPaths[pathKey]; pathsKept++; } } if (pathsKept === 0) { console.warn("Warning: No paths matched the endpointsToKeep list. The output file might be empty or invalid."); } else if (pathsKept < endpointsToKeep.length) { console.warn(`Warning: Only ${pathsKept} out of ${endpointsToKeep.length} specified endpoints were found in the original spec.`); } apiDoc.paths = filteredPaths; // 6. Write the modified YAML back const modifiedYamlContent = yaml.dump(apiDoc); console.error(`Writing modified API file back to: ${tempApiFilePath}`); await fs.writeFile(tempApiFilePath, modifiedYamlContent, 'utf-8'); // 7. Bundle the modified API to the final output path // Ensure the output directory exists const outputDir = path.dirname(outputApiPath); await fs.mkdir(outputDir, { recursive: true }); const bundleCommand = `npx @redocly/cli@latest bundle "${tempApiFilePath}" -o "${outputApiPath}"`; console.error(`Executing bundle command: ${bundleCommand}`); const { stdout: bundleStdout, stderr: bundleStderr } = await exec(bundleCommand); if (bundleStderr) { console.error("Bundle stderr:", bundleStderr); } console.error("Bundle stdout:", bundleStdout); return { content: [{ type: "text", text: `Successfully extracted endpoints and saved to ${outputApiPath}\n${bundleStdout}` }] }; } catch (error: any) { console.error("Extraction process failed:", error); const errorMessage = error.stderr || error.stdout || error.message || "Unknown error occurred during extraction"; return { content: [{ type: "text", text: `Error: ${errorMessage}` }], isError: true }; } finally { // 8. Clean up the temporary directory if (tempDir) { try { console.error(`Cleaning up temp directory: ${tempDir}`); await fs.rm(tempDir, { recursive: true, force: true }); } catch (cleanupError) { console.error(`Failed to clean up temp directory ${tempDir}:`, cleanupError); // Log cleanup error but don't let it mask the primary error } } } } );
Install Server

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/auto-browse/unbundle_openapi_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server