fa-mcp-sdk 0.4.76 → 0.4.77
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/README.md +319 -314
- package/bin/fa-mcp.js +85 -68
- package/cli-template/.claude/agents/javascript-pro.md +276 -276
- package/cli-template/.claude/settings.json +50 -50
- package/cli-template/.claude/skills/upgrade-guide/SKILL.md +2 -1
- package/cli-template/.oxfmtrc.json +41 -0
- package/cli-template/.oxlintrc.json +120 -0
- package/cli-template/CLAUDE.md +358 -355
- package/cli-template/FA-MCP-SDK-DOC/00-FA-MCP-SDK-index.md +132 -132
- package/cli-template/FA-MCP-SDK-DOC/01-getting-started.md +146 -146
- package/cli-template/FA-MCP-SDK-DOC/02-1-tools-and-api.md +431 -431
- package/cli-template/FA-MCP-SDK-DOC/02-2-prompts-and-resources.md +201 -201
- package/cli-template/FA-MCP-SDK-DOC/03-configuration.md +384 -384
- package/cli-template/FA-MCP-SDK-DOC/04-authentication.md +412 -412
- package/cli-template/FA-MCP-SDK-DOC/05-ad-authorization.md +196 -196
- package/cli-template/FA-MCP-SDK-DOC/06-utilities.md +163 -163
- package/cli-template/FA-MCP-SDK-DOC/07-testing-and-operations.md +127 -127
- package/cli-template/jest.config.js +27 -30
- package/cli-template/package.json +10 -5
- package/cli-template/prompt-example-new-MCP.md +101 -101
- package/cli-template/readme-docs/SKILLS.md +1 -1
- package/cli-template/tsconfig.json +58 -58
- package/cli-template/update.cjs +41 -38
- package/config/custom-environment-variables.yaml +63 -63
- package/config/development.yaml +4 -4
- package/config/production.yaml +4 -4
- package/config/test.yaml +26 -26
- package/dist/core/_types_/TNtlm.d.ts.map +1 -1
- package/dist/core/_types_/active-directory-config.d.ts.map +1 -1
- package/dist/core/_types_/config.d.ts.map +1 -1
- package/dist/core/_types_/types.d.ts.map +1 -1
- package/dist/core/ad/group-checker.d.ts.map +1 -1
- package/dist/core/ad/group-checker.js.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 +6 -6
- package/dist/core/agent-tester/agent-tester-router.js.map +1 -1
- package/dist/core/agent-tester/check-llm.d.ts.map +1 -1
- package/dist/core/agent-tester/check-llm.js.map +1 -1
- package/dist/core/agent-tester/services/SummaryMemory.d.ts.map +1 -1
- package/dist/core/agent-tester/services/SummaryMemory.js +3 -9
- package/dist/core/agent-tester/services/SummaryMemory.js.map +1 -1
- package/dist/core/agent-tester/services/TesterAgentService.d.ts.map +1 -1
- package/dist/core/agent-tester/services/TesterAgentService.js +25 -27
- package/dist/core/agent-tester/services/TesterAgentService.js.map +1 -1
- package/dist/core/agent-tester/services/TesterMcpClientService.d.ts.map +1 -1
- package/dist/core/agent-tester/services/TesterMcpClientService.js +26 -25
- package/dist/core/agent-tester/services/TesterMcpClientService.js.map +1 -1
- package/dist/core/auth/admin-auth.d.ts.map +1 -1
- package/dist/core/auth/admin-auth.js +5 -5
- package/dist/core/auth/admin-auth.js.map +1 -1
- package/dist/core/auth/agent-tester-auth.d.ts.map +1 -1
- package/dist/core/auth/agent-tester-auth.js +1 -6
- package/dist/core/auth/agent-tester-auth.js.map +1 -1
- package/dist/core/auth/basic.d.ts.map +1 -1
- package/dist/core/auth/basic.js.map +1 -1
- package/dist/core/auth/ip-check.d.ts.map +1 -1
- package/dist/core/auth/ip-check.js +1 -1
- package/dist/core/auth/ip-check.js.map +1 -1
- package/dist/core/auth/jwt.d.ts.map +1 -1
- package/dist/core/auth/jwt.js +1 -1
- package/dist/core/auth/jwt.js.map +1 -1
- package/dist/core/auth/middleware.d.ts.map +1 -1
- package/dist/core/auth/middleware.js +9 -6
- 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 +6 -6
- package/dist/core/auth/multi-auth.js.map +1 -1
- package/dist/core/auth/revocation.d.ts.map +1 -1
- package/dist/core/auth/revocation.js +2 -6
- package/dist/core/auth/revocation.js.map +1 -1
- package/dist/core/auth/token-generator/ntlm/ntlm-auth-options.d.ts.map +1 -1
- package/dist/core/auth/token-generator/ntlm/ntlm-auth-options.js +2 -2
- package/dist/core/auth/token-generator/ntlm/ntlm-auth-options.js.map +1 -1
- package/dist/core/auth/token-generator/ntlm/ntlm-domain-config.js +1 -1
- package/dist/core/auth/token-generator/ntlm/ntlm-domain-config.js.map +1 -1
- package/dist/core/auth/token-generator/ntlm/ntlm-integration.d.ts.map +1 -1
- package/dist/core/auth/token-generator/ntlm/ntlm-integration.js +4 -2
- package/dist/core/auth/token-generator/ntlm/ntlm-integration.js.map +1 -1
- package/dist/core/auth/token-generator/server.d.ts.map +1 -1
- package/dist/core/auth/token-generator/server.js.map +1 -1
- package/dist/core/bootstrap/init-config.d.ts.map +1 -1
- package/dist/core/bootstrap/init-config.js +2 -2
- package/dist/core/bootstrap/init-config.js.map +1 -1
- package/dist/core/bootstrap/startup-info.d.ts.map +1 -1
- package/dist/core/bootstrap/startup-info.js +3 -7
- package/dist/core/bootstrap/startup-info.js.map +1 -1
- package/dist/core/cache/cache.d.ts.map +1 -1
- package/dist/core/cache/cache.js +2 -2
- package/dist/core/cache/cache.js.map +1 -1
- package/dist/core/consul/deregister.d.ts.map +1 -1
- package/dist/core/consul/deregister.js.map +1 -1
- package/dist/core/consul/get-consul-api.d.ts.map +1 -1
- package/dist/core/consul/get-consul-api.js +1 -2
- package/dist/core/consul/get-consul-api.js.map +1 -1
- package/dist/core/db/pg-db.d.ts.map +1 -1
- package/dist/core/db/pg-db.js +3 -3
- package/dist/core/db/pg-db.js.map +1 -1
- package/dist/core/debug.d.ts.map +1 -1
- package/dist/core/debug.js.map +1 -1
- package/dist/core/errors/BaseMcpError.d.ts.map +1 -1
- package/dist/core/errors/BaseMcpError.js.map +1 -1
- package/dist/core/errors/ValidationError.d.ts.map +1 -1
- package/dist/core/errors/ValidationError.js.map +1 -1
- package/dist/core/errors/errors.d.ts.map +1 -1
- package/dist/core/errors/errors.js +1 -1
- package/dist/core/errors/errors.js.map +1 -1
- package/dist/core/index.d.ts +6 -6
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +5 -5
- package/dist/core/index.js.map +1 -1
- package/dist/core/init-mcp-server.d.ts.map +1 -1
- package/dist/core/init-mcp-server.js.map +1 -1
- package/dist/core/logger.d.ts.map +1 -1
- package/dist/core/logger.js +1 -1
- package/dist/core/logger.js.map +1 -1
- package/dist/core/mcp/create-mcp-server.d.ts.map +1 -1
- package/dist/core/mcp/create-mcp-server.js +1 -1
- package/dist/core/mcp/create-mcp-server.js.map +1 -1
- package/dist/core/mcp/prompts.d.ts.map +1 -1
- package/dist/core/mcp/prompts.js.map +1 -1
- package/dist/core/mcp/readme-assembler.d.ts.map +1 -1
- package/dist/core/mcp/readme-assembler.js +3 -1
- package/dist/core/mcp/readme-assembler.js.map +1 -1
- package/dist/core/mcp/resources.d.ts.map +1 -1
- package/dist/core/mcp/resources.js.map +1 -1
- package/dist/core/mcp/server-stdio.d.ts.map +1 -1
- package/dist/core/utils/formatToolResult.d.ts.map +1 -1
- package/dist/core/utils/formatToolResult.js.map +1 -1
- package/dist/core/utils/port-checker.d.ts.map +1 -1
- package/dist/core/utils/port-checker.js.map +1 -1
- package/dist/core/utils/rate-limit.d.ts.map +1 -1
- package/dist/core/utils/rate-limit.js +2 -8
- package/dist/core/utils/rate-limit.js.map +1 -1
- package/dist/core/utils/testing/BaseMcpClient.d.ts.map +1 -1
- package/dist/core/utils/testing/BaseMcpClient.js.map +1 -1
- package/dist/core/utils/testing/McpHttpClient.d.ts.map +1 -1
- package/dist/core/utils/testing/McpHttpClient.js +2 -2
- package/dist/core/utils/testing/McpHttpClient.js.map +1 -1
- package/dist/core/utils/testing/McpSseClient.d.ts.map +1 -1
- package/dist/core/utils/testing/McpSseClient.js +3 -8
- package/dist/core/utils/testing/McpSseClient.js.map +1 -1
- package/dist/core/utils/testing/McpStdioClient.d.ts.map +1 -1
- package/dist/core/utils/testing/McpStdioClient.js.map +1 -1
- package/dist/core/utils/testing/McpStreamableHttpClient.d.ts.map +1 -1
- package/dist/core/utils/testing/McpStreamableHttpClient.js +7 -8
- package/dist/core/utils/testing/McpStreamableHttpClient.js.map +1 -1
- package/dist/core/utils/utils.d.ts.map +1 -1
- package/dist/core/utils/utils.js +3 -5
- package/dist/core/utils/utils.js.map +1 -1
- package/dist/core/web/admin-router.d.ts.map +1 -1
- package/dist/core/web/admin-router.js +3 -3
- package/dist/core/web/admin-router.js.map +1 -1
- package/dist/core/web/cors.d.ts.map +1 -1
- package/dist/core/web/cors.js.map +1 -1
- package/dist/core/web/favicon-svg.d.ts.map +1 -1
- package/dist/core/web/favicon-svg.js +1 -5
- package/dist/core/web/favicon-svg.js.map +1 -1
- package/dist/core/web/home-api.d.ts.map +1 -1
- package/dist/core/web/home-api.js +7 -8
- package/dist/core/web/home-api.js.map +1 -1
- package/dist/core/web/openapi.d.ts.map +1 -1
- package/dist/core/web/openapi.js +1 -3
- package/dist/core/web/openapi.js.map +1 -1
- package/dist/core/web/server-http.d.ts.map +1 -1
- package/dist/core/web/server-http.js +4 -4
- package/dist/core/web/server-http.js.map +1 -1
- package/dist/core/web/static/agent-tester/index.html +323 -323
- package/dist/core/web/static/agent-tester/script.js +311 -200
- package/dist/core/web/static/agent-tester/styles.css +1840 -1840
- package/dist/core/web/static/home/index.html +220 -220
- package/dist/core/web/static/home/script.js +72 -43
- package/dist/core/web/static/styles.css +927 -927
- package/dist/core/web/static/token-gen/index.html +136 -136
- package/dist/core/web/static/token-gen/script.js +58 -56
- package/dist/core/web/svg-icons.d.ts.map +1 -1
- package/dist/core/web/svg-icons.js +1 -5
- package/dist/core/web/svg-icons.js.map +1 -1
- package/package.json +10 -5
- package/{cli-template/.claude/hooks/eslint-fix.cjs → scripts/cc-hook-oxlint-oxfmt-fix.cjs} +109 -100
- package/scripts/generate-jwt.js +5 -9
- package/scripts/kill-port.js +5 -2
- package/scripts/npm/run.js +1 -2
- package/scripts/remove-nul.js +1 -1
- package/scripts/update-sdk.js +36 -14
- package/src/template/api/router.ts +3 -3
- package/src/template/prompts/agent-brief.ts +0 -1
- package/src/template/start.ts +3 -8
- package/src/template/tools/handle-tool-call.ts +3 -3
- package/src/template/tools/tools.ts +3 -7
- package/src/tests/jest-simple-reporter.js +1 -1
- package/src/tests/mcp/sse/mcp-sse-client-handling.md +111 -111
- package/src/tests/mcp/sse/test-sse-npm-package.js +2 -3
- package/src/tests/mcp/test-cases.js +6 -7
- package/src/tests/mcp/test-http.js +2 -2
- package/src/tests/mcp/test-sse.js +9 -7
- package/src/tests/mcp/test-stdio.js +12 -8
- package/src/tests/utils.ts +4 -3
- package/cli-template/eslint.config.js +0 -27
|
@@ -30,7 +30,7 @@ const LLM_DEFAULTS = {
|
|
|
30
30
|
/**
|
|
31
31
|
* Wrapper around fetch that always includes credentials (session cookie).
|
|
32
32
|
*/
|
|
33
|
-
function apiFetch
|
|
33
|
+
function apiFetch(url, options = {}) {
|
|
34
34
|
return fetch(url, { ...options, credentials: 'include' });
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -38,13 +38,13 @@ function apiFetch (url, options = {}) {
|
|
|
38
38
|
* Auth manager — handles login overlay when agentTester.useAuth is enabled.
|
|
39
39
|
*/
|
|
40
40
|
class AuthManager {
|
|
41
|
-
constructor
|
|
41
|
+
constructor() {
|
|
42
42
|
this._authenticated = false;
|
|
43
43
|
this._authRequired = false;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/** Check auth status and show login if needed. Returns true if app can proceed. */
|
|
47
|
-
async init
|
|
47
|
+
async init() {
|
|
48
48
|
try {
|
|
49
49
|
const resp = await apiFetch(`${API_BASE}/api/auth/status`);
|
|
50
50
|
const status = await resp.json();
|
|
@@ -69,7 +69,7 @@ class AuthManager {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
_showLoginOverlay
|
|
72
|
+
_showLoginOverlay(methods) {
|
|
73
73
|
const overlay = document.getElementById('authOverlay');
|
|
74
74
|
const appEl = document.querySelector('.app');
|
|
75
75
|
overlay.style.display = 'flex';
|
|
@@ -98,18 +98,22 @@ class AuthManager {
|
|
|
98
98
|
tokenForm.addEventListener('submit', (e) => {
|
|
99
99
|
e.preventDefault();
|
|
100
100
|
const token = document.getElementById('authToken').value.trim();
|
|
101
|
-
if (token) {
|
|
101
|
+
if (token) {
|
|
102
|
+
this._login({ token });
|
|
103
|
+
}
|
|
102
104
|
});
|
|
103
105
|
|
|
104
106
|
basicForm.addEventListener('submit', (e) => {
|
|
105
107
|
e.preventDefault();
|
|
106
108
|
const username = document.getElementById('authUsername').value.trim();
|
|
107
109
|
const password = document.getElementById('authPassword').value;
|
|
108
|
-
if (username && password) {
|
|
110
|
+
if (username && password) {
|
|
111
|
+
this._login({ username, password });
|
|
112
|
+
}
|
|
109
113
|
});
|
|
110
114
|
}
|
|
111
115
|
|
|
112
|
-
_bindTabs
|
|
116
|
+
_bindTabs() {
|
|
113
117
|
const tabs = document.querySelectorAll('.auth-tab');
|
|
114
118
|
const tokenForm = document.getElementById('authTokenForm');
|
|
115
119
|
const basicForm = document.getElementById('authBasicForm');
|
|
@@ -130,7 +134,7 @@ class AuthManager {
|
|
|
130
134
|
});
|
|
131
135
|
}
|
|
132
136
|
|
|
133
|
-
async _login
|
|
137
|
+
async _login(credentials) {
|
|
134
138
|
this._hideError();
|
|
135
139
|
try {
|
|
136
140
|
const resp = await apiFetch(`${API_BASE}/api/auth/login`, {
|
|
@@ -159,7 +163,7 @@ class AuthManager {
|
|
|
159
163
|
}
|
|
160
164
|
}
|
|
161
165
|
|
|
162
|
-
_showLogoutButton
|
|
166
|
+
_showLogoutButton() {
|
|
163
167
|
const btn = document.getElementById('logoutBtn');
|
|
164
168
|
if (btn) {
|
|
165
169
|
btn.style.display = '';
|
|
@@ -167,27 +171,29 @@ class AuthManager {
|
|
|
167
171
|
}
|
|
168
172
|
}
|
|
169
173
|
|
|
170
|
-
async _logout
|
|
174
|
+
async _logout() {
|
|
171
175
|
try {
|
|
172
176
|
await apiFetch(`${API_BASE}/api/auth/logout`, { method: 'POST' });
|
|
173
|
-
} catch {
|
|
177
|
+
} catch {
|
|
178
|
+
/* ignore */
|
|
179
|
+
}
|
|
174
180
|
location.reload();
|
|
175
181
|
}
|
|
176
182
|
|
|
177
|
-
_showError
|
|
183
|
+
_showError(msg) {
|
|
178
184
|
const el = document.getElementById('authError');
|
|
179
185
|
el.textContent = msg;
|
|
180
186
|
el.style.display = 'block';
|
|
181
187
|
}
|
|
182
188
|
|
|
183
|
-
_hideError
|
|
189
|
+
_hideError() {
|
|
184
190
|
const el = document.getElementById('authError');
|
|
185
191
|
el.style.display = 'none';
|
|
186
192
|
}
|
|
187
193
|
}
|
|
188
194
|
|
|
189
195
|
class McpAgentTester {
|
|
190
|
-
constructor
|
|
196
|
+
constructor() {
|
|
191
197
|
this.currentSessionId = null;
|
|
192
198
|
this.currentServer = null;
|
|
193
199
|
this.currentSystemPrompt = '';
|
|
@@ -223,22 +229,46 @@ class McpAgentTester {
|
|
|
223
229
|
console.log('MCP Agent Tester initialized');
|
|
224
230
|
}
|
|
225
231
|
|
|
226
|
-
sanitizeHtml
|
|
227
|
-
const allowedTags = [
|
|
228
|
-
'p',
|
|
229
|
-
'
|
|
230
|
-
'
|
|
231
|
-
'
|
|
232
|
-
|
|
232
|
+
sanitizeHtml(html) {
|
|
233
|
+
const allowedTags = new Set([
|
|
234
|
+
'p',
|
|
235
|
+
'br',
|
|
236
|
+
'strong',
|
|
237
|
+
'b',
|
|
238
|
+
'em',
|
|
239
|
+
'i',
|
|
240
|
+
'u',
|
|
241
|
+
'code',
|
|
242
|
+
'pre',
|
|
243
|
+
'h1',
|
|
244
|
+
'h2',
|
|
245
|
+
'h3',
|
|
246
|
+
'h4',
|
|
247
|
+
'h5',
|
|
248
|
+
'h6',
|
|
249
|
+
'ul',
|
|
250
|
+
'ol',
|
|
251
|
+
'li',
|
|
252
|
+
'blockquote',
|
|
253
|
+
'a',
|
|
254
|
+
'span',
|
|
255
|
+
'div',
|
|
256
|
+
'table',
|
|
257
|
+
'thead',
|
|
258
|
+
'tbody',
|
|
259
|
+
'tr',
|
|
260
|
+
'th',
|
|
261
|
+
'td',
|
|
262
|
+
]);
|
|
233
263
|
|
|
234
264
|
const allowedAttributes = {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
265
|
+
a: ['href', 'title', 'target'],
|
|
266
|
+
th: ['colspan', 'rowspan'],
|
|
267
|
+
td: ['colspan', 'rowspan'],
|
|
268
|
+
code: ['class'],
|
|
269
|
+
pre: ['class'],
|
|
270
|
+
span: ['class'],
|
|
271
|
+
div: ['class'],
|
|
242
272
|
};
|
|
243
273
|
|
|
244
274
|
const tempDiv = document.createElement('div');
|
|
@@ -255,7 +285,8 @@ class McpAgentTester {
|
|
|
255
285
|
|
|
256
286
|
const tagName = node.tagName.toLowerCase();
|
|
257
287
|
|
|
258
|
-
if (!allowedTags.
|
|
288
|
+
if (!allowedTags.has(tagName)) {
|
|
289
|
+
// noinspection UnnecessaryLocalVariableJS
|
|
259
290
|
const textNode = document.createTextNode(node.textContent || '');
|
|
260
291
|
return textNode;
|
|
261
292
|
}
|
|
@@ -263,7 +294,7 @@ class McpAgentTester {
|
|
|
263
294
|
const cleanedElement = document.createElement(tagName);
|
|
264
295
|
|
|
265
296
|
const allowedAttrs = allowedAttributes[tagName] || [];
|
|
266
|
-
allowedAttrs.forEach(attr => {
|
|
297
|
+
allowedAttrs.forEach((attr) => {
|
|
267
298
|
if (node.hasAttribute(attr)) {
|
|
268
299
|
const value = node.getAttribute(attr);
|
|
269
300
|
if (attr === 'href') {
|
|
@@ -281,7 +312,7 @@ class McpAgentTester {
|
|
|
281
312
|
}
|
|
282
313
|
});
|
|
283
314
|
|
|
284
|
-
Array.from(node.childNodes).forEach(child => {
|
|
315
|
+
Array.from(node.childNodes).forEach((child) => {
|
|
285
316
|
const cleanedChild = cleanNode(child);
|
|
286
317
|
if (cleanedChild) {
|
|
287
318
|
cleanedElement.appendChild(cleanedChild);
|
|
@@ -291,15 +322,17 @@ class McpAgentTester {
|
|
|
291
322
|
return cleanedElement;
|
|
292
323
|
};
|
|
293
324
|
|
|
294
|
-
const cleanedNodes = Array.from(tempDiv.childNodes)
|
|
325
|
+
const cleanedNodes = Array.from(tempDiv.childNodes)
|
|
326
|
+
.map(cleanNode)
|
|
327
|
+
.filter((node) => node !== null);
|
|
295
328
|
|
|
296
329
|
const finalDiv = document.createElement('div');
|
|
297
|
-
cleanedNodes.forEach(node => finalDiv.appendChild(node));
|
|
330
|
+
cleanedNodes.forEach((node) => finalDiv.appendChild(node));
|
|
298
331
|
|
|
299
332
|
return finalDiv.innerHTML.trim();
|
|
300
333
|
}
|
|
301
334
|
|
|
302
|
-
createFormatToggle
|
|
335
|
+
createFormatToggle(messageId) {
|
|
303
336
|
const toggleContainer = document.createElement('div');
|
|
304
337
|
toggleContainer.className = 'format-toggle-container';
|
|
305
338
|
|
|
@@ -311,7 +344,7 @@ class McpAgentTester {
|
|
|
311
344
|
const options = ['MD', 'HTML'];
|
|
312
345
|
const currentFormat = this.messageFormats[messageId] || 'MD';
|
|
313
346
|
|
|
314
|
-
options.forEach(opt => {
|
|
347
|
+
options.forEach((opt) => {
|
|
315
348
|
const option = document.createElement('option');
|
|
316
349
|
option.value = opt;
|
|
317
350
|
option.textContent = opt;
|
|
@@ -329,7 +362,7 @@ class McpAgentTester {
|
|
|
329
362
|
return toggleContainer;
|
|
330
363
|
}
|
|
331
364
|
|
|
332
|
-
onFormatChange
|
|
365
|
+
onFormatChange(messageId, format) {
|
|
333
366
|
this.messageFormats[messageId] = format;
|
|
334
367
|
const originalText = this.messageTexts[messageId];
|
|
335
368
|
const messageText = document.querySelector(`.message-text[data-message-id="${messageId}"]`);
|
|
@@ -338,7 +371,7 @@ class McpAgentTester {
|
|
|
338
371
|
}
|
|
339
372
|
}
|
|
340
373
|
|
|
341
|
-
handleDefaultFormatChange
|
|
374
|
+
handleDefaultFormatChange() {
|
|
342
375
|
const { value } = this.defaultFormatSelect;
|
|
343
376
|
this.defaultDisplayFormat = value;
|
|
344
377
|
localStorage.setItem('agentTesterDefaultFormat', value);
|
|
@@ -347,7 +380,7 @@ class McpAgentTester {
|
|
|
347
380
|
}
|
|
348
381
|
}
|
|
349
382
|
|
|
350
|
-
renderMessageContent
|
|
383
|
+
renderMessageContent(element, text, format) {
|
|
351
384
|
if (format === 'HTML') {
|
|
352
385
|
element.innerHTML = this.sanitizeHtml(text).trim();
|
|
353
386
|
element.classList.add('html-content');
|
|
@@ -359,7 +392,7 @@ class McpAgentTester {
|
|
|
359
392
|
}
|
|
360
393
|
}
|
|
361
394
|
|
|
362
|
-
initializeElements
|
|
395
|
+
initializeElements() {
|
|
363
396
|
this.sidebar = document.getElementById('sidebar');
|
|
364
397
|
this.sidebarToggle = document.getElementById('sidebarToggle');
|
|
365
398
|
this.sidebarToggleMobile = document.getElementById('sidebarToggleMobile');
|
|
@@ -422,7 +455,7 @@ class McpAgentTester {
|
|
|
422
455
|
this.defaultFormatSelect = document.getElementById('defaultDisplayFormat');
|
|
423
456
|
}
|
|
424
457
|
|
|
425
|
-
bindEvents
|
|
458
|
+
bindEvents() {
|
|
426
459
|
if (this.sidebarToggle) {
|
|
427
460
|
this.sidebarToggle.addEventListener('click', () => this.toggleSidebar());
|
|
428
461
|
}
|
|
@@ -464,7 +497,9 @@ class McpAgentTester {
|
|
|
464
497
|
this.llmModelDropdownToggle.addEventListener('click', (e) => this.toggleLlmModelDropdown(e));
|
|
465
498
|
this.renderLlmModelDropdown();
|
|
466
499
|
this.llmModal.addEventListener('click', (e) => {
|
|
467
|
-
if (e.target === this.llmModal) {
|
|
500
|
+
if (e.target === this.llmModal) {
|
|
501
|
+
this.closeLlmModal();
|
|
502
|
+
}
|
|
468
503
|
});
|
|
469
504
|
document.addEventListener('keydown', (e) => {
|
|
470
505
|
if (e.key === 'Escape' && this.llmModal.style.display === 'flex') {
|
|
@@ -472,13 +507,15 @@ class McpAgentTester {
|
|
|
472
507
|
}
|
|
473
508
|
});
|
|
474
509
|
|
|
475
|
-
document.querySelectorAll('.btn-enlarge').forEach(btn => {
|
|
510
|
+
document.querySelectorAll('.btn-enlarge').forEach((btn) => {
|
|
476
511
|
btn.addEventListener('click', () => this.openPromptModal(btn.dataset.target));
|
|
477
512
|
});
|
|
478
513
|
document.getElementById('promptModalClose').addEventListener('click', () => this.closePromptModal());
|
|
479
514
|
document.getElementById('promptModalSave').addEventListener('click', () => this.savePromptModal());
|
|
480
515
|
document.getElementById('promptModal').addEventListener('click', (e) => {
|
|
481
|
-
if (e.target === e.currentTarget) {
|
|
516
|
+
if (e.target === e.currentTarget) {
|
|
517
|
+
this.closePromptModal();
|
|
518
|
+
}
|
|
482
519
|
});
|
|
483
520
|
|
|
484
521
|
this.messageInput.addEventListener('input', () => this.handleInputChange());
|
|
@@ -487,10 +524,7 @@ class McpAgentTester {
|
|
|
487
524
|
this.clearChatBtn.addEventListener('click', () => this.clearChat());
|
|
488
525
|
|
|
489
526
|
document.addEventListener('click', (e) => {
|
|
490
|
-
if (window.innerWidth <= 768 &&
|
|
491
|
-
!this.sidebar.contains(e.target) &&
|
|
492
|
-
!this.sidebarToggleMobile.contains(e.target) &&
|
|
493
|
-
this.sidebar.classList.contains('open')) {
|
|
527
|
+
if (window.innerWidth <= 768 && !this.sidebar.contains(e.target) && !this.sidebarToggleMobile.contains(e.target) && this.sidebar.classList.contains('open')) {
|
|
494
528
|
this.toggleSidebar();
|
|
495
529
|
}
|
|
496
530
|
});
|
|
@@ -502,24 +536,23 @@ class McpAgentTester {
|
|
|
502
536
|
});
|
|
503
537
|
}
|
|
504
538
|
|
|
505
|
-
initTheme
|
|
539
|
+
initTheme() {
|
|
506
540
|
const saved = localStorage.getItem('mcpAgentTheme');
|
|
507
541
|
let theme = saved;
|
|
508
542
|
if (!theme) {
|
|
509
|
-
theme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
510
|
-
? 'dark' : 'light';
|
|
543
|
+
theme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
511
544
|
}
|
|
512
545
|
this.applyTheme(theme);
|
|
513
546
|
}
|
|
514
547
|
|
|
515
|
-
toggleTheme
|
|
548
|
+
toggleTheme() {
|
|
516
549
|
const current = document.documentElement.getAttribute('data-theme') || 'light';
|
|
517
550
|
const next = current === 'dark' ? 'light' : 'dark';
|
|
518
551
|
this.applyTheme(next);
|
|
519
552
|
localStorage.setItem('mcpAgentTheme', next);
|
|
520
553
|
}
|
|
521
554
|
|
|
522
|
-
applyTheme
|
|
555
|
+
applyTheme(theme) {
|
|
523
556
|
document.documentElement.setAttribute('data-theme', theme);
|
|
524
557
|
if (this.themeToggle) {
|
|
525
558
|
const icon = this.themeToggle.querySelector('.material-icons-round');
|
|
@@ -529,7 +562,7 @@ class McpAgentTester {
|
|
|
529
562
|
}
|
|
530
563
|
}
|
|
531
564
|
|
|
532
|
-
openPromptModal
|
|
565
|
+
openPromptModal(targetId) {
|
|
533
566
|
this._promptModalTarget = document.getElementById(targetId);
|
|
534
567
|
const modal = document.getElementById('promptModal');
|
|
535
568
|
const textarea = document.getElementById('promptModalTextarea');
|
|
@@ -540,7 +573,7 @@ class McpAgentTester {
|
|
|
540
573
|
textarea.focus();
|
|
541
574
|
}
|
|
542
575
|
|
|
543
|
-
closePromptModal
|
|
576
|
+
closePromptModal() {
|
|
544
577
|
const modal = document.getElementById('promptModal');
|
|
545
578
|
const textarea = document.getElementById('promptModalTextarea');
|
|
546
579
|
const saveBtn = document.getElementById('promptModalSave');
|
|
@@ -553,7 +586,7 @@ class McpAgentTester {
|
|
|
553
586
|
this._promptModalTarget = null;
|
|
554
587
|
}
|
|
555
588
|
|
|
556
|
-
savePromptModal
|
|
589
|
+
savePromptModal() {
|
|
557
590
|
if (this._promptModalTarget) {
|
|
558
591
|
this._promptModalTarget.value = document.getElementById('promptModalTextarea').value;
|
|
559
592
|
this.saveFormValuesToStorage();
|
|
@@ -561,18 +594,18 @@ class McpAgentTester {
|
|
|
561
594
|
this.closePromptModal();
|
|
562
595
|
}
|
|
563
596
|
|
|
564
|
-
setupAutoResize
|
|
597
|
+
setupAutoResize() {
|
|
565
598
|
this.messageInput.addEventListener('input', function () {
|
|
566
599
|
this.style.height = 'auto';
|
|
567
600
|
this.style.height = Math.min(this.scrollHeight, 120) + 'px';
|
|
568
601
|
});
|
|
569
602
|
}
|
|
570
603
|
|
|
571
|
-
toggleSidebar
|
|
604
|
+
toggleSidebar() {
|
|
572
605
|
this.sidebar.classList.toggle('open');
|
|
573
606
|
}
|
|
574
607
|
|
|
575
|
-
async loadInitialData
|
|
608
|
+
async loadInitialData() {
|
|
576
609
|
try {
|
|
577
610
|
this.loadFormValuesFromStorage();
|
|
578
611
|
this.loadFormValuesFromURL();
|
|
@@ -596,9 +629,11 @@ class McpAgentTester {
|
|
|
596
629
|
}
|
|
597
630
|
}
|
|
598
631
|
|
|
599
|
-
async autoConnect
|
|
632
|
+
async autoConnect() {
|
|
600
633
|
const serverUrl = this.serverUrlInput.value.trim();
|
|
601
|
-
if (!serverUrl) {
|
|
634
|
+
if (!serverUrl) {
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
602
637
|
|
|
603
638
|
const transport = this.transportSelect.value;
|
|
604
639
|
const serverName = this.generateServerName(serverUrl);
|
|
@@ -663,7 +698,7 @@ class McpAgentTester {
|
|
|
663
698
|
}
|
|
664
699
|
}
|
|
665
700
|
|
|
666
|
-
async loadDefaultConfig
|
|
701
|
+
async loadDefaultConfig() {
|
|
667
702
|
try {
|
|
668
703
|
const response = await apiFetch(`${API_BASE}/api/config`);
|
|
669
704
|
const config = await response.json();
|
|
@@ -682,7 +717,7 @@ class McpAgentTester {
|
|
|
682
717
|
}
|
|
683
718
|
}
|
|
684
719
|
|
|
685
|
-
async handleMcpConnection
|
|
720
|
+
async handleMcpConnection(event) {
|
|
686
721
|
event.preventDefault();
|
|
687
722
|
|
|
688
723
|
const serverUrl = this.serverUrlInput.value.trim();
|
|
@@ -745,7 +780,6 @@ class McpAgentTester {
|
|
|
745
780
|
} else {
|
|
746
781
|
this.showToast('Failed to connect: ' + result.error, 'error');
|
|
747
782
|
}
|
|
748
|
-
|
|
749
783
|
} catch (error) {
|
|
750
784
|
console.error('Connection error:', error);
|
|
751
785
|
this.showToast('Connection failed: ' + error.message, 'error');
|
|
@@ -754,7 +788,7 @@ class McpAgentTester {
|
|
|
754
788
|
}
|
|
755
789
|
}
|
|
756
790
|
|
|
757
|
-
generateServerName
|
|
791
|
+
generateServerName(url) {
|
|
758
792
|
try {
|
|
759
793
|
const parsedUrl = new URL(url);
|
|
760
794
|
const { hostname, port } = parsedUrl;
|
|
@@ -771,7 +805,7 @@ class McpAgentTester {
|
|
|
771
805
|
}
|
|
772
806
|
}
|
|
773
807
|
|
|
774
|
-
async checkRequiredHeaders
|
|
808
|
+
async checkRequiredHeaders() {
|
|
775
809
|
const url = this.serverUrlInput.value.trim();
|
|
776
810
|
|
|
777
811
|
if (!url) {
|
|
@@ -784,7 +818,7 @@ class McpAgentTester {
|
|
|
784
818
|
try {
|
|
785
819
|
const response = await apiFetch(`${API_BASE}/api/mcp/used-headers?url=${encodeURIComponent(url)}`, {
|
|
786
820
|
method: 'GET',
|
|
787
|
-
headers: {
|
|
821
|
+
headers: { Accept: 'application/json' },
|
|
788
822
|
});
|
|
789
823
|
|
|
790
824
|
if (response.ok) {
|
|
@@ -794,7 +828,7 @@ class McpAgentTester {
|
|
|
794
828
|
await this.autoFillAuthHeader();
|
|
795
829
|
|
|
796
830
|
if (this.usedHeaders.length > 0) {
|
|
797
|
-
const reqCount = this.usedHeaders.filter(h => !h.isOptional).length;
|
|
831
|
+
const reqCount = this.usedHeaders.filter((h) => !h.isOptional).length;
|
|
798
832
|
this.showToast(`Found ${this.usedHeaders.length} headers (${reqCount} used)`, 'success');
|
|
799
833
|
this.headersSection.style.display = 'block';
|
|
800
834
|
} else {
|
|
@@ -806,7 +840,6 @@ class McpAgentTester {
|
|
|
806
840
|
this.headersSection.style.display = 'none';
|
|
807
841
|
this.usedHeaders = [];
|
|
808
842
|
}
|
|
809
|
-
|
|
810
843
|
} catch (error) {
|
|
811
844
|
console.log('Headers check failed:', error);
|
|
812
845
|
this.showToast('Headers endpoint not available - proceeding without additional headers', 'info');
|
|
@@ -817,11 +850,11 @@ class McpAgentTester {
|
|
|
817
850
|
}
|
|
818
851
|
}
|
|
819
852
|
|
|
820
|
-
renderHeaderInputs
|
|
853
|
+
renderHeaderInputs() {
|
|
821
854
|
this.dynamicHeaders.innerHTML = '';
|
|
822
855
|
const savedHeaders = this.loadHeaderValuesFromStorage();
|
|
823
856
|
|
|
824
|
-
this.usedHeaders.forEach(header => {
|
|
857
|
+
this.usedHeaders.forEach((header) => {
|
|
825
858
|
const headerGroup = document.createElement('div');
|
|
826
859
|
headerGroup.className = 'header-row';
|
|
827
860
|
|
|
@@ -886,31 +919,31 @@ class McpAgentTester {
|
|
|
886
919
|
this.mcpConfig.headers = this.getHeadersFromForm();
|
|
887
920
|
}
|
|
888
921
|
|
|
889
|
-
showHeaderTooltip
|
|
922
|
+
showHeaderTooltip(e, text) {
|
|
890
923
|
const tip = document.getElementById('headerTooltip');
|
|
891
924
|
tip._sourceEl = e.target;
|
|
892
925
|
tip.textContent = text;
|
|
893
926
|
const rect = e.target.getBoundingClientRect();
|
|
894
927
|
tip.style.left = rect.left + 'px';
|
|
895
|
-
tip.style.top =
|
|
928
|
+
tip.style.top = rect.top - 4 + 'px';
|
|
896
929
|
tip.style.transform = 'translateY(-100%)';
|
|
897
930
|
tip.classList.add('visible');
|
|
898
931
|
}
|
|
899
932
|
|
|
900
|
-
hideHeaderTooltip
|
|
933
|
+
hideHeaderTooltip() {
|
|
901
934
|
const tip = document.getElementById('headerTooltip');
|
|
902
935
|
tip.classList.remove('visible');
|
|
903
936
|
tip._sourceEl = null;
|
|
904
937
|
}
|
|
905
938
|
|
|
906
|
-
copyToClipboard
|
|
939
|
+
copyToClipboard(text) {
|
|
907
940
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
908
941
|
return navigator.clipboard.writeText(text).catch(() => this._fallbackCopy(text));
|
|
909
942
|
}
|
|
910
943
|
return this._fallbackCopy(text);
|
|
911
944
|
}
|
|
912
945
|
|
|
913
|
-
_fallbackCopy
|
|
946
|
+
_fallbackCopy(text) {
|
|
914
947
|
const ta = document.createElement('textarea');
|
|
915
948
|
ta.value = text;
|
|
916
949
|
ta.style.position = 'fixed';
|
|
@@ -922,7 +955,7 @@ class McpAgentTester {
|
|
|
922
955
|
return Promise.resolve();
|
|
923
956
|
}
|
|
924
957
|
|
|
925
|
-
updateHeaderBorder
|
|
958
|
+
updateHeaderBorder(inputEl) {
|
|
926
959
|
if (inputEl.dataset.required === 'true') {
|
|
927
960
|
if (inputEl.value.trim()) {
|
|
928
961
|
inputEl.classList.remove('empty-required');
|
|
@@ -932,12 +965,12 @@ class McpAgentTester {
|
|
|
932
965
|
}
|
|
933
966
|
}
|
|
934
967
|
|
|
935
|
-
getHeaderStorageKey
|
|
968
|
+
getHeaderStorageKey() {
|
|
936
969
|
const url = this.serverUrlInput.value.trim();
|
|
937
970
|
return `mcpHeaderValues_${url}`;
|
|
938
971
|
}
|
|
939
972
|
|
|
940
|
-
saveHeaderValuesToStorage
|
|
973
|
+
saveHeaderValuesToStorage() {
|
|
941
974
|
const headers = this.getHeadersFromForm();
|
|
942
975
|
const key = this.getHeaderStorageKey();
|
|
943
976
|
try {
|
|
@@ -947,7 +980,7 @@ class McpAgentTester {
|
|
|
947
980
|
}
|
|
948
981
|
}
|
|
949
982
|
|
|
950
|
-
loadHeaderValuesFromStorage
|
|
983
|
+
loadHeaderValuesFromStorage() {
|
|
951
984
|
const key = this.getHeaderStorageKey();
|
|
952
985
|
try {
|
|
953
986
|
const stored = localStorage.getItem(key);
|
|
@@ -958,18 +991,18 @@ class McpAgentTester {
|
|
|
958
991
|
}
|
|
959
992
|
}
|
|
960
993
|
|
|
961
|
-
scheduleHeadersUpdate
|
|
994
|
+
scheduleHeadersUpdate() {
|
|
962
995
|
this.mcpConfig.headers = this.getHeadersFromForm();
|
|
963
996
|
|
|
964
997
|
if (this._headersUpdateTimer) {
|
|
965
998
|
clearTimeout(this._headersUpdateTimer);
|
|
966
999
|
}
|
|
967
1000
|
this._headersUpdateTimer = setTimeout(() => {
|
|
968
|
-
this.applyHeadersUpdate().catch(err => console.warn('Apply headers failed:', err));
|
|
1001
|
+
this.applyHeadersUpdate().catch((err) => console.warn('Apply headers failed:', err));
|
|
969
1002
|
}, 600);
|
|
970
1003
|
}
|
|
971
1004
|
|
|
972
|
-
async applyHeadersUpdate
|
|
1005
|
+
async applyHeadersUpdate() {
|
|
973
1006
|
if (!this.currentServer || !this.currentServer.name) {
|
|
974
1007
|
return;
|
|
975
1008
|
}
|
|
@@ -995,14 +1028,14 @@ class McpAgentTester {
|
|
|
995
1028
|
}
|
|
996
1029
|
}
|
|
997
1030
|
|
|
998
|
-
getHeadersFromForm
|
|
1031
|
+
getHeadersFromForm() {
|
|
999
1032
|
const headers = {};
|
|
1000
1033
|
|
|
1001
1034
|
if (this.usedHeaders.length === 0) {
|
|
1002
1035
|
return headers;
|
|
1003
1036
|
}
|
|
1004
1037
|
|
|
1005
|
-
this.usedHeaders.forEach(header => {
|
|
1038
|
+
this.usedHeaders.forEach((header) => {
|
|
1006
1039
|
const input = document.getElementById(`header_${header.name}`);
|
|
1007
1040
|
if (input && input.value.trim()) {
|
|
1008
1041
|
headers[header.name] = input.value.trim();
|
|
@@ -1012,10 +1045,14 @@ class McpAgentTester {
|
|
|
1012
1045
|
return headers;
|
|
1013
1046
|
}
|
|
1014
1047
|
|
|
1015
|
-
isOwnService
|
|
1016
|
-
if (!this.defaultMcpUrl) {
|
|
1048
|
+
isOwnService() {
|
|
1049
|
+
if (!this.defaultMcpUrl) {
|
|
1050
|
+
return false;
|
|
1051
|
+
}
|
|
1017
1052
|
const current = this.serverUrlInput?.value?.trim();
|
|
1018
|
-
if (!current) {
|
|
1053
|
+
if (!current) {
|
|
1054
|
+
return false;
|
|
1055
|
+
}
|
|
1019
1056
|
const norm = (s) => {
|
|
1020
1057
|
try {
|
|
1021
1058
|
const u = new URL(s, window.location.origin);
|
|
@@ -1033,24 +1070,32 @@ class McpAgentTester {
|
|
|
1033
1070
|
return norm(current) === norm(this.defaultMcpUrl);
|
|
1034
1071
|
}
|
|
1035
1072
|
|
|
1036
|
-
async autoFillAuthHeader
|
|
1037
|
-
if (!this.authEnabled) {
|
|
1073
|
+
async autoFillAuthHeader() {
|
|
1074
|
+
if (!this.authEnabled) {
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1038
1077
|
|
|
1039
|
-
const hasAuthHeader = this.usedHeaders.some(h => h.name === 'Authorization');
|
|
1040
|
-
if (!hasAuthHeader) {
|
|
1078
|
+
const hasAuthHeader = this.usedHeaders.some((h) => h.name === 'Authorization');
|
|
1079
|
+
if (!hasAuthHeader) {
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1041
1082
|
|
|
1042
1083
|
const savedHeaders = this.loadHeaderValuesFromStorage();
|
|
1043
1084
|
|
|
1044
1085
|
try {
|
|
1045
1086
|
const response = await apiFetch(`${API_BASE}/api/auth-token`);
|
|
1046
|
-
if (!response.ok) {
|
|
1087
|
+
if (!response.ok) {
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1047
1090
|
|
|
1048
1091
|
const data = await response.json();
|
|
1049
1092
|
this._currentAuthType = data.authType;
|
|
1050
1093
|
|
|
1051
1094
|
// For non-JWT auth, keep user's saved value if any.
|
|
1052
1095
|
// JWT must always be refreshed (short-lived, regenerated on page reload).
|
|
1053
|
-
if (data.authType !== 'jwtToken' && savedHeaders['Authorization']) {
|
|
1096
|
+
if (data.authType !== 'jwtToken' && savedHeaders['Authorization']) {
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1054
1099
|
|
|
1055
1100
|
const input = document.getElementById('header_Authorization');
|
|
1056
1101
|
if (input) {
|
|
@@ -1071,21 +1116,27 @@ class McpAgentTester {
|
|
|
1071
1116
|
|
|
1072
1117
|
// Compute the delay (ms) until the next refresh: ~1/3 of TTL minus a 60s safety window.
|
|
1073
1118
|
// Math.max(30, ...) clamps against negative or too-short delays when ttl/3 - 60 <= 30.
|
|
1074
|
-
_refreshDelayMs
|
|
1119
|
+
_refreshDelayMs(ttlSec) {
|
|
1075
1120
|
const ttl = Number(ttlSec);
|
|
1076
|
-
if (!Number.isFinite(ttl) || ttl <= 0) {
|
|
1121
|
+
if (!Number.isFinite(ttl) || ttl <= 0) {
|
|
1122
|
+
return 3 * 60 * 1000;
|
|
1123
|
+
}
|
|
1077
1124
|
return Math.max(30, ttl / 3 - 60) * 1000;
|
|
1078
1125
|
}
|
|
1079
1126
|
|
|
1080
|
-
startAuthRefresh
|
|
1127
|
+
startAuthRefresh(ttlSec) {
|
|
1081
1128
|
this.stopAuthRefresh();
|
|
1082
|
-
if (ttlSec) {
|
|
1129
|
+
if (ttlSec) {
|
|
1130
|
+
this._authTtlSec = Number(ttlSec);
|
|
1131
|
+
}
|
|
1083
1132
|
this._scheduleNextRefresh(this._refreshDelayMs(this._authTtlSec));
|
|
1084
1133
|
this._attachAuthVisibilityListeners();
|
|
1085
1134
|
}
|
|
1086
1135
|
|
|
1087
|
-
_scheduleNextRefresh
|
|
1088
|
-
if (this._authRefreshTimer) {
|
|
1136
|
+
_scheduleNextRefresh(delayMs) {
|
|
1137
|
+
if (this._authRefreshTimer) {
|
|
1138
|
+
clearTimeout(this._authRefreshTimer);
|
|
1139
|
+
}
|
|
1089
1140
|
this._authRefreshTimer = setTimeout(() => {
|
|
1090
1141
|
this._authRefreshTimer = null;
|
|
1091
1142
|
this._doRefreshAuthToken().finally(() => {
|
|
@@ -1098,14 +1149,20 @@ class McpAgentTester {
|
|
|
1098
1149
|
}, delayMs);
|
|
1099
1150
|
}
|
|
1100
1151
|
|
|
1101
|
-
async _doRefreshAuthToken
|
|
1102
|
-
if (this._authRefreshInFlight) {
|
|
1152
|
+
async _doRefreshAuthToken() {
|
|
1153
|
+
if (this._authRefreshInFlight) {
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1103
1156
|
this._authRefreshInFlight = true;
|
|
1104
1157
|
try {
|
|
1105
1158
|
const response = await apiFetch(`${API_BASE}/api/auth-token/refresh`, { method: 'POST' });
|
|
1106
|
-
if (!response.ok) {
|
|
1159
|
+
if (!response.ok) {
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
1107
1162
|
const data = await response.json();
|
|
1108
|
-
if (data.ttlSec) {
|
|
1163
|
+
if (data.ttlSec) {
|
|
1164
|
+
this._authTtlSec = Number(data.ttlSec);
|
|
1165
|
+
}
|
|
1109
1166
|
const input = document.getElementById('header_Authorization');
|
|
1110
1167
|
if (input) {
|
|
1111
1168
|
input.value = data.token;
|
|
@@ -1119,14 +1176,22 @@ class McpAgentTester {
|
|
|
1119
1176
|
}
|
|
1120
1177
|
}
|
|
1121
1178
|
|
|
1122
|
-
_attachAuthVisibilityListeners
|
|
1123
|
-
if (this._authVisibilityListenerAttached) {
|
|
1179
|
+
_attachAuthVisibilityListeners() {
|
|
1180
|
+
if (this._authVisibilityListenerAttached) {
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1124
1183
|
this._authVisibilityListenerAttached = true;
|
|
1125
1184
|
const handler = () => {
|
|
1126
1185
|
// Background-tab throttling can starve setTimeout — refresh eagerly when the user comes back.
|
|
1127
|
-
if (document.visibilityState !== 'visible') {
|
|
1128
|
-
|
|
1129
|
-
|
|
1186
|
+
if (document.visibilityState !== 'visible') {
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
if (this._currentAuthType !== 'jwtToken') {
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
if (!this.isOwnService()) {
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1130
1195
|
this._doRefreshAuthToken().finally(() => {
|
|
1131
1196
|
if (this._authTtlSec) {
|
|
1132
1197
|
this._scheduleNextRefresh(this._refreshDelayMs(this._authTtlSec));
|
|
@@ -1137,14 +1202,14 @@ class McpAgentTester {
|
|
|
1137
1202
|
window.addEventListener('focus', handler);
|
|
1138
1203
|
}
|
|
1139
1204
|
|
|
1140
|
-
stopAuthRefresh
|
|
1205
|
+
stopAuthRefresh() {
|
|
1141
1206
|
if (this._authRefreshTimer) {
|
|
1142
1207
|
clearTimeout(this._authRefreshTimer);
|
|
1143
1208
|
this._authRefreshTimer = null;
|
|
1144
1209
|
}
|
|
1145
1210
|
}
|
|
1146
1211
|
|
|
1147
|
-
resetConnectionForm
|
|
1212
|
+
resetConnectionForm() {
|
|
1148
1213
|
this.stopAuthRefresh();
|
|
1149
1214
|
this.mcpConnectionForm.reset();
|
|
1150
1215
|
this.serverUrlInput.value = '';
|
|
@@ -1165,7 +1230,7 @@ class McpAgentTester {
|
|
|
1165
1230
|
localStorage.removeItem('mcpAgentFormValues');
|
|
1166
1231
|
}
|
|
1167
1232
|
|
|
1168
|
-
async loadCurrentServer
|
|
1233
|
+
async loadCurrentServer() {
|
|
1169
1234
|
try {
|
|
1170
1235
|
const response = await apiFetch(`${API_BASE}/api/mcp/servers`);
|
|
1171
1236
|
const servers = await response.json();
|
|
@@ -1179,7 +1244,6 @@ class McpAgentTester {
|
|
|
1179
1244
|
this.updateConnectionStatus();
|
|
1180
1245
|
this.renderServerInfo();
|
|
1181
1246
|
}
|
|
1182
|
-
|
|
1183
1247
|
} catch (error) {
|
|
1184
1248
|
console.error('Error loading current server:', error);
|
|
1185
1249
|
this.currentServer = null;
|
|
@@ -1188,7 +1252,7 @@ class McpAgentTester {
|
|
|
1188
1252
|
}
|
|
1189
1253
|
}
|
|
1190
1254
|
|
|
1191
|
-
renderServerInfo
|
|
1255
|
+
renderServerInfo() {
|
|
1192
1256
|
if (!this.currentServer) {
|
|
1193
1257
|
this.connectedServersContainer.innerHTML = '';
|
|
1194
1258
|
return;
|
|
@@ -1220,7 +1284,7 @@ class McpAgentTester {
|
|
|
1220
1284
|
});
|
|
1221
1285
|
}
|
|
1222
1286
|
|
|
1223
|
-
async disconnectServer
|
|
1287
|
+
async disconnectServer() {
|
|
1224
1288
|
if (!this.currentServer) {
|
|
1225
1289
|
return;
|
|
1226
1290
|
}
|
|
@@ -1246,14 +1310,13 @@ class McpAgentTester {
|
|
|
1246
1310
|
} else {
|
|
1247
1311
|
this.showToast('Failed to disconnect', 'error');
|
|
1248
1312
|
}
|
|
1249
|
-
|
|
1250
1313
|
} catch (error) {
|
|
1251
1314
|
console.error('Disconnect error:', error);
|
|
1252
1315
|
this.showToast('Disconnect failed: ' + error.message, 'error');
|
|
1253
1316
|
}
|
|
1254
1317
|
}
|
|
1255
1318
|
|
|
1256
|
-
async handleReconnect
|
|
1319
|
+
async handleReconnect() {
|
|
1257
1320
|
if (!this.currentServer) {
|
|
1258
1321
|
return;
|
|
1259
1322
|
}
|
|
@@ -1297,8 +1360,10 @@ class McpAgentTester {
|
|
|
1297
1360
|
}
|
|
1298
1361
|
}
|
|
1299
1362
|
|
|
1300
|
-
updateConnectionStatus
|
|
1301
|
-
if (!this.connectionStatus) {
|
|
1363
|
+
updateConnectionStatus() {
|
|
1364
|
+
if (!this.connectionStatus) {
|
|
1365
|
+
return;
|
|
1366
|
+
}
|
|
1302
1367
|
if (this.currentServer && this.currentServer.isConnected) {
|
|
1303
1368
|
this.connectionStatus.textContent = `Connected to ${this.currentServer.name}`;
|
|
1304
1369
|
this.connectionStatus.classList.add('connected');
|
|
@@ -1308,7 +1373,7 @@ class McpAgentTester {
|
|
|
1308
1373
|
}
|
|
1309
1374
|
}
|
|
1310
1375
|
|
|
1311
|
-
handleInputChange
|
|
1376
|
+
handleInputChange() {
|
|
1312
1377
|
const { length } = this.messageInput.value;
|
|
1313
1378
|
this.charCount.textContent = `${length}/40000`;
|
|
1314
1379
|
|
|
@@ -1324,16 +1389,18 @@ class McpAgentTester {
|
|
|
1324
1389
|
}
|
|
1325
1390
|
}
|
|
1326
1391
|
|
|
1327
|
-
handleKeyDown
|
|
1392
|
+
handleKeyDown(event) {
|
|
1328
1393
|
if (event.key === 'Enter' && !event.shiftKey) {
|
|
1329
1394
|
event.preventDefault();
|
|
1330
1395
|
this.sendMessage();
|
|
1331
1396
|
}
|
|
1332
1397
|
}
|
|
1333
1398
|
|
|
1334
|
-
async sendMessage
|
|
1399
|
+
async sendMessage() {
|
|
1335
1400
|
const message = this.messageInput.value.trim();
|
|
1336
|
-
if (!message) {
|
|
1401
|
+
if (!message) {
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1337
1404
|
|
|
1338
1405
|
if (!this.validateLlmSettings()) {
|
|
1339
1406
|
return;
|
|
@@ -1357,12 +1424,14 @@ class McpAgentTester {
|
|
|
1357
1424
|
customPrompt: trim(this.customPromptTextarea.value) || undefined,
|
|
1358
1425
|
model: modelConfig.model,
|
|
1359
1426
|
useStreaming: false,
|
|
1360
|
-
mcpConfig: this.mcpConfig.url
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1427
|
+
mcpConfig: this.mcpConfig.url
|
|
1428
|
+
? {
|
|
1429
|
+
url: this.mcpConfig.url,
|
|
1430
|
+
transport: this.mcpConfig.transport,
|
|
1431
|
+
headers: this.mcpConfig.headers,
|
|
1432
|
+
name: this.mcpConfig.name,
|
|
1433
|
+
}
|
|
1434
|
+
: undefined,
|
|
1366
1435
|
modelConfig: modelConfig,
|
|
1367
1436
|
};
|
|
1368
1437
|
|
|
@@ -1381,7 +1450,6 @@ class McpAgentTester {
|
|
|
1381
1450
|
this.currentSessionId = result.sessionId;
|
|
1382
1451
|
|
|
1383
1452
|
this.addMessage(result.message, 'assistant', result.metadata);
|
|
1384
|
-
|
|
1385
1453
|
} catch (error) {
|
|
1386
1454
|
console.error('Send message error:', error);
|
|
1387
1455
|
this.addMessage(`Error: ${error.message}`, 'assistant', { error: true });
|
|
@@ -1391,7 +1459,7 @@ class McpAgentTester {
|
|
|
1391
1459
|
}
|
|
1392
1460
|
}
|
|
1393
1461
|
|
|
1394
|
-
addMessage
|
|
1462
|
+
addMessage(text, sender, metadata = {}) {
|
|
1395
1463
|
const messageId = Date.now() + '_' + Math.random().toString(36).substr(2, 9);
|
|
1396
1464
|
const messageDiv = document.createElement('div');
|
|
1397
1465
|
messageDiv.className = `message ${sender}`;
|
|
@@ -1471,15 +1539,15 @@ class McpAgentTester {
|
|
|
1471
1539
|
this.scrollToBottom();
|
|
1472
1540
|
}
|
|
1473
1541
|
|
|
1474
|
-
showTypingIndicator
|
|
1542
|
+
showTypingIndicator() {
|
|
1475
1543
|
this.typingIndicator.classList.add('visible');
|
|
1476
1544
|
}
|
|
1477
1545
|
|
|
1478
|
-
hideTypingIndicator
|
|
1546
|
+
hideTypingIndicator() {
|
|
1479
1547
|
this.typingIndicator.classList.remove('visible');
|
|
1480
1548
|
}
|
|
1481
1549
|
|
|
1482
|
-
clearChat
|
|
1550
|
+
clearChat() {
|
|
1483
1551
|
const welcomeMessage = this.chatMessages.querySelector('.message.welcome');
|
|
1484
1552
|
this.chatMessages.innerHTML = '';
|
|
1485
1553
|
if (welcomeMessage) {
|
|
@@ -1491,32 +1559,33 @@ class McpAgentTester {
|
|
|
1491
1559
|
this.showToast('Chat cleared', 'success');
|
|
1492
1560
|
}
|
|
1493
1561
|
|
|
1494
|
-
scrollToBottom
|
|
1562
|
+
scrollToBottom() {
|
|
1495
1563
|
setTimeout(() => {
|
|
1496
1564
|
this.chatMessages.scrollTop = this.chatMessages.scrollHeight;
|
|
1497
1565
|
}, 100);
|
|
1498
1566
|
}
|
|
1499
1567
|
|
|
1500
|
-
showLoading
|
|
1568
|
+
showLoading(message = 'Loading...') {
|
|
1501
1569
|
this.loadingOverlay.querySelector('span').textContent = message;
|
|
1502
1570
|
this.loadingOverlay.style.display = 'flex';
|
|
1503
1571
|
}
|
|
1504
1572
|
|
|
1505
|
-
hideLoading
|
|
1573
|
+
hideLoading() {
|
|
1506
1574
|
this.loadingOverlay.style.display = 'none';
|
|
1507
1575
|
}
|
|
1508
1576
|
|
|
1509
|
-
showToast
|
|
1577
|
+
showToast(message, type = 'info') {
|
|
1510
1578
|
const toast = document.createElement('div');
|
|
1511
1579
|
toast.className = `toast ${type}`;
|
|
1512
1580
|
toast.setAttribute('data-testid', `at-toast-${type}`);
|
|
1513
1581
|
|
|
1514
|
-
const icon =
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1582
|
+
const icon =
|
|
1583
|
+
{
|
|
1584
|
+
success: 'check_circle',
|
|
1585
|
+
error: 'error',
|
|
1586
|
+
warning: 'warning',
|
|
1587
|
+
info: 'info',
|
|
1588
|
+
}[type] || 'info';
|
|
1520
1589
|
|
|
1521
1590
|
toast.innerHTML = `
|
|
1522
1591
|
<span class="material-icons-round">${icon}</span>
|
|
@@ -1538,11 +1607,13 @@ class McpAgentTester {
|
|
|
1538
1607
|
});
|
|
1539
1608
|
}
|
|
1540
1609
|
|
|
1541
|
-
initLlmSettings
|
|
1610
|
+
initLlmSettings() {
|
|
1542
1611
|
let stored = {};
|
|
1543
1612
|
try {
|
|
1544
1613
|
stored = JSON.parse(localStorage.getItem(LLM_LS_KEY) || '{}');
|
|
1545
|
-
} catch {
|
|
1614
|
+
} catch {
|
|
1615
|
+
stored = {};
|
|
1616
|
+
}
|
|
1546
1617
|
|
|
1547
1618
|
const merged = { ...LLM_DEFAULTS, ...stored };
|
|
1548
1619
|
const cfg = this.llmDefaults || {};
|
|
@@ -1559,13 +1630,15 @@ class McpAgentTester {
|
|
|
1559
1630
|
|
|
1560
1631
|
this.llmSettings = merged;
|
|
1561
1632
|
|
|
1562
|
-
if (touched) {
|
|
1633
|
+
if (touched) {
|
|
1634
|
+
this.saveLlmSettings();
|
|
1635
|
+
}
|
|
1563
1636
|
|
|
1564
1637
|
this.migrateLegacyLlmSettings();
|
|
1565
1638
|
this.renderModelDisplay();
|
|
1566
1639
|
}
|
|
1567
1640
|
|
|
1568
|
-
migrateLegacyLlmSettings
|
|
1641
|
+
migrateLegacyLlmSettings() {
|
|
1569
1642
|
try {
|
|
1570
1643
|
const legacy = JSON.parse(localStorage.getItem('mcpAgentFormValues') || '{}');
|
|
1571
1644
|
let dirty = false;
|
|
@@ -1581,12 +1654,18 @@ class McpAgentTester {
|
|
|
1581
1654
|
};
|
|
1582
1655
|
for (const [from, to] of Object.entries(map)) {
|
|
1583
1656
|
const raw = legacy[from];
|
|
1584
|
-
if (raw == null || raw === '') {
|
|
1657
|
+
if (raw == null || raw === '') {
|
|
1658
|
+
continue;
|
|
1659
|
+
}
|
|
1585
1660
|
const current = this.llmSettings[to];
|
|
1586
1661
|
const isEmpty = current == null || current === '' || current === LLM_DEFAULTS[to];
|
|
1587
|
-
if (!isEmpty) {
|
|
1662
|
+
if (!isEmpty) {
|
|
1663
|
+
continue;
|
|
1664
|
+
}
|
|
1588
1665
|
const v = numericFields.has(to) ? Number(raw) : raw;
|
|
1589
|
-
if (numericFields.has(to) && Number.isNaN(v)) {
|
|
1666
|
+
if (numericFields.has(to) && Number.isNaN(v)) {
|
|
1667
|
+
continue;
|
|
1668
|
+
}
|
|
1590
1669
|
this.llmSettings[to] = v;
|
|
1591
1670
|
dirty = true;
|
|
1592
1671
|
}
|
|
@@ -1599,10 +1678,12 @@ class McpAgentTester {
|
|
|
1599
1678
|
this.saveLlmSettings();
|
|
1600
1679
|
this.renderModelDisplay();
|
|
1601
1680
|
}
|
|
1602
|
-
} catch {
|
|
1681
|
+
} catch {
|
|
1682
|
+
/* ignore */
|
|
1683
|
+
}
|
|
1603
1684
|
}
|
|
1604
1685
|
|
|
1605
|
-
saveLlmSettings
|
|
1686
|
+
saveLlmSettings() {
|
|
1606
1687
|
try {
|
|
1607
1688
|
localStorage.setItem(LLM_LS_KEY, JSON.stringify(this.llmSettings));
|
|
1608
1689
|
} catch (e) {
|
|
@@ -1610,13 +1691,13 @@ class McpAgentTester {
|
|
|
1610
1691
|
}
|
|
1611
1692
|
}
|
|
1612
1693
|
|
|
1613
|
-
renderModelDisplay
|
|
1694
|
+
renderModelDisplay() {
|
|
1614
1695
|
const name = trim(this.llmSettings.model) || '—';
|
|
1615
1696
|
this.modelDisplay.textContent = name;
|
|
1616
1697
|
this.apiKeyWarning.style.display = this.llmSettings.apiKey ? 'none' : 'block';
|
|
1617
1698
|
}
|
|
1618
1699
|
|
|
1619
|
-
openLlmModal
|
|
1700
|
+
openLlmModal() {
|
|
1620
1701
|
const s = this.llmSettings;
|
|
1621
1702
|
this.llmBaseUrl.value = s.baseURL || '';
|
|
1622
1703
|
this.llmApiKey.value = s.apiKey || '';
|
|
@@ -1629,17 +1710,19 @@ class McpAgentTester {
|
|
|
1629
1710
|
// Reset API key visibility to hidden on open
|
|
1630
1711
|
this.llmApiKey.type = 'password';
|
|
1631
1712
|
const icon = this.llmApiKeyToggle.querySelector('.material-icons-round');
|
|
1632
|
-
if (icon) {
|
|
1713
|
+
if (icon) {
|
|
1714
|
+
icon.textContent = 'visibility';
|
|
1715
|
+
}
|
|
1633
1716
|
|
|
1634
1717
|
this.llmModal.style.display = 'flex';
|
|
1635
1718
|
}
|
|
1636
1719
|
|
|
1637
|
-
closeLlmModal
|
|
1720
|
+
closeLlmModal() {
|
|
1638
1721
|
this.closeLlmModelDropdown();
|
|
1639
1722
|
this.llmModal.style.display = 'none';
|
|
1640
1723
|
}
|
|
1641
1724
|
|
|
1642
|
-
saveLlmModal
|
|
1725
|
+
saveLlmModal() {
|
|
1643
1726
|
const baseURL = trim(this.llmBaseUrl.value);
|
|
1644
1727
|
const apiKey = trim(this.llmApiKey.value);
|
|
1645
1728
|
const model = trim(this.llmModelName.value);
|
|
@@ -1649,13 +1732,23 @@ class McpAgentTester {
|
|
|
1649
1732
|
const toolResultLimitChars = parseInt(this.llmLimitChars.value, 10);
|
|
1650
1733
|
|
|
1651
1734
|
const missing = [];
|
|
1652
|
-
if (!model) {
|
|
1735
|
+
if (!model) {
|
|
1736
|
+
missing.push('Model Name');
|
|
1737
|
+
}
|
|
1653
1738
|
// baseURL is optional (OpenAI default) — empty means use provider default
|
|
1654
1739
|
// apiKey intentionally not required here — its absence triggers the red warning instead
|
|
1655
|
-
if (Number.isNaN(temperature)) {
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
if (!
|
|
1740
|
+
if (Number.isNaN(temperature)) {
|
|
1741
|
+
missing.push('Temperature');
|
|
1742
|
+
}
|
|
1743
|
+
if (!maxTokens) {
|
|
1744
|
+
missing.push('Max Tokens');
|
|
1745
|
+
}
|
|
1746
|
+
if (!maxTurns) {
|
|
1747
|
+
missing.push('Max Turns');
|
|
1748
|
+
}
|
|
1749
|
+
if (!toolResultLimitChars) {
|
|
1750
|
+
missing.push('Limit (chars)');
|
|
1751
|
+
}
|
|
1659
1752
|
|
|
1660
1753
|
if (missing.length) {
|
|
1661
1754
|
this.showToast(`Missing required fields: ${missing.join(', ')}`, 'error');
|
|
@@ -1669,18 +1762,22 @@ class McpAgentTester {
|
|
|
1669
1762
|
this.showToast('LLM settings saved', 'success');
|
|
1670
1763
|
}
|
|
1671
1764
|
|
|
1672
|
-
toggleApiKeyVisibility
|
|
1765
|
+
toggleApiKeyVisibility() {
|
|
1673
1766
|
const icon = this.llmApiKeyToggle.querySelector('.material-icons-round');
|
|
1674
1767
|
if (this.llmApiKey.type === 'password') {
|
|
1675
1768
|
this.llmApiKey.type = 'text';
|
|
1676
|
-
if (icon) {
|
|
1769
|
+
if (icon) {
|
|
1770
|
+
icon.textContent = 'visibility_off';
|
|
1771
|
+
}
|
|
1677
1772
|
} else {
|
|
1678
1773
|
this.llmApiKey.type = 'password';
|
|
1679
|
-
if (icon) {
|
|
1774
|
+
if (icon) {
|
|
1775
|
+
icon.textContent = 'visibility';
|
|
1776
|
+
}
|
|
1680
1777
|
}
|
|
1681
1778
|
}
|
|
1682
1779
|
|
|
1683
|
-
renderLlmModelDropdown
|
|
1780
|
+
renderLlmModelDropdown() {
|
|
1684
1781
|
this.llmModelDropdownList.innerHTML = '';
|
|
1685
1782
|
LLM_PRESET_MODELS.forEach((name) => {
|
|
1686
1783
|
const item = document.createElement('div');
|
|
@@ -1696,7 +1793,7 @@ class McpAgentTester {
|
|
|
1696
1793
|
});
|
|
1697
1794
|
}
|
|
1698
1795
|
|
|
1699
|
-
toggleLlmModelDropdown
|
|
1796
|
+
toggleLlmModelDropdown(e) {
|
|
1700
1797
|
e.preventDefault();
|
|
1701
1798
|
e.stopPropagation();
|
|
1702
1799
|
const visible = this.llmModelDropdownList.style.display !== 'none';
|
|
@@ -1707,7 +1804,7 @@ class McpAgentTester {
|
|
|
1707
1804
|
}
|
|
1708
1805
|
}
|
|
1709
1806
|
|
|
1710
|
-
openLlmModelDropdown
|
|
1807
|
+
openLlmModelDropdown() {
|
|
1711
1808
|
this.llmModelDropdownList.style.display = 'block';
|
|
1712
1809
|
this.llmModelDropdownToggle.classList.add('active');
|
|
1713
1810
|
// Close on outside click (one-shot)
|
|
@@ -1722,17 +1819,21 @@ class McpAgentTester {
|
|
|
1722
1819
|
}, 0);
|
|
1723
1820
|
}
|
|
1724
1821
|
|
|
1725
|
-
closeLlmModelDropdown
|
|
1822
|
+
closeLlmModelDropdown() {
|
|
1726
1823
|
this.llmModelDropdownList.style.display = 'none';
|
|
1727
1824
|
this.llmModelDropdownToggle.classList.remove('active');
|
|
1728
1825
|
}
|
|
1729
1826
|
|
|
1730
|
-
validateLlmSettings
|
|
1827
|
+
validateLlmSettings() {
|
|
1731
1828
|
const s = this.llmSettings;
|
|
1732
1829
|
const missing = [];
|
|
1733
1830
|
// baseURL is optional — empty means use provider default (OpenAI)
|
|
1734
|
-
if (!s.apiKey) {
|
|
1735
|
-
|
|
1831
|
+
if (!s.apiKey) {
|
|
1832
|
+
missing.push('API Key');
|
|
1833
|
+
}
|
|
1834
|
+
if (!s.model) {
|
|
1835
|
+
missing.push('Model Name');
|
|
1836
|
+
}
|
|
1736
1837
|
if (missing.length) {
|
|
1737
1838
|
this.showToast(`Cannot send message — missing: ${missing.join(', ')}. Open LLM Settings.`, 'error');
|
|
1738
1839
|
return false;
|
|
@@ -1740,7 +1841,7 @@ class McpAgentTester {
|
|
|
1740
1841
|
return true;
|
|
1741
1842
|
}
|
|
1742
1843
|
|
|
1743
|
-
getModelConfig
|
|
1844
|
+
getModelConfig() {
|
|
1744
1845
|
const s = this.llmSettings;
|
|
1745
1846
|
return {
|
|
1746
1847
|
baseURL: s.baseURL,
|
|
@@ -1753,7 +1854,7 @@ class McpAgentTester {
|
|
|
1753
1854
|
};
|
|
1754
1855
|
}
|
|
1755
1856
|
|
|
1756
|
-
handleServerUrlChange
|
|
1857
|
+
handleServerUrlChange() {
|
|
1757
1858
|
this.stopAuthRefresh();
|
|
1758
1859
|
let url = this.serverUrlInput.value.trim();
|
|
1759
1860
|
|
|
@@ -1781,7 +1882,7 @@ class McpAgentTester {
|
|
|
1781
1882
|
this.saveFormValuesToStorage();
|
|
1782
1883
|
}
|
|
1783
1884
|
|
|
1784
|
-
resetAgentPrompt
|
|
1885
|
+
resetAgentPrompt() {
|
|
1785
1886
|
if (this.originalAgentPrompt) {
|
|
1786
1887
|
this.systemPromptTextarea.value = this.originalAgentPrompt;
|
|
1787
1888
|
this.currentSystemPrompt = this.originalAgentPrompt;
|
|
@@ -1790,8 +1891,10 @@ class McpAgentTester {
|
|
|
1790
1891
|
}
|
|
1791
1892
|
}
|
|
1792
1893
|
|
|
1793
|
-
viewOriginalPrompt
|
|
1794
|
-
if (!this.originalAgentPrompt) {
|
|
1894
|
+
viewOriginalPrompt() {
|
|
1895
|
+
if (!this.originalAgentPrompt) {
|
|
1896
|
+
return;
|
|
1897
|
+
}
|
|
1795
1898
|
const modal = document.getElementById('promptModal');
|
|
1796
1899
|
const textarea = document.getElementById('promptModalTextarea');
|
|
1797
1900
|
const title = document.getElementById('promptModalTitle');
|
|
@@ -1806,12 +1909,12 @@ class McpAgentTester {
|
|
|
1806
1909
|
textarea.focus();
|
|
1807
1910
|
}
|
|
1808
1911
|
|
|
1809
|
-
updateResetPromptButton
|
|
1912
|
+
updateResetPromptButton() {
|
|
1810
1913
|
this.btnResetAgentPrompt.style.display = this.originalAgentPrompt ? '' : 'none';
|
|
1811
1914
|
this.updatePromptModifiedState();
|
|
1812
1915
|
}
|
|
1813
1916
|
|
|
1814
|
-
updatePromptModifiedState
|
|
1917
|
+
updatePromptModifiedState() {
|
|
1815
1918
|
const hasOriginal = !!this.originalAgentPrompt;
|
|
1816
1919
|
const isModified = hasOriginal && this.systemPromptTextarea.value.trim() !== this.originalAgentPrompt.trim();
|
|
1817
1920
|
this.promptModifiedBadge.style.display = isModified ? '' : 'none';
|
|
@@ -1823,7 +1926,7 @@ class McpAgentTester {
|
|
|
1823
1926
|
}
|
|
1824
1927
|
}
|
|
1825
1928
|
|
|
1826
|
-
saveFormValuesToStorage
|
|
1929
|
+
saveFormValuesToStorage() {
|
|
1827
1930
|
const formData = {
|
|
1828
1931
|
serverUrl: this.serverUrlInput.value,
|
|
1829
1932
|
transport: this.transportSelect.value,
|
|
@@ -1833,7 +1936,7 @@ class McpAgentTester {
|
|
|
1833
1936
|
localStorage.setItem('mcpAgentFormValues', JSON.stringify(formData));
|
|
1834
1937
|
}
|
|
1835
1938
|
|
|
1836
|
-
loadFormValuesFromURL
|
|
1939
|
+
loadFormValuesFromURL() {
|
|
1837
1940
|
try {
|
|
1838
1941
|
const params = new URLSearchParams(window.location.search);
|
|
1839
1942
|
const serverUrl = params.get('serverUrl');
|
|
@@ -1850,22 +1953,30 @@ class McpAgentTester {
|
|
|
1850
1953
|
}
|
|
1851
1954
|
}
|
|
1852
1955
|
|
|
1853
|
-
loadFormValuesFromStorage
|
|
1956
|
+
loadFormValuesFromStorage() {
|
|
1854
1957
|
try {
|
|
1855
1958
|
const stored = localStorage.getItem('mcpAgentFormValues');
|
|
1856
1959
|
if (stored) {
|
|
1857
1960
|
const formData = JSON.parse(stored);
|
|
1858
|
-
if (formData.serverUrl) {
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
if (formData.
|
|
1961
|
+
if (formData.serverUrl) {
|
|
1962
|
+
this.serverUrlInput.value = formData.serverUrl;
|
|
1963
|
+
}
|
|
1964
|
+
if (formData.transport) {
|
|
1965
|
+
this.transportSelect.value = formData.transport;
|
|
1966
|
+
}
|
|
1967
|
+
if (formData.agentPrompt) {
|
|
1968
|
+
this.systemPromptTextarea.value = trim(formData.agentPrompt);
|
|
1969
|
+
}
|
|
1970
|
+
if (formData.customPrompt) {
|
|
1971
|
+
this.customPromptTextarea.value = trim(formData.customPrompt);
|
|
1972
|
+
}
|
|
1862
1973
|
}
|
|
1863
1974
|
} catch (error) {
|
|
1864
1975
|
console.error('Error loading form values from storage:', error);
|
|
1865
1976
|
}
|
|
1866
1977
|
}
|
|
1867
1978
|
|
|
1868
|
-
getSavedUrls
|
|
1979
|
+
getSavedUrls() {
|
|
1869
1980
|
try {
|
|
1870
1981
|
const saved = localStorage.getItem('mcpSavedUrls');
|
|
1871
1982
|
return saved ? JSON.parse(saved) : [];
|
|
@@ -1875,7 +1986,7 @@ class McpAgentTester {
|
|
|
1875
1986
|
}
|
|
1876
1987
|
}
|
|
1877
1988
|
|
|
1878
|
-
saveSavedUrls
|
|
1989
|
+
saveSavedUrls(urls) {
|
|
1879
1990
|
try {
|
|
1880
1991
|
localStorage.setItem('mcpSavedUrls', JSON.stringify(urls));
|
|
1881
1992
|
} catch (error) {
|
|
@@ -1883,7 +1994,7 @@ class McpAgentTester {
|
|
|
1883
1994
|
}
|
|
1884
1995
|
}
|
|
1885
1996
|
|
|
1886
|
-
addUrlToSaved
|
|
1997
|
+
addUrlToSaved(url) {
|
|
1887
1998
|
if (!url || url.trim() === '') {
|
|
1888
1999
|
return;
|
|
1889
2000
|
}
|
|
@@ -1891,7 +2002,7 @@ class McpAgentTester {
|
|
|
1891
2002
|
url = url.trim();
|
|
1892
2003
|
let savedUrls = this.getSavedUrls();
|
|
1893
2004
|
|
|
1894
|
-
savedUrls = savedUrls.filter(savedUrl => savedUrl !== url);
|
|
2005
|
+
savedUrls = savedUrls.filter((savedUrl) => savedUrl !== url);
|
|
1895
2006
|
|
|
1896
2007
|
savedUrls.unshift(url);
|
|
1897
2008
|
|
|
@@ -1901,14 +2012,14 @@ class McpAgentTester {
|
|
|
1901
2012
|
this.renderSavedUrls();
|
|
1902
2013
|
}
|
|
1903
2014
|
|
|
1904
|
-
removeUrlFromSaved
|
|
2015
|
+
removeUrlFromSaved(url) {
|
|
1905
2016
|
let savedUrls = this.getSavedUrls();
|
|
1906
|
-
savedUrls = savedUrls.filter(savedUrl => savedUrl !== url);
|
|
2017
|
+
savedUrls = savedUrls.filter((savedUrl) => savedUrl !== url);
|
|
1907
2018
|
this.saveSavedUrls(savedUrls);
|
|
1908
2019
|
this.renderSavedUrls();
|
|
1909
2020
|
}
|
|
1910
2021
|
|
|
1911
|
-
renderSavedUrls
|
|
2022
|
+
renderSavedUrls() {
|
|
1912
2023
|
const savedUrls = this.getSavedUrls();
|
|
1913
2024
|
this.savedUrlsList.innerHTML = '';
|
|
1914
2025
|
|
|
@@ -1920,7 +2031,7 @@ class McpAgentTester {
|
|
|
1920
2031
|
return;
|
|
1921
2032
|
}
|
|
1922
2033
|
|
|
1923
|
-
savedUrls.forEach(url => {
|
|
2034
|
+
savedUrls.forEach((url) => {
|
|
1924
2035
|
const item = document.createElement('div');
|
|
1925
2036
|
item.className = 'dropdown-item';
|
|
1926
2037
|
item.setAttribute('data-testid', 'at-saved-url-item');
|
|
@@ -1947,14 +2058,14 @@ class McpAgentTester {
|
|
|
1947
2058
|
});
|
|
1948
2059
|
}
|
|
1949
2060
|
|
|
1950
|
-
selectUrl
|
|
2061
|
+
selectUrl(url) {
|
|
1951
2062
|
this.serverUrlInput.value = url;
|
|
1952
2063
|
this.handleServerUrlChange();
|
|
1953
2064
|
this.closeUrlDropdown();
|
|
1954
2065
|
this.autoConnect();
|
|
1955
2066
|
}
|
|
1956
2067
|
|
|
1957
|
-
toggleUrlDropdown
|
|
2068
|
+
toggleUrlDropdown(e) {
|
|
1958
2069
|
e.preventDefault();
|
|
1959
2070
|
e.stopPropagation();
|
|
1960
2071
|
|
|
@@ -1967,7 +2078,7 @@ class McpAgentTester {
|
|
|
1967
2078
|
}
|
|
1968
2079
|
}
|
|
1969
2080
|
|
|
1970
|
-
openUrlDropdown
|
|
2081
|
+
openUrlDropdown() {
|
|
1971
2082
|
this.renderSavedUrls();
|
|
1972
2083
|
this.serverUrlDropdownList.style.display = 'block';
|
|
1973
2084
|
this.serverUrlDropdown.classList.add('active');
|
|
@@ -1980,12 +2091,12 @@ class McpAgentTester {
|
|
|
1980
2091
|
}
|
|
1981
2092
|
}
|
|
1982
2093
|
|
|
1983
|
-
closeUrlDropdown
|
|
2094
|
+
closeUrlDropdown() {
|
|
1984
2095
|
this.serverUrlDropdownList.style.display = 'none';
|
|
1985
2096
|
this.serverUrlDropdown.classList.remove('active');
|
|
1986
2097
|
}
|
|
1987
2098
|
|
|
1988
|
-
addCurrentUrlToSaved
|
|
2099
|
+
addCurrentUrlToSaved() {
|
|
1989
2100
|
const currentUrl = this.serverUrlInput.value.trim();
|
|
1990
2101
|
if (currentUrl) {
|
|
1991
2102
|
this.addUrlToSaved(currentUrl);
|
|
@@ -1994,7 +2105,7 @@ class McpAgentTester {
|
|
|
1994
2105
|
}
|
|
1995
2106
|
}
|
|
1996
2107
|
|
|
1997
|
-
handleClickOutside
|
|
2108
|
+
handleClickOutside(e) {
|
|
1998
2109
|
const container = e.target.closest('.custom-select-container');
|
|
1999
2110
|
if (!container) {
|
|
2000
2111
|
this.closeUrlDropdown();
|