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.
Files changed (46) hide show
  1. package/cli-template/FA-MCP-SDK-DOC/00-FA-MCP-SDK-index.md +45 -161
  2. package/cli-template/FA-MCP-SDK-DOC/01-getting-started.md +71 -226
  3. package/cli-template/FA-MCP-SDK-DOC/02-1-tools-and-api.md +80 -360
  4. package/cli-template/FA-MCP-SDK-DOC/02-2-prompts-and-resources.md +191 -342
  5. package/cli-template/FA-MCP-SDK-DOC/03-configuration.md +141 -279
  6. package/cli-template/FA-MCP-SDK-DOC/04-authentication.md +73 -522
  7. package/cli-template/FA-MCP-SDK-DOC/05-ad-authorization.md +68 -419
  8. package/cli-template/FA-MCP-SDK-DOC/06-utilities.md +64 -447
  9. package/cli-template/FA-MCP-SDK-DOC/07-testing-and-operations.md +39 -196
  10. package/cli-template/package.json +2 -1
  11. package/config/local.yaml +1 -1
  12. package/dist/core/_types_/types.d.ts +36 -10
  13. package/dist/core/_types_/types.d.ts.map +1 -1
  14. package/dist/core/auth/admin-auth.js +1 -1
  15. package/dist/core/auth/admin-auth.js.map +1 -1
  16. package/dist/core/auth/middleware.js +8 -8
  17. package/dist/core/auth/middleware.js.map +1 -1
  18. package/dist/core/auth/multi-auth.d.ts.map +1 -1
  19. package/dist/core/auth/multi-auth.js +15 -14
  20. package/dist/core/auth/multi-auth.js.map +1 -1
  21. package/dist/core/index.d.ts +1 -1
  22. package/dist/core/index.d.ts.map +1 -1
  23. package/dist/core/index.js.map +1 -1
  24. package/dist/core/mcp/create-mcp-server.js +8 -9
  25. package/dist/core/mcp/create-mcp-server.js.map +1 -1
  26. package/dist/core/mcp/prompts.d.ts +10 -5
  27. package/dist/core/mcp/prompts.d.ts.map +1 -1
  28. package/dist/core/mcp/prompts.js +17 -15
  29. package/dist/core/mcp/prompts.js.map +1 -1
  30. package/dist/core/mcp/resources.d.ts +4 -4
  31. package/dist/core/mcp/resources.d.ts.map +1 -1
  32. package/dist/core/mcp/resources.js +21 -20
  33. package/dist/core/mcp/resources.js.map +1 -1
  34. package/dist/core/utils/utils.d.ts +2 -1
  35. package/dist/core/utils/utils.d.ts.map +1 -1
  36. package/dist/core/utils/utils.js +2 -2
  37. package/dist/core/utils/utils.js.map +1 -1
  38. package/dist/core/web/home-api.d.ts.map +1 -1
  39. package/dist/core/web/home-api.js +4 -3
  40. package/dist/core/web/home-api.js.map +1 -1
  41. package/dist/core/web/server-http.d.ts.map +1 -1
  42. package/dist/core/web/server-http.js +36 -21
  43. package/dist/core/web/server-http.js.map +1 -1
  44. package/package.json +1 -1
  45. package/scripts/update-doc.js +21 -0
  46. package/src/template/start.ts +1 -1
@@ -1,184 +1,86 @@
1
- # Tools and REST API Development
1
+ # Tools and REST API
2
2
 
3
3
  ## Tool Development
4
4
 
5
- ### Tool Definition in `src/tools/tools.ts`
5
+ ### Tool Definition (`src/tools/tools.ts`)
6
6
 
7
7
  ```typescript
8
8
  import { Tool } from '@modelcontextprotocol/sdk/types.js';
9
- import { IToolInputSchema } from 'fa-mcp-sdk';
10
-
11
- export const tools: Tool[] = [
12
- {
13
- name: 'my_custom_tool',
14
- description: 'Description of what this tool does',
15
- inputSchema: {
16
- type: 'object',
17
- properties: {
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 in `src/tools/handle-tool-call.ts`
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 contains { user: string, ... } if JWT authentication is enabled
41
-
42
- logger.info(`Tool called: ${name}`);
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
- return await handleMyCustomTool(args);
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 execution failed for ${name}:`, error);
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
- ### HTTP Headers in Tool Handler
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
- **Key Features:**
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
- import { IToolHandlerParams } from 'fa-mcp-sdk';
98
-
99
- export const handleToolCall = async (params: IToolHandlerParams): Promise<any> => {
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
- **Header Normalization Details:**
60
+ ### Transport-Based Credentials
135
61
 
136
62
  ```typescript
137
- // Original headers from client:
138
- {
139
- 'Authorization': 'Bearer token123',
140
- 'X-Custom-Header': 'value',
141
- 'USER-AGENT': 'MyClient/1.0'
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
- The SDK supports custom REST API endpoints alongside MCP tools. Define your endpoints in `src/api/router.ts` using [tsoa](https://tsoa-community.github.io/docs/) decorators for automatic OpenAPI/Swagger documentation generation.
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
- **Swagger is generated automatically** when the server starts if `swagger/openapi.yaml` doesn't exist. The specification is built from tsoa-decorated controllers in your `src/api/` directory.
173
-
174
- - **Swagger UI**: Available at `/docs`
175
- - **OpenAPI spec**: Available at `/api/openapi.json` and `/api/openapi.yaml`
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
- To regenerate the spec, simply delete `swagger/openapi.yaml` and restart the server.
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
- // Response interfaces for tsoa (used in OpenAPI schema generation)
190
- export interface UserResponse {
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
- logger.info(`Getting user: ${userId}`);
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
- @Body() body: CreateUserRequest
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
- ### Tags Organization
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
- ### Common tsoa Decorators
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
- | Decorator | Usage | Example |
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 Express Routes
134
+ ### Manual Routes
295
135
 
296
- For endpoints not requiring OpenAPI documentation, use standard Express routing:
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', timestamp: Date.now() });
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
- title: string;
346
- version: string;
347
- description?: string;
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; // Custom CSS overrides
372
- customSiteTitle?: string; // Browser tab title
373
- customfavIcon?: string; // Custom favicon URL
162
+ customCss?: string;
163
+ customSiteTitle?: string;
164
+ customfavIcon?: string;
374
165
  swaggerOptions?: {
375
- persistAuthorization?: boolean; // Remember auth between reloads
376
- displayRequestDuration?: boolean; // Show request timing
377
- docExpansion?: 'none' | 'list' | 'full'; // Default expansion
378
- defaultModelsExpandDepth?: number; // Schema expansion depth
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
- ### `configureOpenAPI()`
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 server'
181
+ description: 'Production'
463
182
 
464
183
  webServer:
465
184
  auth:
466
- enabled: true # Adds Bearer auth to OpenAPI spec
185
+ enabled: true # Adds Bearer auth to spec
467
186
  ```
468
187
 
188
+
469
189
  ### Example: Complete API Setup
470
190
 
471
191
  ```typescript