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,528 +1,129 @@
|
|
|
1
|
-
# Authentication
|
|
1
|
+
# Authentication
|
|
2
2
|
|
|
3
|
-
##
|
|
4
|
-
|
|
5
|
-
### `TTokenType`
|
|
6
|
-
|
|
7
|
-
Type identifier for authentication methods. Used to indicate which authentication mechanism was used for a request.
|
|
3
|
+
## Auth Types
|
|
8
4
|
|
|
9
5
|
```typescript
|
|
10
|
-
import { TTokenType } from 'fa-mcp-sdk';
|
|
11
|
-
|
|
12
|
-
// Type Definition:
|
|
13
6
|
type TTokenType = 'permanent' | 'JWT';
|
|
14
7
|
|
|
15
|
-
// Usage in authentication results:
|
|
16
8
|
interface AuthResult {
|
|
17
9
|
success: boolean;
|
|
18
|
-
|
|
10
|
+
error?: string;
|
|
11
|
+
authType?: 'permanentServerTokens' | 'jwtToken' | 'basic' | 'custom';
|
|
19
12
|
username?: string;
|
|
20
|
-
|
|
13
|
+
isTokenDecrypted?: boolean;
|
|
14
|
+
payload?: any;
|
|
21
15
|
}
|
|
22
16
|
```
|
|
23
17
|
|
|
24
|
-
|
|
25
|
-
|-------|-------------|
|
|
26
|
-
| `'permanent'` | Permanent server token from `permanentServerTokens` config |
|
|
27
|
-
| `'JWT'` | JSON Web Token authentication |
|
|
28
|
-
|
|
29
|
-
---
|
|
30
|
-
|
|
31
|
-
## Token-based Authentication
|
|
18
|
+
## Token Operations
|
|
32
19
|
|
|
33
20
|
```typescript
|
|
34
|
-
import {
|
|
35
|
-
ICheckTokenResult,
|
|
36
|
-
ITokenPayload,
|
|
37
|
-
generateToken
|
|
38
|
-
} from 'fa-mcp-sdk';
|
|
39
|
-
|
|
40
|
-
// Note: checkJwtToken is internal. Use createAuthMW() or getMultiAuthError() for authentication.
|
|
41
|
-
|
|
42
|
-
// Types used:
|
|
43
|
-
export interface ICheckTokenResult {
|
|
44
|
-
payload?: ITokenPayload, // Token payload with user data
|
|
45
|
-
errorReason?: string, // Error message if validation failed
|
|
46
|
-
isTokenDecrypted?: boolean, // Whether token was successfully decrypted
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface ITokenPayload {
|
|
50
|
-
user: string, // Username
|
|
51
|
-
expire: number, // Expiration timestamp
|
|
52
|
-
[key: string]: any, // Additional payload data
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Note: Token validation is handled automatically by createAuthMW() middleware.
|
|
56
|
-
// For programmatic validation, use getMultiAuthError() which supports all auth methods.
|
|
57
|
-
|
|
58
|
-
// generateToken - create JWT token
|
|
59
|
-
// Function Signature:
|
|
60
|
-
const generateToken = (user: string, liveTimeSec: number, payload?: any): string {...}
|
|
61
|
-
|
|
62
|
-
// Example:
|
|
63
|
-
const token = generateToken('john_doe', 3600, { role: 'admin' }); // 1 hour token
|
|
64
|
-
|
|
65
|
-
// Deprecated: authByToken was replaced by createAuthMW universal middleware
|
|
66
|
-
// Use createAuthMW instead for all authentication scenarios:
|
|
21
|
+
import { generateToken } from 'fa-mcp-sdk';
|
|
67
22
|
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
-
// User is authenticated, authInfo available on req
|
|
71
|
-
const authInfo = (req as any).authInfo;
|
|
72
|
-
res.json({
|
|
73
|
-
message: 'Access granted',
|
|
74
|
-
authType: authInfo?.authType,
|
|
75
|
-
username: authInfo?.username
|
|
76
|
-
});
|
|
77
|
-
});
|
|
23
|
+
// Generate JWT (liveTimeSec = seconds until expiry)
|
|
24
|
+
const token = generateToken('john_doe', 3600, { role: 'admin' }); // 1 hour
|
|
78
25
|
```
|
|
79
26
|
|
|
80
|
-
## Test Authentication
|
|
27
|
+
## Test Authentication
|
|
81
28
|
|
|
82
29
|
```typescript
|
|
83
|
-
import { getAuthHeadersForTests } from 'fa-mcp-sdk';
|
|
84
|
-
|
|
85
|
-
//
|
|
86
|
-
// Function Signature:
|
|
87
|
-
function getAuthHeadersForTests(): object {...}
|
|
88
|
-
|
|
89
|
-
// Determines authentication headers based on appConfig.webServer.auth configuration.
|
|
90
|
-
// Returns Authorization header using the first valid auth method found.
|
|
91
|
-
//
|
|
92
|
-
// Priority order (CPU-optimized, fastest first):
|
|
93
|
-
// 1. permanentServerTokens - if at least one token is defined
|
|
94
|
-
// 2. basic auth - if username AND password are both set
|
|
95
|
-
// 3. JWT token - if jwtToken.encryptKey is set, generates token on the fly
|
|
96
|
-
//
|
|
97
|
-
// Returns empty object if auth is not enabled or no valid method configured.
|
|
98
|
-
|
|
99
|
-
// Examples:
|
|
30
|
+
import { getAuthHeadersForTests, McpHttpClient, appConfig } from 'fa-mcp-sdk';
|
|
31
|
+
|
|
32
|
+
// Auto-generates auth headers based on config (permanent → basic → JWT priority)
|
|
100
33
|
const headers = getAuthHeadersForTests();
|
|
101
34
|
|
|
102
|
-
//
|
|
103
|
-
const response = await fetch(
|
|
35
|
+
// Usage
|
|
36
|
+
const response = await fetch(`http://localhost:${appConfig.webServer.port}/mcp`, {
|
|
104
37
|
method: 'POST',
|
|
105
|
-
headers: {
|
|
106
|
-
|
|
107
|
-
...headers // Automatically adds Authorization header if auth is enabled
|
|
108
|
-
},
|
|
109
|
-
body: JSON.stringify(requestBody)
|
|
38
|
+
headers: { 'Content-Type': 'application/json', ...headers },
|
|
39
|
+
body: JSON.stringify({ jsonrpc: '2.0', method: 'tools/call', params: {...}, id: 1 })
|
|
110
40
|
});
|
|
111
41
|
|
|
112
|
-
//
|
|
113
|
-
import { McpHttpClient } from 'fa-mcp-sdk';
|
|
114
|
-
|
|
42
|
+
// With test client
|
|
115
43
|
const client = new McpHttpClient('http://localhost:3000');
|
|
116
|
-
const
|
|
117
|
-
const result = await client.callTool('my_tool', { query: 'test' }, authHeaders);
|
|
118
|
-
|
|
119
|
-
// Return value examples based on configuration:
|
|
120
|
-
|
|
121
|
-
// If permanentServerTokens configured:
|
|
122
|
-
// { Authorization: 'Bearer server-token-1' }
|
|
123
|
-
|
|
124
|
-
// If basic auth configured:
|
|
125
|
-
// { Authorization: 'Basic YWRtaW46cGFzc3dvcmQ=' } // base64 of 'admin:password'
|
|
126
|
-
|
|
127
|
-
// If JWT encryptKey configured:
|
|
128
|
-
// { Authorization: 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...' }
|
|
129
|
-
|
|
130
|
-
// If auth.enabled = false or no valid method:
|
|
131
|
-
// {}
|
|
132
|
-
|
|
133
|
-
// Typical test setup:
|
|
134
|
-
import { getAuthHeadersForTests, appConfig } from 'fa-mcp-sdk';
|
|
135
|
-
|
|
136
|
-
describe('MCP Server Tests', () => {
|
|
137
|
-
const baseUrl = `http://localhost:${appConfig.webServer.port}`;
|
|
138
|
-
const authHeaders = getAuthHeadersForTests();
|
|
139
|
-
|
|
140
|
-
it('should call tool with authentication', async () => {
|
|
141
|
-
const response = await fetch(`${baseUrl}/mcp`, {
|
|
142
|
-
method: 'POST',
|
|
143
|
-
headers: {
|
|
144
|
-
'Content-Type': 'application/json',
|
|
145
|
-
...authHeaders
|
|
146
|
-
},
|
|
147
|
-
body: JSON.stringify({
|
|
148
|
-
jsonrpc: '2.0',
|
|
149
|
-
method: 'tools/call',
|
|
150
|
-
params: { name: 'my_tool', arguments: { query: 'test' } },
|
|
151
|
-
id: 1
|
|
152
|
-
})
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
expect(response.ok).toBe(true);
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
## Token Generator Authorization Handler
|
|
161
|
-
|
|
162
|
-
The Token Generator admin page (`/admin/`) can be protected with an additional
|
|
163
|
-
custom authorization layer beyond the standard authentication. This allows you
|
|
164
|
-
to implement fine-grained access control, such as restricting access to specific
|
|
165
|
-
AD groups or roles.
|
|
166
|
-
|
|
167
|
-
### Types
|
|
168
|
-
|
|
169
|
-
```typescript
|
|
170
|
-
import { TokenGenAuthHandler, TokenGenAuthInput, AuthResult } from 'fa-mcp-sdk';
|
|
171
|
-
|
|
172
|
-
// Input data passed to the authorization handler
|
|
173
|
-
interface TokenGenAuthInput {
|
|
174
|
-
user: string; // Username from authentication
|
|
175
|
-
domain?: string; // Domain (only for NTLM auth)
|
|
176
|
-
payload?: Record<string, any>; // JWT payload (only for jwtToken auth)
|
|
177
|
-
authType: 'jwtToken' | 'basic' | 'ntlm' | 'permanentServerTokens';
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Authorization handler function type
|
|
181
|
-
type TokenGenAuthHandler = (input: TokenGenAuthInput) => Promise<AuthResult> | AuthResult;
|
|
44
|
+
const result = await client.callTool('tool', args, getAuthHeadersForTests());
|
|
182
45
|
```
|
|
183
46
|
|
|
184
|
-
|
|
47
|
+
## Token Generator Authorization
|
|
185
48
|
|
|
186
|
-
|
|
49
|
+
Protect `/admin/` page with custom authorization:
|
|
187
50
|
|
|
188
51
|
```typescript
|
|
189
|
-
import {
|
|
52
|
+
import { TokenGenAuthHandler, initADGroupChecker } from 'fa-mcp-sdk';
|
|
190
53
|
|
|
191
|
-
// Example 1: Restrict to specific AD groups (NTLM authentication)
|
|
192
54
|
const { isUserInGroup } = initADGroupChecker();
|
|
193
55
|
|
|
194
56
|
const tokenGenAuthHandler: TokenGenAuthHandler = async (input) => {
|
|
195
|
-
//
|
|
57
|
+
// input: { user, domain?, payload?, authType }
|
|
196
58
|
if (input.authType === 'ntlm') {
|
|
197
59
|
const isAdmin = await isUserInGroup(input.user, 'TokenGeneratorAdmins');
|
|
198
|
-
if (!isAdmin) {
|
|
199
|
-
return {
|
|
200
|
-
success: false,
|
|
201
|
-
error: `User ${input.user} is not authorized to access Token Generator`,
|
|
202
|
-
};
|
|
203
|
-
}
|
|
60
|
+
if (!isAdmin) return { success: false, error: `User not authorized` };
|
|
204
61
|
}
|
|
205
62
|
return { success: true, username: input.user };
|
|
206
63
|
};
|
|
207
64
|
|
|
208
|
-
|
|
209
|
-
const tokenGenAuthHandler: TokenGenAuthHandler = async (input) => {
|
|
210
|
-
if (input.authType === 'jwtToken') {
|
|
211
|
-
const roles = input.payload?.roles || [];
|
|
212
|
-
if (!roles.includes('token-admin')) {
|
|
213
|
-
return {
|
|
214
|
-
success: false,
|
|
215
|
-
error: 'Missing required role: token-admin',
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
return { success: true, username: input.user };
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
// Example 3: Simple whitelist check
|
|
223
|
-
const allowedUsers = ['admin', 'john.doe', 'jane.smith'];
|
|
224
|
-
|
|
225
|
-
const tokenGenAuthHandler: TokenGenAuthHandler = (input) => {
|
|
226
|
-
if (!allowedUsers.includes(input.user.toLowerCase())) {
|
|
227
|
-
return {
|
|
228
|
-
success: false,
|
|
229
|
-
error: `User ${input.user} is not in the allowed users list`,
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
return { success: true, username: input.user };
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
// Use in McpServerData
|
|
236
|
-
const serverData: McpServerData = {
|
|
237
|
-
tools,
|
|
238
|
-
toolHandler: handleToolCall,
|
|
239
|
-
agentBrief: AGENT_BRIEF,
|
|
240
|
-
agentPrompt: AGENT_PROMPT,
|
|
241
|
-
|
|
242
|
-
// Add custom authorization for Token Generator
|
|
243
|
-
tokenGenAuthHandler,
|
|
244
|
-
|
|
245
|
-
// ... other configuration
|
|
246
|
-
};
|
|
247
|
-
|
|
248
|
-
await initMcpServer(serverData);
|
|
65
|
+
const serverData: McpServerData = { ..., tokenGenAuthHandler };
|
|
249
66
|
```
|
|
250
67
|
|
|
251
|
-
### Behavior
|
|
252
|
-
|
|
253
|
-
- **If `tokenGenAuthHandler` is not provided**: All authenticated users can access Token Generator
|
|
254
|
-
- **If handler returns `{ success: true }`**: User is authorized
|
|
255
|
-
- **If handler returns `{ success: false, error: '...' }`**: User receives 403 Forbidden with error message
|
|
256
|
-
- **Handler errors**: Caught and returned as 403 with error message
|
|
257
|
-
|
|
258
|
-
### Auth Type Input Details
|
|
259
|
-
|
|
260
|
-
| Auth Type | `user` | `domain` | `payload` |
|
|
261
|
-
|-----------|--------|----------|-----------|
|
|
262
|
-
| `ntlm` | NTLM username | NTLM domain | - |
|
|
263
|
-
| `basic` | Basic auth username | - | - |
|
|
264
|
-
| `jwtToken` | JWT `user` claim | - | Full JWT payload |
|
|
265
|
-
| `permanentServerTokens` | "Unknown" | - | - |
|
|
266
|
-
|
|
267
|
-
---
|
|
268
|
-
|
|
269
68
|
## Multi-Authentication System
|
|
270
69
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
### Types and Interfaces
|
|
274
|
-
|
|
275
|
-
```typescript
|
|
276
|
-
import {
|
|
277
|
-
AuthType,
|
|
278
|
-
AuthResult,
|
|
279
|
-
AuthDetectionResult,
|
|
280
|
-
CustomAuthValidator,
|
|
281
|
-
checkMultiAuth,
|
|
282
|
-
detectAuthConfiguration,
|
|
283
|
-
logAuthConfiguration,
|
|
284
|
-
createAuthMW, // Universal authentication middleware
|
|
285
|
-
getMultiAuthError, // Programmatic authentication checking
|
|
286
|
-
} from 'fa-mcp-sdk';
|
|
287
|
-
|
|
288
|
-
// Authentication types in CPU priority order (low to high cost)
|
|
289
|
-
export type AuthType = 'permanentServerTokens' | 'jwtToken' | 'basic' | 'custom';
|
|
290
|
-
|
|
291
|
-
// Custom Authentication validator function (black box - receives full request)
|
|
292
|
-
export type CustomAuthValidator = (req: any) => Promise<AuthResult> | AuthResult;
|
|
293
|
-
|
|
294
|
-
// Authentication result interface
|
|
295
|
-
export interface AuthResult {
|
|
296
|
-
success: boolean;
|
|
297
|
-
error?: string;
|
|
298
|
-
authType?: AuthType;
|
|
299
|
-
username?: string;
|
|
300
|
-
isTokenDecrypted?: boolean; // only for JWT
|
|
301
|
-
payload?: any;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// Authentication detection result
|
|
305
|
-
export interface AuthDetectionResult {
|
|
306
|
-
configured: AuthType[]; // Authentication types found in configuration
|
|
307
|
-
configuredSet: Set<AuthType>; // Set of configured auth types for quick lookup
|
|
308
|
-
configuredTypes: string; // Comma-separated string of configured types
|
|
309
|
-
errors: Record<string, string[]>; // Configuration errors by auth type
|
|
310
|
-
}
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
### Core Multi-Authentication Functions
|
|
314
|
-
|
|
315
|
-
```typescript
|
|
316
|
-
// checkMultiAuth - validate using all configured authentication methods
|
|
317
|
-
// Function Signature:
|
|
318
|
-
async function checkMultiAuth(req: Request): Promise<AuthResult> {...}
|
|
319
|
-
|
|
320
|
-
// Example:
|
|
321
|
-
const result = await checkMultiAuth(req);
|
|
70
|
+
### createAuthMW()
|
|
322
71
|
|
|
323
|
-
|
|
324
|
-
console.log(`Authenticated via ${result.authType} as ${result.username}`);
|
|
325
|
-
} else {
|
|
326
|
-
console.log('Authentication failed:', result.error);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// detectAuthConfiguration - analyze auth configuration
|
|
330
|
-
// Function Signature:
|
|
331
|
-
function detectAuthConfiguration(): AuthDetectionResult {...}
|
|
332
|
-
|
|
333
|
-
// Example:
|
|
334
|
-
const detection = detectAuthConfiguration();
|
|
335
|
-
console.log('Configured auth types:', detection.configured);
|
|
336
|
-
console.log('Configured types string:', detection.configuredTypes);
|
|
337
|
-
console.log('Configuration errors:', detection.errors);
|
|
338
|
-
|
|
339
|
-
// logAuthConfiguration - log auth system status (debugging)
|
|
340
|
-
// Function Signature:
|
|
341
|
-
function logAuthConfiguration(): void {...}
|
|
342
|
-
|
|
343
|
-
// Example:
|
|
344
|
-
logAuthConfiguration();
|
|
345
|
-
// Output:
|
|
346
|
-
// Auth system configuration:
|
|
347
|
-
// - enabled: true
|
|
348
|
-
// - configured types: permanentServerTokens, basic
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
### Multi-Authentication Middleware
|
|
72
|
+
Universal middleware supporting all auth methods:
|
|
352
73
|
|
|
353
74
|
```typescript
|
|
354
|
-
import
|
|
355
|
-
import {
|
|
356
|
-
createAuthMW,
|
|
357
|
-
getMultiAuthError,
|
|
358
|
-
} from 'fa-mcp-sdk';
|
|
359
|
-
|
|
360
|
-
// Universal authentication middleware with flexible options
|
|
361
|
-
const app = express();
|
|
75
|
+
import { createAuthMW } from 'fa-mcp-sdk';
|
|
362
76
|
|
|
363
|
-
// Basic usage - handles all authentication scenarios automatically
|
|
364
77
|
const authMW = createAuthMW();
|
|
365
78
|
app.use('/api', authMW);
|
|
366
79
|
|
|
367
80
|
app.get('/api/protected', (req, res) => {
|
|
368
81
|
const authInfo = (req as any).authInfo;
|
|
369
|
-
res.json({
|
|
370
|
-
message: 'Access granted',
|
|
371
|
-
authType: authInfo?.authType,
|
|
372
|
-
username: authInfo?.username,
|
|
373
|
-
});
|
|
82
|
+
res.json({ authType: authInfo?.authType, username: authInfo?.username });
|
|
374
83
|
});
|
|
375
84
|
|
|
376
|
-
// Advanced
|
|
377
|
-
const
|
|
378
|
-
mcpPaths: ['/mcp', '/messages', '/sse'
|
|
379
|
-
logConfig: true,
|
|
380
|
-
});
|
|
381
|
-
app.use('/custom-endpoints', customAuthMW);
|
|
382
|
-
|
|
383
|
-
// createAuthMW - Universal authentication middleware
|
|
384
|
-
// Function Signature:
|
|
385
|
-
function createAuthMW(options?: {
|
|
386
|
-
mcpPaths?: string[]; // Paths to check for public MCP requests (default: ['/mcp', '/messages', '/sse'])
|
|
387
|
-
logConfig?: boolean; // Log auth configuration on first request (default: from LOG_AUTH_CONFIG env)
|
|
388
|
-
}): (req: Request, res: Response, next: NextFunction) => Promise<void>
|
|
389
|
-
|
|
390
|
-
// Features:
|
|
391
|
-
// ✅ Combines all authentication methods (standard + custom validator)
|
|
392
|
-
// ✅ Supports public MCP resources/prompts (requireAuth: false)
|
|
393
|
-
// ✅ Configurable MCP paths
|
|
394
|
-
// ✅ CPU-optimized authentication order
|
|
395
|
-
// ✅ Automatic auth method detection
|
|
396
|
-
// ✅ Request context enrichment (req.authInfo)
|
|
397
|
-
|
|
398
|
-
// getMultiAuthError - Programmatic authentication checking
|
|
399
|
-
// Function Signature:
|
|
400
|
-
async function getMultiAuthError(req: Request): Promise<{ code: number, message: string } | undefined>
|
|
401
|
-
|
|
402
|
-
// Returns error object if authentication failed, undefined if successful
|
|
403
|
-
// Uses checkMultiAuth internally - supports all authentication methods
|
|
404
|
-
|
|
405
|
-
// Example - Custom middleware with different auth levels
|
|
406
|
-
app.use('/api/custom', async (req, res, next) => {
|
|
407
|
-
if (req.path.startsWith('/api/custom/public')) {
|
|
408
|
-
return next(); // Public endpoints
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
if (req.path.startsWith('/api/custom/admin')) {
|
|
412
|
-
// Admin endpoints - require server tokens only
|
|
413
|
-
const token = (req.headers.authorization || '').replace(/^Bearer */, '');
|
|
414
|
-
if (appConfig.webServer.auth.permanentServerTokens.includes(token)) {
|
|
415
|
-
return next();
|
|
416
|
-
}
|
|
417
|
-
return res.status(403).json({ error: 'Admin access required' });
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Regular endpoints - use full multi-auth
|
|
421
|
-
try {
|
|
422
|
-
const authError = await getMultiAuthError(req);
|
|
423
|
-
if (authError) {
|
|
424
|
-
res.status(authError.code).send(authError.message);
|
|
425
|
-
return;
|
|
426
|
-
}
|
|
427
|
-
next();
|
|
428
|
-
} catch (error) {
|
|
429
|
-
res.status(500).send('Authentication error');
|
|
430
|
-
}
|
|
85
|
+
// Advanced options
|
|
86
|
+
const authMW = createAuthMW({
|
|
87
|
+
mcpPaths: ['/mcp', '/messages', '/sse'], // Paths with public resource access
|
|
88
|
+
logConfig: true, // Log config on first request
|
|
431
89
|
});
|
|
432
90
|
```
|
|
433
91
|
|
|
434
|
-
###
|
|
92
|
+
### getMultiAuthError()
|
|
435
93
|
|
|
436
|
-
|
|
94
|
+
Programmatic auth checking:
|
|
437
95
|
|
|
438
96
|
```typescript
|
|
439
|
-
import {
|
|
440
|
-
|
|
441
|
-
// Database-backed authentication with request context
|
|
442
|
-
const databaseAuthValidator: CustomAuthValidator = async (req): Promise<AuthResult> => {
|
|
443
|
-
try {
|
|
444
|
-
// Extract authentication data from various sources
|
|
445
|
-
const authHeader = req.headers.authorization;
|
|
446
|
-
const username = req.headers['x-username'];
|
|
447
|
-
const apiKey = req.headers['x-api-key'];
|
|
448
|
-
|
|
449
|
-
if (authHeader?.startsWith('Basic ')) {
|
|
450
|
-
const [user, pass] = Buffer.from(authHeader.slice(6), 'base64').toString().split(':');
|
|
451
|
-
const dbUser = await getUserFromDatabase(user);
|
|
452
|
-
|
|
453
|
-
if (dbUser && await comparePassword(pass, dbUser.hashedPassword)) {
|
|
454
|
-
return {
|
|
455
|
-
success: true,
|
|
456
|
-
authType: 'basic',
|
|
457
|
-
username: dbUser.username,
|
|
458
|
-
payload: { userId: dbUser.id, roles: dbUser.roles }
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
if (apiKey && username) {
|
|
464
|
-
const isValid = await validateUserApiKey(username, apiKey);
|
|
465
|
-
if (isValid) {
|
|
466
|
-
return {
|
|
467
|
-
success: true,
|
|
468
|
-
authType: 'basic',
|
|
469
|
-
username: username,
|
|
470
|
-
payload: { apiKey: apiKey.substring(0, 8) + '...' }
|
|
471
|
-
};
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
return { success: false, error: 'Invalid credentials' };
|
|
476
|
-
} catch (error) {
|
|
477
|
-
console.error('Database authentication error:', error);
|
|
478
|
-
return { success: false, error: 'Database authentication error' };
|
|
479
|
-
}
|
|
480
|
-
};
|
|
481
|
-
|
|
482
|
-
// Use custom validator in MCP server
|
|
483
|
-
const serverData: McpServerData = {
|
|
484
|
-
tools,
|
|
485
|
-
toolHandler,
|
|
486
|
-
agentBrief: 'My MCP Server',
|
|
487
|
-
agentPrompt: 'Server with custom authentication',
|
|
488
|
-
|
|
489
|
-
// Provide custom authentication validator (black box function)
|
|
490
|
-
customAuthValidator: databaseAuthValidator,
|
|
97
|
+
import { getMultiAuthError } from 'fa-mcp-sdk';
|
|
491
98
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
99
|
+
const authError = await getMultiAuthError(req);
|
|
100
|
+
if (authError) {
|
|
101
|
+
return res.status(authError.code).send(authError.message);
|
|
102
|
+
}
|
|
496
103
|
```
|
|
497
104
|
|
|
498
|
-
###
|
|
105
|
+
### Custom Authentication
|
|
499
106
|
|
|
500
|
-
```
|
|
501
|
-
|
|
502
|
-
curl -H "Authorization: Bearer server-token-1" http://localhost:3000/mcp
|
|
107
|
+
```typescript
|
|
108
|
+
import { CustomAuthValidator, AuthResult } from 'fa-mcp-sdk';
|
|
503
109
|
|
|
504
|
-
|
|
505
|
-
|
|
110
|
+
const customValidator: CustomAuthValidator = async (req): Promise<AuthResult> => {
|
|
111
|
+
const apiKey = req.headers['x-api-key'];
|
|
112
|
+
const valid = await validateApiKey(apiKey);
|
|
506
113
|
|
|
507
|
-
|
|
508
|
-
|
|
114
|
+
if (valid) return { success: true, authType: 'custom', username: 'api-user' };
|
|
115
|
+
return { success: false, error: 'Invalid API key' };
|
|
116
|
+
};
|
|
509
117
|
|
|
510
|
-
|
|
511
|
-
curl -H "X-User-ID: john.doe" \
|
|
512
|
-
-H "X-API-Key: custom-api-key-12345" \
|
|
513
|
-
-H "X-Client-IP: 192.168.1.10" \
|
|
514
|
-
http://localhost:3000/mcp
|
|
118
|
+
const serverData: McpServerData = { ..., customAuthValidator: customValidator };
|
|
515
119
|
```
|
|
516
120
|
|
|
517
|
-
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.
|
|
518
|
-
|
|
519
|
-
---
|
|
520
|
-
|
|
521
121
|
## AD Group Checking
|
|
522
122
|
|
|
523
|
-
### Configuration
|
|
123
|
+
### Configuration
|
|
524
124
|
|
|
525
125
|
```yaml
|
|
126
|
+
# config/local.yaml
|
|
526
127
|
ad:
|
|
527
128
|
domains:
|
|
528
129
|
MYDOMAIN:
|
|
@@ -530,7 +131,6 @@ ad:
|
|
|
530
131
|
controllers: ['ldap://dc1.corp.com']
|
|
531
132
|
username: 'svc_account@corp.com'
|
|
532
133
|
password: '***'
|
|
533
|
-
# baseDn: 'DC=corp,DC=com' # Optional, auto-derived from controller URL
|
|
534
134
|
```
|
|
535
135
|
|
|
536
136
|
### Usage
|
|
@@ -541,86 +141,37 @@ import { initADGroupChecker } from 'fa-mcp-sdk';
|
|
|
541
141
|
const { isUserInGroup, groupChecker } = initADGroupChecker();
|
|
542
142
|
|
|
543
143
|
const isAdmin = await isUserInGroup('john.doe', 'Admins');
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
groupChecker.clearCache(); // Clear cache if needed
|
|
144
|
+
groupChecker.clearCache(); // Clear if needed
|
|
547
145
|
```
|
|
548
146
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
## Advanced Authorization with AD Group Membership
|
|
147
|
+
## Client Examples
|
|
552
148
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
2. **Access Restriction to ALL MCP Tools** - Checking in `toolHandler`
|
|
557
|
-
3. **Access Restriction to SPECIFIC MCP Tools** - Per-tool group requirements
|
|
149
|
+
```bash
|
|
150
|
+
# Permanent token
|
|
151
|
+
curl -H "Authorization: Bearer server-token-1" http://localhost:3000/mcp
|
|
558
152
|
|
|
559
|
-
|
|
153
|
+
# JWT
|
|
154
|
+
curl -H "Authorization: Bearer eyJ..." http://localhost:3000/mcp
|
|
560
155
|
|
|
561
|
-
|
|
156
|
+
# Basic Auth
|
|
157
|
+
curl -H "Authorization: Basic $(echo -n 'admin:password' | base64)" http://localhost:3000/mcp
|
|
562
158
|
|
|
563
|
-
|
|
159
|
+
# Custom headers
|
|
160
|
+
curl -H "X-API-Key: custom-key" http://localhost:3000/mcp
|
|
161
|
+
```
|
|
564
162
|
|
|
565
|
-
|
|
163
|
+
## Token Generator App
|
|
566
164
|
|
|
567
165
|
```typescript
|
|
568
166
|
import { generateTokenApp } from 'fa-mcp-sdk';
|
|
569
167
|
|
|
570
|
-
//
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
// Start Token Generator on default port (3030)
|
|
574
|
-
generateTokenApp();
|
|
575
|
-
|
|
576
|
-
// Start on custom port
|
|
577
|
-
generateTokenApp(1234);
|
|
578
|
-
|
|
579
|
-
// Can also be run directly from command line:
|
|
580
|
-
// npx ts-node node_modules/fa-mcp-sdk/dist/core/auth/token-generator/server.js
|
|
168
|
+
generateTokenApp(); // Port 3030
|
|
169
|
+
generateTokenApp(1234); // Custom port
|
|
581
170
|
```
|
|
582
171
|
|
|
583
|
-
**Features:**
|
|
584
|
-
- Web UI for JWT token generation
|
|
585
|
-
- Token validation interface
|
|
586
|
-
- NTLM authentication support (if configured in AD settings)
|
|
587
|
-
- Service info endpoint with authentication status
|
|
588
|
-
|
|
589
|
-
**Environment Variables:**
|
|
590
|
-
- `TOKEN_GEN_PORT` - Override default port (3030)
|
|
591
|
-
|
|
592
172
|
**Endpoints:**
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
| `/admin/api/validate-token` | POST | Validate existing token |
|
|
599
|
-
| `/admin/api/service-info` | GET | Get service information |
|
|
600
|
-
| `/admin/api/auth-status` | GET | Get authentication status |
|
|
601
|
-
| `/admin/logout` | GET | Logout endpoint |
|
|
602
|
-
|
|
603
|
-
**Request Body for Token Generation:**
|
|
604
|
-
|
|
605
|
-
```typescript
|
|
606
|
-
interface GenerateTokenRequest {
|
|
607
|
-
user: string; // Username for the token
|
|
608
|
-
timeValue: number; // Duration value
|
|
609
|
-
timeUnit: 'minutes' | 'hours' | 'days' | 'months' | 'years';
|
|
610
|
-
payload?: Record<string, any>; // Optional additional payload
|
|
611
|
-
}
|
|
612
|
-
```
|
|
613
|
-
|
|
614
|
-
**Example Usage:**
|
|
615
|
-
|
|
616
|
-
```typescript
|
|
617
|
-
// Programmatic token generation (without UI)
|
|
618
|
-
import { generateToken } from 'fa-mcp-sdk';
|
|
619
|
-
|
|
620
|
-
// Generate a 1-hour token
|
|
621
|
-
const token = generateToken('john.doe', 3600, { role: 'admin' });
|
|
622
|
-
console.log('Generated token:', token);
|
|
623
|
-
|
|
624
|
-
// Token validation is handled automatically by createAuthMW() middleware
|
|
625
|
-
// or use getMultiAuthError() for programmatic validation
|
|
626
|
-
```
|
|
173
|
+
- `/` - Web UI
|
|
174
|
+
- `/admin/api/generate-token` - POST: Generate token
|
|
175
|
+
- `/admin/api/validate-token` - POST: Validate token
|
|
176
|
+
- `/admin/api/service-info` - GET: Service info
|
|
177
|
+
- `/admin/api/auth-status` - GET: Auth status
|