@powerduck/openapi-mcp-server 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Powerduck limited
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,92 +1,423 @@
1
- A production-oriented TypeScript library and runtime that converts OpenAPI documents into MCP services.
1
+ # @powerduck/openapi-mcp-server
2
2
 
3
- ## Features
3
+ Turn any OpenAPI 3.2 document into a fully functional MCP (Model Context Protocol) server. Automatically generates tools, prompts, and resources from your API spec. Supports both stdio and HTTP (SSE) transports.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@powerduck/openapi-mcp-server)](https://www.npmjs.com/package/@powerduck/openapi-mcp-server)
6
+ [![license](https://img.shields.io/npm/l/@powerduck/openapi-mcp-server)](https://github.com/PowerDuckie/openapi-mcp-server/blob/main/LICENSE)
7
+
8
+ ## Links
9
+
10
+ - [Official Website](https://www.powerduck.com/opensource/openapi-mcp-server.html)
11
+ - [Documentation](https://www.powerduck.com/docs/openapi-mcp-server/introduction)
12
+ - [Live Demo](https://www.powerduck.com/demo/openapi-mcp-server.html)
13
+ - [GitHub](https://github.com/PowerDuckie/openapi-mcp-server)
14
+ - [npm](https://www.npmjs.com/package/@powerduck/openapi-mcp-server)
4
15
 
5
- - Tools generated from OpenAPI operations
6
- - Prompts generated from API metadata and operations
7
- - Resources generated from the OpenAPI catalog
8
- - HTTP and STDIO MCP transports
9
- - Admin Web UI
10
- - Persistent runtime state
11
- - Stronger validation and safer request execution
12
- - Production-oriented structure for future SaaS evolution
16
+ ---
13
17
 
14
- ## Install
18
+ ## Quick Start
19
+
20
+ ### Install
15
21
 
16
22
  ```bash
17
- npm i @powerduck/openapi-mcp-server
23
+ npm install @powerduck/openapi-mcp-server
18
24
  ```
19
25
 
20
- ## Start web runtime
26
+ ### Run as a stdio server (CLI)
21
27
 
22
28
  ```bash
23
- npm run start -- serve --port 3000 --host 127.0.0.1
29
+ npx @powerduck/openapi-mcp-server serve --spec ./openapi.json
24
30
  ```
25
31
 
26
- ## Start STDIO runtime
32
+ ### Run as an HTTP server (CLI)
27
33
 
28
34
  ```bash
29
- node dist/cli.js serve --transport stdio --spec ./openapi.yaml
35
+ npx @powerduck/openapi-mcp-server serve \
36
+ --spec ./openapi.json \
37
+ --transport http \
38
+ --port 3000 \
39
+ --route-prefix /mcp
30
40
  ```
31
41
 
32
- ## CLI usage
42
+ ### Programmatic stdio server
33
43
 
34
- ### Web mode
44
+ ```typescript
45
+ import { startStdioServer } from "@powerduck/openapi-mcp-server";
35
46
 
36
- ```bash
37
- openapi-mcp serve \
38
- --transport web \
39
- --port 3000 \
40
- --host 127.0.0.1 \
41
- --api-key your-admin-key
47
+ await startStdioServer({
48
+ specPath: "./openapi.json",
49
+ serverName: "My API MCP Server",
50
+ serverVersion: "1.0.0",
51
+ });
42
52
  ```
43
53
 
44
- ### STDIO mode
54
+ ### Programmatic HTTP server (Express)
45
55
 
46
- ```bash
47
- openapi-mcp serve \
48
- --transport stdio \
49
- --spec ./openapi.yaml \
50
- --base-url https://api.example.com
56
+ ```typescript
57
+ import express from "express";
58
+ import { attachSseRoutes } from "@powerduck/openapi-mcp-server";
59
+
60
+ const app = express();
61
+
62
+ attachSseRoutes(
63
+ app,
64
+ () => "./openapi.json", // spec provider: path, URL, or parsed document
65
+ () => ({ userId: "user-123" }), // context provider (optional)
66
+ (req) => req.headers["x-api-key"] === "secret", // route guard (optional)
67
+ );
68
+
69
+ app.listen(3000, () => {
70
+ console.log("MCP SSE server running at http://localhost:3000/mcp");
71
+ });
72
+ ```
73
+
74
+ ### Generate tools from a spec
75
+
76
+ ```typescript
77
+ import { loadOpenApiSpec, generateTools } from "@powerduck/openapi-mcp-server";
78
+
79
+ const spec = await loadOpenApiSpec("./openapi.json");
80
+ const tools = generateTools(spec);
81
+
82
+ console.log(`Generated ${tools.length} tools:`);
83
+ for (const tool of tools) {
84
+ console.log(`- ${tool.name}: ${tool.description}`);
85
+ }
86
+ ```
87
+
88
+ ---
89
+
90
+ ## Features
91
+
92
+ - **Automatic tool generation** — every operation becomes an MCP tool with a JSON Schema input schema derived from parameters and request body
93
+ - **Prompt generation** — operations with `x-mcp-prompt` become MCP prompts with templated messages
94
+ - **Resource generation** — operations marked with `x-mcp-resource` become readable MCP resources
95
+ - **Two transports** — stdio for local CLI tools and IDEs, HTTP (SSE) for remote servers and web clients
96
+ - **Authentication** — Bearer token, API key, and custom auth middleware for HTTP transport
97
+ - **Admin server** — optional REST admin API for health checks, spec reload, and diagnostics
98
+ - **Context injection** — per-request context provider for user IDs, tenant info, etc.
99
+ - **Route guards** — custom authorization function for HTTP transport
100
+ - **Spec loading** — load from file path, URL, or parsed object; JSON and YAML supported
101
+ - **Built on `@powerduck/openapi-request`** — full OpenAPI parameter serialization for tool execution
102
+ - **Dual ESM/CJS builds** — works with `import` and `require`
103
+
104
+ ---
105
+
106
+ ## CLI Usage
107
+
108
+ ```
109
+ openapi-mcp serve [options]
110
+
111
+ Options:
112
+ --spec <path> Path or URL to OpenAPI 3.2 spec (required)
113
+ --transport <mode> Transport mode: stdio or http (default: stdio)
114
+ --port <number> HTTP server port (default: 3000)
115
+ --host <string> HTTP server host (default: 0.0.0.0)
116
+ --route-prefix <path> HTTP route prefix for MCP endpoints (default: /mcp)
117
+ --server-name <name> MCP server name (default: OpenAPI MCP Server)
118
+ --server-version <ver> MCP server version (default: 1.0.0)
119
+ --admin Enable admin REST API
120
+ --admin-port <number> Admin server port (default: 3001)
121
+ --auth-type <type> Auth type: bearer, apikey, or none (default: none)
122
+ --auth-token <token> Bearer token or API key value
123
+ --auth-header <name> API key header name (default: x-api-key)
124
+ -h, --help Show help
125
+ -v, --version Show version
126
+ ```
127
+
128
+ ---
129
+
130
+ ## MCP Extensions
131
+
132
+ Control how operations are exposed to MCP clients using OpenAPI extensions:
133
+
134
+ ### `x-mcp-tool`
135
+
136
+ Mark an operation as an MCP tool (all operations are tools by default):
137
+
138
+ ```json
139
+ {
140
+ "paths": {
141
+ "/users/{id}": {
142
+ "get": {
143
+ "operationId": "getUser",
144
+ "x-mcp-tool": {
145
+ "name": "get_user",
146
+ "description": "Fetch a user by ID"
147
+ }
148
+ }
149
+ }
150
+ }
151
+ }
152
+ ```
153
+
154
+ ### `x-mcp-prompt`
155
+
156
+ Mark an operation as an MCP prompt:
157
+
158
+ ```json
159
+ {
160
+ "paths": {
161
+ "/search": {
162
+ "get": {
163
+ "operationId": "search",
164
+ "x-mcp-prompt": {
165
+ "name": "search_docs",
166
+ "description": "Search the documentation",
167
+ "arguments": [
168
+ { "name": "query", "description": "Search query", "required": true }
169
+ ],
170
+ "messages": [
171
+ { "role": "user", "content": "Search for: {{query}}" }
172
+ ]
173
+ }
174
+ }
175
+ }
176
+ }
177
+ }
178
+ ```
179
+
180
+ ### `x-mcp-resource`
181
+
182
+ Mark an operation as a readable MCP resource:
183
+
184
+ ```json
185
+ {
186
+ "paths": {
187
+ "/docs/{slug}": {
188
+ "get": {
189
+ "operationId": "getDoc",
190
+ "x-mcp-resource": {
191
+ "uriTemplate": "docs://{slug}",
192
+ "name": "Documentation page",
193
+ "mimeType": "text/markdown"
194
+ }
195
+ }
196
+ }
197
+ }
198
+ }
51
199
  ```
52
200
 
53
- ## Production notes
201
+ ### `x-mcp-ignore`
202
+
203
+ Exclude an operation from MCP entirely:
204
+
205
+ ```json
206
+ {
207
+ "paths": {
208
+ "/internal/debug": {
209
+ "get": {
210
+ "x-mcp-ignore": true
211
+ }
212
+ }
213
+ }
214
+ }
215
+ ```
216
+
217
+ ---
218
+
219
+ ## Programmatic API
220
+
221
+ ### `loadOpenApiSpec(input)`
222
+
223
+ Loads an OpenAPI spec from a file path, URL, or parsed object. Returns the parsed document.
224
+
225
+ ```typescript
226
+ const spec = await loadOpenApiSpec("./openapi.json");
227
+ const specFromUrl = await loadOpenApiSpec("https://api.example.com/openapi.json");
228
+ const specFromObject = await loadOpenApiSpec({ openapi: "3.2.0", ... });
229
+ ```
230
+
231
+ ### `generateTools(spec)`
232
+
233
+ Generates an array of MCP tool definitions from the spec.
234
+
235
+ ### `generateToolsDetailed(spec)`
236
+
237
+ Generates tools with additional metadata (operationId, path, method).
238
+
239
+ ### `generatePrompts(spec)`
54
240
 
55
- This version is production-oriented, but you should still add the following for SaaS deployment:
241
+ Generates MCP prompt definitions from operations with `x-mcp-prompt`.
56
242
 
57
- - tenant isolation
58
- - database-backed project registry
59
- - rate limits
60
- - audit logs
61
- - RBAC
62
- - secure secret storage
63
- - upstream host allowlists
64
- - comprehensive test suites
65
- - full OpenAPI parameter serialization coverage
66
- - full requestBody content negotiation support
243
+ ### `generateResources(spec)`
67
244
 
68
- ## Project structure
245
+ Generates MCP resource definitions from operations with `x-mcp-resource`.
246
+
247
+ ### `executeToolCall(spec, toolName, arguments, context?)`
248
+
249
+ Executes a tool by name, passing the arguments and optional context. Returns the tool result.
250
+
251
+ ### `buildMcpServer(options)`
252
+
253
+ Builds an MCP server instance (transport-agnostic).
254
+
255
+ ### `startStdioServer(options)`
256
+
257
+ Starts a stdio MCP server. Blocks until the server is closed.
258
+
259
+ ### `attachSseRoutes(app, specProvider, contextProvider?, routeGuard?)`
260
+
261
+ Attaches MCP SSE routes to an Express-compatible app. This is the public API for HTTP transport.
262
+
263
+ | Parameter | Type | Description |
264
+ |---|---|---|
265
+ | `app` | `Express` | Express app instance |
266
+ | `specProvider` | `() => string \| object \| Promise<string \| object>` | Returns spec path, URL, or parsed document |
267
+ | `contextProvider` | `(req) => Record<string, unknown> \| Promise<Record<string, unknown>>` | Optional. Returns per-request context |
268
+ | `routeGuard` | `(req) => boolean \| Promise<boolean>` | Optional. Returns true if the request is authorized |
269
+
270
+ ### `startAdminServer(options)`
271
+
272
+ Starts an optional admin REST API server for health checks and diagnostics.
273
+
274
+ ---
275
+
276
+ ## Authentication
277
+
278
+ ### Bearer token (HTTP)
279
+
280
+ ```typescript
281
+ import { createAuthMiddleware } from "@powerduck/openapi-mcp-server";
282
+
283
+ app.use("/mcp", createAuthMiddleware({
284
+ type: "bearer",
285
+ token: "your-secret-token",
286
+ }));
287
+ ```
288
+
289
+ ### API key (HTTP)
290
+
291
+ ```typescript
292
+ app.use("/mcp", createAuthMiddleware({
293
+ type: "apikey",
294
+ token: "your-api-key",
295
+ headerName: "x-api-key",
296
+ }));
297
+ ```
298
+
299
+ ### Custom auth
300
+
301
+ Use the `routeGuard` parameter of `attachSseRoutes`:
302
+
303
+ ```typescript
304
+ attachSseRoutes(
305
+ app,
306
+ specProvider,
307
+ contextProvider,
308
+ (req) => {
309
+ return verifyJwt(req.headers.authorization);
310
+ },
311
+ );
312
+ ```
313
+
314
+ ---
315
+
316
+ ## Context Injection
317
+
318
+ Pass per-request context (user ID, tenant, etc.) to tool executions:
319
+
320
+ ```typescript
321
+ attachSseRoutes(
322
+ app,
323
+ () => "./openapi.json",
324
+ (req) => ({
325
+ userId: req.headers["x-user-id"],
326
+ tenantId: req.headers["x-tenant-id"],
327
+ }),
328
+ );
329
+ ```
330
+
331
+ The context is available in tool execution and can be used for authorization or data scoping.
332
+
333
+ ---
334
+
335
+ ## Admin Server
336
+
337
+ Enable the admin REST API with `--admin` or programmatically:
338
+
339
+ ```typescript
340
+ import { startAdminServer } from "@powerduck/openapi-mcp-server";
341
+
342
+ await startAdminServer({
343
+ port: 3001,
344
+ specPath: "./openapi.json",
345
+ });
346
+ ```
347
+
348
+ ### Endpoints
349
+
350
+ | Method | Path | Description |
351
+ |---|---|---|
352
+ | `GET` | `/health` | Health check |
353
+ | `GET` | `/spec` | Current loaded spec info |
354
+ | `POST` | `/reload` | Reload the spec from disk |
355
+ | `GET` | `/tools` | List generated tools |
356
+ | `GET` | `/prompts` | List generated prompts |
357
+ | `GET` | `/resources` | List generated resources |
358
+
359
+ ---
360
+
361
+ ## MCP Client Configuration (Claude Desktop)
362
+
363
+ Add to your `claude_desktop_config.json`:
364
+
365
+ ```json
366
+ {
367
+ "mcpServers": {
368
+ "my-api": {
369
+ "command": "npx",
370
+ "args": ["@powerduck/openapi-mcp-server", "serve", "--spec", "/path/to/openapi.json"]
371
+ }
372
+ }
373
+ }
374
+ ```
375
+
376
+ For HTTP transport:
377
+
378
+ ```json
379
+ {
380
+ "mcpServers": {
381
+ "my-api": {
382
+ "url": "http://localhost:3000/mcp"
383
+ }
384
+ }
385
+ }
386
+ ```
387
+
388
+ ---
389
+
390
+ ## Development
391
+
392
+ ```bash
393
+ # Install dependencies
394
+ npm install
395
+
396
+ # Type check
397
+ npm run typecheck
398
+
399
+ # Build (ESM + CJS + type declarations)
400
+ npm run build
401
+
402
+ # Run tests
403
+ npm test
404
+
405
+ # Watch mode
406
+ npx vitest watch
407
+ ```
69
408
 
70
- - `src/core`: spec parsing, operation traversal, tool generation, request building, execution
71
- - `src/mcp`: MCP server creation and transports
72
- - `src/registry`: prompts and resources registries
73
- - `src/runtime`: runtime service registry
74
- - `src/server`: admin HTTP server
75
- - `src/webui`: browser UI
76
- - `src/config`: persistence helpers
409
+ ---
77
410
 
78
- ## Web UI
411
+ ## Related Packages
79
412
 
80
- The UI supports:
413
+ - [`@powerduck/openapi-parser`](https://www.npmjs.com/package/@powerduck/openapi-parser) — OpenAPI 3.2 parser, validator, and upgrader
414
+ - [`@powerduck/openapi-request`](https://www.npmjs.com/package/@powerduck/openapi-request) — Execute OpenAPI operations with full parameter serialization
415
+ - [`@powerduck/openapi-codegen`](https://www.npmjs.com/package/@powerduck/openapi-codegen) — Generate runnable request examples in 21 languages
416
+ - [`@powerduck/openapi-cli`](https://www.npmjs.com/package/@powerduck/openapi-cli) — CI-ready batch testing for OpenAPI documents
417
+ - [`@powerduck/x-to-openapi`](https://www.npmjs.com/package/@powerduck/x-to-openapi) — Convert curl commands and Postman Collections to OpenAPI 3.2
81
418
 
82
- - upload and paste OpenAPI documents
83
- - view tools, prompts, and resources
84
- - inspect runtime services
85
- - stop services
86
- - basic MCP debugging hints
87
- - SSE endpoint discovery
88
- - STDIO tooltip guidance
419
+ ---
89
420
 
90
- ## Important implementation policy
421
+ ## License
91
422
 
92
- All source comments are written in American English.
423
+ MIT
@@ -1,6 +1,6 @@
1
1
  import { Express } from 'express';
2
2
  import { Server } from 'node:http';
3
- import { Document } from '@scalar/openapi-types/3.2';
3
+ import { Oas32Document } from '@powerduck/openapi-parser';
4
4
  import { Prompt, PromptArgument, Resource, Tool } from '@modelcontextprotocol/sdk/types.js';
5
5
 
6
6
  /** How the MCP server is exposed to a client. */
@@ -96,7 +96,7 @@ interface SecurityContext {
96
96
  }
97
97
  /** Mutable runtime state of the loaded specification. */
98
98
  interface AppState {
99
- spec: Document | null;
99
+ spec: Oas32Document | null;
100
100
  baseUrlOverride?: string | undefined;
101
101
  specSource?: SpecSource | undefined;
102
102
  }
@@ -1,6 +1,6 @@
1
1
  import { Express } from 'express';
2
2
  import { Server } from 'node:http';
3
- import { Document } from '@scalar/openapi-types/3.2';
3
+ import { Oas32Document } from '@powerduck/openapi-parser';
4
4
  import { Prompt, PromptArgument, Resource, Tool } from '@modelcontextprotocol/sdk/types.js';
5
5
 
6
6
  /** How the MCP server is exposed to a client. */
@@ -96,7 +96,7 @@ interface SecurityContext {
96
96
  }
97
97
  /** Mutable runtime state of the loaded specification. */
98
98
  interface AppState {
99
- spec: Document | null;
99
+ spec: Oas32Document | null;
100
100
  baseUrlOverride?: string | undefined;
101
101
  specSource?: SpecSource | undefined;
102
102
  }