fa-mcp-sdk 0.4.134 → 0.4.137
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.
|
@@ -30,6 +30,10 @@
|
|
|
30
30
|
<label for="authToken">Token</label>
|
|
31
31
|
<input type="password" id="authToken" placeholder="Enter access token" autocomplete="off" data-testid="at-auth-token-input">
|
|
32
32
|
</div>
|
|
33
|
+
<label class="auth-remember" data-testid="at-auth-token-remember-label">
|
|
34
|
+
<input type="checkbox" id="authTokenRemember" checked data-testid="at-auth-token-remember">
|
|
35
|
+
<span>Remember me on this device</span>
|
|
36
|
+
</label>
|
|
33
37
|
<button type="submit" class="btn btn-primary auth-submit" data-testid="at-auth-token-submit">
|
|
34
38
|
<span class="material-icons-round">login</span>
|
|
35
39
|
Sign In
|
|
@@ -45,6 +49,10 @@
|
|
|
45
49
|
<label for="authPassword">Password</label>
|
|
46
50
|
<input type="password" id="authPassword" placeholder="Password" autocomplete="current-password" data-testid="at-auth-password">
|
|
47
51
|
</div>
|
|
52
|
+
<label class="auth-remember" data-testid="at-auth-basic-remember-label">
|
|
53
|
+
<input type="checkbox" id="authBasicRemember" checked data-testid="at-auth-basic-remember">
|
|
54
|
+
<span>Remember me on this device</span>
|
|
55
|
+
</label>
|
|
48
56
|
<button type="submit" class="btn btn-primary auth-submit" data-testid="at-auth-basic-submit">
|
|
49
57
|
<span class="material-icons-round">login</span>
|
|
50
58
|
Sign In
|
|
@@ -363,6 +371,9 @@
|
|
|
363
371
|
</div>
|
|
364
372
|
</section>
|
|
365
373
|
</div>
|
|
374
|
+
<div class="settings-modal-footer">
|
|
375
|
+
<button type="button" class="btn btn-primary" id="settingsModalOk" data-testid="at-settings-modal-ok">OK</button>
|
|
376
|
+
</div>
|
|
366
377
|
</div>
|
|
367
378
|
</div>
|
|
368
379
|
|
|
@@ -38,6 +38,8 @@ function apiFetch(url, options = {}) {
|
|
|
38
38
|
* Auth manager — handles login overlay when agentTester.useAuth is enabled.
|
|
39
39
|
*/
|
|
40
40
|
class AuthManager {
|
|
41
|
+
static LS_KEY = 'agentTesterAuthCreds';
|
|
42
|
+
|
|
41
43
|
constructor() {
|
|
42
44
|
this._authenticated = false;
|
|
43
45
|
this._authRequired = false;
|
|
@@ -61,7 +63,13 @@ class AuthManager {
|
|
|
61
63
|
return true;
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
|
|
66
|
+
// Try silent re-login with saved credentials before showing overlay
|
|
67
|
+
const saved = this._loadSavedCreds();
|
|
68
|
+
if (saved && (await this._login(saved, { silent: true }))) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
this._showLoginOverlay(status.methods || [], saved);
|
|
65
73
|
return false; // block app init until authenticated
|
|
66
74
|
} catch (e) {
|
|
67
75
|
console.warn('Auth status check failed, proceeding without auth:', e);
|
|
@@ -69,7 +77,39 @@ class AuthManager {
|
|
|
69
77
|
}
|
|
70
78
|
}
|
|
71
79
|
|
|
72
|
-
|
|
80
|
+
_loadSavedCreds() {
|
|
81
|
+
try {
|
|
82
|
+
const raw = localStorage.getItem(AuthManager.LS_KEY);
|
|
83
|
+
if (!raw) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const obj = JSON.parse(raw);
|
|
87
|
+
if (obj && (obj.token || (obj.username && obj.password))) {
|
|
88
|
+
return obj;
|
|
89
|
+
}
|
|
90
|
+
} catch {
|
|
91
|
+
/* ignore */
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
_saveCreds(creds) {
|
|
97
|
+
try {
|
|
98
|
+
localStorage.setItem(AuthManager.LS_KEY, JSON.stringify(creds));
|
|
99
|
+
} catch {
|
|
100
|
+
/* ignore */
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
_clearSavedCreds() {
|
|
105
|
+
try {
|
|
106
|
+
localStorage.removeItem(AuthManager.LS_KEY);
|
|
107
|
+
} catch {
|
|
108
|
+
/* ignore */
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
_showLoginOverlay(methods, saved) {
|
|
73
113
|
const overlay = document.getElementById('authOverlay');
|
|
74
114
|
const appEl = document.querySelector('.app');
|
|
75
115
|
overlay.style.display = 'flex';
|
|
@@ -82,10 +122,30 @@ class AuthManager {
|
|
|
82
122
|
const basicForm = document.getElementById('authBasicForm');
|
|
83
123
|
const tabs = document.getElementById('authTabs');
|
|
84
124
|
|
|
125
|
+
// Pre-fill from saved credentials (if any)
|
|
126
|
+
if (saved?.token) {
|
|
127
|
+
document.getElementById('authToken').value = saved.token;
|
|
128
|
+
}
|
|
129
|
+
if (saved?.username) {
|
|
130
|
+
document.getElementById('authUsername').value = saved.username;
|
|
131
|
+
}
|
|
132
|
+
if (saved?.password) {
|
|
133
|
+
document.getElementById('authPassword').value = saved.password;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// If saved creds match a single available method, switch to that tab.
|
|
137
|
+
const preferBasic = saved?.username && hasBasic && !saved?.token;
|
|
138
|
+
|
|
85
139
|
if (hasToken && hasBasic) {
|
|
86
140
|
tabs.style.display = 'flex';
|
|
87
|
-
|
|
88
|
-
|
|
141
|
+
if (preferBasic) {
|
|
142
|
+
tokenForm.style.display = 'none';
|
|
143
|
+
basicForm.style.display = 'flex';
|
|
144
|
+
document.querySelectorAll('.auth-tab').forEach((t) => t.classList.toggle('active', t.dataset.tab === 'basic'));
|
|
145
|
+
} else {
|
|
146
|
+
tokenForm.style.display = 'flex';
|
|
147
|
+
basicForm.style.display = 'none';
|
|
148
|
+
}
|
|
89
149
|
this._bindTabs();
|
|
90
150
|
} else if (hasBasic) {
|
|
91
151
|
tokenForm.style.display = 'none';
|
|
@@ -98,8 +158,9 @@ class AuthManager {
|
|
|
98
158
|
tokenForm.addEventListener('submit', (e) => {
|
|
99
159
|
e.preventDefault();
|
|
100
160
|
const token = document.getElementById('authToken').value.trim();
|
|
161
|
+
const remember = document.getElementById('authTokenRemember').checked;
|
|
101
162
|
if (token) {
|
|
102
|
-
this._login({ token });
|
|
163
|
+
this._login({ token }, { remember });
|
|
103
164
|
}
|
|
104
165
|
});
|
|
105
166
|
|
|
@@ -107,8 +168,9 @@ class AuthManager {
|
|
|
107
168
|
e.preventDefault();
|
|
108
169
|
const username = document.getElementById('authUsername').value.trim();
|
|
109
170
|
const password = document.getElementById('authPassword').value;
|
|
171
|
+
const remember = document.getElementById('authBasicRemember').checked;
|
|
110
172
|
if (username && password) {
|
|
111
|
-
this._login({ username, password });
|
|
173
|
+
this._login({ username, password }, { remember });
|
|
112
174
|
}
|
|
113
175
|
});
|
|
114
176
|
}
|
|
@@ -134,8 +196,17 @@ class AuthManager {
|
|
|
134
196
|
});
|
|
135
197
|
}
|
|
136
198
|
|
|
137
|
-
|
|
138
|
-
|
|
199
|
+
/**
|
|
200
|
+
* Attempt login. Options:
|
|
201
|
+
* - silent: on failure, suppress error UI and return false (used for auto-login)
|
|
202
|
+
* - remember: on success, persist credentials to localStorage; on omission, leave LS untouched
|
|
203
|
+
*
|
|
204
|
+
* Returns true on success, false on failure.
|
|
205
|
+
*/
|
|
206
|
+
async _login(credentials, { silent = false, remember } = {}) {
|
|
207
|
+
if (!silent) {
|
|
208
|
+
this._hideError();
|
|
209
|
+
}
|
|
139
210
|
try {
|
|
140
211
|
const resp = await apiFetch(`${API_BASE}/api/auth/login`, {
|
|
141
212
|
method: 'POST',
|
|
@@ -144,13 +215,23 @@ class AuthManager {
|
|
|
144
215
|
});
|
|
145
216
|
|
|
146
217
|
if (!resp.ok) {
|
|
147
|
-
|
|
218
|
+
if (silent) {
|
|
219
|
+
this._clearSavedCreds();
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
const err = await resp.json().catch(() => ({}));
|
|
148
223
|
this._showError(err.error || 'Authentication failed');
|
|
149
|
-
return;
|
|
224
|
+
return false;
|
|
150
225
|
}
|
|
151
226
|
|
|
152
227
|
this._authenticated = true;
|
|
153
228
|
|
|
229
|
+
if (remember === true) {
|
|
230
|
+
this._saveCreds(credentials);
|
|
231
|
+
} else if (remember === false) {
|
|
232
|
+
this._clearSavedCreds();
|
|
233
|
+
}
|
|
234
|
+
|
|
154
235
|
// Hide overlay, show app
|
|
155
236
|
document.getElementById('authOverlay').style.display = 'none';
|
|
156
237
|
document.querySelector('.app').style.display = 'flex';
|
|
@@ -158,8 +239,12 @@ class AuthManager {
|
|
|
158
239
|
|
|
159
240
|
// Initialize the main app after successful login
|
|
160
241
|
window.mcpAgentTester = new McpAgentTester();
|
|
242
|
+
return true;
|
|
161
243
|
} catch (_e) {
|
|
162
|
-
|
|
244
|
+
if (!silent) {
|
|
245
|
+
this._showError('Connection error');
|
|
246
|
+
}
|
|
247
|
+
return false;
|
|
163
248
|
}
|
|
164
249
|
}
|
|
165
250
|
|
|
@@ -172,6 +257,7 @@ class AuthManager {
|
|
|
172
257
|
}
|
|
173
258
|
|
|
174
259
|
async _logout() {
|
|
260
|
+
this._clearSavedCreds();
|
|
175
261
|
try {
|
|
176
262
|
await apiFetch(`${API_BASE}/api/auth/logout`, { method: 'POST' });
|
|
177
263
|
} catch {
|
|
@@ -1216,6 +1302,7 @@ class McpAgentTester {
|
|
|
1216
1302
|
this.settingsModal = document.getElementById('settingsModal');
|
|
1217
1303
|
this.settingsBtn = document.getElementById('settingsBtn');
|
|
1218
1304
|
this.settingsModalClose = document.getElementById('settingsModalClose');
|
|
1305
|
+
this.settingsModalOk = document.getElementById('settingsModalOk');
|
|
1219
1306
|
|
|
1220
1307
|
// LLM settings — collapsed view + modal
|
|
1221
1308
|
this.modelDisplay = document.getElementById('modelDisplay');
|
|
@@ -1375,12 +1462,8 @@ class McpAgentTester {
|
|
|
1375
1462
|
if (this.settingsModalClose) {
|
|
1376
1463
|
this.settingsModalClose.addEventListener('click', () => this.closeSettingsModal());
|
|
1377
1464
|
}
|
|
1378
|
-
if (this.
|
|
1379
|
-
this.
|
|
1380
|
-
if (e.target === this.settingsModal) {
|
|
1381
|
-
this.closeSettingsModal();
|
|
1382
|
-
}
|
|
1383
|
-
});
|
|
1465
|
+
if (this.settingsModalOk) {
|
|
1466
|
+
this.settingsModalOk.addEventListener('click', () => this.closeSettingsModal());
|
|
1384
1467
|
}
|
|
1385
1468
|
document.addEventListener('keydown', (e) => {
|
|
1386
1469
|
if (e.key === 'Escape' && this.settingsModal && this.settingsModal.style.display === 'flex') {
|
|
@@ -521,6 +521,15 @@ body {
|
|
|
521
521
|
color: var(--text);
|
|
522
522
|
}
|
|
523
523
|
|
|
524
|
+
#logoutBtn {
|
|
525
|
+
color: var(--error);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
#logoutBtn:hover {
|
|
529
|
+
background-color: var(--error-bg);
|
|
530
|
+
color: var(--error);
|
|
531
|
+
}
|
|
532
|
+
|
|
524
533
|
.btn-danger {
|
|
525
534
|
background: var(--error-bg);
|
|
526
535
|
color: var(--error);
|
|
@@ -2117,6 +2126,13 @@ textarea.prompt-modified {
|
|
|
2117
2126
|
margin-bottom: 0;
|
|
2118
2127
|
}
|
|
2119
2128
|
|
|
2129
|
+
.settings-modal-footer {
|
|
2130
|
+
display: flex;
|
|
2131
|
+
justify-content: flex-end;
|
|
2132
|
+
padding: 12px 20px;
|
|
2133
|
+
border-top: 1px solid var(--border);
|
|
2134
|
+
}
|
|
2135
|
+
|
|
2120
2136
|
/* ============================================
|
|
2121
2137
|
LLM Settings Modal
|
|
2122
2138
|
============================================ */
|
|
@@ -2334,6 +2350,24 @@ textarea.prompt-modified {
|
|
|
2334
2350
|
box-shadow: 0 0 0 3px var(--primary-glow);
|
|
2335
2351
|
}
|
|
2336
2352
|
|
|
2353
|
+
.auth-remember {
|
|
2354
|
+
display: flex;
|
|
2355
|
+
align-items: center;
|
|
2356
|
+
gap: 8px;
|
|
2357
|
+
font-size: 0.85rem;
|
|
2358
|
+
color: var(--text-secondary);
|
|
2359
|
+
cursor: pointer;
|
|
2360
|
+
user-select: none;
|
|
2361
|
+
}
|
|
2362
|
+
|
|
2363
|
+
.auth-remember input[type="checkbox"] {
|
|
2364
|
+
width: 16px;
|
|
2365
|
+
height: 16px;
|
|
2366
|
+
margin: 0;
|
|
2367
|
+
cursor: pointer;
|
|
2368
|
+
accent-color: var(--primary);
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2337
2371
|
.auth-submit {
|
|
2338
2372
|
display: flex;
|
|
2339
2373
|
align-items: center;
|
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.4.
|
|
4
|
+
"version": "0.4.137",
|
|
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",
|