diff --git a/README.md b/README.md index b80e974..9002fe2 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A Model Context Protocol (MCP) server that exposes OpenAPI schema information to ## Features -- Load any OpenAPI schema file (JSON or YAML) specified via command line argument +- Load OpenAPI schema from a **local file path** or **URL** (JSON or YAML) via command line argument - Explore API paths, operations, parameters, and schemas - View detailed request and response schemas - Look up component definitions and examples @@ -15,18 +15,20 @@ A Model Context Protocol (MCP) server that exposes OpenAPI schema information to ### Command Line -Run the MCP server with a specific schema file: +Run the MCP server with a local schema file or a remote URL: ```bash # Use the default openapi.yaml in current directory npx -y mcp-openapi-schema -# Use a specific schema file (relative path) +# Use a local schema file (relative or absolute path) npx -y mcp-openapi-schema ../petstore.json - -# Use a specific schema file (absolute path) npx -y mcp-openapi-schema /absolute/path/to/api-spec.yaml +# Use a remote schema URL +npx -y mcp-openapi-schema https://example.com/openapi.yaml +npx -y mcp-openapi-schema https://petstore3.swagger.io/api/v3/openapi.json + # Show help npx -y mcp-openapi-schema --help ``` @@ -41,6 +43,10 @@ To use this MCP server with Claude Desktop, edit your `claude_desktop_config.jso "OpenAPI Schema": { "command": "npx", "args": ["-y", "mcp-openapi-schema", "/ABSOLUTE/PATH/TO/openapi.yaml"] + }, + "Petstore API (URL)": { + "command": "npx", + "args": ["-y", "mcp-openapi-schema", "https://petstore3.swagger.io/api/v3/openapi.json"] } } } @@ -61,8 +67,11 @@ To use this MCP server with Claude Code CLI, follow these steps: # Basic syntax claude mcp add openapi-schema npx -y mcp-openapi-schema - # Example with specific schema + # Example with local schema file claude mcp add petstore-api npx -y mcp-openapi-schema ~/Projects/petstore.yaml + + # Example with remote schema URL + claude mcp add petstore-remote npx -y mcp-openapi-schema https://petstore3.swagger.io/api/v3/openapi.json ``` 2. **Verify the MCP server is registered** diff --git a/example-usage.mjs b/example-usage.mjs index 65fe4ba..9c177e2 100644 --- a/example-usage.mjs +++ b/example-usage.mjs @@ -7,12 +7,15 @@ import { fileURLToPath } from "url"; const __dirname = dirname(fileURLToPath(import.meta.url)); -// Set up the MCP client to communicate with our server +// Set up the MCP client to communicate with our server. +// You can pass a local path (YAML/JSON) or a URL: +// args: [resolve(__dirname, "index.mjs"), resolve(__dirname, "./sample-petstore.yaml")] +// args: [resolve(__dirname, "index.mjs"), "https://petstore3.swagger.io/api/v3/openapi.json"] const transport = new StdioClientTransport({ command: "node", args: [ resolve(__dirname, "index.mjs"), - resolve(__dirname, "./sample-petstore.yaml") + resolve(__dirname, "./sample-petstore.yaml"), ], }); diff --git a/index.mjs b/index.mjs index 10032e4..a330b2d 100755 --- a/index.mjs +++ b/index.mjs @@ -18,28 +18,36 @@ if (args.includes("--help") || args.includes("-h")) { OpenAPI Schema Model Context Protocol Server Usage: - node index.mjs [path/to/openapi.yaml] + node index.mjs [path-or-url] Arguments: - path/to/openapi.yaml Path to the OpenAPI schema file (JSON or YAML) (optional) - If not provided, defaults to openapi.yaml + path-or-url Path to a local OpenAPI file (JSON or YAML), or URL to a remote schema (optional). + If not provided, defaults to openapi.yaml Examples: - node index.mjs # Uses default openapi.yaml - node index.mjs ../petstore.json # Uses petstore OpenAPI spec + node index.mjs + node index.mjs ../petstore.json node index.mjs /absolute/path/to/api-schema.yaml + node index.mjs https://example.com/openapi.yaml + node index.mjs https://petstore3.swagger.io/api/v3/openapi.json `); process.exit(0); } const schemaArg = args[0]; +/** Returns true if the given string looks like an HTTP(S) URL. */ +const isUrl = (s) => typeof s === "string" && /^https?:\/\//i.test(s.trim()); + const loadSchema = async () => { - // Default to openapi.yaml if no argument provided - const schemaPath = resolve(schemaArg ?? "openapi.yaml"); + const defaultPath = "openapi.yaml"; + const schemaInput = schemaArg ?? defaultPath; try { - // Parse and validate the OpenAPI document + if (isUrl(schemaInput)) { + return await SwaggerParser.validate(schemaInput.trim(), { validate: { schema: false } }); + } + const schemaPath = resolve(schemaInput); return await SwaggerParser.validate(schemaPath, { validate: { schema: false } }); } catch (error) { console.error(`Error loading schema: ${error.message}`); @@ -49,14 +57,23 @@ const loadSchema = async () => { const openApiDoc = await loadSchema(); -// Extract schema name from file path or from the OpenAPI info +// Extract schema name from OpenAPI info, or from path/URL (e.g. path/to/openapi.yaml or https://host/spec.json) const schemaName = openApiDoc.info?.title || (schemaArg - ? schemaArg - .split("/") - .pop() - .replace(/\.(yaml|json)$/i, "") + ? (() => { + const s = schemaArg.trim(); + if (isUrl(s)) { + try { + const pathname = new URL(s).pathname; + const base = pathname.split("/").filter(Boolean).pop() || "openapi"; + return base.replace(/\.(yaml|yml|json)$/i, "") || "openapi"; + } catch { + return "openapi"; + } + } + return s.split("/").pop().replace(/\.(yaml|yml|json)$/i, "") || "openapi"; + })() : "openapi"); const server = new McpServer({