fa-mcp-sdk 0.2.182 → 0.2.192

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 (31) hide show
  1. package/cli-template/.claude/agents/fa-mcp-sdk.md +158 -0
  2. package/cli-template/FA-MCP-SDK-DOC/00-FA-MCP-SDK-index.md +216 -0
  3. package/cli-template/FA-MCP-SDK-DOC/01-getting-started.md +209 -0
  4. package/cli-template/FA-MCP-SDK-DOC/02-tools-and-api.md +321 -0
  5. package/cli-template/FA-MCP-SDK-DOC/03-configuration.md +415 -0
  6. package/cli-template/FA-MCP-SDK-DOC/04-authentication.md +544 -0
  7. package/cli-template/FA-MCP-SDK-DOC/05-ad-authorization.md +476 -0
  8. package/cli-template/FA-MCP-SDK-DOC/06-utilities.md +394 -0
  9. package/cli-template/FA-MCP-SDK-DOC/07-testing-and-operations.md +171 -0
  10. package/dist/core/_types_/types.d.ts +0 -5
  11. package/dist/core/_types_/types.d.ts.map +1 -1
  12. package/dist/core/index.d.ts +2 -1
  13. package/dist/core/index.d.ts.map +1 -1
  14. package/dist/core/index.js +2 -0
  15. package/dist/core/index.js.map +1 -1
  16. package/dist/core/web/home-api.js +1 -1
  17. package/dist/core/web/home-api.js.map +1 -1
  18. package/dist/core/web/openapi.d.ts +64 -0
  19. package/dist/core/web/openapi.d.ts.map +1 -0
  20. package/dist/core/web/openapi.js +235 -0
  21. package/dist/core/web/openapi.js.map +1 -0
  22. package/dist/core/web/server-http.d.ts.map +1 -1
  23. package/dist/core/web/server-http.js +11 -9
  24. package/dist/core/web/server-http.js.map +1 -1
  25. package/dist/core/web/static/home/index.html +4 -2
  26. package/dist/core/web/static/home/script.js +2 -2
  27. package/package.json +9 -12
  28. package/src/template/api/router.ts +66 -4
  29. package/src/template/start.ts +0 -5
  30. package/cli-template/FA-MCP-SDK.md +0 -2540
  31. package/src/template/api/swagger.ts +0 -167
@@ -0,0 +1,544 @@
1
+ # Authentication and Security
2
+
3
+ ## Token-based Authentication
4
+
5
+ ```typescript
6
+ import {
7
+ ICheckTokenResult,
8
+ checkJwtToken,
9
+ generateToken
10
+ } from 'fa-mcp-sdk';
11
+
12
+ // Types used:
13
+ export interface ICheckTokenResult {
14
+ payload?: ITokenPayload, // Token payload with user data
15
+ errorReason?: string, // Error message if validation failed
16
+ isTokenDecrypted?: boolean, // Whether token was successfully decrypted
17
+ }
18
+
19
+ export interface ITokenPayload {
20
+ user: string, // Username
21
+ expire: number, // Expiration timestamp
22
+ [key: string]: any, // Additional payload data
23
+ }
24
+
25
+ // checkJwtToken - validate token and return detailed result
26
+ // Function Signature:
27
+ const checkJwtToken = (arg: {
28
+ token: string,
29
+ expectedUser?: string,
30
+ expectedService?: string,
31
+ }): ICheckTokenResult {...}
32
+
33
+ // Example:
34
+ const tokenResult = checkJwtToken({
35
+ token: 'user_provided_token',
36
+ expectedUser: 'john_doe',
37
+ expectedService: 'my-mcp-server'
38
+ });
39
+
40
+ if (!tokenResult.errorReason) {
41
+ console.log('Valid token for user:', tokenResult.payload?.user);
42
+ } else {
43
+ console.log('Auth failed:', tokenResult.errorReason);
44
+ }
45
+
46
+ // generateToken - create JWT token
47
+ // Function Signature:
48
+ const generateToken = (user: string, liveTimeSec: number, payload?: any): string {...}
49
+
50
+ // Example:
51
+ const token = generateToken('john_doe', 3600, { role: 'admin' }); // 1 hour token
52
+
53
+ // Deprecated: authByToken was replaced by createAuthMW universal middleware
54
+ // Use createAuthMW instead for all authentication scenarios:
55
+
56
+ // Example - Modern approach:
57
+ app.post('/api/secure', createAuthMW(), (req, res) => {
58
+ // User is authenticated, authInfo available on req
59
+ const authInfo = (req as any).authInfo;
60
+ res.json({
61
+ message: 'Access granted',
62
+ authType: authInfo?.authType,
63
+ username: authInfo?.username
64
+ });
65
+ });
66
+ ```
67
+
68
+ ## Test Authentication Headers
69
+
70
+ ```typescript
71
+ import { getAuthHeadersForTests } from 'fa-mcp-sdk';
72
+
73
+ // getAuthHeadersForTests - automatically generate authentication headers for testing
74
+ // Function Signature:
75
+ function getAuthHeadersForTests(): object {...}
76
+
77
+ // Determines authentication headers based on appConfig.webServer.auth configuration.
78
+ // Returns Authorization header using the first valid auth method found.
79
+ //
80
+ // Priority order (CPU-optimized, fastest first):
81
+ // 1. permanentServerTokens - if at least one token is defined
82
+ // 2. basic auth - if username AND password are both set
83
+ // 3. JWT token - if jwtToken.encryptKey is set, generates token on the fly
84
+ //
85
+ // Returns empty object if auth is not enabled or no valid method configured.
86
+
87
+ // Examples:
88
+ const headers = getAuthHeadersForTests();
89
+
90
+ // Use in fetch requests
91
+ const response = await fetch('http://localhost:3000/mcp', {
92
+ method: 'POST',
93
+ headers: {
94
+ 'Content-Type': 'application/json',
95
+ ...headers // Automatically adds Authorization header if auth is enabled
96
+ },
97
+ body: JSON.stringify(requestBody)
98
+ });
99
+
100
+ // Use with test clients
101
+ import { McpHttpClient } from 'fa-mcp-sdk';
102
+
103
+ const client = new McpHttpClient('http://localhost:3000');
104
+ const authHeaders = getAuthHeadersForTests();
105
+ const result = await client.callTool('my_tool', { query: 'test' }, authHeaders);
106
+
107
+ // Return value examples based on configuration:
108
+
109
+ // If permanentServerTokens configured:
110
+ // { Authorization: 'Bearer server-token-1' }
111
+
112
+ // If basic auth configured:
113
+ // { Authorization: 'Basic YWRtaW46cGFzc3dvcmQ=' } // base64 of 'admin:password'
114
+
115
+ // If JWT encryptKey configured:
116
+ // { Authorization: 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...' }
117
+
118
+ // If auth.enabled = false or no valid method:
119
+ // {}
120
+
121
+ // Typical test setup:
122
+ import { getAuthHeadersForTests, appConfig } from 'fa-mcp-sdk';
123
+
124
+ describe('MCP Server Tests', () => {
125
+ const baseUrl = `http://localhost:${appConfig.webServer.port}`;
126
+ const authHeaders = getAuthHeadersForTests();
127
+
128
+ it('should call tool with authentication', async () => {
129
+ const response = await fetch(`${baseUrl}/mcp`, {
130
+ method: 'POST',
131
+ headers: {
132
+ 'Content-Type': 'application/json',
133
+ ...authHeaders
134
+ },
135
+ body: JSON.stringify({
136
+ jsonrpc: '2.0',
137
+ method: 'tools/call',
138
+ params: { name: 'my_tool', arguments: { query: 'test' } },
139
+ id: 1
140
+ })
141
+ });
142
+
143
+ expect(response.ok).toBe(true);
144
+ });
145
+ });
146
+ ```
147
+
148
+ ## Token Generator Authorization Handler
149
+
150
+ The Token Generator admin page (`/admin/`) can be protected with an additional
151
+ custom authorization layer beyond the standard authentication. This allows you
152
+ to implement fine-grained access control, such as restricting access to specific
153
+ AD groups or roles.
154
+
155
+ ### Types
156
+
157
+ ```typescript
158
+ import { TokenGenAuthHandler, TokenGenAuthInput, AuthResult } from 'fa-mcp-sdk';
159
+
160
+ // Input data passed to the authorization handler
161
+ interface TokenGenAuthInput {
162
+ user: string; // Username from authentication
163
+ domain?: string; // Domain (only for NTLM auth)
164
+ payload?: Record<string, any>; // JWT payload (only for jwtToken auth)
165
+ authType: 'jwtToken' | 'basic' | 'ntlm' | 'permanentServerTokens';
166
+ }
167
+
168
+ // Authorization handler function type
169
+ type TokenGenAuthHandler = (input: TokenGenAuthInput) => Promise<AuthResult> | AuthResult;
170
+ ```
171
+
172
+ ### Configuration
173
+
174
+ Add `tokenGenAuthHandler` to your `McpServerData` in `src/start.ts`:
175
+
176
+ ```typescript
177
+ import { initMcpServer, McpServerData, TokenGenAuthHandler, initADGroupChecker } from 'fa-mcp-sdk';
178
+
179
+ // Example 1: Restrict to specific AD groups (NTLM authentication)
180
+ const { isUserInGroup } = initADGroupChecker();
181
+
182
+ const tokenGenAuthHandler: TokenGenAuthHandler = async (input) => {
183
+ // Only check for NTLM-authenticated users
184
+ if (input.authType === 'ntlm') {
185
+ const isAdmin = await isUserInGroup(input.user, 'TokenGeneratorAdmins');
186
+ if (!isAdmin) {
187
+ return {
188
+ success: false,
189
+ error: `User ${input.user} is not authorized to access Token Generator`,
190
+ };
191
+ }
192
+ }
193
+ return { success: true, username: input.user };
194
+ };
195
+
196
+ // Example 2: Check JWT payload for specific claims
197
+ const tokenGenAuthHandler: TokenGenAuthHandler = async (input) => {
198
+ if (input.authType === 'jwtToken') {
199
+ const roles = input.payload?.roles || [];
200
+ if (!roles.includes('token-admin')) {
201
+ return {
202
+ success: false,
203
+ error: 'Missing required role: token-admin',
204
+ };
205
+ }
206
+ }
207
+ return { success: true, username: input.user };
208
+ };
209
+
210
+ // Example 3: Simple whitelist check
211
+ const allowedUsers = ['admin', 'john.doe', 'jane.smith'];
212
+
213
+ const tokenGenAuthHandler: TokenGenAuthHandler = (input) => {
214
+ if (!allowedUsers.includes(input.user.toLowerCase())) {
215
+ return {
216
+ success: false,
217
+ error: `User ${input.user} is not in the allowed users list`,
218
+ };
219
+ }
220
+ return { success: true, username: input.user };
221
+ };
222
+
223
+ // Use in McpServerData
224
+ const serverData: McpServerData = {
225
+ tools,
226
+ toolHandler: handleToolCall,
227
+ agentBrief: AGENT_BRIEF,
228
+ agentPrompt: AGENT_PROMPT,
229
+
230
+ // Add custom authorization for Token Generator
231
+ tokenGenAuthHandler,
232
+
233
+ // ... other configuration
234
+ };
235
+
236
+ await initMcpServer(serverData);
237
+ ```
238
+
239
+ ### Behavior
240
+
241
+ - **If `tokenGenAuthHandler` is not provided**: All authenticated users can access Token Generator
242
+ - **If handler returns `{ success: true }`**: User is authorized
243
+ - **If handler returns `{ success: false, error: '...' }`**: User receives 403 Forbidden with error message
244
+ - **Handler errors**: Caught and returned as 403 with error message
245
+
246
+ ### Auth Type Input Details
247
+
248
+ | Auth Type | `user` | `domain` | `payload` |
249
+ |-----------|--------|----------|-----------|
250
+ | `ntlm` | NTLM username | NTLM domain | - |
251
+ | `basic` | Basic auth username | - | - |
252
+ | `jwtToken` | JWT `user` claim | - | Full JWT payload |
253
+ | `permanentServerTokens` | "Unknown" | - | - |
254
+
255
+ ---
256
+
257
+ ## Multi-Authentication System
258
+
259
+ The FA-MCP-SDK supports a comprehensive multi-authentication system that allows multiple authentication methods to work together with CPU-optimized performance ordering.
260
+
261
+ ### Types and Interfaces
262
+
263
+ ```typescript
264
+ import {
265
+ AuthType,
266
+ AuthResult,
267
+ AuthDetectionResult,
268
+ CustomAuthValidator,
269
+ checkMultiAuth,
270
+ detectAuthConfiguration,
271
+ logAuthConfiguration,
272
+ createAuthMW, // Universal authentication middleware
273
+ getMultiAuthError, // Programmatic authentication checking
274
+ } from 'fa-mcp-sdk';
275
+
276
+ // Authentication types in CPU priority order (low to high cost)
277
+ export type AuthType = 'permanentServerTokens' | 'jwtToken' | 'basic' | 'custom';
278
+
279
+ // Custom Authentication validator function (black box - receives full request)
280
+ export type CustomAuthValidator = (req: any) => Promise<AuthResult> | AuthResult;
281
+
282
+ // Authentication result interface
283
+ export interface AuthResult {
284
+ success: boolean;
285
+ error?: string;
286
+ authType?: AuthType;
287
+ username?: string;
288
+ isTokenDecrypted?: boolean; // only for JWT
289
+ payload?: any;
290
+ }
291
+
292
+ // Authentication detection result
293
+ export interface AuthDetectionResult {
294
+ configured: AuthType[]; // Authentication types found in configuration
295
+ valid: AuthType[]; // Authentication types properly configured and ready
296
+ errors: Record<string, string[]>; // Configuration errors by auth type
297
+ }
298
+ ```
299
+
300
+ ### Core Multi-Authentication Functions
301
+
302
+ ```typescript
303
+ // checkMultiAuth - validate using all configured authentication methods
304
+ // Function Signature:
305
+ async function checkMultiAuth(req: Request): Promise<AuthResult> {...}
306
+
307
+ // Example:
308
+ const result = await checkMultiAuth(req);
309
+
310
+ if (result.success) {
311
+ console.log(`Authenticated via ${result.authType} as ${result.username}`);
312
+ } else {
313
+ console.log('Authentication failed:', result.error);
314
+ }
315
+
316
+ // detectAuthConfiguration - analyze auth configuration
317
+ // Function Signature:
318
+ function detectAuthConfiguration(): AuthDetectionResult {...}
319
+
320
+ // Example:
321
+ const detection = detectAuthConfiguration();
322
+ console.log('Configured auth types:', detection.configured);
323
+ console.log('Valid auth types:', detection.valid);
324
+ console.log('Configuration errors:', detection.errors);
325
+
326
+ // logAuthConfiguration - log auth system status (debugging)
327
+ // Function Signature:
328
+ function logAuthConfiguration(): void {...}
329
+
330
+ // Example:
331
+ logAuthConfiguration();
332
+ // Output:
333
+ // Auth system configuration:
334
+ // - enabled: true
335
+ // - configured types: permanentServerTokens, basic
336
+ ```
337
+
338
+ ### Multi-Authentication Middleware
339
+
340
+ ```typescript
341
+ import express from 'express';
342
+ import {
343
+ createAuthMW,
344
+ getMultiAuthError,
345
+ } from 'fa-mcp-sdk';
346
+
347
+ // Universal authentication middleware with flexible options
348
+ const app = express();
349
+
350
+ // Basic usage - handles all authentication scenarios automatically
351
+ const authMW = createAuthMW();
352
+ app.use('/api', authMW);
353
+
354
+ app.get('/api/protected', (req, res) => {
355
+ const authInfo = (req as any).authInfo;
356
+ res.json({
357
+ message: 'Access granted',
358
+ authType: authInfo?.authType,
359
+ username: authInfo?.username,
360
+ });
361
+ });
362
+
363
+ // Advanced usage with custom options
364
+ const customAuthMW = createAuthMW({
365
+ mcpPaths: ['/mcp', '/messages', '/sse', '/custom'], // Custom MCP paths
366
+ logConfig: true, // Force logging
367
+ });
368
+ app.use('/custom-endpoints', customAuthMW);
369
+
370
+ // createAuthMW - Universal authentication middleware
371
+ // Function Signature:
372
+ function createAuthMW(options?: {
373
+ mcpPaths?: string[]; // Paths to check for public MCP requests (default: ['/mcp', '/messages', '/sse'])
374
+ logConfig?: boolean; // Log auth configuration on first request (default: from LOG_AUTH_CONFIG env)
375
+ }): (req: Request, res: Response, next: NextFunction) => Promise<void>
376
+
377
+ // Features:
378
+ // ✅ Combines all authentication methods (standard + custom validator)
379
+ // ✅ Supports public MCP resources/prompts (requireAuth: false)
380
+ // ✅ Configurable MCP paths
381
+ // ✅ CPU-optimized authentication order
382
+ // ✅ Automatic auth method detection
383
+ // ✅ Request context enrichment (req.authInfo)
384
+
385
+ // getMultiAuthError - Programmatic authentication checking
386
+ // Function Signature:
387
+ async function getMultiAuthError(req: Request): Promise<{ code: number, message: string } | undefined>
388
+
389
+ // Returns error object if authentication failed, undefined if successful
390
+ // Uses checkMultiAuth internally - supports all authentication methods
391
+
392
+ // Example - Custom middleware with different auth levels
393
+ app.use('/api/custom', async (req, res, next) => {
394
+ if (req.path.startsWith('/api/custom/public')) {
395
+ return next(); // Public endpoints
396
+ }
397
+
398
+ if (req.path.startsWith('/api/custom/admin')) {
399
+ // Admin endpoints - require server tokens only
400
+ const token = (req.headers.authorization || '').replace(/^Bearer */, '');
401
+ if (appConfig.webServer.auth.permanentServerTokens.includes(token)) {
402
+ return next();
403
+ }
404
+ return res.status(403).json({ error: 'Admin access required' });
405
+ }
406
+
407
+ // Regular endpoints - use full multi-auth
408
+ try {
409
+ const authError = await getMultiAuthError(req);
410
+ if (authError) {
411
+ res.status(authError.code).send(authError.message);
412
+ return;
413
+ }
414
+ next();
415
+ } catch (error) {
416
+ res.status(500).send('Authentication error');
417
+ }
418
+ });
419
+ ```
420
+
421
+ ### Custom Authentication
422
+
423
+ You can provide custom authentication validation functions through the `McpServerData` interface. The custom validator receives the full Express request object, allowing for flexible authentication logic:
424
+
425
+ ```typescript
426
+ import { McpServerData, CustomAuthValidator } from 'fa-mcp-sdk';
427
+
428
+ // Database-backed authentication with request context
429
+ const databaseAuthValidator: CustomAuthValidator = async (req): Promise<AuthResult> => {
430
+ try {
431
+ // Extract authentication data from various sources
432
+ const authHeader = req.headers.authorization;
433
+ const username = req.headers['x-username'];
434
+ const apiKey = req.headers['x-api-key'];
435
+
436
+ if (authHeader?.startsWith('Basic ')) {
437
+ const [user, pass] = Buffer.from(authHeader.slice(6), 'base64').toString().split(':');
438
+ const dbUser = await getUserFromDatabase(user);
439
+
440
+ if (dbUser && await comparePassword(pass, dbUser.hashedPassword)) {
441
+ return {
442
+ success: true,
443
+ authType: 'basic',
444
+ username: dbUser.username,
445
+ payload: { userId: dbUser.id, roles: dbUser.roles }
446
+ };
447
+ }
448
+ }
449
+
450
+ if (apiKey && username) {
451
+ const isValid = await validateUserApiKey(username, apiKey);
452
+ if (isValid) {
453
+ return {
454
+ success: true,
455
+ authType: 'basic',
456
+ username: username,
457
+ payload: { apiKey: apiKey.substring(0, 8) + '...' }
458
+ };
459
+ }
460
+ }
461
+
462
+ return { success: false, error: 'Invalid credentials' };
463
+ } catch (error) {
464
+ console.error('Database authentication error:', error);
465
+ return { success: false, error: 'Database authentication error' };
466
+ }
467
+ };
468
+
469
+ // Use custom validator in MCP server
470
+ const serverData: McpServerData = {
471
+ tools,
472
+ toolHandler,
473
+ agentBrief: 'My MCP Server',
474
+ agentPrompt: 'Server with custom authentication',
475
+
476
+ // Provide custom authentication validator (black box function)
477
+ customAuthValidator: databaseAuthValidator,
478
+
479
+ // ... other configuration
480
+ };
481
+
482
+ await initMcpServer(serverData);
483
+ ```
484
+
485
+ ### Client Usage Examples
486
+
487
+ ```bash
488
+ # Using permanent server token
489
+ curl -H "Authorization: Bearer server-token-1" http://localhost:3000/mcp
490
+
491
+ # Using JWT token
492
+ curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhb..." http://localhost:3000/mcp
493
+
494
+ # Using Basic Authentication
495
+ curl -H "Authorization: Basic $(echo -n 'admin:password' | base64)" http://localhost:3000/mcp
496
+
497
+ # Using custom headers for custom validator
498
+ curl -H "X-User-ID: john.doe" \
499
+ -H "X-API-Key: custom-api-key-12345" \
500
+ -H "X-Client-IP: 192.168.1.10" \
501
+ http://localhost:3000/mcp
502
+ ```
503
+
504
+ The multi-authentication system automatically tries authentication methods in CPU-optimized order (fastest first) and returns on the first successful match, providing both performance and flexibility.
505
+
506
+ ---
507
+
508
+ ## AD Group Checking
509
+
510
+ ### Configuration (`config/local.yaml`)
511
+
512
+ ```yaml
513
+ ad:
514
+ domains:
515
+ MYDOMAIN:
516
+ default: true
517
+ controllers: ['ldap://dc1.corp.com']
518
+ username: 'svc_account@corp.com'
519
+ password: '***'
520
+ # baseDn: 'DC=corp,DC=com' # Optional, auto-derived from controller URL
521
+ ```
522
+
523
+ ### Usage
524
+
525
+ ```typescript
526
+ import { initADGroupChecker } from 'fa-mcp-sdk';
527
+
528
+ const { isUserInGroup, groupChecker } = initADGroupChecker();
529
+
530
+ const isAdmin = await isUserInGroup('john.doe', 'Admins');
531
+ const isDeveloper = await isUserInGroup('john.doe', 'Developers');
532
+
533
+ groupChecker.clearCache(); // Clear cache if needed
534
+ ```
535
+
536
+ ---
537
+
538
+ ## Advanced Authorization with AD Group Membership
539
+
540
+ See the separate documentation file `05-ad-authorization.md` for detailed examples of:
541
+
542
+ 1. **HTTP Server Level Access Restriction** - Using `customAuthValidator`
543
+ 2. **Access Restriction to ALL MCP Tools** - Checking in `toolHandler`
544
+ 3. **Access Restriction to SPECIFIC MCP Tools** - Per-tool group requirements