fa-mcp-sdk 0.4.13 → 0.4.14
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/CLAUDE.md +1 -1
- package/cli-template/FA-MCP-SDK-DOC/00-FA-MCP-SDK-index.md +1 -1
- package/cli-template/FA-MCP-SDK-DOC/01-getting-started.md +1 -0
- package/cli-template/FA-MCP-SDK-DOC/03-configuration.md +5 -0
- package/cli-template/FA-MCP-SDK-DOC/04-authentication.md +19 -0
- package/cli-template/FA-MCP-SDK-DOC/08-agent-tester-and-headless-api.md +311 -8
- package/cli-template/package.json +1 -1
- package/config/_local.yaml +15 -3
- package/config/custom-environment-variables.yaml +3 -0
- package/config/default.yaml +10 -1
- package/config/local_.yaml +112 -0
- package/dist/core/_types_/config.d.ts +12 -2
- package/dist/core/_types_/config.d.ts.map +1 -1
- package/dist/core/agent-tester/agent-tester-router.d.ts.map +1 -1
- package/dist/core/agent-tester/agent-tester-router.js +39 -1
- package/dist/core/agent-tester/agent-tester-router.js.map +1 -1
- package/dist/core/auth/agent-tester-auth.d.ts +42 -0
- package/dist/core/auth/agent-tester-auth.d.ts.map +1 -0
- package/dist/core/auth/agent-tester-auth.js +166 -0
- package/dist/core/auth/agent-tester-auth.js.map +1 -0
- package/dist/core/auth/middleware.d.ts.map +1 -1
- package/dist/core/auth/middleware.js +4 -0
- package/dist/core/auth/middleware.js.map +1 -1
- package/dist/core/bootstrap/init-config.d.ts.map +1 -1
- package/dist/core/bootstrap/init-config.js +3 -0
- package/dist/core/bootstrap/init-config.js.map +1 -1
- package/dist/core/web/home-api.d.ts.map +1 -1
- package/dist/core/web/home-api.js +7 -1
- 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 +6 -6
- package/dist/core/web/server-http.js.map +1 -1
- package/dist/core/web/static/agent-tester/index.html +94 -47
- package/dist/core/web/static/agent-tester/script.js +192 -21
- package/dist/core/web/static/agent-tester/styles.css +156 -0
- package/package.json +1 -1
|
@@ -1,6 +1,165 @@
|
|
|
1
1
|
const API_BASE = '/agent-tester';
|
|
2
2
|
const trim = (s) => String(s || '').trim();
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Wrapper around fetch that always includes credentials (session cookie).
|
|
6
|
+
*/
|
|
7
|
+
function apiFetch (url, options = {}) {
|
|
8
|
+
return fetch(url, { ...options, credentials: 'include' });
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Auth manager — handles login overlay when agentTester.useAuth is enabled.
|
|
13
|
+
*/
|
|
14
|
+
class AuthManager {
|
|
15
|
+
constructor () {
|
|
16
|
+
this._authenticated = false;
|
|
17
|
+
this._authRequired = false;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Check auth status and show login if needed. Returns true if app can proceed. */
|
|
21
|
+
async init () {
|
|
22
|
+
try {
|
|
23
|
+
const resp = await apiFetch(`${API_BASE}/api/auth/status`);
|
|
24
|
+
const status = await resp.json();
|
|
25
|
+
|
|
26
|
+
if (!status.authRequired) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this._authRequired = true;
|
|
31
|
+
|
|
32
|
+
if (status.authenticated) {
|
|
33
|
+
this._authenticated = true;
|
|
34
|
+
this._showLogoutButton();
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this._showLoginOverlay(status.methods || []);
|
|
39
|
+
return false; // block app init until authenticated
|
|
40
|
+
} catch (e) {
|
|
41
|
+
console.warn('Auth status check failed, proceeding without auth:', e);
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
_showLoginOverlay (methods) {
|
|
47
|
+
const overlay = document.getElementById('authOverlay');
|
|
48
|
+
const appEl = document.querySelector('.app');
|
|
49
|
+
overlay.style.display = 'flex';
|
|
50
|
+
appEl.style.display = 'none';
|
|
51
|
+
|
|
52
|
+
const hasToken = methods.includes('token');
|
|
53
|
+
const hasBasic = methods.includes('basic');
|
|
54
|
+
|
|
55
|
+
const tokenForm = document.getElementById('authTokenForm');
|
|
56
|
+
const basicForm = document.getElementById('authBasicForm');
|
|
57
|
+
const tabs = document.getElementById('authTabs');
|
|
58
|
+
|
|
59
|
+
if (hasToken && hasBasic) {
|
|
60
|
+
tabs.style.display = 'flex';
|
|
61
|
+
tokenForm.style.display = 'flex';
|
|
62
|
+
basicForm.style.display = 'none';
|
|
63
|
+
this._bindTabs();
|
|
64
|
+
} else if (hasBasic) {
|
|
65
|
+
tokenForm.style.display = 'none';
|
|
66
|
+
basicForm.style.display = 'flex';
|
|
67
|
+
} else {
|
|
68
|
+
tokenForm.style.display = 'flex';
|
|
69
|
+
basicForm.style.display = 'none';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
tokenForm.addEventListener('submit', (e) => {
|
|
73
|
+
e.preventDefault();
|
|
74
|
+
const token = document.getElementById('authToken').value.trim();
|
|
75
|
+
if (token) { this._login({ token }); }
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
basicForm.addEventListener('submit', (e) => {
|
|
79
|
+
e.preventDefault();
|
|
80
|
+
const username = document.getElementById('authUsername').value.trim();
|
|
81
|
+
const password = document.getElementById('authPassword').value;
|
|
82
|
+
if (username && password) { this._login({ username, password }); }
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
_bindTabs () {
|
|
87
|
+
const tabs = document.querySelectorAll('.auth-tab');
|
|
88
|
+
const tokenForm = document.getElementById('authTokenForm');
|
|
89
|
+
const basicForm = document.getElementById('authBasicForm');
|
|
90
|
+
|
|
91
|
+
tabs.forEach((tab) => {
|
|
92
|
+
tab.addEventListener('click', () => {
|
|
93
|
+
tabs.forEach((t) => t.classList.remove('active'));
|
|
94
|
+
tab.classList.add('active');
|
|
95
|
+
if (tab.dataset.tab === 'token') {
|
|
96
|
+
tokenForm.style.display = 'flex';
|
|
97
|
+
basicForm.style.display = 'none';
|
|
98
|
+
} else {
|
|
99
|
+
tokenForm.style.display = 'none';
|
|
100
|
+
basicForm.style.display = 'flex';
|
|
101
|
+
}
|
|
102
|
+
this._hideError();
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async _login (credentials) {
|
|
108
|
+
this._hideError();
|
|
109
|
+
try {
|
|
110
|
+
const resp = await apiFetch(`${API_BASE}/api/auth/login`, {
|
|
111
|
+
method: 'POST',
|
|
112
|
+
headers: { 'Content-Type': 'application/json' },
|
|
113
|
+
body: JSON.stringify(credentials),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
if (!resp.ok) {
|
|
117
|
+
const err = await resp.json();
|
|
118
|
+
this._showError(err.error || 'Authentication failed');
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
this._authenticated = true;
|
|
123
|
+
|
|
124
|
+
// Hide overlay, show app
|
|
125
|
+
document.getElementById('authOverlay').style.display = 'none';
|
|
126
|
+
document.querySelector('.app').style.display = 'flex';
|
|
127
|
+
this._showLogoutButton();
|
|
128
|
+
|
|
129
|
+
// Initialize the main app after successful login
|
|
130
|
+
window.mcpAgentTester = new McpAgentTester();
|
|
131
|
+
} catch (_e) {
|
|
132
|
+
this._showError('Connection error');
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
_showLogoutButton () {
|
|
137
|
+
const btn = document.getElementById('logoutBtn');
|
|
138
|
+
if (btn) {
|
|
139
|
+
btn.style.display = '';
|
|
140
|
+
btn.addEventListener('click', () => this._logout());
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async _logout () {
|
|
145
|
+
try {
|
|
146
|
+
await apiFetch(`${API_BASE}/api/auth/logout`, { method: 'POST' });
|
|
147
|
+
} catch { /* ignore */ }
|
|
148
|
+
location.reload();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
_showError (msg) {
|
|
152
|
+
const el = document.getElementById('authError');
|
|
153
|
+
el.textContent = msg;
|
|
154
|
+
el.style.display = 'block';
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
_hideError () {
|
|
158
|
+
const el = document.getElementById('authError');
|
|
159
|
+
el.style.display = 'none';
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
4
163
|
class McpAgentTester {
|
|
5
164
|
constructor () {
|
|
6
165
|
this.currentSessionId = null;
|
|
@@ -118,6 +277,7 @@ class McpAgentTester {
|
|
|
118
277
|
const select = document.createElement('select');
|
|
119
278
|
select.className = 'format-toggle';
|
|
120
279
|
select.dataset.messageId = messageId;
|
|
280
|
+
select.setAttribute('data-testid', 'at-message-format-toggle');
|
|
121
281
|
|
|
122
282
|
const options = ['MD', 'HTML'];
|
|
123
283
|
const currentFormat = this.messageFormats[messageId] || 'MD';
|
|
@@ -391,7 +551,7 @@ class McpAgentTester {
|
|
|
391
551
|
this.showLoading('Auto-connecting to MCP server...');
|
|
392
552
|
|
|
393
553
|
try {
|
|
394
|
-
const response = await
|
|
554
|
+
const response = await apiFetch(`${API_BASE}/api/mcp/connect`, {
|
|
395
555
|
method: 'POST',
|
|
396
556
|
headers: { 'Content-Type': 'application/json' },
|
|
397
557
|
body: JSON.stringify(connectionData),
|
|
@@ -441,7 +601,7 @@ class McpAgentTester {
|
|
|
441
601
|
|
|
442
602
|
async loadDefaultConfig () {
|
|
443
603
|
try {
|
|
444
|
-
const response = await
|
|
604
|
+
const response = await apiFetch(`${API_BASE}/api/config`);
|
|
445
605
|
const config = await response.json();
|
|
446
606
|
this.defaultMcpUrl = config.defaultMcpUrl || null;
|
|
447
607
|
this.authEnabled = !!config.authEnabled;
|
|
@@ -475,7 +635,7 @@ class McpAgentTester {
|
|
|
475
635
|
this.showLoading('Connecting to MCP server...');
|
|
476
636
|
|
|
477
637
|
try {
|
|
478
|
-
const response = await
|
|
638
|
+
const response = await apiFetch(`${API_BASE}/api/mcp/connect`, {
|
|
479
639
|
method: 'POST',
|
|
480
640
|
headers: { 'Content-Type': 'application/json' },
|
|
481
641
|
body: JSON.stringify(connectionData),
|
|
@@ -555,7 +715,7 @@ class McpAgentTester {
|
|
|
555
715
|
this.showLoading('Checking used headers...');
|
|
556
716
|
|
|
557
717
|
try {
|
|
558
|
-
const response = await
|
|
718
|
+
const response = await apiFetch(`${API_BASE}/api/mcp/used-headers?url=${encodeURIComponent(url)}`, {
|
|
559
719
|
method: 'GET',
|
|
560
720
|
headers: { 'Accept': 'application/json' },
|
|
561
721
|
});
|
|
@@ -605,6 +765,7 @@ class McpAgentTester {
|
|
|
605
765
|
const tooltipAttr = hasDesc ? ` data-tooltip="${header.description.replace(/"/g, '"')}"` : '';
|
|
606
766
|
const inputClass = isRequired ? 'header-value used-header' : 'header-value';
|
|
607
767
|
|
|
768
|
+
headerGroup.setAttribute('data-testid', `at-header-row-${header.name}`);
|
|
608
769
|
headerGroup.innerHTML = `
|
|
609
770
|
<span class="${nameClass}"${tooltipAttr}>${header.name}</span>
|
|
610
771
|
<input
|
|
@@ -614,6 +775,7 @@ class McpAgentTester {
|
|
|
614
775
|
placeholder="${header.name}"
|
|
615
776
|
data-header-name="${header.name}"
|
|
616
777
|
data-required="${isRequired}"
|
|
778
|
+
data-testid="at-header-input-${header.name}"
|
|
617
779
|
value="${savedValue.replace(/"/g, '"')}"
|
|
618
780
|
>
|
|
619
781
|
`;
|
|
@@ -725,7 +887,7 @@ class McpAgentTester {
|
|
|
725
887
|
}
|
|
726
888
|
const headers = this.getHeadersFromForm();
|
|
727
889
|
try {
|
|
728
|
-
const resp = await
|
|
890
|
+
const resp = await apiFetch(`${API_BASE}/api/mcp/headers`, {
|
|
729
891
|
method: 'POST',
|
|
730
892
|
headers: { 'Content-Type': 'application/json' },
|
|
731
893
|
body: JSON.stringify({ serverName: this.currentServer.name, headers }),
|
|
@@ -777,7 +939,7 @@ class McpAgentTester {
|
|
|
777
939
|
if (savedHeaders['Authorization']) {return;}
|
|
778
940
|
|
|
779
941
|
try {
|
|
780
|
-
const response = await
|
|
942
|
+
const response = await apiFetch(`${API_BASE}/api/auth-token`);
|
|
781
943
|
if (!response.ok) {return;}
|
|
782
944
|
|
|
783
945
|
const data = await response.json();
|
|
@@ -804,7 +966,7 @@ class McpAgentTester {
|
|
|
804
966
|
this.stopAuthRefresh();
|
|
805
967
|
this._authRefreshInterval = setInterval(async () => {
|
|
806
968
|
try {
|
|
807
|
-
const response = await
|
|
969
|
+
const response = await apiFetch(`${API_BASE}/api/auth-token/refresh`, { method: 'POST' });
|
|
808
970
|
if (!response.ok) {return;}
|
|
809
971
|
|
|
810
972
|
const data = await response.json();
|
|
@@ -848,7 +1010,7 @@ class McpAgentTester {
|
|
|
848
1010
|
|
|
849
1011
|
async loadCurrentServer () {
|
|
850
1012
|
try {
|
|
851
|
-
const response = await
|
|
1013
|
+
const response = await apiFetch(`${API_BASE}/api/mcp/servers`);
|
|
852
1014
|
const servers = await response.json();
|
|
853
1015
|
|
|
854
1016
|
if (servers && servers.length > 0) {
|
|
@@ -880,15 +1042,15 @@ class McpAgentTester {
|
|
|
880
1042
|
|
|
881
1043
|
if (server.isConnected) {
|
|
882
1044
|
this.connectedServersContainer.innerHTML = `
|
|
883
|
-
<div class="server-status-row">
|
|
884
|
-
<span class="server-status connected">${toolCount} tools <span class="material-icons-round">check_circle</span> connected</span>
|
|
885
|
-
<button type="button" class="btn btn-danger disconnect-btn"><span class="material-icons-round">link_off</span>Disconnect</button>
|
|
1045
|
+
<div class="server-status-row" data-testid="at-server-status-row">
|
|
1046
|
+
<span class="server-status connected" data-testid="at-server-status-connected">${toolCount} tools <span class="material-icons-round">check_circle</span> connected</span>
|
|
1047
|
+
<button type="button" class="btn btn-danger disconnect-btn" data-testid="at-disconnect-btn"><span class="material-icons-round">link_off</span>Disconnect</button>
|
|
886
1048
|
</div>`;
|
|
887
1049
|
} else {
|
|
888
1050
|
this.connectedServersContainer.innerHTML = `
|
|
889
|
-
<div class="server-status-row">
|
|
890
|
-
<span class="server-status disconnected"><span class="material-icons-round">cancel</span>Disconnected</span>
|
|
891
|
-
<button type="button" class="btn btn-secondary reconnect-btn"><span class="material-icons-round">refresh</span>Reconnect</button>
|
|
1051
|
+
<div class="server-status-row" data-testid="at-server-status-row">
|
|
1052
|
+
<span class="server-status disconnected" data-testid="at-server-status-disconnected"><span class="material-icons-round">cancel</span>Disconnected</span>
|
|
1053
|
+
<button type="button" class="btn btn-secondary reconnect-btn" data-testid="at-reconnect-btn"><span class="material-icons-round">refresh</span>Reconnect</button>
|
|
892
1054
|
</div>`;
|
|
893
1055
|
}
|
|
894
1056
|
|
|
@@ -909,7 +1071,7 @@ class McpAgentTester {
|
|
|
909
1071
|
this.stopAuthRefresh();
|
|
910
1072
|
|
|
911
1073
|
try {
|
|
912
|
-
const response = await
|
|
1074
|
+
const response = await apiFetch(`${API_BASE}/api/mcp/disconnect/${this.currentServer.name}`, { method: 'POST' });
|
|
913
1075
|
|
|
914
1076
|
if (response.ok) {
|
|
915
1077
|
this.showToast(`Disconnected from ${this.currentServer.name}`, 'success');
|
|
@@ -947,7 +1109,7 @@ class McpAgentTester {
|
|
|
947
1109
|
this.showLoading('Reconnecting to MCP server...');
|
|
948
1110
|
|
|
949
1111
|
try {
|
|
950
|
-
const response = await
|
|
1112
|
+
const response = await apiFetch(`${API_BASE}/api/mcp/connect`, {
|
|
951
1113
|
method: 'POST',
|
|
952
1114
|
headers: { 'Content-Type': 'application/json' },
|
|
953
1115
|
body: JSON.stringify(connectionData),
|
|
@@ -1045,7 +1207,7 @@ class McpAgentTester {
|
|
|
1045
1207
|
modelConfig: modelConfig,
|
|
1046
1208
|
};
|
|
1047
1209
|
|
|
1048
|
-
const response = await
|
|
1210
|
+
const response = await apiFetch(`${API_BASE}/api/chat/message`, {
|
|
1049
1211
|
method: 'POST',
|
|
1050
1212
|
headers: { 'Content-Type': 'application/json' },
|
|
1051
1213
|
body: JSON.stringify(requestData),
|
|
@@ -1075,6 +1237,7 @@ class McpAgentTester {
|
|
|
1075
1237
|
const messageDiv = document.createElement('div');
|
|
1076
1238
|
messageDiv.className = `message ${sender}`;
|
|
1077
1239
|
messageDiv.dataset.messageId = messageId;
|
|
1240
|
+
messageDiv.setAttribute('data-testid', `at-message-${sender}`);
|
|
1078
1241
|
|
|
1079
1242
|
if (metadata.error) {
|
|
1080
1243
|
messageDiv.classList.add('error');
|
|
@@ -1098,6 +1261,7 @@ class McpAgentTester {
|
|
|
1098
1261
|
const messageText = document.createElement('div');
|
|
1099
1262
|
messageText.className = 'message-text';
|
|
1100
1263
|
messageText.dataset.messageId = messageId;
|
|
1264
|
+
messageText.setAttribute('data-testid', `at-message-text-${sender}`);
|
|
1101
1265
|
|
|
1102
1266
|
if (sender === 'assistant' && !metadata.error) {
|
|
1103
1267
|
const format = this.messageFormats[messageId];
|
|
@@ -1186,6 +1350,7 @@ class McpAgentTester {
|
|
|
1186
1350
|
showToast (message, type = 'info') {
|
|
1187
1351
|
const toast = document.createElement('div');
|
|
1188
1352
|
toast.className = `toast ${type}`;
|
|
1353
|
+
toast.setAttribute('data-testid', `at-toast-${type}`);
|
|
1189
1354
|
|
|
1190
1355
|
const icon = {
|
|
1191
1356
|
'success': 'check_circle',
|
|
@@ -1419,11 +1584,12 @@ class McpAgentTester {
|
|
|
1419
1584
|
savedUrls.forEach(url => {
|
|
1420
1585
|
const item = document.createElement('div');
|
|
1421
1586
|
item.className = 'dropdown-item';
|
|
1587
|
+
item.setAttribute('data-testid', 'at-saved-url-item');
|
|
1422
1588
|
|
|
1423
1589
|
item.innerHTML = `
|
|
1424
1590
|
<div class="url-item">
|
|
1425
|
-
<span class="url-text" title="${url}">${url}</span>
|
|
1426
|
-
<button class="delete-btn" title="Delete URL">
|
|
1591
|
+
<span class="url-text" title="${url}" data-testid="at-saved-url-text">${url}</span>
|
|
1592
|
+
<button class="delete-btn" title="Delete URL" data-testid="at-saved-url-delete">
|
|
1427
1593
|
<span class="material-icons-round" style="font-size: 16px;">close</span>
|
|
1428
1594
|
</button>
|
|
1429
1595
|
</div>
|
|
@@ -1498,6 +1664,11 @@ class McpAgentTester {
|
|
|
1498
1664
|
}
|
|
1499
1665
|
|
|
1500
1666
|
// Initialize the app when DOM is loaded
|
|
1501
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
1502
|
-
|
|
1667
|
+
document.addEventListener('DOMContentLoaded', async () => {
|
|
1668
|
+
const authManager = new AuthManager();
|
|
1669
|
+
const canProceed = await authManager.init();
|
|
1670
|
+
if (canProceed) {
|
|
1671
|
+
window.mcpAgentTester = new McpAgentTester();
|
|
1672
|
+
}
|
|
1673
|
+
// If !canProceed, AuthManager shows login overlay and creates McpAgentTester after successful login
|
|
1503
1674
|
});
|
|
@@ -1488,3 +1488,159 @@ body {
|
|
|
1488
1488
|
.btn-primary:hover {
|
|
1489
1489
|
opacity: 0.9;
|
|
1490
1490
|
}
|
|
1491
|
+
|
|
1492
|
+
/* ============================================
|
|
1493
|
+
Auth Overlay (Login Screen)
|
|
1494
|
+
============================================ */
|
|
1495
|
+
|
|
1496
|
+
.auth-overlay {
|
|
1497
|
+
position: fixed;
|
|
1498
|
+
inset: 0;
|
|
1499
|
+
z-index: 10000;
|
|
1500
|
+
display: flex;
|
|
1501
|
+
align-items: center;
|
|
1502
|
+
justify-content: center;
|
|
1503
|
+
background: var(--bg-overlay);
|
|
1504
|
+
backdrop-filter: blur(4px);
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
.auth-card {
|
|
1508
|
+
background: var(--bg-surface);
|
|
1509
|
+
border: 1px solid var(--border);
|
|
1510
|
+
border-radius: var(--radius-xl);
|
|
1511
|
+
box-shadow: var(--shadow-lg);
|
|
1512
|
+
padding: 40px 36px 32px;
|
|
1513
|
+
width: 100%;
|
|
1514
|
+
max-width: 380px;
|
|
1515
|
+
animation: authFadeIn 0.25s ease-out;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
@keyframes authFadeIn {
|
|
1519
|
+
from { opacity: 0; transform: translateY(12px); }
|
|
1520
|
+
to { opacity: 1; transform: translateY(0); }
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
.auth-header {
|
|
1524
|
+
text-align: center;
|
|
1525
|
+
margin-bottom: 28px;
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
.auth-lock-icon {
|
|
1529
|
+
font-size: 40px;
|
|
1530
|
+
color: var(--primary);
|
|
1531
|
+
margin-bottom: 8px;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
.auth-header h2 {
|
|
1535
|
+
margin: 0;
|
|
1536
|
+
font-size: 1.4rem;
|
|
1537
|
+
font-weight: 700;
|
|
1538
|
+
color: var(--text);
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
.auth-subtitle {
|
|
1542
|
+
margin: 4px 0 0;
|
|
1543
|
+
font-size: 0.85rem;
|
|
1544
|
+
color: var(--text-secondary);
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
.auth-tabs {
|
|
1548
|
+
display: flex;
|
|
1549
|
+
gap: 0;
|
|
1550
|
+
margin-bottom: 20px;
|
|
1551
|
+
border-bottom: 1px solid var(--border);
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
.auth-tab {
|
|
1555
|
+
flex: 1;
|
|
1556
|
+
padding: 10px 0;
|
|
1557
|
+
background: none;
|
|
1558
|
+
border: none;
|
|
1559
|
+
border-bottom: 2px solid transparent;
|
|
1560
|
+
color: var(--text-secondary);
|
|
1561
|
+
font-size: 0.85rem;
|
|
1562
|
+
font-weight: 600;
|
|
1563
|
+
cursor: pointer;
|
|
1564
|
+
transition: color 0.15s, border-color 0.15s;
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
.auth-tab:hover {
|
|
1568
|
+
color: var(--text);
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
.auth-tab.active {
|
|
1572
|
+
color: var(--primary);
|
|
1573
|
+
border-bottom-color: var(--primary);
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
.auth-form {
|
|
1577
|
+
display: flex;
|
|
1578
|
+
flex-direction: column;
|
|
1579
|
+
gap: 16px;
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
.auth-form .form-group {
|
|
1583
|
+
display: flex;
|
|
1584
|
+
flex-direction: column;
|
|
1585
|
+
gap: 6px;
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
.auth-form label {
|
|
1589
|
+
font-size: 0.8rem;
|
|
1590
|
+
font-weight: 600;
|
|
1591
|
+
color: var(--text-secondary);
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
.auth-form input {
|
|
1595
|
+
padding: 10px 14px;
|
|
1596
|
+
border: 1px solid var(--border-input);
|
|
1597
|
+
border-radius: var(--radius);
|
|
1598
|
+
background: var(--bg-input);
|
|
1599
|
+
color: var(--text);
|
|
1600
|
+
font-size: 0.9rem;
|
|
1601
|
+
font-family: inherit;
|
|
1602
|
+
transition: border-color 0.15s, box-shadow 0.15s;
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
.auth-form input:focus {
|
|
1606
|
+
outline: none;
|
|
1607
|
+
border-color: var(--border-focus);
|
|
1608
|
+
box-shadow: 0 0 0 3px var(--primary-glow);
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
.auth-submit {
|
|
1612
|
+
display: flex;
|
|
1613
|
+
align-items: center;
|
|
1614
|
+
justify-content: center;
|
|
1615
|
+
gap: 8px;
|
|
1616
|
+
width: 100%;
|
|
1617
|
+
padding: 12px;
|
|
1618
|
+
margin-top: 4px;
|
|
1619
|
+
background: var(--primary);
|
|
1620
|
+
color: var(--text-on-primary);
|
|
1621
|
+
border: none;
|
|
1622
|
+
border-radius: var(--radius);
|
|
1623
|
+
font-size: 0.9rem;
|
|
1624
|
+
font-weight: 600;
|
|
1625
|
+
cursor: pointer;
|
|
1626
|
+
transition: background 0.15s;
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
.auth-submit:hover {
|
|
1630
|
+
background: var(--primary-hover);
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
.auth-submit .material-icons-round {
|
|
1634
|
+
font-size: 18px;
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
.auth-error {
|
|
1638
|
+
margin-top: 12px;
|
|
1639
|
+
padding: 10px 14px;
|
|
1640
|
+
background: var(--error-bg);
|
|
1641
|
+
border: 1px solid var(--error-border);
|
|
1642
|
+
border-radius: var(--radius);
|
|
1643
|
+
color: var(--error);
|
|
1644
|
+
font-size: 0.8rem;
|
|
1645
|
+
text-align: center;
|
|
1646
|
+
}
|
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.14",
|
|
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",
|