@mseep/mcp-openapi-schema-explorer
Version:
MCP OpenAPI schema explorer
72 lines • 3.55 kB
JavaScript
import { ResourceTemplate, } from '@modelcontextprotocol/sdk/server/mcp.js';
import { RenderableDocument } from '../rendering/document.js';
import { RenderablePaths } from '../rendering/paths.js';
import { RenderableComponents } from '../rendering/components.js';
import { createErrorResult } from '../rendering/utils.js';
// Import shared handler utils
import { formatResults, isOpenAPIV3 } from './handler-utils.js'; // Already has .js
const BASE_URI = 'openapi://';
// Removed duplicated FormattedResultItem type - now imported from handler-utils
// Removed duplicated formatResults function - now imported from handler-utils
/**
* Handles requests for top-level OpenAPI fields (info, servers, paths list, components list).
* Corresponds to the `openapi://{field}` template.
*/
export class TopLevelFieldHandler {
constructor(specLoader, formatter) {
this.specLoader = specLoader;
this.formatter = formatter;
this.handleRequest = async (uri, variables
// matchedTemplate is not needed if we only handle one template
) => {
// Return type uses the defined array structure
const field = variables.field;
const context = { formatter: this.formatter, baseUri: BASE_URI };
let resultItems;
try {
const spec = await this.specLoader.getTransformedSpec({
// Use 'schema' as placeholder resourceType for transformation context
resourceType: 'schema',
format: 'openapi',
});
// Use imported type guard
if (!isOpenAPIV3(spec)) {
throw new Error('Only OpenAPI v3 specifications are supported');
}
const renderableDoc = new RenderableDocument(spec);
// Route based on the field name
if (field === 'paths') {
const pathsObj = renderableDoc.getPathsObject();
resultItems = new RenderablePaths(pathsObj).renderList(context);
}
else if (field === 'components') {
const componentsObj = renderableDoc.getComponentsObject();
resultItems = new RenderableComponents(componentsObj).renderList(context);
}
else {
// Handle other top-level fields (info, servers, tags, etc.)
const fieldObject = renderableDoc.getTopLevelField(field);
resultItems = renderableDoc.renderTopLevelFieldDetail(context, fieldObject, field);
}
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
console.error(`Error handling request ${uri.href}: ${message}`);
resultItems = createErrorResult(field, message); // Use field as uriSuffix for error
}
// Format results into the final structure
const contents = formatResults(context, resultItems);
// Return the object with the correctly typed contents array
// Use imported formatResults
return { contents };
};
}
getTemplate() {
// TODO: Add completion logic if needed
return new ResourceTemplate(`${BASE_URI}{field}`, {
list: undefined,
complete: undefined,
});
}
} // Ensure class closing brace is present
//# sourceMappingURL=top-level-field-handler.js.map