fix: graceful fallback for specs with broken $refs

- parseSpec now tries dereference first, falls back to parse on failure
- Shows warning when spec has broken references
- Tested with Moravia Symfonie API (293 paths, 381 operations)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
rimskij 2026-01-12 14:55:26 +01:00
parent 641a9e56dc
commit 409194781e
2 changed files with 26 additions and 5 deletions

View file

@ -4,13 +4,30 @@ import type { ParsedSpec, OpenAPISpec } from './types.js';
const HTTP_METHODS = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] as const;
export async function parseSpec(specPath: string): Promise<{
export async function parseSpec(specPath: string, options?: { dereference?: boolean }): Promise<{
spec: OpenAPISpec;
metadata: ParsedSpec;
dereferenced: boolean;
}> {
const spec = await SwaggerParser.dereference(specPath);
const shouldDereference = options?.dereference !== false;
let spec: OpenAPISpec;
let dereferenced = false;
if (shouldDereference) {
try {
spec = await SwaggerParser.dereference(specPath);
dereferenced = true;
} catch {
// Fallback to parse without dereferencing if refs are broken
spec = await SwaggerParser.parse(specPath);
}
} else {
spec = await SwaggerParser.parse(specPath);
}
const metadata = extractMetadata(spec);
return { spec, metadata };
return { spec, metadata, dereferenced };
}
export async function bundleSpec(specPath: string): Promise<OpenAPISpec> {

View file

@ -15,15 +15,19 @@ export async function parseToolHandler({ path }: { path: string }): Promise<{
structuredContent: Record<string, unknown>;
}> {
try {
const { spec, metadata } = await parseSpec(path);
const { spec, metadata, dereferenced } = await parseSpec(path);
const text = formatMetadata(metadata);
let text = formatMetadata(metadata);
if (!dereferenced) {
text += '\n\n**Warning**: Spec has broken $refs. Parsed without dereferencing.';
}
return {
content: [{ type: 'text', text }],
structuredContent: {
success: true,
metadata,
dereferenced,
spec,
},
};