@ivotoby/openapi-mcp-server 1.6.1 → 1.8.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.
Files changed (4) hide show
  1. package/README.md +291 -226
  2. package/dist/bundle.js +248 -66
  3. package/dist/cli.js +248 -66
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -4,6 +4,19 @@
4
4
 
5
5
  A Model Context Protocol (MCP) server that exposes OpenAPI endpoints as MCP resources. This server allows Large Language Models to discover and interact with REST APIs defined by OpenAPI specifications through the MCP protocol.
6
6
 
7
+ ## 📖 Documentation
8
+
9
+ - **[User Guide](#user-guide)** - For users wanting to use this MCP server with Claude Desktop, Cursor, or other MCP clients
10
+ - **[Library Usage](#library-usage)** - For developers creating custom MCP servers using this package as a library
11
+ - **[Developer Guide](./docs/developer-guide.md)** - For contributors and developers working on the codebase
12
+ - **[AuthProvider Guide](./docs/auth-provider-guide.md)** - Detailed authentication patterns and examples
13
+
14
+ ---
15
+
16
+ # User Guide
17
+
18
+ This section covers how to use the MCP server as an end user with Claude Desktop, Cursor, or other MCP-compatible tools.
19
+
7
20
  ## Overview
8
21
 
9
22
  This MCP server can be used in two ways:
@@ -16,176 +29,6 @@ The server supports two transport methods:
16
29
  1. **Stdio Transport** (default): For direct integration with AI systems like Claude Desktop that manage MCP connections through standard input/output.
17
30
  2. **Streamable HTTP Transport**: For connecting to the server over HTTP, allowing web clients and other HTTP-capable systems to use the MCP protocol.
18
31
 
19
- ## 🚀 Using as a Library
20
-
21
- Create dedicated MCP servers for specific APIs by importing and configuring the `OpenAPIServer` class. This approach is ideal for:
22
-
23
- - **Custom Authentication**: Implement complex authentication patterns with the `AuthProvider` interface
24
- - **API-Specific Optimizations**: Filter endpoints, customize error handling, and optimize for specific use cases
25
- - **Distribution**: Package your server as a standalone npm module for easy sharing
26
- - **Integration**: Embed the server in larger applications or add custom middleware
27
-
28
- ### Basic Library Usage
29
-
30
- ```typescript
31
- import { OpenAPIServer } from "@ivotoby/openapi-mcp-server"
32
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
33
-
34
- const config = {
35
- name: "my-api-server",
36
- version: "1.0.0",
37
- apiBaseUrl: "https://api.example.com",
38
- openApiSpec: "https://api.example.com/openapi.json",
39
- specInputMethod: "url" as const,
40
- headers: {
41
- Authorization: "Bearer your-token",
42
- "X-API-Key": "your-api-key",
43
- },
44
- transportType: "stdio" as const,
45
- toolsMode: "all" as const,
46
- }
47
-
48
- const server = new OpenAPIServer(config)
49
- const transport = new StdioServerTransport()
50
- await server.start(transport)
51
- ```
52
-
53
- ### Advanced Authentication with AuthProvider
54
-
55
- For APIs with token expiration, refresh requirements, or complex authentication:
56
-
57
- ```typescript
58
- import { OpenAPIServer, AuthProvider } from "@ivotoby/openapi-mcp-server"
59
- import { AxiosError } from "axios"
60
-
61
- class MyAuthProvider implements AuthProvider {
62
- async getAuthHeaders(): Promise<Record<string, string>> {
63
- // Called before each request - return fresh headers
64
- if (this.isTokenExpired()) {
65
- await this.refreshToken()
66
- }
67
- return { Authorization: `Bearer ${this.token}` }
68
- }
69
-
70
- async handleAuthError(error: AxiosError): Promise<boolean> {
71
- // Called on 401/403 errors - return true to retry
72
- if (error.response?.status === 401) {
73
- await this.refreshToken()
74
- return true // Retry the request
75
- }
76
- return false
77
- }
78
- }
79
-
80
- const authProvider = new MyAuthProvider()
81
- const config = {
82
- // ... other config
83
- authProvider: authProvider, // Use AuthProvider instead of static headers
84
- }
85
- ```
86
-
87
- **📁 See the [examples/](./examples/) directory for complete, runnable examples including:**
88
-
89
- - Basic library usage with static authentication
90
- - AuthProvider implementations for different scenarios
91
- - Real-world Beatport API integration
92
- - Production-ready packaging patterns
93
-
94
- ## 🔐 Dynamic Authentication with AuthProvider
95
-
96
- The `AuthProvider` interface enables sophisticated authentication scenarios that static headers cannot handle:
97
-
98
- ### Key Features
99
-
100
- - **Dynamic Headers**: Fresh authentication headers for each request
101
- - **Token Expiration Handling**: Automatic detection and handling of expired tokens
102
- - **Authentication Error Recovery**: Retry logic for recoverable authentication failures
103
- - **Custom Error Messages**: Provide clear, actionable guidance to users
104
-
105
- ### AuthProvider Interface
106
-
107
- ```typescript
108
- interface AuthProvider {
109
- /**
110
- * Get authentication headers for the current request
111
- * Called before each API request to get fresh headers
112
- */
113
- getAuthHeaders(): Promise<Record<string, string>>
114
-
115
- /**
116
- * Handle authentication errors from API responses
117
- * Called when the API returns 401 or 403 errors
118
- * Return true to retry the request, false otherwise
119
- */
120
- handleAuthError(error: AxiosError): Promise<boolean>
121
- }
122
- ```
123
-
124
- ### Common Patterns
125
-
126
- #### Automatic Token Refresh
127
-
128
- ```typescript
129
- class RefreshableAuthProvider implements AuthProvider {
130
- async getAuthHeaders(): Promise<Record<string, string>> {
131
- if (this.isTokenExpired()) {
132
- await this.refreshToken()
133
- }
134
- return { Authorization: `Bearer ${this.accessToken}` }
135
- }
136
-
137
- async handleAuthError(error: AxiosError): Promise<boolean> {
138
- if (error.response?.status === 401) {
139
- await this.refreshToken()
140
- return true // Retry with fresh token
141
- }
142
- return false
143
- }
144
- }
145
- ```
146
-
147
- #### Manual Token Management (e.g., Beatport)
148
-
149
- ```typescript
150
- class ManualTokenAuthProvider implements AuthProvider {
151
- async getAuthHeaders(): Promise<Record<string, string>> {
152
- if (!this.token || this.isTokenExpired()) {
153
- throw new Error(
154
- "Token expired. Please get a new token from your browser:\n" +
155
- "1. Go to the API website and log in\n" +
156
- "2. Open browser dev tools (F12)\n" +
157
- "3. Copy the Authorization header from any API request\n" +
158
- "4. Update your token using updateToken()",
159
- )
160
- }
161
- return { Authorization: `Bearer ${this.token}` }
162
- }
163
-
164
- updateToken(token: string): void {
165
- this.token = token
166
- this.tokenExpiry = new Date(Date.now() + 3600000) // 1 hour
167
- }
168
- }
169
- ```
170
-
171
- #### API Key Authentication
172
-
173
- ```typescript
174
- class ApiKeyAuthProvider implements AuthProvider {
175
- constructor(private apiKey: string) {}
176
-
177
- async getAuthHeaders(): Promise<Record<string, string>> {
178
- return { "X-API-Key": this.apiKey }
179
- }
180
-
181
- async handleAuthError(error: AxiosError): Promise<boolean> {
182
- throw new Error("API key authentication failed. Please check your key.")
183
- }
184
- }
185
- ```
186
-
187
- **📖 For detailed AuthProvider documentation and examples, see [docs/auth-provider-guide.md](./docs/auth-provider-guide.md)**
188
-
189
32
  ## Quick Start for Users
190
33
 
191
34
  ### Option 1: Using with Claude Desktop (Stdio Transport)
@@ -266,27 +109,6 @@ curl -N http://localhost:3000/mcp -H "Mcp-Session-Id: your-session-id"
266
109
  curl -X DELETE http://localhost:3000/mcp -H "Mcp-Session-Id: your-session-id"
267
110
  ```
268
111
 
269
- ## Transport Types
270
-
271
- ### Stdio Transport (Default)
272
-
273
- The stdio transport is designed for direct integration with AI systems like Claude Desktop that manage MCP connections through standard input/output. This is the simplest setup and requires no network configuration.
274
-
275
- **When to use**: When integrating with Claude Desktop or other systems that support stdio-based MCP communication.
276
-
277
- ### Streamable HTTP Transport
278
-
279
- The HTTP transport allows the MCP server to be accessed over HTTP, enabling web applications and other HTTP-capable clients to interact with the MCP protocol. It supports session management, streaming responses, and standard HTTP methods.
280
-
281
- **Key features**:
282
-
283
- - Session management with Mcp-Session-Id header
284
- - HTTP responses for `initialize` and `tools/list` requests are sent synchronously on the POST.
285
- - Other server-to-client messages (e.g., `tools/execute` results, notifications) are streamed over a GET connection using Server-Sent Events (SSE).
286
- - Support for POST/GET/DELETE methods
287
-
288
- **When to use**: When you need to expose the MCP server to web clients or systems that communicate over HTTP rather than stdio.
289
-
290
112
  ## Configuration Options
291
113
 
292
114
  The server can be configured through environment variables or command line arguments:
@@ -304,7 +126,7 @@ The server can be configured through environment variables or command line argum
304
126
  - `HTTP_PORT` - Port for HTTP transport (default: 3000)
305
127
  - `HTTP_HOST` - Host for HTTP transport (default: "127.0.0.1")
306
128
  - `ENDPOINT_PATH` - Endpoint path for HTTP transport (default: "/mcp")
307
- - `TOOLS_MODE` - Tools loading mode: "all" (load all endpoint-based tools) or "dynamic" (load only meta-tools) (default: "all")
129
+ - `TOOLS_MODE` - Tools loading mode: "all" (load all endpoint-based tools), "dynamic" (load only meta-tools), or "explicit" (load only tools specified in includeTools) (default: "all")
308
130
  - `DISABLE_ABBREVIATION` - Disable name optimization (this could throw errors when name is > 64 chars)
309
131
 
310
132
  ### Command Line Arguments
@@ -422,40 +244,14 @@ Only one specification source can be used at a time. The server will validate th
422
244
 
423
245
  If multiple sources are specified, the server will exit with an error message.
424
246
 
425
- ### OpenAPI Schema Processing
426
-
427
- #### Reference Resolution
428
-
429
- This MCP server implements robust OpenAPI reference (`$ref`) resolution to ensure accurate representation of API schemas:
430
-
431
- - **Parameter References**: Fully resolves `$ref` pointers to parameter components in the OpenAPI spec
432
- - **Schema References**: Handles nested schema references within parameters and request bodies
433
- - **Recursive References**: Prevents infinite loops by detecting and handling circular references
434
- - **Nested Properties**: Preserves complex nested object and array structures with all their attributes
435
-
436
- ### Input Schema Composition
437
-
438
- The server intelligently merges parameters and request bodies into a unified input schema for each tool:
439
-
440
- - **Parameters + Request Body Merging**: Combines path, query, and body parameters into a single schema
441
- - **Collision Handling**: Resolves naming conflicts by prefixing body properties that conflict with parameter names
442
- - **Type Preservation**: Maintains the original type information for all schema elements
443
- - **Metadata Retention**: Preserves descriptions, formats, defaults, enums, and other schema attributes
444
-
445
- ### Complex Schema Support
446
-
447
- The MCP server handles various OpenAPI schema complexities:
448
-
449
- - **Primitive Type Bodies**: Wraps non-object request bodies in a "body" property
450
- - **Object Bodies**: Flattens object properties into the tool's input schema
451
- - **Array Bodies**: Properly handles array schemas with their nested item definitions
452
- - **Required Properties**: Tracks and preserves which parameters and properties are required
453
-
454
247
  ## Tool Loading & Filtering Options
455
248
 
456
249
  Based on the Stainless article "What We Learned Converting Complex OpenAPI Specs to MCP Servers" (https://www.stainless.com/blog/what-we-learned-converting-complex-openapi-specs-to-mcp-servers), the following flags were added to control which API endpoints (tools) are loaded:
457
250
 
458
- - `--tools <all|dynamic>`: Choose to load all tools (default) or only dynamic meta-tools (`list-api-endpoints`, `get-api-endpoint-schema`, `invoke-api-endpoint`).
251
+ - `--tools <all|dynamic|explicit>`: Choose tool loading mode:
252
+ - `all` (default): Load all tools from the OpenAPI spec, applying any specified filters
253
+ - `dynamic`: Load only dynamic meta-tools (`list-api-endpoints`, `get-api-endpoint-schema`, `invoke-api-endpoint`)
254
+ - `explicit`: Load only tools explicitly listed in `--tool` options, ignoring all other filters
459
255
  - `--tool <toolId>`: Import only specified tool IDs or names. Can be used multiple times.
460
256
  - `--tag <tag>`: Import only tools with the specified OpenAPI tag. Can be used multiple times.
461
257
  - `--resource <resource>`: Import only tools under the specified resource path prefixes. Can be used multiple times.
@@ -467,7 +263,10 @@ Based on the Stainless article "What We Learned Converting Complex OpenAPI Specs
467
263
  # Load only dynamic meta-tools
468
264
  npx @ivotoby/openapi-mcp-server --api-base-url https://api.example.com --openapi-spec https://api.example.com/openapi.json --tools dynamic
469
265
 
470
- # Load only the GET /users endpoint tool
266
+ # Load only explicitly specified tools (ignores other filters)
267
+ npx @ivotoby/openapi-mcp-server --api-base-url https://api.example.com --openapi-spec https://api.example.com/openapi.json --tools explicit --tool GET::users --tool POST::users
268
+
269
+ # Load only the GET /users endpoint tool (using all mode with filtering)
471
270
  npx @ivotoby/openapi-mcp-server --api-base-url https://api.example.com --openapi-spec https://api.example.com/openapi.json --tool GET-users
472
271
 
473
272
  # Load tools tagged with "user" under the "/users" resource
@@ -477,6 +276,27 @@ npx @ivotoby/openapi-mcp-server --api-base-url https://api.example.com --openapi
477
276
  npx @ivotoby/openapi-mcp-server --api-base-url https://api.example.com --openapi-spec https://api.example.com/openapi.json --operation post
478
277
  ```
479
278
 
279
+ ## Transport Types
280
+
281
+ ### Stdio Transport (Default)
282
+
283
+ The stdio transport is designed for direct integration with AI systems like Claude Desktop that manage MCP connections through standard input/output. This is the simplest setup and requires no network configuration.
284
+
285
+ **When to use**: When integrating with Claude Desktop or other systems that support stdio-based MCP communication.
286
+
287
+ ### Streamable HTTP Transport
288
+
289
+ The HTTP transport allows the MCP server to be accessed over HTTP, enabling web applications and other HTTP-capable clients to interact with the MCP protocol. It supports session management, streaming responses, and standard HTTP methods.
290
+
291
+ **Key features**:
292
+
293
+ - Session management with Mcp-Session-Id header
294
+ - HTTP responses for `initialize` and `tools/list` requests are sent synchronously on the POST.
295
+ - Other server-to-client messages (e.g., `tools/execute` results, notifications) are streamed over a GET connection using Server-Sent Events (SSE).
296
+ - Support for POST/GET/DELETE methods
297
+
298
+ **When to use**: When you need to expose the MCP server to web clients or systems that communicate over HTTP rather than stdio.
299
+
480
300
  ## Security Considerations
481
301
 
482
302
  - The HTTP transport validates Origin headers to prevent DNS rebinding attacks
@@ -496,6 +316,247 @@ To see debug logs:
496
316
  npx @ivotoby/openapi-mcp-server --transport http &2>debug.log
497
317
  ```
498
318
 
319
+ ---
320
+
321
+ # Library Usage
322
+
323
+ This section is for developers who want to use this package as a library to create custom MCP servers.
324
+
325
+ ## 🚀 Using as a Library
326
+
327
+ Create dedicated MCP servers for specific APIs by importing and configuring the `OpenAPIServer` class. This approach is ideal for:
328
+
329
+ - **Custom Authentication**: Implement complex authentication patterns with the `AuthProvider` interface
330
+ - **API-Specific Optimizations**: Filter endpoints, customize error handling, and optimize for specific use cases
331
+ - **Distribution**: Package your server as a standalone npm module for easy sharing
332
+ - **Integration**: Embed the server in larger applications or add custom middleware
333
+
334
+ ### Basic Library Usage
335
+
336
+ ```typescript
337
+ import { OpenAPIServer } from "@ivotoby/openapi-mcp-server"
338
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
339
+
340
+ const config = {
341
+ name: "my-api-server",
342
+ version: "1.0.0",
343
+ apiBaseUrl: "https://api.example.com",
344
+ openApiSpec: "https://api.example.com/openapi.json",
345
+ specInputMethod: "url" as const,
346
+ headers: {
347
+ Authorization: "Bearer your-token",
348
+ "X-API-Key": "your-api-key",
349
+ },
350
+ transportType: "stdio" as const,
351
+ toolsMode: "all" as const, // Options: "all", "dynamic", "explicit"
352
+ }
353
+
354
+ const server = new OpenAPIServer(config)
355
+ const transport = new StdioServerTransport()
356
+ await server.start(transport)
357
+ ```
358
+
359
+ ### Tool Loading Modes
360
+
361
+ The `toolsMode` configuration option controls which tools are loaded from your OpenAPI specification:
362
+
363
+ ```typescript
364
+ // Load all tools from the spec (default)
365
+ const config = {
366
+ // ... other config
367
+ toolsMode: "all" as const,
368
+ // Optional: Apply filters to control which tools are loaded
369
+ includeTools: ["GET::users", "POST::users"], // Only these tools
370
+ includeTags: ["public"], // Only tools with these tags
371
+ includeResources: ["users"], // Only tools under these resources
372
+ includeOperations: ["get", "post"], // Only these HTTP methods
373
+ }
374
+
375
+ // Load only dynamic meta-tools for API exploration
376
+ const config = {
377
+ // ... other config
378
+ toolsMode: "dynamic" as const,
379
+ // Provides: list-api-endpoints, get-api-endpoint-schema, invoke-api-endpoint
380
+ }
381
+
382
+ // Load only explicitly specified tools (ignores other filters)
383
+ const config = {
384
+ // ... other config
385
+ toolsMode: "explicit" as const,
386
+ includeTools: ["GET::users", "POST::users"], // Only these exact tools
387
+ // includeTags, includeResources, includeOperations are ignored in explicit mode
388
+ }
389
+ ```
390
+
391
+ ### Advanced Authentication with AuthProvider
392
+
393
+ For APIs with token expiration, refresh requirements, or complex authentication:
394
+
395
+ ```typescript
396
+ import { OpenAPIServer, AuthProvider } from "@ivotoby/openapi-mcp-server"
397
+ import { AxiosError } from "axios"
398
+
399
+ class MyAuthProvider implements AuthProvider {
400
+ async getAuthHeaders(): Promise<Record<string, string>> {
401
+ // Called before each request - return fresh headers
402
+ if (this.isTokenExpired()) {
403
+ await this.refreshToken()
404
+ }
405
+ return { Authorization: `Bearer ${this.token}` }
406
+ }
407
+
408
+ async handleAuthError(error: AxiosError): Promise<boolean> {
409
+ // Called on 401/403 errors - return true to retry
410
+ if (error.response?.status === 401) {
411
+ await this.refreshToken()
412
+ return true // Retry the request
413
+ }
414
+ return false
415
+ }
416
+ }
417
+
418
+ const authProvider = new MyAuthProvider()
419
+ const config = {
420
+ // ... other config
421
+ authProvider: authProvider, // Use AuthProvider instead of static headers
422
+ }
423
+ ```
424
+
425
+ **📁 See the [examples/](./examples/) directory for complete, runnable examples including:**
426
+
427
+ - Basic library usage with static authentication
428
+ - AuthProvider implementations for different scenarios
429
+ - Real-world Beatport API integration
430
+ - Production-ready packaging patterns
431
+
432
+ ## 🔐 Dynamic Authentication with AuthProvider
433
+
434
+ The `AuthProvider` interface enables sophisticated authentication scenarios that static headers cannot handle:
435
+
436
+ ### Key Features
437
+
438
+ - **Dynamic Headers**: Fresh authentication headers for each request
439
+ - **Token Expiration Handling**: Automatic detection and handling of expired tokens
440
+ - **Authentication Error Recovery**: Retry logic for recoverable authentication failures
441
+ - **Custom Error Messages**: Provide clear, actionable guidance to users
442
+
443
+ ### AuthProvider Interface
444
+
445
+ ```typescript
446
+ interface AuthProvider {
447
+ /**
448
+ * Get authentication headers for the current request
449
+ * Called before each API request to get fresh headers
450
+ */
451
+ getAuthHeaders(): Promise<Record<string, string>>
452
+
453
+ /**
454
+ * Handle authentication errors from API responses
455
+ * Called when the API returns 401 or 403 errors
456
+ * Return true to retry the request, false otherwise
457
+ */
458
+ handleAuthError(error: AxiosError): Promise<boolean>
459
+ }
460
+ ```
461
+
462
+ ### Common Patterns
463
+
464
+ #### Automatic Token Refresh
465
+
466
+ ```typescript
467
+ class RefreshableAuthProvider implements AuthProvider {
468
+ async getAuthHeaders(): Promise<Record<string, string>> {
469
+ if (this.isTokenExpired()) {
470
+ await this.refreshToken()
471
+ }
472
+ return { Authorization: `Bearer ${this.accessToken}` }
473
+ }
474
+
475
+ async handleAuthError(error: AxiosError): Promise<boolean> {
476
+ if (error.response?.status === 401) {
477
+ await this.refreshToken()
478
+ return true // Retry with fresh token
479
+ }
480
+ return false
481
+ }
482
+ }
483
+ ```
484
+
485
+ #### Manual Token Management (e.g., Beatport)
486
+
487
+ ```typescript
488
+ class ManualTokenAuthProvider implements AuthProvider {
489
+ async getAuthHeaders(): Promise<Record<string, string>> {
490
+ if (!this.token || this.isTokenExpired()) {
491
+ throw new Error(
492
+ "Token expired. Please get a new token from your browser:\n" +
493
+ "1. Go to the API website and log in\n" +
494
+ "2. Open browser dev tools (F12)\n" +
495
+ "3. Copy the Authorization header from any API request\n" +
496
+ "4. Update your token using updateToken()",
497
+ )
498
+ }
499
+ return { Authorization: `Bearer ${this.token}` }
500
+ }
501
+
502
+ updateToken(token: string): void {
503
+ this.token = token
504
+ this.tokenExpiry = new Date(Date.now() + 3600000) // 1 hour
505
+ }
506
+ }
507
+ ```
508
+
509
+ #### API Key Authentication
510
+
511
+ ```typescript
512
+ class ApiKeyAuthProvider implements AuthProvider {
513
+ constructor(private apiKey: string) {}
514
+
515
+ async getAuthHeaders(): Promise<Record<string, string>> {
516
+ return { "X-API-Key": this.apiKey }
517
+ }
518
+
519
+ async handleAuthError(error: AxiosError): Promise<boolean> {
520
+ throw new Error("API key authentication failed. Please check your key.")
521
+ }
522
+ }
523
+ ```
524
+
525
+ **📖 For detailed AuthProvider documentation and examples, see [docs/auth-provider-guide.md](./docs/auth-provider-guide.md)**
526
+
527
+ ### OpenAPI Schema Processing
528
+
529
+ #### Reference Resolution
530
+
531
+ This MCP server implements robust OpenAPI reference (`$ref`) resolution to ensure accurate representation of API schemas:
532
+
533
+ - **Parameter References**: Fully resolves `$ref` pointers to parameter components in the OpenAPI spec
534
+ - **Schema References**: Handles nested schema references within parameters and request bodies
535
+ - **Recursive References**: Prevents infinite loops by detecting and handling circular references
536
+ - **Nested Properties**: Preserves complex nested object and array structures with all their attributes
537
+
538
+ ### Input Schema Composition
539
+
540
+ The server intelligently merges parameters and request bodies into a unified input schema for each tool:
541
+
542
+ - **Parameters + Request Body Merging**: Combines path, query, and body parameters into a single schema
543
+ - **Collision Handling**: Resolves naming conflicts by prefixing body properties that conflict with parameter names
544
+ - **Type Preservation**: Maintains the original type information for all schema elements
545
+ - **Metadata Retention**: Preserves descriptions, formats, defaults, enums, and other schema attributes
546
+
547
+ ### Complex Schema Support
548
+
549
+ The MCP server handles various OpenAPI schema complexities:
550
+
551
+ - **Primitive Type Bodies**: Wraps non-object request bodies in a "body" property
552
+ - **Object Bodies**: Flattens object properties into the tool's input schema
553
+ - **Array Bodies**: Properly handles array schemas with their nested item definitions
554
+ - **Required Properties**: Tracks and preserves which parameters and properties are required
555
+
556
+ ---
557
+
558
+ # Developer Information
559
+
499
560
  ## For Developers
500
561
 
501
562
  ### Development Tools
@@ -523,7 +584,11 @@ To see debug logs:
523
584
  4. Run tests and linting: `npm run typecheck && npm run lint`
524
585
  5. Submit a pull request
525
586
 
526
- ## FAQ
587
+ **📖 For comprehensive developer documentation, see [docs/developer-guide.md](./docs/developer-guide.md)**
588
+
589
+ ---
590
+
591
+ # FAQ
527
592
 
528
593
  **Q: What is a "tool"?**
529
594
  A: A tool corresponds to a single API endpoint derived from your OpenAPI specification, exposed as an MCP resource.
@@ -541,7 +606,7 @@ A: Use the `AuthProvider` interface instead of static headers. AuthProvider allo
541
606
  A: `AuthProvider` is an interface for dynamic authentication that gets fresh headers before each request and handles authentication errors. Use it when your API has expiring tokens, requires token refresh, or needs complex authentication logic that static headers can't handle.
542
607
 
543
608
  **Q: How do I filter which tools are loaded?**
544
- A: Use the `--tool`, `--tag`, `--resource`, and `--operation` flags, or set `TOOLS_MODE=dynamic` for meta-tools only.
609
+ A: Use the `--tool`, `--tag`, `--resource`, and `--operation` flags with `--tools all` (default), set `--tools dynamic` for meta-tools only, or use `--tools explicit` to load only tools specified with `--tool` (ignoring other filters).
545
610
 
546
611
  **Q: When should I use dynamic mode?**
547
612
  A: Dynamic mode provides meta-tools (`list-api-endpoints`, `get-api-endpoint-schema`, `invoke-api-endpoint`) to inspect and interact with endpoints without preloading all operations, which is useful for large or changing APIs.
@@ -562,7 +627,7 @@ A: The server detects naming conflicts and automatically prefixes body property
562
627
  A: Yes! When using the library approach, you can create a dedicated npm package for your API. See the Beatport example for a complete implementation that can be packaged and distributed as `npx your-api-mcp-server`.
563
628
 
564
629
  **Q: Where can I find development and contribution guidelines?**
565
- A: See the "For Developers" section above for commands (`npm run build`, `npm run dev`, etc) and pull request workflow.
630
+ A: See the [Developer Guide](./docs/developer-guide.md) for comprehensive documentation on architecture, key concepts, development workflow, and contribution guidelines.
566
631
 
567
632
  ## License
568
633