fa-mcp-sdk 0.2.174 → 0.2.184
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-spec.md → FA-MCP-SDK.md} +577 -1
- package/cli-template/package.json +2 -2
- package/config/_local.yaml +1 -1
- package/config/default.yaml +1 -1
- package/config/local.yaml +10 -2
- package/dist/core/_types_/types.d.ts +35 -0
- package/dist/core/_types_/types.d.ts.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/web/admin-router.d.ts.map +1 -1
- package/dist/core/web/admin-router.js +112 -30
- package/dist/core/web/admin-router.js.map +1 -1
- package/dist/core/web/home-api.d.ts.map +1 -1
- package/dist/core/web/home-api.js +13 -0
- package/dist/core/web/home-api.js.map +1 -1
- package/dist/core/web/static/home/index.html +12 -0
- package/dist/core/web/static/home/script.js +7 -0
- package/dist/core/web/static/token-gen/index.html +64 -41
- package/dist/core/web/static/token-gen/script.js +195 -7
- package/package.json +2 -6
- package/src/template/_examples/multi-auth-examples.ts +0 -508
|
@@ -1,5 +1,165 @@
|
|
|
1
1
|
let keyValuePairCount = 0;
|
|
2
2
|
|
|
3
|
+
// ===========================
|
|
4
|
+
// Token Authentication Module
|
|
5
|
+
// ===========================
|
|
6
|
+
|
|
7
|
+
const AUTH_TOKEN_KEY = 'adminAuthToken';
|
|
8
|
+
let requiresBearerToken = false;
|
|
9
|
+
|
|
10
|
+
// Get stored auth token from sessionStorage
|
|
11
|
+
function getStoredToken () {
|
|
12
|
+
return sessionStorage.getItem(AUTH_TOKEN_KEY);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Store auth token in sessionStorage
|
|
16
|
+
function storeToken (token) {
|
|
17
|
+
sessionStorage.setItem(AUTH_TOKEN_KEY, token);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Clear stored auth token
|
|
21
|
+
function clearStoredToken () {
|
|
22
|
+
sessionStorage.removeItem(AUTH_TOKEN_KEY);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Show token authentication modal
|
|
26
|
+
function showTokenModal (errorMessage = null) {
|
|
27
|
+
const modal = document.getElementById('tokenModal');
|
|
28
|
+
const errorDiv = document.getElementById('tokenAuthError');
|
|
29
|
+
|
|
30
|
+
if (errorMessage) {
|
|
31
|
+
errorDiv.innerHTML = `<strong>Error:</strong> ${errorMessage}`;
|
|
32
|
+
errorDiv.style.display = 'block';
|
|
33
|
+
} else {
|
|
34
|
+
errorDiv.style.display = 'none';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
modal.style.display = 'flex';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Hide token authentication modal
|
|
41
|
+
function hideTokenModal () {
|
|
42
|
+
const modal = document.getElementById('tokenModal');
|
|
43
|
+
modal.style.display = 'none';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Authenticated fetch wrapper - adds Authorization header if token auth is required
|
|
47
|
+
async function authFetch (url, options = {}) {
|
|
48
|
+
const token = getStoredToken();
|
|
49
|
+
|
|
50
|
+
if (requiresBearerToken && token) {
|
|
51
|
+
options.headers = {
|
|
52
|
+
...options.headers,
|
|
53
|
+
'Authorization': `Bearer ${token}`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const response = await fetch(url, options);
|
|
58
|
+
|
|
59
|
+
// Handle 401 Unauthorized - show token modal if available
|
|
60
|
+
if (response.status === 401 && requiresBearerToken) {
|
|
61
|
+
clearStoredToken();
|
|
62
|
+
const errorData = await response.json().catch(() => ({}));
|
|
63
|
+
const errorMessage = errorData.error || 'Authentication failed';
|
|
64
|
+
|
|
65
|
+
// Try to show modal, but if it's not available, throw with descriptive error
|
|
66
|
+
const modal = document.getElementById('tokenModal');
|
|
67
|
+
if (modal) {
|
|
68
|
+
showTokenModal(errorMessage + '. Please enter a valid token.');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Throw error with status code for form error handling
|
|
72
|
+
const error = new Error(`401 Unauthorized: ${errorMessage}`);
|
|
73
|
+
error.status = 401;
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return response;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Check auth config and initialize authentication if needed
|
|
81
|
+
async function initializeAuth () {
|
|
82
|
+
try {
|
|
83
|
+
// Get auth config from public endpoint (no auth required)
|
|
84
|
+
const response = await fetch('/admin/api/auth-config');
|
|
85
|
+
const config = await response.json();
|
|
86
|
+
|
|
87
|
+
if (config.success && config.requiresBearerToken) {
|
|
88
|
+
requiresBearerToken = true;
|
|
89
|
+
|
|
90
|
+
// Check if we have a stored token
|
|
91
|
+
const storedToken = getStoredToken();
|
|
92
|
+
if (!storedToken) {
|
|
93
|
+
showTokenModal();
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Verify token is still valid by making an authenticated request
|
|
98
|
+
try {
|
|
99
|
+
const verifyResponse = await authFetch('/admin/api/auth-status');
|
|
100
|
+
const verifyData = await verifyResponse.json();
|
|
101
|
+
|
|
102
|
+
if (!verifyData.success || !verifyData.isAuthenticated) {
|
|
103
|
+
clearStoredToken();
|
|
104
|
+
showTokenModal('Token is invalid or expired.');
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
} catch (error) {
|
|
108
|
+
// authFetch already handles 401 and shows modal
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return true;
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error('Error checking auth config:', error);
|
|
116
|
+
return true; // Continue anyway if config check fails
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Handle token authentication form submission
|
|
121
|
+
function setupTokenAuthForm () {
|
|
122
|
+
const form = document.getElementById('tokenAuthForm');
|
|
123
|
+
if (!form) {return;}
|
|
124
|
+
|
|
125
|
+
form.addEventListener('submit', async (e) => {
|
|
126
|
+
e.preventDefault();
|
|
127
|
+
|
|
128
|
+
const tokenInput = document.getElementById('authTokenInput');
|
|
129
|
+
const token = tokenInput.value.trim();
|
|
130
|
+
|
|
131
|
+
if (!token) {
|
|
132
|
+
showTokenModal('Please enter a token.');
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Store token and try to authenticate
|
|
137
|
+
storeToken(token);
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
const response = await authFetch('/admin/api/auth-status');
|
|
141
|
+
const data = await response.json();
|
|
142
|
+
|
|
143
|
+
if (data.success && data.isAuthenticated) {
|
|
144
|
+
hideTokenModal();
|
|
145
|
+
tokenInput.value = '';
|
|
146
|
+
// Reload auth status and initialize form
|
|
147
|
+
loadAuthStatus();
|
|
148
|
+
initializeForm();
|
|
149
|
+
} else {
|
|
150
|
+
clearStoredToken();
|
|
151
|
+
showTokenModal(data.error || 'Invalid token.');
|
|
152
|
+
}
|
|
153
|
+
} catch (error) {
|
|
154
|
+
// Error already handled in authFetch
|
|
155
|
+
if (error.message !== 'Unauthorized') {
|
|
156
|
+
clearStoredToken();
|
|
157
|
+
showTokenModal('Authentication failed: ' + error.message);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
3
163
|
// Set primary color CSS variable
|
|
4
164
|
function setPrimaryColor (color) {
|
|
5
165
|
if (color) {
|
|
@@ -181,7 +341,7 @@ function renderAuthStatus (data) {
|
|
|
181
341
|
// Load authentication status from API
|
|
182
342
|
async function loadAuthStatus () {
|
|
183
343
|
try {
|
|
184
|
-
const response = await
|
|
344
|
+
const response = await authFetch('/admin/api/auth-status');
|
|
185
345
|
const data = await response.json();
|
|
186
346
|
if (data.success) {
|
|
187
347
|
renderAuthStatus(data);
|
|
@@ -214,7 +374,7 @@ document.getElementById('generateForm').addEventListener('submit', async (e) =>
|
|
|
214
374
|
};
|
|
215
375
|
|
|
216
376
|
try {
|
|
217
|
-
const response = await
|
|
377
|
+
const response = await authFetch('/admin/api/generate-token', {
|
|
218
378
|
method: 'POST',
|
|
219
379
|
headers: { 'Content-Type': 'application/json' },
|
|
220
380
|
body: JSON.stringify(requestData),
|
|
@@ -263,7 +423,7 @@ document.getElementById('validateForm').addEventListener('submit', async (e) =>
|
|
|
263
423
|
const token = formData.get('token').trim();
|
|
264
424
|
|
|
265
425
|
try {
|
|
266
|
-
const response = await
|
|
426
|
+
const response = await authFetch('/admin/api/validate-token', {
|
|
267
427
|
method: 'POST',
|
|
268
428
|
headers: { 'Content-Type': 'application/json' },
|
|
269
429
|
body: JSON.stringify({ token }),
|
|
@@ -319,19 +479,25 @@ Reason: ${result.error}
|
|
|
319
479
|
async function initializeForm () {
|
|
320
480
|
try {
|
|
321
481
|
// Getting information about the service
|
|
322
|
-
const response = await
|
|
482
|
+
const response = await authFetch('/admin/api/service-info');
|
|
323
483
|
const data = await response.json();
|
|
324
484
|
const serviceName = data.serviceName;
|
|
325
485
|
|
|
326
486
|
// Set theme color
|
|
327
487
|
setPrimaryColor(data.primaryColor);
|
|
328
488
|
|
|
489
|
+
// Clear existing key-value pairs before re-initializing
|
|
490
|
+
const container = document.getElementById('keyValuePairs');
|
|
491
|
+
container.innerHTML = '';
|
|
492
|
+
keyValuePairCount = 0;
|
|
493
|
+
|
|
329
494
|
// Adding a pre-filled pair serviceName
|
|
330
495
|
addKeyValuePair('service', serviceName, true);
|
|
331
496
|
addKeyValuePair('issue', '', true, 'URL of request for the issuance of a token in JIRA');
|
|
332
497
|
|
|
333
498
|
} catch (error) {
|
|
334
499
|
console.error('Error loading service info:', error);
|
|
500
|
+
return;
|
|
335
501
|
}
|
|
336
502
|
// Add one empty pair for the user
|
|
337
503
|
addKeyValuePair();
|
|
@@ -340,6 +506,19 @@ async function initializeForm () {
|
|
|
340
506
|
// Logout function
|
|
341
507
|
async function logout () {
|
|
342
508
|
try {
|
|
509
|
+
// For token-based auth, just clear the stored token
|
|
510
|
+
if (requiresBearerToken) {
|
|
511
|
+
clearStoredToken();
|
|
512
|
+
showTokenModal();
|
|
513
|
+
// Clear auth status display
|
|
514
|
+
const container = document.getElementById('authStatusContainer');
|
|
515
|
+
if (container) {
|
|
516
|
+
container.style.display = 'none';
|
|
517
|
+
}
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// For other auth types (NTLM, Basic), make logout request
|
|
343
522
|
const response = await fetch('/admin/logout', {
|
|
344
523
|
method: 'GET',
|
|
345
524
|
credentials: 'include',
|
|
@@ -359,7 +538,16 @@ async function logout () {
|
|
|
359
538
|
}
|
|
360
539
|
|
|
361
540
|
// Initialization on page load
|
|
362
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
363
|
-
|
|
364
|
-
|
|
541
|
+
document.addEventListener('DOMContentLoaded', async () => {
|
|
542
|
+
// Setup token auth form handler
|
|
543
|
+
setupTokenAuthForm();
|
|
544
|
+
|
|
545
|
+
// Initialize authentication (check if token is needed and valid)
|
|
546
|
+
const authOk = await initializeAuth();
|
|
547
|
+
|
|
548
|
+
if (authOk) {
|
|
549
|
+
// Load auth status and form only if authenticated
|
|
550
|
+
loadAuthStatus();
|
|
551
|
+
initializeForm();
|
|
552
|
+
}
|
|
365
553
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fa-mcp-sdk",
|
|
3
3
|
"productName": "FA MCP SDK",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.184",
|
|
5
5
|
"description": "Core infrastructure and templates for building Model Context Protocol (MCP) servers with TypeScript",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/core/index.js",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"homepage": "https://github.com/Bazilio-san/fa-mcp-sdk#readme",
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"@modelcontextprotocol/sdk": "^1.24.3",
|
|
69
|
-
"af-ad-ts": "^0.0.
|
|
69
|
+
"af-ad-ts": "^0.0.69",
|
|
70
70
|
"af-db-ts": "^3.0.23",
|
|
71
71
|
"af-logger-ts": "^0.0.24",
|
|
72
72
|
"chalk": "^5.6.2",
|
|
@@ -96,11 +96,7 @@
|
|
|
96
96
|
"@types/node": "^24.10.1",
|
|
97
97
|
"@types/swagger-jsdoc": "^6.0.4",
|
|
98
98
|
"@types/swagger-ui-express": "^4.1.8",
|
|
99
|
-
"@typescript-eslint/eslint-plugin": "^8.48.1",
|
|
100
|
-
"@typescript-eslint/parser": "^8.48.1",
|
|
101
99
|
"eslint": "^9.39.1",
|
|
102
|
-
"eslint-plugin-import": "^2.32.0",
|
|
103
|
-
"eslint-plugin-unused-imports": "^4.3.0",
|
|
104
100
|
"rimraf": "^6.1.2",
|
|
105
101
|
"typescript": "^5.9.3"
|
|
106
102
|
}
|