fa-mcp-sdk 0.2.249 → 0.2.258
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/cli-template/FA-MCP-SDK-DOC/00-FA-MCP-SDK-index.md +45 -161
- package/cli-template/FA-MCP-SDK-DOC/01-getting-started.md +71 -226
- package/cli-template/FA-MCP-SDK-DOC/02-1-tools-and-api.md +80 -360
- package/cli-template/FA-MCP-SDK-DOC/02-2-prompts-and-resources.md +191 -342
- package/cli-template/FA-MCP-SDK-DOC/03-configuration.md +141 -279
- package/cli-template/FA-MCP-SDK-DOC/04-authentication.md +73 -522
- package/cli-template/FA-MCP-SDK-DOC/05-ad-authorization.md +68 -419
- package/cli-template/FA-MCP-SDK-DOC/06-utilities.md +64 -447
- package/cli-template/FA-MCP-SDK-DOC/07-testing-and-operations.md +39 -196
- package/cli-template/package.json +2 -1
- package/config/local.yaml +1 -1
- package/dist/core/_types_/types.d.ts +36 -10
- package/dist/core/_types_/types.d.ts.map +1 -1
- package/dist/core/auth/admin-auth.js +1 -1
- package/dist/core/auth/admin-auth.js.map +1 -1
- package/dist/core/auth/middleware.js +8 -8
- package/dist/core/auth/middleware.js.map +1 -1
- package/dist/core/auth/multi-auth.d.ts.map +1 -1
- package/dist/core/auth/multi-auth.js +15 -14
- package/dist/core/auth/multi-auth.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/mcp/create-mcp-server.js +8 -9
- package/dist/core/mcp/create-mcp-server.js.map +1 -1
- package/dist/core/mcp/prompts.d.ts +10 -5
- package/dist/core/mcp/prompts.d.ts.map +1 -1
- package/dist/core/mcp/prompts.js +17 -15
- package/dist/core/mcp/prompts.js.map +1 -1
- package/dist/core/mcp/resources.d.ts +4 -4
- package/dist/core/mcp/resources.d.ts.map +1 -1
- package/dist/core/mcp/resources.js +21 -20
- package/dist/core/mcp/resources.js.map +1 -1
- package/dist/core/utils/utils.d.ts +2 -1
- package/dist/core/utils/utils.d.ts.map +1 -1
- package/dist/core/utils/utils.js +2 -2
- package/dist/core/utils/utils.js.map +1 -1
- package/dist/core/web/home-api.d.ts.map +1 -1
- package/dist/core/web/home-api.js +4 -3
- package/dist/core/web/home-api.js.map +1 -1
- package/dist/core/web/server-http.d.ts.map +1 -1
- package/dist/core/web/server-http.js +36 -21
- package/dist/core/web/server-http.js.map +1 -1
- package/package.json +1 -1
- package/scripts/update-doc.js +21 -0
- package/src/template/start.ts +1 -1
|
@@ -1,184 +1,86 @@
|
|
|
1
|
-
# Tools and REST API
|
|
1
|
+
# Tools and REST API
|
|
2
2
|
|
|
3
3
|
## Tool Development
|
|
4
4
|
|
|
5
|
-
### Tool Definition
|
|
5
|
+
### Tool Definition (`src/tools/tools.ts`)
|
|
6
6
|
|
|
7
7
|
```typescript
|
|
8
8
|
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
type: '
|
|
17
|
-
|
|
18
|
-
query: {
|
|
19
|
-
type: 'string',
|
|
20
|
-
description: 'Input query or text',
|
|
21
|
-
},
|
|
22
|
-
options: {
|
|
23
|
-
type: 'object',
|
|
24
|
-
description: 'Optional configuration',
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
required: ['query'],
|
|
9
|
+
|
|
10
|
+
export const tools: Tool[] = [{
|
|
11
|
+
name: 'my_custom_tool',
|
|
12
|
+
description: 'Description of what this tool does',
|
|
13
|
+
inputSchema: {
|
|
14
|
+
type: 'object',
|
|
15
|
+
properties: {
|
|
16
|
+
query: { type: 'string', description: 'Input query' },
|
|
17
|
+
options: { type: 'object', description: 'Optional config' },
|
|
28
18
|
},
|
|
19
|
+
required: ['query'],
|
|
29
20
|
},
|
|
30
|
-
];
|
|
21
|
+
}];
|
|
31
22
|
```
|
|
32
23
|
|
|
33
|
-
### Tool Handler
|
|
24
|
+
### Tool Handler (`src/tools/handle-tool-call.ts`)
|
|
34
25
|
|
|
35
26
|
```typescript
|
|
36
27
|
import { formatToolResult, ToolExecutionError, logger, IToolHandlerParams } from 'fa-mcp-sdk';
|
|
37
28
|
|
|
38
29
|
export const handleToolCall = async (params: IToolHandlerParams): Promise<any> => {
|
|
39
|
-
const { name, arguments: args, headers, payload } = params;
|
|
40
|
-
// payload
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// Access normalized HTTP headers (all header names are lowercase)
|
|
45
|
-
if (headers) {
|
|
46
|
-
const authHeader = headers.authorization;
|
|
47
|
-
const userAgent = headers['user-agent'];
|
|
48
|
-
const customHeader = headers['x-custom-header'];
|
|
49
|
-
logger.info(`Headers available: authorization=${!!authHeader}, user-agent=${userAgent}`);
|
|
50
|
-
}
|
|
30
|
+
const { name, arguments: args, headers, payload, transport } = params;
|
|
31
|
+
// payload: { user: string, ... } if JWT auth enabled
|
|
32
|
+
// transport: 'stdio' | 'sse' | 'http'
|
|
33
|
+
// headers: normalized lowercase keys
|
|
51
34
|
|
|
52
35
|
try {
|
|
53
36
|
switch (name) {
|
|
54
37
|
case 'my_custom_tool':
|
|
55
|
-
|
|
56
|
-
|
|
38
|
+
if (!args?.query) throw new ToolExecutionError(name, 'Query required');
|
|
39
|
+
return formatToolResult({ message: `Processed: ${args.query}` });
|
|
57
40
|
default:
|
|
58
41
|
throw new ToolExecutionError(name, `Unknown tool: ${name}`);
|
|
59
42
|
}
|
|
60
43
|
} catch (error) {
|
|
61
|
-
logger.error(`Tool
|
|
44
|
+
logger.error(`Tool ${name} failed:`, error);
|
|
62
45
|
throw error;
|
|
63
46
|
}
|
|
64
47
|
};
|
|
65
|
-
|
|
66
|
-
async function handleMyCustomTool(args: any): Promise<string> {
|
|
67
|
-
const { query, options } = args || {};
|
|
68
|
-
|
|
69
|
-
if (!query) {
|
|
70
|
-
throw new ToolExecutionError('my_custom_tool', 'Query parameter is required');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Your tool logic here
|
|
74
|
-
const result = {
|
|
75
|
-
message: `Processed: ${query}`,
|
|
76
|
-
timestamp: new Date().toISOString(),
|
|
77
|
-
options: options || {},
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
return formatToolResult(result);
|
|
81
|
-
}
|
|
82
48
|
```
|
|
83
49
|
|
|
84
|
-
###
|
|
85
|
-
|
|
86
|
-
The FA-MCP-SDK automatically passes normalized HTTP headers to your `toolHandler` function, enabling context-aware tool execution based on client information.
|
|
50
|
+
### Headers Access
|
|
87
51
|
|
|
88
|
-
|
|
89
|
-
- All headers are automatically normalized to lowercase
|
|
90
|
-
- Available in both HTTP and SSE transports (SSE provides empty headers object)
|
|
91
|
-
- Headers are sanitized and only string values are passed
|
|
92
|
-
- Array header values are joined with `', '` separator
|
|
93
|
-
|
|
94
|
-
**Example Usage:**
|
|
52
|
+
Headers are normalized to lowercase. Available in HTTP/SSE transports:
|
|
95
53
|
|
|
96
54
|
```typescript
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const { name, arguments: args, headers, payload } = params;
|
|
101
|
-
|
|
102
|
-
// Access client information via headers
|
|
103
|
-
if (headers) {
|
|
104
|
-
const authHeader = headers.authorization; // Lowercase normalized
|
|
105
|
-
const userAgent = headers['user-agent']; // Browser/client info
|
|
106
|
-
const clientIP = headers['x-real-ip'] || headers['x-forwarded-for']; // Proxy headers
|
|
107
|
-
const customData = headers['x-custom-header']; // Custom headers
|
|
108
|
-
|
|
109
|
-
logger.info(`Tool ${name} called by ${userAgent} from IP ${clientIP}`);
|
|
110
|
-
|
|
111
|
-
// Conditional logic based on client
|
|
112
|
-
if (userAgent?.includes('mobile')) {
|
|
113
|
-
return await handleMobileRequest(args);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Custom authorization beyond standard auth
|
|
117
|
-
if (customData === 'admin-mode' && authHeader) {
|
|
118
|
-
return await handleAdminRequest(args);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Regular tool logic
|
|
123
|
-
switch (name) {
|
|
124
|
-
case 'get_user_data':
|
|
125
|
-
// Use headers for audit logging
|
|
126
|
-
return await getUserData(args, {
|
|
127
|
-
clientIP: headers?.['x-real-ip'],
|
|
128
|
-
userAgent: headers?.['user-agent']
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
};
|
|
55
|
+
const authHeader = headers?.authorization;
|
|
56
|
+
const userAgent = headers?.['user-agent'];
|
|
57
|
+
const clientIP = headers?.['x-real-ip'] || headers?.['x-forwarded-for'];
|
|
132
58
|
```
|
|
133
59
|
|
|
134
|
-
|
|
60
|
+
### Transport-Based Credentials
|
|
135
61
|
|
|
136
62
|
```typescript
|
|
137
|
-
|
|
138
|
-
{
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
'
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Normalized headers passed to toolHandler:
|
|
145
|
-
{
|
|
146
|
-
'authorization': 'Bearer token123',
|
|
147
|
-
'x-custom-header': 'value',
|
|
148
|
-
'user-agent': 'MyClient/1.0'
|
|
63
|
+
function getApiKey(params: IToolHandlerParams): string {
|
|
64
|
+
if (params.transport === 'stdio') {
|
|
65
|
+
return process.env.EXTERNAL_API_KEY || ''; // Local: ENV
|
|
66
|
+
}
|
|
67
|
+
return params.headers?.['x-api-key'] || ''; // HTTP/SSE: headers
|
|
149
68
|
}
|
|
150
69
|
```
|
|
151
70
|
|
|
152
|
-
**Transport Differences:**
|
|
153
|
-
|
|
154
|
-
- **HTTP Transport**: Full headers available from Express request object
|
|
155
|
-
- **SSE Transport**: Headers preserved from initial SSE connection establishment (GET /sse request)
|
|
156
|
-
|
|
157
|
-
**Common Use Cases:**
|
|
158
|
-
- Client identification and analytics
|
|
159
|
-
- Custom authorization checks beyond standard authentication
|
|
160
|
-
- Request routing based on client capabilities
|
|
161
|
-
- Audit logging with client context
|
|
162
|
-
- Rate limiting per client type
|
|
163
|
-
|
|
164
|
-
---
|
|
165
|
-
|
|
166
71
|
## REST API Endpoints
|
|
167
72
|
|
|
168
|
-
|
|
73
|
+
Define REST endpoints in `src/api/router.ts` using [tsoa](https://tsoa-community.github.io/docs/) decorators.
|
|
169
74
|
|
|
170
75
|
### OpenAPI Generation
|
|
171
76
|
|
|
172
|
-
**
|
|
173
|
-
|
|
174
|
-
- **
|
|
175
|
-
-
|
|
77
|
+
- **Auto-generated** on startup if `swagger/openapi.yaml` missing
|
|
78
|
+
- **Swagger UI**: `/docs`
|
|
79
|
+
- **Spec**: `/api/openapi.json`, `/api/openapi.yaml`
|
|
80
|
+
- Regenerate: delete `swagger/openapi.yaml` and restart
|
|
176
81
|
|
|
177
|
-
|
|
82
|
+
### Controller Example
|
|
178
83
|
|
|
179
|
-
### Basic Controller Example
|
|
180
|
-
|
|
181
|
-
**`src/api/router.ts`:**
|
|
182
84
|
```typescript
|
|
183
85
|
import { Router } from 'express';
|
|
184
86
|
import { Route, Get, Post, Body, Tags, Query } from 'tsoa';
|
|
@@ -186,286 +88,104 @@ import { logger } from 'fa-mcp-sdk';
|
|
|
186
88
|
|
|
187
89
|
export const apiRouter: Router = Router();
|
|
188
90
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
id: string;
|
|
192
|
-
name: string;
|
|
193
|
-
email: string;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export interface CreateUserRequest {
|
|
197
|
-
name: string;
|
|
198
|
-
email: string;
|
|
199
|
-
}
|
|
91
|
+
interface UserResponse { id: string; name: string; email: string; }
|
|
92
|
+
interface CreateUserRequest { name: string; email: string; }
|
|
200
93
|
|
|
201
|
-
/**
|
|
202
|
-
* User Management Controller
|
|
203
|
-
* All methods in this class will be under /api prefix
|
|
204
|
-
*/
|
|
205
94
|
@Route('api')
|
|
206
95
|
export class UserController {
|
|
207
|
-
/**
|
|
208
|
-
* Get user by ID
|
|
209
|
-
* @param userId The user's unique identifier
|
|
210
|
-
*/
|
|
211
96
|
@Get('users/{userId}')
|
|
212
97
|
@Tags('Users')
|
|
213
98
|
public async getUser(userId: string): Promise<UserResponse> {
|
|
214
|
-
|
|
215
|
-
return {
|
|
216
|
-
id: userId,
|
|
217
|
-
name: 'John Doe',
|
|
218
|
-
email: 'john@example.com',
|
|
219
|
-
};
|
|
99
|
+
return { id: userId, name: 'John', email: 'john@example.com' };
|
|
220
100
|
}
|
|
221
101
|
|
|
222
|
-
/**
|
|
223
|
-
* Create a new user
|
|
224
|
-
*/
|
|
225
102
|
@Post('users')
|
|
226
103
|
@Tags('Users')
|
|
227
|
-
public async createUser(
|
|
228
|
-
|
|
229
|
-
): Promise<UserResponse> {
|
|
230
|
-
logger.info(`Creating user: ${body.name}`);
|
|
231
|
-
return {
|
|
232
|
-
id: 'new-user-id',
|
|
233
|
-
name: body.name,
|
|
234
|
-
email: body.email,
|
|
235
|
-
};
|
|
104
|
+
public async createUser(@Body() body: CreateUserRequest): Promise<UserResponse> {
|
|
105
|
+
return { id: 'new-id', name: body.name, email: body.email };
|
|
236
106
|
}
|
|
237
107
|
|
|
238
|
-
/**
|
|
239
|
-
* Search users by query
|
|
240
|
-
*/
|
|
241
108
|
@Get('users')
|
|
242
109
|
@Tags('Users')
|
|
243
|
-
public async searchUsers(
|
|
244
|
-
@Query() query?: string,
|
|
245
|
-
@Query() limit?: number
|
|
246
|
-
): Promise<UserResponse[]> {
|
|
247
|
-
logger.info(`Searching users: ${query}, limit: ${limit}`);
|
|
110
|
+
public async searchUsers(@Query() query?: string, @Query() limit?: number): Promise<UserResponse[]> {
|
|
248
111
|
return [];
|
|
249
112
|
}
|
|
250
113
|
}
|
|
251
114
|
```
|
|
252
115
|
|
|
253
|
-
###
|
|
254
|
-
|
|
255
|
-
Use `@Tags()` decorator to organize endpoints in Swagger UI:
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
@Route('api')
|
|
259
|
-
export class MyController {
|
|
260
|
-
// This endpoint appears in "Users" section
|
|
261
|
-
@Get('users')
|
|
262
|
-
@Tags('Users')
|
|
263
|
-
public async listUsers(): Promise<User[]> { ... }
|
|
264
|
-
|
|
265
|
-
// This endpoint appears in "Admin" section
|
|
266
|
-
@Get('admin/stats')
|
|
267
|
-
@Tags('Admin')
|
|
268
|
-
public async getStats(): Promise<Stats> { ... }
|
|
269
|
-
|
|
270
|
-
// This endpoint appears in BOTH sections
|
|
271
|
-
@Get('admin/users')
|
|
272
|
-
@Tags('Admin', 'Users')
|
|
273
|
-
public async adminListUsers(): Promise<User[]> { ... }
|
|
274
|
-
}
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
**Important**: Apply `@Tags()` to individual methods, not the class. Class-level `@Tags()` applies to ALL methods, which may cause unintended grouping.
|
|
116
|
+
### tsoa Decorators
|
|
278
117
|
|
|
279
|
-
|
|
118
|
+
| Decorator | Example |
|
|
119
|
+
|-----------|---------|
|
|
120
|
+
| `@Route('prefix')` | `@Route('api')` |
|
|
121
|
+
| `@Get('path')` | `@Get('users/{id}')` |
|
|
122
|
+
| `@Post('path')` | `@Post('users')` |
|
|
123
|
+
| `@Put('path')` | `@Put('users/{id}')` |
|
|
124
|
+
| `@Delete('path')` | `@Delete('users/{id}')` |
|
|
125
|
+
| `@Tags('name')` | `@Tags('Users')` |
|
|
126
|
+
| `@Body()` | `@Body() data: Request` |
|
|
127
|
+
| `@Query()` | `@Query() search?: string` |
|
|
128
|
+
| `@Path()` | `@Path() id: string` |
|
|
129
|
+
| `@Header()` | `@Header('x-api-key') key: string` |
|
|
130
|
+
| `@Security('bearerAuth')` | Mark endpoint as requiring auth |
|
|
280
131
|
|
|
281
|
-
|
|
282
|
-
|-----------|-------|---------|
|
|
283
|
-
| `@Route('prefix')` | Set route prefix | `@Route('api')` |
|
|
284
|
-
| `@Get('path')` | GET endpoint | `@Get('users/{id}')` |
|
|
285
|
-
| `@Post('path')` | POST endpoint | `@Post('users')` |
|
|
286
|
-
| `@Put('path')` | PUT endpoint | `@Put('users/{id}')` |
|
|
287
|
-
| `@Delete('path')` | DELETE endpoint | `@Delete('users/{id}')` |
|
|
288
|
-
| `@Tags('name')` | Swagger section | `@Tags('Users')` |
|
|
289
|
-
| `@Body()` | Request body | `@Body() data: CreateRequest` |
|
|
290
|
-
| `@Query()` | Query parameter | `@Query() search?: string` |
|
|
291
|
-
| `@Path()` | Path parameter | `@Path() id: string` |
|
|
292
|
-
| `@Header()` | Header value | `@Header('x-api-key') apiKey: string` |
|
|
132
|
+
**Note**: Apply `@Tags()` to methods, not class.
|
|
293
133
|
|
|
294
|
-
### Manual
|
|
134
|
+
### Manual Routes
|
|
295
135
|
|
|
296
|
-
For
|
|
136
|
+
For routes without OpenAPI docs:
|
|
297
137
|
|
|
298
138
|
```typescript
|
|
299
|
-
import { Router } from 'express';
|
|
300
139
|
import { createAuthMW } from 'fa-mcp-sdk';
|
|
301
140
|
|
|
302
|
-
export const apiRouter: Router = Router();
|
|
303
|
-
|
|
304
141
|
const authMW = createAuthMW();
|
|
305
|
-
|
|
306
|
-
// Manual route with authentication
|
|
307
142
|
apiRouter.get('/internal/status', authMW, (req, res) => {
|
|
308
|
-
res.json({ status: 'ok'
|
|
143
|
+
res.json({ status: 'ok' });
|
|
309
144
|
});
|
|
310
|
-
|
|
311
|
-
// tsoa controllers are still processed for OpenAPI generation
|
|
312
|
-
@Route('api')
|
|
313
|
-
export class PublicController {
|
|
314
|
-
@Get('health')
|
|
315
|
-
@Tags('Server')
|
|
316
|
-
public async health(): Promise<{ status: string }> {
|
|
317
|
-
return { status: 'healthy' };
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
145
|
```
|
|
321
146
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
## OpenAPI/Swagger API Reference
|
|
325
|
-
|
|
326
|
-
### Types
|
|
147
|
+
## OpenAPI Types
|
|
327
148
|
|
|
328
149
|
```typescript
|
|
329
|
-
import {
|
|
330
|
-
configureOpenAPI,
|
|
331
|
-
createSwaggerUIAssetsMiddleware,
|
|
332
|
-
OpenAPISpecResponse,
|
|
333
|
-
SwaggerUIConfig
|
|
334
|
-
} from 'fa-mcp-sdk';
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
### `OpenAPISpecResponse`
|
|
150
|
+
import { configureOpenAPI, OpenAPISpecResponse, SwaggerUIConfig } from 'fa-mcp-sdk';
|
|
338
151
|
|
|
339
|
-
Type representing the OpenAPI 3.0 specification structure.
|
|
340
|
-
|
|
341
|
-
```typescript
|
|
342
152
|
interface OpenAPISpecResponse {
|
|
343
153
|
openapi: string; // '3.0.0'
|
|
344
|
-
info: {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
}
|
|
349
|
-
servers?: Array<{
|
|
350
|
-
url: string;
|
|
351
|
-
description: string;
|
|
352
|
-
}>;
|
|
353
|
-
paths: Record<string, any>; // API endpoint definitions
|
|
354
|
-
components?: {
|
|
355
|
-
schemas?: Record<string, any>;
|
|
356
|
-
securitySchemes?: Record<string, any>;
|
|
357
|
-
};
|
|
358
|
-
tags?: Array<{
|
|
359
|
-
name: string;
|
|
360
|
-
description: string;
|
|
361
|
-
}>;
|
|
154
|
+
info: { title: string; version: string; description?: string };
|
|
155
|
+
servers?: Array<{ url: string; description: string }>;
|
|
156
|
+
paths: Record<string, any>;
|
|
157
|
+
components?: { schemas?: Record<string, any>; securitySchemes?: Record<string, any> };
|
|
158
|
+
tags?: Array<{ name: string; description: string }>;
|
|
362
159
|
}
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
### `SwaggerUIConfig`
|
|
366
160
|
|
|
367
|
-
Configuration options for customizing Swagger UI appearance and behavior.
|
|
368
|
-
|
|
369
|
-
```typescript
|
|
370
161
|
interface SwaggerUIConfig {
|
|
371
|
-
customCss?: string;
|
|
372
|
-
customSiteTitle?: string;
|
|
373
|
-
customfavIcon?: string;
|
|
162
|
+
customCss?: string;
|
|
163
|
+
customSiteTitle?: string;
|
|
164
|
+
customfavIcon?: string;
|
|
374
165
|
swaggerOptions?: {
|
|
375
|
-
persistAuthorization?: boolean;
|
|
376
|
-
displayRequestDuration?: boolean;
|
|
377
|
-
docExpansion?: 'none' | 'list' | 'full';
|
|
378
|
-
defaultModelsExpandDepth?: number;
|
|
379
|
-
urls?: Array<{ // Multiple spec sources
|
|
380
|
-
name: string;
|
|
381
|
-
url: string;
|
|
382
|
-
}>;
|
|
166
|
+
persistAuthorization?: boolean;
|
|
167
|
+
displayRequestDuration?: boolean;
|
|
168
|
+
docExpansion?: 'none' | 'list' | 'full';
|
|
169
|
+
defaultModelsExpandDepth?: number;
|
|
383
170
|
};
|
|
384
171
|
}
|
|
385
172
|
```
|
|
386
173
|
|
|
387
|
-
###
|
|
388
|
-
|
|
389
|
-
Automatically configures and serves OpenAPI documentation for APIs with tsoa decorators. Called internally by `initMcpServer()` when `httpComponents.apiRouter` is provided.
|
|
390
|
-
|
|
391
|
-
```typescript
|
|
392
|
-
// Function Signature:
|
|
393
|
-
async function configureOpenAPI(apiRouter?: Router | null): Promise<{
|
|
394
|
-
swaggerUi?: any;
|
|
395
|
-
swaggerSpecs?: any;
|
|
396
|
-
} | null>;
|
|
397
|
-
|
|
398
|
-
// Behavior:
|
|
399
|
-
// 1. Checks for swagger/openapi.yaml in project root
|
|
400
|
-
// 2. If not found, generates spec using tsoa programmatic API
|
|
401
|
-
// 3. Enhances spec with app configuration (servers, auth, info)
|
|
402
|
-
// 4. Creates /api/openapi.json and /api/openapi.yaml endpoints
|
|
403
|
-
// 5. Returns Swagger UI middleware for /docs endpoint
|
|
404
|
-
|
|
405
|
-
// The function is called automatically - typically no manual invocation needed
|
|
406
|
-
// To customize, modify config/default.yaml:
|
|
407
|
-
|
|
408
|
-
// config/default.yaml
|
|
409
|
-
swagger:
|
|
410
|
-
servers:
|
|
411
|
-
- url: 'https://api.production.com'
|
|
412
|
-
description: 'Production server'
|
|
413
|
-
- url: 'https://api.staging.com'
|
|
414
|
-
description: 'Staging server'
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
### `createSwaggerUIAssetsMiddleware()`
|
|
418
|
-
|
|
419
|
-
Creates Express middleware for serving Swagger UI static assets. Used internally to set up the `/docs` endpoint.
|
|
420
|
-
|
|
421
|
-
```typescript
|
|
422
|
-
import { createSwaggerUIAssetsMiddleware } from 'fa-mcp-sdk';
|
|
423
|
-
|
|
424
|
-
// Function Signature:
|
|
425
|
-
function createSwaggerUIAssetsMiddleware(): RequestHandler[];
|
|
426
|
-
|
|
427
|
-
// Returns swagger-ui-express.serve middleware array
|
|
428
|
-
// Typically used internally by configureOpenAPI()
|
|
429
|
-
|
|
430
|
-
// Manual usage (advanced):
|
|
431
|
-
import express from 'express';
|
|
432
|
-
const app = express();
|
|
433
|
-
|
|
434
|
-
app.use('/docs', createSwaggerUIAssetsMiddleware(), swaggerUiSetup);
|
|
435
|
-
```
|
|
436
|
-
|
|
437
|
-
### OpenAPI Specification Generation
|
|
438
|
-
|
|
439
|
-
The OpenAPI specification is generated automatically when the server starts:
|
|
440
|
-
|
|
441
|
-
1. **Automatic Generation**: If `swagger/openapi.yaml` doesn't exist, it's generated from tsoa-decorated controllers
|
|
442
|
-
2. **Manual Regeneration**: Delete `swagger/openapi.yaml` and restart the server
|
|
443
|
-
3. **Source Files**: Controllers in `src/api/*.ts` are scanned for decorators
|
|
444
|
-
|
|
445
|
-
**Generated Spec Location:**
|
|
446
|
-
- `swagger/openapi.yaml` - YAML format (primary)
|
|
447
|
-
- Runtime endpoints: `/api/openapi.json`, `/api/openapi.yaml`
|
|
448
|
-
|
|
449
|
-
**Accessing Documentation:**
|
|
450
|
-
- Swagger UI: `http://localhost:{port}/docs`
|
|
451
|
-
- Raw spec: `http://localhost:{port}/api/openapi.json`
|
|
452
|
-
|
|
453
|
-
### Configuration via YAML
|
|
174
|
+
### Swagger Config
|
|
454
175
|
|
|
455
176
|
```yaml
|
|
456
177
|
# config/default.yaml
|
|
457
178
|
swagger:
|
|
458
179
|
servers:
|
|
459
|
-
- url: 'http://localhost:3000'
|
|
460
|
-
description: 'Development server'
|
|
461
180
|
- url: 'https://api.example.com'
|
|
462
|
-
description: 'Production
|
|
181
|
+
description: 'Production'
|
|
463
182
|
|
|
464
183
|
webServer:
|
|
465
184
|
auth:
|
|
466
|
-
enabled: true # Adds Bearer auth to
|
|
185
|
+
enabled: true # Adds Bearer auth to spec
|
|
467
186
|
```
|
|
468
187
|
|
|
188
|
+
|
|
469
189
|
### Example: Complete API Setup
|
|
470
190
|
|
|
471
191
|
```typescript
|