import fs from 'node:fs'
import path from 'node:path'
import { OpenAPIV3 } from 'openapi-types'
import OpenAPISchemaValidator from 'openapi-schema-validator'
import { log } from 'apify'
import { MCPProxy } from './openapi-mcp-server/mcp/proxy.js'
export class ValidationError extends Error {
constructor(public errors: any[]) {
super('OpenAPI validation failed')
this.name = 'ValidationError'
}
}
async function loadOpenApiSpec(specPath: string, baseUrl: string | undefined): Promise<OpenAPIV3.Document> {
let rawSpec: string
try {
rawSpec = fs.readFileSync(path.resolve(process.cwd(), specPath), 'utf-8')
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error)
log.error(`Failed to read OpenAPI specification file: ${errorMessage}`)
throw new Error(`Failed to read OpenAPI specification file: ${errorMessage}`)
}
// Parse and validate the OpenApi Spec
try {
const parsed = JSON.parse(rawSpec) as OpenAPIV3.Document
// Override baseUrl if specified.
if (baseUrl && parsed.servers && Array.isArray(parsed.servers) && parsed.servers.length > 0) {
parsed.servers[0].url = baseUrl
} else if (baseUrl) {
// If no servers array exists, create one
parsed.servers = [{ url: baseUrl }]
}
return parsed
} catch (error) {
if (error instanceof ValidationError) {
throw error
}
const errorMessage = error instanceof Error ? error.message : String(error)
log.error(`Failed to parse OpenAPI spec: ${errorMessage}`)
throw new Error(`Failed to parse OpenAPI spec: ${errorMessage}`)
}
}
export async function initProxy(specPath: string, baseUrl: string |undefined) {
const openApiSpec = await loadOpenApiSpec(specPath, baseUrl)
const proxy = new MCPProxy('Notion API', openApiSpec)
return proxy
}