fa-mcp-sdk 0.2.3
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/LICENSE +21 -0
- package/README.md +283 -0
- package/dist/core/_types_/types.d.ts +67 -0
- package/dist/core/_types_/types.d.ts.map +1 -0
- package/dist/core/_types_/types.js +2 -0
- package/dist/core/_types_/types.js.map +1 -0
- package/dist/core/bootstrap/dotenv.d.ts +3 -0
- package/dist/core/bootstrap/dotenv.d.ts.map +1 -0
- package/dist/core/bootstrap/dotenv.js +3 -0
- package/dist/core/bootstrap/dotenv.js.map +1 -0
- package/dist/core/bootstrap/init-config.d.ts +11 -0
- package/dist/core/bootstrap/init-config.d.ts.map +1 -0
- package/dist/core/bootstrap/init-config.js +52 -0
- package/dist/core/bootstrap/init-config.js.map +1 -0
- package/dist/core/bootstrap/startup-info.d.ts +6 -0
- package/dist/core/bootstrap/startup-info.d.ts.map +1 -0
- package/dist/core/bootstrap/startup-info.js +43 -0
- package/dist/core/bootstrap/startup-info.js.map +1 -0
- package/dist/core/constants.d.ts +2 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +2 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/consul/access-points-updater.d.ts +5 -0
- package/dist/core/consul/access-points-updater.d.ts.map +1 -0
- package/dist/core/consul/access-points-updater.js +11 -0
- package/dist/core/consul/access-points-updater.js.map +1 -0
- package/dist/core/consul/deregister.d.ts +2 -0
- package/dist/core/consul/deregister.d.ts.map +1 -0
- package/dist/core/consul/deregister.js +21 -0
- package/dist/core/consul/deregister.js.map +1 -0
- package/dist/core/consul/get-consul-api.d.ts +2 -0
- package/dist/core/consul/get-consul-api.d.ts.map +1 -0
- package/dist/core/consul/get-consul-api.js +18 -0
- package/dist/core/consul/get-consul-api.js.map +1 -0
- package/dist/core/consul/register.d.ts +2 -0
- package/dist/core/consul/register.d.ts.map +1 -0
- package/dist/core/consul/register.js +6 -0
- package/dist/core/consul/register.js.map +1 -0
- package/dist/core/db/pg-db.d.ts +50 -0
- package/dist/core/db/pg-db.d.ts.map +1 -0
- package/dist/core/db/pg-db.js +89 -0
- package/dist/core/db/pg-db.js.map +1 -0
- package/dist/core/debug.d.ts +5 -0
- package/dist/core/debug.d.ts.map +1 -0
- package/dist/core/debug.js +32 -0
- package/dist/core/debug.js.map +1 -0
- package/dist/core/ee.d.ts +3 -0
- package/dist/core/ee.d.ts.map +1 -0
- package/dist/core/ee.js +4 -0
- package/dist/core/ee.js.map +1 -0
- package/dist/core/errors/BaseMcpError.d.ts +19 -0
- package/dist/core/errors/BaseMcpError.d.ts.map +1 -0
- package/dist/core/errors/BaseMcpError.js +47 -0
- package/dist/core/errors/BaseMcpError.js.map +1 -0
- package/dist/core/errors/ValidationError.d.ts +5 -0
- package/dist/core/errors/ValidationError.d.ts.map +1 -0
- package/dist/core/errors/ValidationError.js +7 -0
- package/dist/core/errors/ValidationError.js.map +1 -0
- package/dist/core/errors/errors.d.ts +24 -0
- package/dist/core/errors/errors.d.ts.map +1 -0
- package/dist/core/errors/errors.js +49 -0
- package/dist/core/errors/errors.js.map +1 -0
- package/dist/core/index.d.ts +19 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +16 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/init-mcp-server.d.ts +8 -0
- package/dist/core/init-mcp-server.d.ts.map +1 -0
- package/dist/core/init-mcp-server.js +101 -0
- package/dist/core/init-mcp-server.js.map +1 -0
- package/dist/core/logger.d.ts +6 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +53 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/mcp/create-mcp-server.d.ts +6 -0
- package/dist/core/mcp/create-mcp-server.d.ts.map +1 -0
- package/dist/core/mcp/create-mcp-server.js +44 -0
- package/dist/core/mcp/create-mcp-server.js.map +1 -0
- package/dist/core/mcp/prompts.d.ts +10 -0
- package/dist/core/mcp/prompts.d.ts.map +1 -0
- package/dist/core/mcp/prompts.js +56 -0
- package/dist/core/mcp/prompts.js.map +1 -0
- package/dist/core/mcp/resources.d.ts +14 -0
- package/dist/core/mcp/resources.d.ts.map +1 -0
- package/dist/core/mcp/resources.js +72 -0
- package/dist/core/mcp/resources.js.map +1 -0
- package/dist/core/mcp/server-stdio.d.ts +5 -0
- package/dist/core/mcp/server-stdio.d.ts.map +1 -0
- package/dist/core/mcp/server-stdio.js +13 -0
- package/dist/core/mcp/server-stdio.js.map +1 -0
- package/dist/core/token/gen-token-app/gen-token-server.d.ts +2 -0
- package/dist/core/token/gen-token-app/gen-token-server.d.ts.map +1 -0
- package/dist/core/token/gen-token-app/gen-token-server.js +115 -0
- package/dist/core/token/gen-token-app/gen-token-server.js.map +1 -0
- package/dist/core/token/gen-token-app/html.d.ts +2 -0
- package/dist/core/token/gen-token-app/html.d.ts.map +1 -0
- package/dist/core/token/gen-token-app/html.js +500 -0
- package/dist/core/token/gen-token-app/html.js.map +1 -0
- package/dist/core/token/i-token.d.ts +13 -0
- package/dist/core/token/i-token.d.ts.map +1 -0
- package/dist/core/token/i-token.js +2 -0
- package/dist/core/token/i-token.js.map +1 -0
- package/dist/core/token/token-core.d.ts +24 -0
- package/dist/core/token/token-core.d.ts.map +1 -0
- package/dist/core/token/token-core.js +130 -0
- package/dist/core/token/token-core.js.map +1 -0
- package/dist/core/token/token.d.ts +17 -0
- package/dist/core/token/token.d.ts.map +1 -0
- package/dist/core/token/token.js +62 -0
- package/dist/core/token/token.js.map +1 -0
- package/dist/core/utils/formatToolResult.d.ts +7 -0
- package/dist/core/utils/formatToolResult.d.ts.map +1 -0
- package/dist/core/utils/formatToolResult.js +68 -0
- package/dist/core/utils/formatToolResult.js.map +1 -0
- package/dist/core/utils/rate-limit.d.ts +17 -0
- package/dist/core/utils/rate-limit.d.ts.map +1 -0
- package/dist/core/utils/rate-limit.js +56 -0
- package/dist/core/utils/rate-limit.js.map +1 -0
- package/dist/core/utils/utils.d.ts +6 -0
- package/dist/core/utils/utils.d.ts.map +1 -0
- package/dist/core/utils/utils.js +12 -0
- package/dist/core/utils/utils.js.map +1 -0
- package/dist/core/web/about-page/css.d.ts +2 -0
- package/dist/core/web/about-page/css.d.ts.map +1 -0
- package/dist/core/web/about-page/css.js +534 -0
- package/dist/core/web/about-page/css.js.map +1 -0
- package/dist/core/web/about-page/render.d.ts +2 -0
- package/dist/core/web/about-page/render.d.ts.map +1 -0
- package/dist/core/web/about-page/render.js +679 -0
- package/dist/core/web/about-page/render.js.map +1 -0
- package/dist/core/web/cors.d.ts +5 -0
- package/dist/core/web/cors.d.ts.map +1 -0
- package/dist/core/web/cors.js +22 -0
- package/dist/core/web/cors.js.map +1 -0
- package/dist/core/web/favicon-svg.d.ts +7 -0
- package/dist/core/web/favicon-svg.d.ts.map +1 -0
- package/dist/core/web/favicon-svg.js +44 -0
- package/dist/core/web/favicon-svg.js.map +1 -0
- package/dist/core/web/server-http.d.ts +5 -0
- package/dist/core/web/server-http.d.ts.map +1 -0
- package/dist/core/web/server-http.js +275 -0
- package/dist/core/web/server-http.js.map +1 -0
- package/package.json +88 -0
|
@@ -0,0 +1,679 @@
|
|
|
1
|
+
import { getResourcesList } from '../../mcp/resources.js';
|
|
2
|
+
import { getPromptsList } from '../../mcp/prompts.js';
|
|
3
|
+
import { getMainDBConnectionStatus } from '../../db/pg-db.js';
|
|
4
|
+
import { getFaviconSvg } from '../favicon-svg.js';
|
|
5
|
+
import { appConfig, getProjectData } from '../../bootstrap/init-config.js';
|
|
6
|
+
import { getCss } from './css.js';
|
|
7
|
+
const startTime = new Date();
|
|
8
|
+
const getUptime = () => {
|
|
9
|
+
const uptimeMs = Date.now() - startTime.getTime();
|
|
10
|
+
const uptimeSeconds = Math.floor(uptimeMs / 1000);
|
|
11
|
+
const hours = Math.floor(uptimeSeconds / 3600);
|
|
12
|
+
const minutes = Math.floor((uptimeSeconds % 3600) / 60);
|
|
13
|
+
const seconds = uptimeSeconds % 60;
|
|
14
|
+
if (hours > 0) {
|
|
15
|
+
return `${hours}h ${minutes}m ${seconds}s`;
|
|
16
|
+
}
|
|
17
|
+
else if (minutes > 0) {
|
|
18
|
+
return `${minutes}m ${seconds}s`;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
return `${seconds}s`;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const encodeSvgForDataUri = (svg) => {
|
|
25
|
+
// Encode SVG for use in data URI
|
|
26
|
+
return encodeURIComponent(svg)
|
|
27
|
+
.replace(/'/g, '%27')
|
|
28
|
+
.replace(/"/g, '%22');
|
|
29
|
+
};
|
|
30
|
+
export const renderAboutPage = async () => {
|
|
31
|
+
const { version, repo } = appConfig;
|
|
32
|
+
const serviceTitle = appConfig.productName.replace(/MCP/i, '').replace(/\s{2,}/g, ' ').trim();
|
|
33
|
+
const staffSvg = getFaviconSvg();
|
|
34
|
+
const iconEncoded = encodeSvgForDataUri(staffSvg);
|
|
35
|
+
const { resources } = getResourcesList();
|
|
36
|
+
const { prompts } = getPromptsList();
|
|
37
|
+
const { tools, httpComponents } = global.__MCP_PROJECT_DATA__;
|
|
38
|
+
const statusText = 'online';
|
|
39
|
+
const statusClass = 'online';
|
|
40
|
+
let swaggerInfo = '';
|
|
41
|
+
if (httpComponents?.swagger) {
|
|
42
|
+
swaggerInfo = `<!-- Swagger -->
|
|
43
|
+
<section class="info-section">
|
|
44
|
+
<div class="info-row">
|
|
45
|
+
<span class="label">API Reference:</span>
|
|
46
|
+
<span class="value">
|
|
47
|
+
<a href="/docs" target="_blank" rel="noopener" class="clickable">Swagger</a>
|
|
48
|
+
</span>
|
|
49
|
+
</div>
|
|
50
|
+
</section>`;
|
|
51
|
+
}
|
|
52
|
+
let dbInfo = '';
|
|
53
|
+
if (appConfig.isMainDBUsed) {
|
|
54
|
+
const dbStatus = await getMainDBConnectionStatus();
|
|
55
|
+
const { host, port, database } = appConfig.db.postgres.dbs.main;
|
|
56
|
+
dbInfo = `<!-- Database Info -->
|
|
57
|
+
<section class="info-section">
|
|
58
|
+
<div class="info-row">
|
|
59
|
+
<span class="label">Database:</span>
|
|
60
|
+
<div>
|
|
61
|
+
<span class="value">${host}:${port}/${database} • </span>
|
|
62
|
+
<span class="value ${dbStatus}">${dbStatus}</span>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</section>`;
|
|
66
|
+
}
|
|
67
|
+
const { getConsulUIAddress = (_s) => '', assets } = getProjectData();
|
|
68
|
+
const footerData = [];
|
|
69
|
+
if (repo) {
|
|
70
|
+
footerData.push(`<a href="${repo}" target="_blank" rel="noopener">GitHub Repository</a>`);
|
|
71
|
+
}
|
|
72
|
+
if (assets?.maintainerHtml) {
|
|
73
|
+
footerData.push(assets?.maintainerHtml);
|
|
74
|
+
}
|
|
75
|
+
let consulInfo = '';
|
|
76
|
+
if (!appConfig.consul.service.noRegOnStart) {
|
|
77
|
+
const { id } = appConfig.consul.service;
|
|
78
|
+
if (id) {
|
|
79
|
+
consulInfo = `<!-- Consul Info -->
|
|
80
|
+
<section class="info-section">
|
|
81
|
+
<div class="info-row">
|
|
82
|
+
<span class="label">Consul id:</span>
|
|
83
|
+
<span class="value"><a href="${getConsulUIAddress(id)}" target="_blank" rel="noopener" class="clickable">${id}</a></span>
|
|
84
|
+
</div>
|
|
85
|
+
</section>`;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const docType = '<!DOCTYPE html>';
|
|
89
|
+
// @formatter:off
|
|
90
|
+
return docType + `
|
|
91
|
+
<html lang="en">
|
|
92
|
+
<head>
|
|
93
|
+
<meta charset="UTF-8" />
|
|
94
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
95
|
+
<title>${serviceTitle} MCP Server</title>
|
|
96
|
+
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,${iconEncoded}">
|
|
97
|
+
<style>${getCss(appConfig.uiColor.primary)}</style>
|
|
98
|
+
</head>
|
|
99
|
+
<body>
|
|
100
|
+
<div class="simple-container">
|
|
101
|
+
<!-- Header -->
|
|
102
|
+
<header class="simple-header">
|
|
103
|
+
<div class="header-row">
|
|
104
|
+
<div class="header-title">
|
|
105
|
+
<div class="service-icon">${staffSvg}</div>
|
|
106
|
+
<h1>${serviceTitle} MCP Server</h1>
|
|
107
|
+
</div>
|
|
108
|
+
<div class="status ${statusClass}">${statusText}</div>
|
|
109
|
+
</div>
|
|
110
|
+
</header>
|
|
111
|
+
|
|
112
|
+
<!-- Main Content -->
|
|
113
|
+
<main class="simple-main">
|
|
114
|
+
<!-- Basic Info -->
|
|
115
|
+
<section class="info-section">
|
|
116
|
+
<div class="info-row">
|
|
117
|
+
<span class="label">Service:</span>
|
|
118
|
+
<span class="value">${appConfig.description}</span>
|
|
119
|
+
</div>
|
|
120
|
+
<div class="info-row">
|
|
121
|
+
<span class="label">Version:</span>
|
|
122
|
+
<span class="value">${version}</span>
|
|
123
|
+
</div>
|
|
124
|
+
<div class="info-row">
|
|
125
|
+
<span class="label">Tools:</span>
|
|
126
|
+
<span class="value clickable" onclick="openModal('tools')">${tools.length} available</span>
|
|
127
|
+
</div>
|
|
128
|
+
<div class="info-row">
|
|
129
|
+
<span class="label">Resources:</span>
|
|
130
|
+
<span class="value clickable" onclick="openModal('resources')">${resources.length} available</span>
|
|
131
|
+
</div>
|
|
132
|
+
<div class="info-row">
|
|
133
|
+
<span class="label">Prompts:</span>
|
|
134
|
+
<span class="value clickable" onclick="openModal('prompts')">${prompts.length} available</span>
|
|
135
|
+
</div>
|
|
136
|
+
<div class="info-row">
|
|
137
|
+
<span class="label">Uptime:</span>
|
|
138
|
+
<span class="value">${getUptime()}</span>
|
|
139
|
+
</div>
|
|
140
|
+
</section>
|
|
141
|
+
${dbInfo}
|
|
142
|
+
<!-- Transport Info -->
|
|
143
|
+
<section class="info-section">
|
|
144
|
+
<div class="info-row">
|
|
145
|
+
<span class="label">HTTP Transport:</span>
|
|
146
|
+
<span class="value"><code>GET /sse</code> • <code>POST /mcp</code></span>
|
|
147
|
+
</div>
|
|
148
|
+
</section>
|
|
149
|
+
|
|
150
|
+
${swaggerInfo}
|
|
151
|
+
|
|
152
|
+
${consulInfo}
|
|
153
|
+
|
|
154
|
+
<!-- Health Check -->
|
|
155
|
+
<section class="info-section">
|
|
156
|
+
<div class="info-row">
|
|
157
|
+
<span class="label">Health Check:</span>
|
|
158
|
+
<span class="value clickable" onclick="openHealthCheckModal()">Check Server Health</span>
|
|
159
|
+
</div>
|
|
160
|
+
</section>
|
|
161
|
+
|
|
162
|
+
</main>
|
|
163
|
+
|
|
164
|
+
<!-- Modal Overlays -->
|
|
165
|
+
<!-- Tools Modal -->
|
|
166
|
+
<div id="tools-modal" class="modal-overlay" style="display: none;">
|
|
167
|
+
<div class="modal-content">
|
|
168
|
+
<div class="modal-header">
|
|
169
|
+
<h3>Available Tools (${tools.length})</h3>
|
|
170
|
+
<button class="modal-close" onclick="closeModal('tools')">×</button>
|
|
171
|
+
</div>
|
|
172
|
+
<div class="modal-body">
|
|
173
|
+
<div class="table-container">
|
|
174
|
+
<table class="details-table" id="tools-table">
|
|
175
|
+
<thead>
|
|
176
|
+
<tr>
|
|
177
|
+
<th>Name</th>
|
|
178
|
+
<th>Description</th>
|
|
179
|
+
<th>Actions</th>
|
|
180
|
+
</tr>
|
|
181
|
+
</thead>
|
|
182
|
+
<tbody>
|
|
183
|
+
<!-- Content will be dynamically loaded -->
|
|
184
|
+
</tbody>
|
|
185
|
+
</table>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
|
|
191
|
+
<!-- Resources Modal -->
|
|
192
|
+
<div id="resources-modal" class="modal-overlay" style="display: none;">
|
|
193
|
+
<div class="modal-content">
|
|
194
|
+
<div class="modal-header">
|
|
195
|
+
<h3>Available Resources (${resources.length})</h3>
|
|
196
|
+
<button class="modal-close" onclick="closeModal('resources')">×</button>
|
|
197
|
+
</div>
|
|
198
|
+
<div class="modal-body">
|
|
199
|
+
<div class="table-container">
|
|
200
|
+
<table class="details-table" id="resources-table">
|
|
201
|
+
<thead>
|
|
202
|
+
<tr>
|
|
203
|
+
<th>URI</th>
|
|
204
|
+
<th>Name</th>
|
|
205
|
+
<th>Description</th>
|
|
206
|
+
<th>MIME Type</th>
|
|
207
|
+
<th>Actions</th>
|
|
208
|
+
</tr>
|
|
209
|
+
</thead>
|
|
210
|
+
<tbody>
|
|
211
|
+
<!-- Content will be dynamically loaded -->
|
|
212
|
+
</tbody>
|
|
213
|
+
</table>
|
|
214
|
+
</div>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
|
|
219
|
+
<!-- Prompts Modal -->
|
|
220
|
+
<div id="prompts-modal" class="modal-overlay" style="display: none;">
|
|
221
|
+
<div class="modal-content">
|
|
222
|
+
<div class="modal-header">
|
|
223
|
+
<h3>Available Prompts (${prompts.length})</h3>
|
|
224
|
+
<button class="modal-close" onclick="closeModal('prompts')">×</button>
|
|
225
|
+
</div>
|
|
226
|
+
<div class="modal-body">
|
|
227
|
+
<div class="table-container">
|
|
228
|
+
<table class="details-table" id="prompts-table">
|
|
229
|
+
<thead>
|
|
230
|
+
<tr>
|
|
231
|
+
<th>Name</th>
|
|
232
|
+
<th>Actions</th>
|
|
233
|
+
</tr>
|
|
234
|
+
</thead>
|
|
235
|
+
<tbody>
|
|
236
|
+
<!-- Content will be dynamically loaded -->
|
|
237
|
+
</tbody>
|
|
238
|
+
</table>
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
242
|
+
</div>
|
|
243
|
+
|
|
244
|
+
<!-- Health Check Modal -->
|
|
245
|
+
<div id="health-modal" class="modal-overlay" style="display: none;">
|
|
246
|
+
<div class="modal-content">
|
|
247
|
+
<div class="modal-header">
|
|
248
|
+
<h3>Server Health Check</h3>
|
|
249
|
+
<button class="modal-close" onclick="closeModal('health')">×</button>
|
|
250
|
+
</div>
|
|
251
|
+
<div class="modal-body">
|
|
252
|
+
<div class="loading-cell" id="health-loading">
|
|
253
|
+
<div class="loading-spinner"></div>
|
|
254
|
+
Checking server health...
|
|
255
|
+
</div>
|
|
256
|
+
<pre class="json-content" id="health-result" style="display: none;"></pre>
|
|
257
|
+
<div class="error-message" id="health-error" style="display: none;"></div>
|
|
258
|
+
</div>
|
|
259
|
+
</div>
|
|
260
|
+
</div>
|
|
261
|
+
|
|
262
|
+
<!-- Footer -->
|
|
263
|
+
<footer class="simple-footer">
|
|
264
|
+
<p>
|
|
265
|
+
${footerData.join(' • ')}
|
|
266
|
+
</p>
|
|
267
|
+
</footer>
|
|
268
|
+
</div>
|
|
269
|
+
|
|
270
|
+
<script>
|
|
271
|
+
// Store data globally
|
|
272
|
+
let toolsData = [];
|
|
273
|
+
let resourcesData = [];
|
|
274
|
+
let promptsData = [];
|
|
275
|
+
|
|
276
|
+
// Initialize data when page loads
|
|
277
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
278
|
+
try {
|
|
279
|
+
toolsData = ${JSON.stringify(tools)};
|
|
280
|
+
resourcesData = ${JSON.stringify(resources)};
|
|
281
|
+
promptsData = ${JSON.stringify(prompts)};
|
|
282
|
+
} catch (error) {
|
|
283
|
+
console.error('Error parsing data:', error);
|
|
284
|
+
toolsData = [];
|
|
285
|
+
resourcesData = [];
|
|
286
|
+
promptsData = [];
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
function openModal(sectionName) {
|
|
291
|
+
const modal = document.getElementById(sectionName + '-modal');
|
|
292
|
+
const tableBody = document.getElementById(sectionName + '-table').querySelector('tbody');
|
|
293
|
+
|
|
294
|
+
// Show loading state
|
|
295
|
+
tableBody.innerHTML = '<tr><td colspan="100%" class="loading-cell"><div class="loading-spinner"></div> Loading...</td></tr>';
|
|
296
|
+
modal.style.display = 'flex';
|
|
297
|
+
|
|
298
|
+
// Load data with small delay to show loading animation
|
|
299
|
+
setTimeout(function() {
|
|
300
|
+
loadTableData(sectionName);
|
|
301
|
+
}, 300);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function closeModal(sectionName) {
|
|
305
|
+
const modal = document.getElementById(sectionName + '-modal');
|
|
306
|
+
modal.style.display = 'none';
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function loadTableData(sectionName) {
|
|
310
|
+
const tableBody = document.getElementById(sectionName + '-table').querySelector('tbody');
|
|
311
|
+
let data, html;
|
|
312
|
+
|
|
313
|
+
switch(sectionName) {
|
|
314
|
+
case 'tools':
|
|
315
|
+
data = toolsData;
|
|
316
|
+
html = generateToolsTableRows(data);
|
|
317
|
+
break;
|
|
318
|
+
case 'resources':
|
|
319
|
+
data = resourcesData;
|
|
320
|
+
html = generateResourcesTableRows(data);
|
|
321
|
+
break;
|
|
322
|
+
case 'prompts':
|
|
323
|
+
data = promptsData;
|
|
324
|
+
html = generatePromptsTableRows(data);
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
tableBody.innerHTML = html;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function generateToolsTableRows(tools) {
|
|
332
|
+
if (!tools || tools.length === 0) {
|
|
333
|
+
return '<tr><td colspan="3" class="loading-cell">No tools available</td></tr>';
|
|
334
|
+
}
|
|
335
|
+
return tools.map((tool, index) =>
|
|
336
|
+
'<tr>' +
|
|
337
|
+
'<td><code>' + tool.name + '</code></td>' +
|
|
338
|
+
'<td>' + (tool.annotations?.title || tool.description) + '</td>' +
|
|
339
|
+
'<td>' +
|
|
340
|
+
'<a class="detail-link" id="tools-toggle-' + index + '" onclick="toggleDetails(\\\'tools\\\', ' + index + ')">details</a>' +
|
|
341
|
+
'</td>' +
|
|
342
|
+
'</tr>' +
|
|
343
|
+
'<tr id="tools-detail-' + index + '" class="detail-row" style="display: none;">' +
|
|
344
|
+
'<td colspan="3">' +
|
|
345
|
+
'<div class="detail-content">' +
|
|
346
|
+
'<div class="loading-spinner" style="display: none;"></div>' +
|
|
347
|
+
'<pre class="json-content" style="display: none;"></pre>' +
|
|
348
|
+
'</div>' +
|
|
349
|
+
'</td>' +
|
|
350
|
+
'</tr>'
|
|
351
|
+
).join('');
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function generateResourcesTableRows(resources) {
|
|
355
|
+
if (!resources || resources.length === 0) {
|
|
356
|
+
return '<tr><td colspan="5" class="loading-cell">No resources available</td></tr>';
|
|
357
|
+
}
|
|
358
|
+
return resources.map((resource, index) =>
|
|
359
|
+
'<tr>' +
|
|
360
|
+
'<td><code>' + resource.uri + '</code></td>' +
|
|
361
|
+
'<td>' + resource.name + '</td>' +
|
|
362
|
+
'<td>' + resource.description + '</td>' +
|
|
363
|
+
'<td><code>' + resource.mimeType + '</code></td>' +
|
|
364
|
+
'<td>' +
|
|
365
|
+
'<a class="detail-link" id="resources-toggle-details-' + index + '" onclick="toggleResourceDetails(\\\'resources\\\', ' + index + ', \\\'details\\\')">details</a>' +
|
|
366
|
+
' / ' +
|
|
367
|
+
'<a class="detail-link" id="resources-toggle-resource-' + index + '" onclick="toggleResourceDetails(\\\'resources\\\', ' + index + ', \\\'resource\\\')">resource</a>' +
|
|
368
|
+
'</td>' +
|
|
369
|
+
'</tr>' +
|
|
370
|
+
'<tr id="resources-detail-' + index + '" class="detail-row" style="display: none;">' +
|
|
371
|
+
'<td colspan="5">' +
|
|
372
|
+
'<div class="detail-content">' +
|
|
373
|
+
'<div class="loading-spinner"></div>' +
|
|
374
|
+
'<pre class="json-content" style="display: none;"></pre>' +
|
|
375
|
+
'<div class="resource-content" style="display: none;"></div>' +
|
|
376
|
+
'</div>' +
|
|
377
|
+
'</td>' +
|
|
378
|
+
'</tr>'
|
|
379
|
+
).join('');
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function generatePromptsTableRows(prompts) {
|
|
383
|
+
if (!prompts || prompts.length === 0) {
|
|
384
|
+
return '<tr><td colspan="2" class="loading-cell">No prompts available</td></tr>';
|
|
385
|
+
}
|
|
386
|
+
return prompts.map((prompt, index) =>
|
|
387
|
+
'<tr>' +
|
|
388
|
+
'<td><code>' + prompt.name + '</code></td>' +
|
|
389
|
+
'<td>' +
|
|
390
|
+
'<a class="detail-link" id="prompts-toggle-details-' + index + '" onclick="togglePromptDetails(\\\'prompts\\\', ' + index + ', \\\'details\\\')">details</a>' +
|
|
391
|
+
' / ' +
|
|
392
|
+
'<a class="detail-link" id="prompts-toggle-prompt-' + index + '" onclick="togglePromptDetails(\\\'prompts\\\', ' + index + ', \\\'prompt\\\')">prompt</a>' +
|
|
393
|
+
'</td>' +
|
|
394
|
+
'</tr>' +
|
|
395
|
+
'<tr id="prompts-detail-' + index + '" class="detail-row" style="display: none;">' +
|
|
396
|
+
'<td colspan="2">' +
|
|
397
|
+
'<div class="detail-content">' +
|
|
398
|
+
'<div class="loading-spinner"></div>' +
|
|
399
|
+
'<pre class="json-content" style="display: none;"></pre>' +
|
|
400
|
+
'<div class="prompt-content" style="display: none;"></div>' +
|
|
401
|
+
'</div>' +
|
|
402
|
+
'</td>' +
|
|
403
|
+
'</tr>'
|
|
404
|
+
).join('');
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function toggleDetails(sectionName, index) {
|
|
408
|
+
const detailRow = document.getElementById(sectionName + '-detail-' + index);
|
|
409
|
+
const toggleLink = document.getElementById(sectionName + '-toggle-' + index);
|
|
410
|
+
const loadingSpinner = detailRow.querySelector('.loading-spinner');
|
|
411
|
+
const jsonContent = detailRow.querySelector('.json-content');
|
|
412
|
+
|
|
413
|
+
if (detailRow.style.display === 'none') {
|
|
414
|
+
// Show the detail row with loading state
|
|
415
|
+
detailRow.style.display = 'table-row';
|
|
416
|
+
toggleLink.textContent = 'hide';
|
|
417
|
+
loadingSpinner.style.display = 'block';
|
|
418
|
+
jsonContent.style.display = 'none';
|
|
419
|
+
|
|
420
|
+
// Simulate loading delay and show content
|
|
421
|
+
setTimeout(() => {
|
|
422
|
+
let data;
|
|
423
|
+
let textContent;
|
|
424
|
+
switch(sectionName) {
|
|
425
|
+
case 'tools':
|
|
426
|
+
data = {
|
|
427
|
+
name: toolsData[index].name,
|
|
428
|
+
description: toolsData[index].description,
|
|
429
|
+
inputSchema: toolsData[index].inputSchema,
|
|
430
|
+
annotations: toolsData[index].annotations
|
|
431
|
+
};
|
|
432
|
+
textContent = JSON.stringify(data, null, 2);
|
|
433
|
+
break;
|
|
434
|
+
case 'resources':
|
|
435
|
+
data = resourcesData[index].content || resourcesData[index];
|
|
436
|
+
textContent = JSON.stringify(data, null, 2);
|
|
437
|
+
// Try to parse JSON from contents[0]?.text and add explanation
|
|
438
|
+
const text = data.contents?.[0]?.text;
|
|
439
|
+
if (text) {
|
|
440
|
+
try {
|
|
441
|
+
const parsedJson = JSON.parse(text);
|
|
442
|
+
data.contents[0].text = parsedJson;
|
|
443
|
+
textContent = 'Text field - deserialized data:\\n\\n' + JSON.stringify(data, null, 2);
|
|
444
|
+
} catch (e) {
|
|
445
|
+
// If parsing fails, keep original data
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
break;
|
|
449
|
+
case 'prompts':
|
|
450
|
+
data = promptsData[index];
|
|
451
|
+
textContent = JSON.stringify(data, null, 2)
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
loadingSpinner.style.display = 'none';
|
|
456
|
+
jsonContent.style.display = 'block';
|
|
457
|
+
jsonContent.textContent = textContent;
|
|
458
|
+
}, 500);
|
|
459
|
+
} else {
|
|
460
|
+
// Hide the detail row
|
|
461
|
+
detailRow.style.display = 'none';
|
|
462
|
+
toggleLink.textContent = 'details';
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Handle prompt details and prompt content display
|
|
467
|
+
async function togglePromptDetails(sectionName, index, displayType) {
|
|
468
|
+
const detailRow = document.getElementById(sectionName + '-detail-' + index);
|
|
469
|
+
const toggleLinkDetails = document.getElementById(sectionName + '-toggle-details-' + index);
|
|
470
|
+
const toggleLinkPrompt = document.getElementById(sectionName + '-toggle-prompt-' + index);
|
|
471
|
+
const loadingSpinner = detailRow.querySelector('.loading-spinner');
|
|
472
|
+
const jsonContent = detailRow.querySelector('.json-content');
|
|
473
|
+
const promptContent = detailRow.querySelector('.prompt-content');
|
|
474
|
+
|
|
475
|
+
const isCurrentlyHidden = detailRow.style.display === 'none';
|
|
476
|
+
const currentToggleLink = displayType === 'details' ? toggleLinkDetails : toggleLinkPrompt;
|
|
477
|
+
const otherToggleLink = displayType === 'details' ? toggleLinkPrompt : toggleLinkDetails;
|
|
478
|
+
|
|
479
|
+
if (isCurrentlyHidden || currentToggleLink.textContent === displayType) {
|
|
480
|
+
// Show the detail row with loading state
|
|
481
|
+
detailRow.style.display = 'table-row';
|
|
482
|
+
currentToggleLink.textContent = 'hide';
|
|
483
|
+
otherToggleLink.textContent = displayType === 'details' ? 'prompt' : 'details';
|
|
484
|
+
loadingSpinner.style.display = 'block';
|
|
485
|
+
jsonContent.style.display = 'none';
|
|
486
|
+
promptContent.style.display = 'none';
|
|
487
|
+
|
|
488
|
+
if (displayType === 'details') {
|
|
489
|
+
// Show JSON details
|
|
490
|
+
setTimeout(() => {
|
|
491
|
+
const data = promptsData[index];
|
|
492
|
+
const textContent = JSON.stringify(data, null, 2);
|
|
493
|
+
loadingSpinner.style.display = 'none';
|
|
494
|
+
jsonContent.style.display = 'block';
|
|
495
|
+
jsonContent.textContent = textContent;
|
|
496
|
+
}, 300);
|
|
497
|
+
} else {
|
|
498
|
+
// Fetch and show prompt content
|
|
499
|
+
try {
|
|
500
|
+
const promptName = promptsData[index].name;
|
|
501
|
+
const response = await fetch('/mcp', {
|
|
502
|
+
method: 'POST',
|
|
503
|
+
headers: { 'Content-Type': 'application/json' },
|
|
504
|
+
body: JSON.stringify({
|
|
505
|
+
jsonrpc: '2.0',
|
|
506
|
+
id: Date.now(),
|
|
507
|
+
method: 'prompts/get',
|
|
508
|
+
params: { name: promptName }
|
|
509
|
+
})
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
if (!response.ok) {
|
|
513
|
+
throw new Error('HTTP ' + response.status);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const result = await response.json();
|
|
517
|
+
const messages = result.result?.messages || [];
|
|
518
|
+
let promptText = '';
|
|
519
|
+
|
|
520
|
+
messages.forEach((msg, i) => {
|
|
521
|
+
if (i > 0) promptText += '\\n\\n---\\n\\n';
|
|
522
|
+
promptText += 'Role: ' + msg.role + '\\n\\n';
|
|
523
|
+
if (typeof msg.content === 'string') {
|
|
524
|
+
promptText += msg.content;
|
|
525
|
+
} else if (msg.content?.text) {
|
|
526
|
+
promptText += msg.content.text;
|
|
527
|
+
} else {
|
|
528
|
+
promptText += JSON.stringify(msg.content, null, 2);
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
loadingSpinner.style.display = 'none';
|
|
533
|
+
promptContent.style.display = 'block';
|
|
534
|
+
promptContent.innerHTML = '<pre class="json-content">' + promptText + '</pre>';
|
|
535
|
+
} catch (error) {
|
|
536
|
+
loadingSpinner.style.display = 'none';
|
|
537
|
+
promptContent.style.display = 'block';
|
|
538
|
+
promptContent.innerHTML = '<div class="error-message">Failed to load prompt: ' + error.message + '</div>';
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
} else {
|
|
542
|
+
// Hide the detail row
|
|
543
|
+
detailRow.style.display = 'none';
|
|
544
|
+
toggleLinkDetails.textContent = 'details';
|
|
545
|
+
toggleLinkPrompt.textContent = 'prompt';
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Handle resource details and resource content display
|
|
550
|
+
async function toggleResourceDetails(sectionName, index, displayType) {
|
|
551
|
+
const detailRow = document.getElementById(sectionName + '-detail-' + index);
|
|
552
|
+
const toggleLinkDetails = document.getElementById(sectionName + '-toggle-details-' + index);
|
|
553
|
+
const toggleLinkResource = document.getElementById(sectionName + '-toggle-resource-' + index);
|
|
554
|
+
const loadingSpinner = detailRow.querySelector('.loading-spinner');
|
|
555
|
+
const jsonContent = detailRow.querySelector('.json-content');
|
|
556
|
+
const resourceContent = detailRow.querySelector('.resource-content');
|
|
557
|
+
|
|
558
|
+
const isCurrentlyHidden = detailRow.style.display === 'none';
|
|
559
|
+
const currentToggleLink = displayType === 'details' ? toggleLinkDetails : toggleLinkResource;
|
|
560
|
+
const otherToggleLink = displayType === 'details' ? toggleLinkResource : toggleLinkDetails;
|
|
561
|
+
|
|
562
|
+
if (isCurrentlyHidden || currentToggleLink.textContent === displayType) {
|
|
563
|
+
// Show the detail row with loading state
|
|
564
|
+
detailRow.style.display = 'table-row';
|
|
565
|
+
currentToggleLink.textContent = 'hide';
|
|
566
|
+
otherToggleLink.textContent = displayType === 'details' ? 'resource' : 'details';
|
|
567
|
+
loadingSpinner.style.display = 'block';
|
|
568
|
+
jsonContent.style.display = 'none';
|
|
569
|
+
resourceContent.style.display = 'none';
|
|
570
|
+
|
|
571
|
+
if (displayType === 'details') {
|
|
572
|
+
// Show JSON details
|
|
573
|
+
setTimeout(() => {
|
|
574
|
+
const data = resourcesData[index];
|
|
575
|
+
const textContent = JSON.stringify(data, null, 2);
|
|
576
|
+
loadingSpinner.style.display = 'none';
|
|
577
|
+
jsonContent.style.display = 'block';
|
|
578
|
+
jsonContent.textContent = textContent;
|
|
579
|
+
}, 300);
|
|
580
|
+
} else {
|
|
581
|
+
// Fetch and show resource content
|
|
582
|
+
try {
|
|
583
|
+
const resourceUri = resourcesData[index].uri;
|
|
584
|
+
const response = await fetch('/mcp', {
|
|
585
|
+
method: 'POST',
|
|
586
|
+
headers: { 'Content-Type': 'application/json' },
|
|
587
|
+
body: JSON.stringify({
|
|
588
|
+
jsonrpc: '2.0',
|
|
589
|
+
id: Date.now(),
|
|
590
|
+
method: 'resources/read',
|
|
591
|
+
params: { uri: resourceUri }
|
|
592
|
+
})
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
if (!response.ok) {
|
|
596
|
+
throw new Error('HTTP ' + response.status);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
const result = await response.json();
|
|
600
|
+
const contents = result.result?.contents || [];
|
|
601
|
+
let resourceText = '';
|
|
602
|
+
|
|
603
|
+
contents.forEach((content, i) => {
|
|
604
|
+
if (i > 0) resourceText += '\\n\\n---\\n\\n';
|
|
605
|
+
resourceText += 'URI: ' + content.uri + '\\n';
|
|
606
|
+
resourceText += 'MIME Type: ' + content.mimeType + '\\n\\n';
|
|
607
|
+
if (content.text) {
|
|
608
|
+
resourceText += content.text;
|
|
609
|
+
} else if (content.blob) {
|
|
610
|
+
resourceText += '[Binary content: ' + content.blob.length + ' bytes]';
|
|
611
|
+
} else {
|
|
612
|
+
resourceText += JSON.stringify(content, null, 2);
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
loadingSpinner.style.display = 'none';
|
|
617
|
+
resourceContent.style.display = 'block';
|
|
618
|
+
resourceContent.innerHTML = '<pre class="json-content">' + resourceText + '</pre>';
|
|
619
|
+
} catch (error) {
|
|
620
|
+
loadingSpinner.style.display = 'none';
|
|
621
|
+
resourceContent.style.display = 'block';
|
|
622
|
+
resourceContent.innerHTML = '<div class="error-message">Failed to load resource: ' + error.message + '</div>';
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
} else {
|
|
626
|
+
// Hide the detail row
|
|
627
|
+
detailRow.style.display = 'none';
|
|
628
|
+
toggleLinkDetails.textContent = 'details';
|
|
629
|
+
toggleLinkResource.textContent = 'resource';
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// Health Check Modal
|
|
634
|
+
async function openHealthCheckModal() {
|
|
635
|
+
const modal = document.getElementById('health-modal');
|
|
636
|
+
const loading = document.getElementById('health-loading');
|
|
637
|
+
const result = document.getElementById('health-result');
|
|
638
|
+
const error = document.getElementById('health-error');
|
|
639
|
+
|
|
640
|
+
// Show modal with loading state
|
|
641
|
+
modal.style.display = 'flex';
|
|
642
|
+
loading.style.display = 'block';
|
|
643
|
+
result.style.display = 'none';
|
|
644
|
+
error.style.display = 'none';
|
|
645
|
+
|
|
646
|
+
try {
|
|
647
|
+
const response = await fetch('/health');
|
|
648
|
+
|
|
649
|
+
if (!response.ok) {
|
|
650
|
+
throw new Error('HTTP ' + response.status + ': ' + response.statusText);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
const data = await response.json();
|
|
654
|
+
|
|
655
|
+
// Hide loading and show result
|
|
656
|
+
loading.style.display = 'none';
|
|
657
|
+
result.style.display = 'block';
|
|
658
|
+
result.textContent = JSON.stringify(data, null, 2);
|
|
659
|
+
} catch (err) {
|
|
660
|
+
// Hide loading and show error
|
|
661
|
+
loading.style.display = 'none';
|
|
662
|
+
error.style.display = 'block';
|
|
663
|
+
error.textContent = 'Error: ' + (err.message || 'Failed to fetch health check data');
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// Close modal when clicking outside
|
|
668
|
+
document.addEventListener('click', function(event) {
|
|
669
|
+
if (event.target.classList.contains('modal-overlay')) {
|
|
670
|
+
const modalId = event.target.id;
|
|
671
|
+
const sectionName = modalId.replace('-modal', '');
|
|
672
|
+
closeModal(sectionName);
|
|
673
|
+
}
|
|
674
|
+
});
|
|
675
|
+
</script>
|
|
676
|
+
</body>
|
|
677
|
+
</html>`;
|
|
678
|
+
};
|
|
679
|
+
//# sourceMappingURL=render.js.map
|