@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.
- package/README.md +291 -226
- package/dist/bundle.js +248 -66
- package/dist/cli.js +248 -66
- 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)
|
|
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
|
|
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
|
|
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
|
-
|
|
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,
|
|
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
|
|
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
|
|