agent-discover 1.3.9 → 1.4.0

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.
Files changed (40) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +31 -7
  3. package/agent-desk-plugin.json +10 -3
  4. package/dist/context.d.ts +2 -0
  5. package/dist/context.d.ts.map +1 -1
  6. package/dist/context.js +15 -0
  7. package/dist/context.js.map +1 -1
  8. package/dist/domain/log.d.ts +7 -3
  9. package/dist/domain/log.d.ts.map +1 -1
  10. package/dist/domain/log.js +15 -5
  11. package/dist/domain/log.js.map +1 -1
  12. package/dist/domain/presets.d.ts +30 -0
  13. package/dist/domain/presets.d.ts.map +1 -0
  14. package/dist/domain/presets.js +76 -0
  15. package/dist/domain/presets.js.map +1 -0
  16. package/dist/domain/proxy.d.ts +153 -0
  17. package/dist/domain/proxy.d.ts.map +1 -1
  18. package/dist/domain/proxy.js +396 -3
  19. package/dist/domain/proxy.js.map +1 -1
  20. package/dist/domain/sampling.d.ts +9 -0
  21. package/dist/domain/sampling.d.ts.map +1 -0
  22. package/dist/domain/sampling.js +68 -0
  23. package/dist/domain/sampling.js.map +1 -0
  24. package/dist/storage/database.js +21 -0
  25. package/dist/storage/database.js.map +1 -1
  26. package/dist/transport/rest.d.ts.map +1 -1
  27. package/dist/transport/rest.js +349 -0
  28. package/dist/transport/rest.js.map +1 -1
  29. package/dist/transport/ws.d.ts.map +1 -1
  30. package/dist/transport/ws.js +32 -0
  31. package/dist/transport/ws.js.map +1 -1
  32. package/dist/ui/app.js +16 -0
  33. package/dist/ui/index.html +3 -0
  34. package/dist/ui/markdown.js +102 -0
  35. package/dist/ui/schema-form.js +393 -0
  36. package/dist/ui/styles.css +724 -0
  37. package/dist/ui/tester-window.html +116 -0
  38. package/dist/ui/tester-window.js +153 -0
  39. package/dist/ui/tester.js +1412 -0
  40. package/package.json +1 -1
@@ -0,0 +1,116 @@
1
+ <!doctype html>
2
+ <html lang="en" data-theme="dark">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>MCP Tester</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9
+ <link
10
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
11
+ rel="stylesheet"
12
+ />
13
+ <link
14
+ href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap"
15
+ rel="stylesheet"
16
+ />
17
+ <link rel="stylesheet" href="/styles.css" />
18
+ <style>
19
+ body {
20
+ margin: 0;
21
+ background: var(--bg);
22
+ color: var(--text);
23
+ font-family: Inter, system-ui, sans-serif;
24
+ }
25
+ .tw-root {
26
+ display: flex;
27
+ flex-direction: column;
28
+ height: 100vh;
29
+ }
30
+ .tw-head {
31
+ display: flex;
32
+ align-items: center;
33
+ gap: 10px;
34
+ padding: 10px 16px;
35
+ border-bottom: 1px solid var(--border);
36
+ background: var(--bg-alt);
37
+ }
38
+ .tw-name {
39
+ font-weight: 600;
40
+ font-size: 14px;
41
+ }
42
+ .tw-meta {
43
+ color: var(--text-muted);
44
+ font-size: 12px;
45
+ }
46
+ .tw-theme {
47
+ margin-left: auto;
48
+ background: transparent;
49
+ border: 1px solid var(--border);
50
+ color: var(--text-muted);
51
+ border-radius: 4px;
52
+ padding: 4px 8px;
53
+ cursor: pointer;
54
+ }
55
+ .tw-body {
56
+ flex: 1;
57
+ min-height: 0;
58
+ overflow: auto;
59
+ padding: 14px 18px;
60
+ }
61
+ .tw-body .tester-shell {
62
+ padding: 0;
63
+ }
64
+ .tw-body .tester-list {
65
+ max-height: none;
66
+ }
67
+ .tw-body .tester-popout {
68
+ display: none;
69
+ }
70
+ .tw-conn {
71
+ display: inline-flex;
72
+ align-items: center;
73
+ gap: 6px;
74
+ font-size: 11px;
75
+ color: var(--text-muted);
76
+ }
77
+ .tw-conn::before {
78
+ content: '';
79
+ width: 8px;
80
+ height: 8px;
81
+ border-radius: 50%;
82
+ background: #888;
83
+ }
84
+ .tw-conn.connected::before {
85
+ background: #27ae60;
86
+ }
87
+ .tw-conn.disconnected::before {
88
+ background: #c9394b;
89
+ }
90
+ </style>
91
+ </head>
92
+ <body>
93
+ <div class="tw-root">
94
+ <div class="tw-head">
95
+ <span class="material-symbols-outlined" style="color: var(--accent)">bug_report</span>
96
+ <div>
97
+ <div class="tw-name" id="tw-name">Loading…</div>
98
+ <div class="tw-meta" id="tw-meta"></div>
99
+ </div>
100
+ <span class="tw-conn" id="tw-conn">connecting</span>
101
+ <button class="tw-theme" id="tw-theme" title="Toggle theme">
102
+ <span class="material-symbols-outlined" style="font-size: 14px">dark_mode</span>
103
+ </button>
104
+ </div>
105
+ <div class="tw-body" id="tw-body">
106
+ <div class="hint">Connecting…</div>
107
+ </div>
108
+ </div>
109
+
110
+ <script src="/morphdom.min.js"></script>
111
+ <script src="/markdown.js"></script>
112
+ <script src="/schema-form.js"></script>
113
+ <script src="/tester.js"></script>
114
+ <script src="/tester-window.js"></script>
115
+ </body>
116
+ </html>
@@ -0,0 +1,153 @@
1
+ /* eslint-disable */
2
+ (function () {
3
+ 'use strict';
4
+ var AD = (window.AD = window.AD || {});
5
+ AD._baseUrl = '';
6
+ AD._fetch = function (url, opts) {
7
+ return fetch(AD._baseUrl + url, opts);
8
+ };
9
+ AD._root = document;
10
+
11
+ var ctx = parseContext();
12
+ var ws = null;
13
+
14
+ function parseContext() {
15
+ // Accepts: /tester/<id> and /tester/transient/<handle>
16
+ var parts = location.pathname.replace(/^\/+/, '').split('/').filter(Boolean);
17
+ if (parts[0] !== 'tester') return { mode: 'invalid' };
18
+ if (parts[1] === 'transient' && parts[2]) {
19
+ return { mode: 'transient', handle: parts[2] };
20
+ }
21
+ if (parts[1]) {
22
+ var id = parseInt(parts[1], 10);
23
+ if (!isNaN(id)) return { mode: 'server', id: id };
24
+ }
25
+ return { mode: 'invalid' };
26
+ }
27
+
28
+ function setConn(cls, text) {
29
+ var el = document.getElementById('tw-conn');
30
+ if (!el) return;
31
+ el.className = 'tw-conn ' + cls;
32
+ el.textContent = text;
33
+ }
34
+
35
+ function connectWs() {
36
+ var proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
37
+ ws = new WebSocket(proto + '//' + location.host);
38
+ ws.onopen = function () {
39
+ setConn('connected', 'connected');
40
+ };
41
+ ws.onmessage = function (evt) {
42
+ try {
43
+ var msg = JSON.parse(evt.data);
44
+ if ((msg.type === 'notification' || msg.type === 'progress') && AD.onTesterEvent) {
45
+ AD.onTesterEvent(msg);
46
+ } else if (msg.type === 'elicitation_request' && AD.onElicitationRequest) {
47
+ AD.onElicitationRequest(msg);
48
+ }
49
+ } catch (e) {
50
+ /* ignore */
51
+ }
52
+ };
53
+ ws.onclose = function () {
54
+ setConn('disconnected', 'disconnected');
55
+ setTimeout(connectWs, 2000);
56
+ };
57
+ ws.onerror = function () {
58
+ ws.close();
59
+ };
60
+ }
61
+
62
+ function initTheme() {
63
+ var toggle = document.getElementById('tw-theme');
64
+ var saved = localStorage.getItem('agent-discover-theme');
65
+ if (saved === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
66
+ else if (saved === 'light') document.documentElement.removeAttribute('data-theme');
67
+ if (!toggle) return;
68
+ toggle.addEventListener('click', function () {
69
+ var isDark = document.documentElement.getAttribute('data-theme') === 'dark';
70
+ if (isDark) document.documentElement.removeAttribute('data-theme');
71
+ else document.documentElement.setAttribute('data-theme', 'dark');
72
+ localStorage.setItem('agent-discover-theme', isDark ? 'light' : 'dark');
73
+ });
74
+ }
75
+
76
+ function fetchServerName(callback) {
77
+ if (ctx.mode === 'server') {
78
+ AD._fetch('/api/servers/' + ctx.id)
79
+ .then(function (r) {
80
+ return r.json();
81
+ })
82
+ .then(function (body) {
83
+ callback(body && body.name ? body.name : 'server ' + ctx.id, body);
84
+ })
85
+ .catch(function () {
86
+ callback('server ' + ctx.id, null);
87
+ });
88
+ return;
89
+ }
90
+ if (ctx.mode === 'transient') {
91
+ callback('transient ' + ctx.handle, { transient: true });
92
+ return;
93
+ }
94
+ callback('invalid', null);
95
+ }
96
+
97
+ function mount() {
98
+ if (ctx.mode === 'invalid') {
99
+ document.getElementById('tw-body').innerHTML =
100
+ '<div class="hint error">Invalid tester URL. Expected /tester/&lt;id&gt; or /tester/transient/&lt;handle&gt;.</div>';
101
+ return;
102
+ }
103
+
104
+ initTheme();
105
+ connectWs();
106
+
107
+ fetchServerName(function (name, info) {
108
+ document.getElementById('tw-name').textContent = name;
109
+ document.getElementById('tw-meta').textContent =
110
+ ctx.mode === 'transient' ? 'transient · handle ' + ctx.handle : 'registered server';
111
+ document.title = name + ' — MCP Tester';
112
+
113
+ // The tester module expects a numeric "serverId" key for state. For
114
+ // transient mode we synthesise a stable negative id derived from the
115
+ // handle so rendering paths keep working.
116
+ var renderId = ctx.mode === 'transient' ? 't-' + ctx.handle : ctx.id;
117
+ var serverObj = {
118
+ id: renderId,
119
+ name: name,
120
+ capabilities: (info && info.capabilities) || {},
121
+ };
122
+
123
+ var body = document.getElementById('tw-body');
124
+ body.innerHTML = AD.renderTesterShell(serverObj);
125
+ if (ctx.mode === 'transient' && AD._setTesterHandle) {
126
+ AD._setTesterHandle(renderId, ctx.handle);
127
+ }
128
+ // Kick off data loads
129
+ if (AD.openTesterFor) AD.openTesterFor(renderId);
130
+ });
131
+
132
+ window.addEventListener('beforeunload', function () {
133
+ if (ctx.mode === 'transient') {
134
+ // Release the transient on the server side so we don't leak a child
135
+ // process behind a TTL. navigator.sendBeacon survives the unload.
136
+ try {
137
+ navigator.sendBeacon(
138
+ '/api/transient/' + encodeURIComponent(ctx.handle),
139
+ new Blob([''], { type: 'application/json' }),
140
+ );
141
+ } catch (e) {
142
+ /* ignore */
143
+ }
144
+ }
145
+ });
146
+ }
147
+
148
+ if (document.readyState === 'loading') {
149
+ document.addEventListener('DOMContentLoaded', mount);
150
+ } else {
151
+ mount();
152
+ }
153
+ })();