@loop_ouroboros/mcp-hub-lite 1.3.0 → 1.3.2
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/CHANGELOG.md +59 -0
- package/README.md +410 -331
- package/dist/client/assets/{HomeView-Bi2bkUKf.js → HomeView-DplI3V-h.js} +1 -1
- package/dist/client/assets/{ResourceDetailView-DyuSovH9.js → ResourceDetailView-CeHPn99Y.js} +1 -1
- package/dist/client/assets/ResourcesView-C1ObRhYS.js +1 -0
- package/dist/client/assets/{ServerDashboard-BGyyZAti.js → ServerDashboard-D7wG4Gvt.js} +1 -1
- package/dist/client/assets/ServerDetail-G23phOcJ.js +2 -0
- package/dist/client/assets/{ServerListView-yQPVJFHG.js → ServerListView-BFiZLtPO.js} +1 -1
- package/dist/client/assets/{ServerStatusTags.vue_vue_type_script_setup_true_lang-C8gQlxGE.js → ServerStatusTags.vue_vue_type_script_setup_true_lang-Deb_SbFw.js} +1 -1
- package/dist/client/assets/SettingsView-QBFLZ6fP.js +1 -0
- package/dist/client/assets/ToolCallDialog-DYS-ADCL.js +1 -0
- package/dist/client/assets/ToolsView-DYwgtm7W.js +1 -0
- package/dist/client/assets/_baseClone-DQno9YO3.js +1 -0
- package/dist/client/assets/{el-form-item-DfWq_kSy.js → el-form-item-DF0zzQdH.js} +2 -2
- package/dist/client/assets/el-input-C_p2Qw42.js +1 -0
- package/dist/client/assets/el-loading-BaenpNzU.js +1 -0
- package/dist/client/assets/el-overlay-MbIUXSQ7.js +1 -0
- package/dist/client/assets/el-radio-group-COnCjCcz.js +1 -0
- package/dist/client/assets/el-skeleton-item-qj0eQP4s.js +1 -0
- package/dist/client/assets/el-switch-BZbXqB3_.js +1 -0
- package/dist/client/assets/el-tab-pane-w7RltRLd.js +1 -0
- package/dist/client/assets/el-table-column-OD8zhFcD.js +1 -0
- package/dist/client/assets/index-DwhULJXZ.js +2 -0
- package/dist/client/assets/{index-Bzz3tYbS.css → index-UtsV0Cvh.css} +1 -1
- package/dist/client/assets/{omit-BIIebEYo.js → omit-BAJQlviJ.js} +1 -1
- package/dist/client/assets/raf-B1Ry7ruA.js +1 -0
- package/dist/client/assets/{vue-vendor-Dwcr0jep.js → vue-vendor-ClSvefnQ.js} +1 -1
- package/dist/client/index.html +3 -3
- package/dist/server/shared/models/constants.d.ts +5 -0
- package/dist/server/shared/models/constants.d.ts.map +1 -1
- package/dist/server/shared/models/constants.js +4 -0
- package/dist/server/shared/models/server.model.d.ts +14 -0
- package/dist/server/shared/models/server.model.d.ts.map +1 -1
- package/dist/server/shared/models/server.model.js +27 -4
- package/dist/server/src/api/mcp/gateway.d.ts +10 -6
- package/dist/server/src/api/mcp/gateway.d.ts.map +1 -1
- package/dist/server/src/api/mcp/gateway.js +235 -69
- package/dist/server/src/api/web/hub-tools.d.ts.map +1 -1
- package/dist/server/src/api/web/hub-tools.js +2 -2
- package/dist/server/src/api/web/search.d.ts +1 -1
- package/dist/server/src/api/web/search.d.ts.map +1 -1
- package/dist/server/src/api/web/search.js +18 -16
- package/dist/server/src/api/web/sessions.d.ts +1 -27
- package/dist/server/src/api/web/sessions.d.ts.map +1 -1
- package/dist/server/src/api/web/sessions.js +8 -97
- package/dist/server/src/app.d.ts.map +1 -1
- package/dist/server/src/app.js +5 -0
- package/dist/server/src/cli/commands/status.js +39 -1
- package/dist/server/src/cli/commands/use-guide.d.ts +0 -8
- package/dist/server/src/cli/commands/use-guide.d.ts.map +1 -1
- package/dist/server/src/cli/commands/use-guide.js +28 -170
- package/dist/server/src/cli/server.d.ts +10 -0
- package/dist/server/src/cli/server.d.ts.map +1 -1
- package/dist/server/src/cli/server.js +31 -1
- package/dist/server/src/models/system-tools.constants.d.ts +1 -0
- package/dist/server/src/models/system-tools.constants.d.ts.map +1 -1
- package/dist/server/src/server/dev-server.js +2 -0
- package/dist/server/src/server/runner.d.ts.map +1 -1
- package/dist/server/src/server/runner.js +2 -0
- package/dist/server/src/services/connection/connection-manager.d.ts +2 -0
- package/dist/server/src/services/connection/connection-manager.d.ts.map +1 -1
- package/dist/server/src/services/connection/connection-manager.js +14 -7
- package/dist/server/src/services/gateway/gateway.service.d.ts +13 -0
- package/dist/server/src/services/gateway/gateway.service.d.ts.map +1 -1
- package/dist/server/src/services/gateway/gateway.service.js +72 -0
- package/dist/server/src/services/gateway/global-transport.d.ts +20 -10
- package/dist/server/src/services/gateway/global-transport.d.ts.map +1 -1
- package/dist/server/src/services/gateway/global-transport.js +50 -34
- package/dist/server/src/services/gateway/request-handlers/initialize-handler.d.ts.map +1 -1
- package/dist/server/src/services/gateway/request-handlers/initialize-handler.js +22 -6
- package/dist/server/src/services/gateway/request-handlers/resources-handler.d.ts.map +1 -1
- package/dist/server/src/services/gateway/request-handlers/resources-handler.js +5 -1
- package/dist/server/src/services/gateway/request-handlers/system-tools-handler.d.ts.map +1 -1
- package/dist/server/src/services/gateway/request-handlers/system-tools-handler.js +3 -2
- package/dist/server/src/services/gateway/session-manager.d.ts +101 -0
- package/dist/server/src/services/gateway/session-manager.d.ts.map +1 -0
- package/dist/server/src/services/gateway/session-manager.js +256 -0
- package/dist/server/src/services/hub-tools/resource-generator.d.ts +1 -1
- package/dist/server/src/services/hub-tools/resource-generator.d.ts.map +1 -1
- package/dist/server/src/services/hub-tools/resource-generator.js +11 -9
- package/dist/server/src/services/hub-tools/system-tool-definitions.d.ts.map +1 -1
- package/dist/server/src/services/hub-tools/system-tool-definitions.js +7 -0
- package/dist/server/src/services/hub-tools.service.d.ts +1 -1
- package/dist/server/src/services/hub-tools.service.d.ts.map +1 -1
- package/dist/server/src/services/hub-tools.service.js +23 -15
- package/dist/server/src/services/system-tool-handler.js +1 -1
- package/dist/server/src/utils/json-utils.d.ts +9 -0
- package/dist/server/src/utils/json-utils.d.ts.map +1 -1
- package/dist/server/src/utils/json-utils.js +19 -0
- package/dist/server/src/utils/logger/index.d.ts +1 -1
- package/dist/server/src/utils/logger/index.d.ts.map +1 -1
- package/dist/server/src/utils/logger/index.js +1 -1
- package/dist/server/src/utils/logger/log-context.d.ts +1 -0
- package/dist/server/src/utils/logger/log-context.d.ts.map +1 -1
- package/dist/server/src/utils/logger/log-formatter.d.ts.map +1 -1
- package/dist/server/src/utils/logger/log-formatter.js +25 -11
- package/dist/server/src/utils/logger/log-output.d.ts +17 -1
- package/dist/server/src/utils/logger/log-output.d.ts.map +1 -1
- package/dist/server/src/utils/logger/log-output.js +46 -40
- package/dist/server/src/utils/logger/logger.d.ts.map +1 -1
- package/dist/server/src/utils/logger/logger.js +18 -2
- package/dist/server/src/utils/request-context.d.ts +8 -70
- package/dist/server/src/utils/request-context.d.ts.map +1 -1
- package/dist/server/src/utils/request-context.js +11 -70
- package/dist/server/src/utils/search-matcher.d.ts +6 -0
- package/dist/server/src/utils/search-matcher.d.ts.map +1 -0
- package/dist/server/src/utils/search-matcher.js +24 -0
- package/dist/server/tests/unit/config/config.schema.test.js +2 -1
- package/dist/server/tests/unit/server/runner.test.js +14 -7
- package/dist/server/tests/unit/services/gateway-session-mode.test.d.ts +2 -0
- package/dist/server/tests/unit/services/gateway-session-mode.test.d.ts.map +1 -0
- package/dist/server/tests/unit/services/gateway-session-mode.test.js +174 -0
- package/dist/server/tests/unit/services/hub-tools.service.test.js +299 -4
- package/dist/server/tests/unit/utils/config.test.js +14 -7
- package/dist/server/tests/unit/utils/log-output.test.d.ts +2 -0
- package/dist/server/tests/unit/utils/log-output.test.d.ts.map +1 -0
- package/dist/server/tests/unit/utils/log-output.test.js +198 -0
- package/dist/server/vitest.config.d.ts.map +1 -1
- package/dist/server/vitest.config.js +0 -2
- package/package.json +1 -1
- package/dist/client/assets/ResourcesView-CU0VbNy5.js +0 -1
- package/dist/client/assets/ServerDetail-bcQ8BVXR.js +0 -2
- package/dist/client/assets/SettingsView-B1DxbFP3.js +0 -1
- package/dist/client/assets/ToolCallDialog-DEapCO06.js +0 -1
- package/dist/client/assets/ToolsView-DA0u_bCw.js +0 -1
- package/dist/client/assets/_baseClone-B991Lvrt.js +0 -1
- package/dist/client/assets/el-input-5YzZrwir.js +0 -1
- package/dist/client/assets/el-loading-DE3FcxNH.js +0 -1
- package/dist/client/assets/el-overlay-BTeTueuN.js +0 -1
- package/dist/client/assets/el-radio-group-Y1E2bxIW.js +0 -1
- package/dist/client/assets/el-skeleton-item-DhgR50Jx.js +0 -1
- package/dist/client/assets/el-switch-fF--nMSD.js +0 -1
- package/dist/client/assets/el-tab-pane-rvS_KTwP.js +0 -1
- package/dist/client/assets/el-table-column-B1O8mY47.js +0 -1
- package/dist/client/assets/index-DkqV9kH4.js +0 -2
- package/dist/client/assets/raf-Cj-gATZv.js +0 -1
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Manager for stateful Streamable HTTP MCP transport.
|
|
3
|
+
*
|
|
4
|
+
* Each client session owns a StreamableHTTPServerTransport + McpServer pair.
|
|
5
|
+
* Sessions are identified by mcp-session-id header (generated by the SDK).
|
|
6
|
+
* Notifications are broadcast to all active sessions via their McpServer instances.
|
|
7
|
+
*/
|
|
8
|
+
import { logger, LOG_MODULES } from '../../utils/logger/index.js';
|
|
9
|
+
import { getGatewayDebugSetting } from '../../utils/json-utils.js';
|
|
10
|
+
import { configManager } from '../../config/config-manager.js';
|
|
11
|
+
const CLEANUP_INTERVAL_MS = 60 * 1000; // every minute
|
|
12
|
+
const PING_COOLDOWN_MS = 30 * 1000; // min interval between pings
|
|
13
|
+
const PING_TIMEOUT_MS = 10 * 1000; // per-ping timeout
|
|
14
|
+
export class SessionManager {
|
|
15
|
+
sessions = new Map();
|
|
16
|
+
cleanupTimer = null;
|
|
17
|
+
pendingClientMetadata = new WeakMap();
|
|
18
|
+
/**
|
|
19
|
+
* Registers a newly created session.
|
|
20
|
+
*/
|
|
21
|
+
addSession(sessionId, transport, server) {
|
|
22
|
+
const pendingMeta = this.pendingClientMetadata.get(server);
|
|
23
|
+
this.pendingClientMetadata.delete(server);
|
|
24
|
+
this.sessions.set(sessionId, {
|
|
25
|
+
sessionId,
|
|
26
|
+
transport,
|
|
27
|
+
server,
|
|
28
|
+
createdAt: Date.now(),
|
|
29
|
+
lastAccessedAt: Date.now(),
|
|
30
|
+
isClosing: false,
|
|
31
|
+
activeSseCount: 0,
|
|
32
|
+
lastPingedAt: 0,
|
|
33
|
+
pingPending: false,
|
|
34
|
+
clientName: pendingMeta?.clientName,
|
|
35
|
+
clientVersion: pendingMeta?.clientVersion,
|
|
36
|
+
protocolVersion: pendingMeta?.protocolVersion,
|
|
37
|
+
createdByMethod: 'POST',
|
|
38
|
+
lastMethod: 'POST'
|
|
39
|
+
});
|
|
40
|
+
if (getGatewayDebugSetting()) {
|
|
41
|
+
logger.debug(`Session registered: ${sessionId} (total: ${this.sessions.size}, activeSseCount: 0)`, LOG_MODULES.GATEWAY);
|
|
42
|
+
}
|
|
43
|
+
this.ensureCleanupTimer();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Looks up an existing session by ID and updates lastAccessedAt.
|
|
47
|
+
*/
|
|
48
|
+
getSession(sessionId) {
|
|
49
|
+
const session = this.sessions.get(sessionId);
|
|
50
|
+
if (session && !session.isClosing) {
|
|
51
|
+
session.lastAccessedAt = Date.now();
|
|
52
|
+
return session;
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Marks an SSE stream as opened for the given session.
|
|
58
|
+
* Prevents the session from being cleaned up while the stream is active.
|
|
59
|
+
*/
|
|
60
|
+
markSseOpened(sessionId) {
|
|
61
|
+
const session = this.sessions.get(sessionId);
|
|
62
|
+
if (session && !session.isClosing) {
|
|
63
|
+
session.activeSseCount++;
|
|
64
|
+
if (getGatewayDebugSetting()) {
|
|
65
|
+
logger.debug(`Session ${sessionId} SSE opened (activeSseCount: ${session.activeSseCount})`, LOG_MODULES.GATEWAY);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Marks an SSE stream as closed for the given session.
|
|
71
|
+
*/
|
|
72
|
+
markSseClosed(sessionId) {
|
|
73
|
+
const session = this.sessions.get(sessionId);
|
|
74
|
+
if (session) {
|
|
75
|
+
session.activeSseCount = Math.max(0, session.activeSseCount - 1);
|
|
76
|
+
if (getGatewayDebugSetting()) {
|
|
77
|
+
logger.debug(`Session ${sessionId} SSE closed (activeSseCount: ${session.activeSseCount})`, LOG_MODULES.GATEWAY);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Removes a session (called on DELETE or onsessionclosed).
|
|
83
|
+
*/
|
|
84
|
+
removeSession(sessionId) {
|
|
85
|
+
const session = this.sessions.get(sessionId);
|
|
86
|
+
if (!session || session.isClosing)
|
|
87
|
+
return;
|
|
88
|
+
session.isClosing = true;
|
|
89
|
+
try {
|
|
90
|
+
session.transport.close().catch((err) => {
|
|
91
|
+
logger.debug(`Error closing transport for session ${sessionId}: ${err}`, LOG_MODULES.GATEWAY);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// transport may already be closed
|
|
96
|
+
}
|
|
97
|
+
this.sessions.delete(sessionId);
|
|
98
|
+
if (getGatewayDebugSetting()) {
|
|
99
|
+
logger.debug(`Session removed: ${sessionId} (total: ${this.sessions.size}, age: ${Date.now() - session.createdAt}ms, activeSseCount: ${session.activeSseCount})`, LOG_MODULES.GATEWAY);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
pendingBroadcasts = new Map();
|
|
103
|
+
BROADCAST_DEBOUNCE_MS = 3000;
|
|
104
|
+
/**
|
|
105
|
+
* Broadcasts a notification to all active sessions.
|
|
106
|
+
* Debounced: same-type notifications within BROADCAST_DEBOUNCE_MS are coalesced.
|
|
107
|
+
* @param method - 'tools' for sendToolListChanged, 'resources' for sendResourceListChanged
|
|
108
|
+
*/
|
|
109
|
+
broadcastNotification(method) {
|
|
110
|
+
// Skip if a debounce timer for this method type is already pending
|
|
111
|
+
if (this.pendingBroadcasts.has(method))
|
|
112
|
+
return;
|
|
113
|
+
this.pendingBroadcasts.set(method, setTimeout(() => {
|
|
114
|
+
this.pendingBroadcasts.delete(method);
|
|
115
|
+
if (this.sessions.size === 0)
|
|
116
|
+
return;
|
|
117
|
+
for (const [sessionId, state] of this.sessions) {
|
|
118
|
+
if (state.isClosing)
|
|
119
|
+
continue;
|
|
120
|
+
try {
|
|
121
|
+
if (method === 'tools') {
|
|
122
|
+
state.server.sendToolListChanged();
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
state.server.sendResourceListChanged();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
logger.debug(`Failed to broadcast ${method} notification to session ${sessionId}: ${error}`, LOG_MODULES.GATEWAY);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}, this.BROADCAST_DEBOUNCE_MS));
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Removes sessions that have been idle longer than SESSION_TIMEOUT_MS.
|
|
136
|
+
*/
|
|
137
|
+
cleanupStaleSessions() {
|
|
138
|
+
const now = Date.now();
|
|
139
|
+
const staleIds = [];
|
|
140
|
+
let skippedClosing = 0;
|
|
141
|
+
let skippedSse = 0;
|
|
142
|
+
let pingFailed = 0;
|
|
143
|
+
for (const [id, state] of this.sessions) {
|
|
144
|
+
if (state.isClosing) {
|
|
145
|
+
skippedClosing++;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
// Ping from last cycle timed out — session is dead
|
|
149
|
+
if (state.pingPending) {
|
|
150
|
+
state.pingPending = false;
|
|
151
|
+
pingFailed++;
|
|
152
|
+
staleIds.push(id);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (state.activeSseCount > 0) {
|
|
156
|
+
if (now - state.lastPingedAt < PING_COOLDOWN_MS) {
|
|
157
|
+
skippedSse++;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
state.lastPingedAt = now;
|
|
161
|
+
state.pingPending = true;
|
|
162
|
+
// Fire-and-forget concurrent ping with timeout
|
|
163
|
+
const pingWithTimeout = Promise.race([
|
|
164
|
+
state.server.server.ping(),
|
|
165
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Ping timeout')), PING_TIMEOUT_MS))
|
|
166
|
+
]);
|
|
167
|
+
pingWithTimeout.then(() => {
|
|
168
|
+
const s = this.sessions.get(id);
|
|
169
|
+
if (s) {
|
|
170
|
+
s.pingPending = false;
|
|
171
|
+
s.lastAccessedAt = Date.now();
|
|
172
|
+
}
|
|
173
|
+
}, () => {
|
|
174
|
+
// Keep pingPending=true so the next cycle cleans up this dead session
|
|
175
|
+
});
|
|
176
|
+
skippedSse++;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (now - state.lastAccessedAt > configManager.getConfig().security.idleConnectionTimeout) {
|
|
180
|
+
staleIds.push(id);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (getGatewayDebugSetting() && (staleIds.length > 0 || skippedSse > 0 || pingFailed > 0)) {
|
|
184
|
+
logger.debug(`Stale cleanup: total=${this.sessions.size} stale=${staleIds.length} skippedClosing=${skippedClosing} skippedSse=${skippedSse} pingFailed=${pingFailed}`, LOG_MODULES.GATEWAY);
|
|
185
|
+
}
|
|
186
|
+
for (const id of staleIds) {
|
|
187
|
+
logger.info(`Removing stale session: ${id}`, LOG_MODULES.GATEWAY);
|
|
188
|
+
this.removeSession(id);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
ensureCleanupTimer() {
|
|
192
|
+
if (this.cleanupTimer)
|
|
193
|
+
return;
|
|
194
|
+
this.cleanupTimer = setInterval(() => this.cleanupStaleSessions(), CLEANUP_INTERVAL_MS);
|
|
195
|
+
this.cleanupTimer.unref();
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Shuts down all sessions. Called on server shutdown.
|
|
199
|
+
*/
|
|
200
|
+
shutdownAll() {
|
|
201
|
+
if (this.cleanupTimer) {
|
|
202
|
+
clearInterval(this.cleanupTimer);
|
|
203
|
+
this.cleanupTimer = null;
|
|
204
|
+
}
|
|
205
|
+
for (const timer of this.pendingBroadcasts.values()) {
|
|
206
|
+
clearTimeout(timer);
|
|
207
|
+
}
|
|
208
|
+
this.pendingBroadcasts.clear();
|
|
209
|
+
for (const [id] of this.sessions) {
|
|
210
|
+
this.removeSession(id);
|
|
211
|
+
}
|
|
212
|
+
logger.info('All sessions shut down', LOG_MODULES.GATEWAY);
|
|
213
|
+
}
|
|
214
|
+
/** Returns the current session count (for diagnostics). */
|
|
215
|
+
get sessionCount() {
|
|
216
|
+
return this.sessions.size;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Stores client metadata against a McpServer instance so that
|
|
220
|
+
* addSession() can consume it when the session is registered later.
|
|
221
|
+
*/
|
|
222
|
+
storePendingClientMetadata(server, metadata) {
|
|
223
|
+
this.pendingClientMetadata.set(server, metadata);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Returns metadata for all active sessions. Does not expose internal
|
|
227
|
+
* transport or server references.
|
|
228
|
+
*/
|
|
229
|
+
getAllSessions() {
|
|
230
|
+
const result = [];
|
|
231
|
+
for (const state of this.sessions.values()) {
|
|
232
|
+
result.push({
|
|
233
|
+
sessionId: state.sessionId,
|
|
234
|
+
clientName: state.clientName,
|
|
235
|
+
clientVersion: state.clientVersion,
|
|
236
|
+
protocolVersion: state.protocolVersion,
|
|
237
|
+
createdByMethod: state.createdByMethod,
|
|
238
|
+
lastMethod: state.lastMethod,
|
|
239
|
+
createdAt: new Date(state.createdAt).toLocaleString(),
|
|
240
|
+
lastAccessedAt: new Date(state.lastAccessedAt).toLocaleString(),
|
|
241
|
+
isClosing: state.isClosing,
|
|
242
|
+
activeSseCount: state.activeSseCount
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
return result;
|
|
246
|
+
}
|
|
247
|
+
/** Updates the last HTTP method seen for a session. */
|
|
248
|
+
updateSessionMethod(sessionId, method) {
|
|
249
|
+
const session = this.sessions.get(sessionId);
|
|
250
|
+
if (session) {
|
|
251
|
+
session.lastMethod = method;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/** Singleton instance. */
|
|
256
|
+
export const sessionManager = new SessionManager();
|
|
@@ -58,5 +58,5 @@ export declare function generateDynamicResources(): Resource[];
|
|
|
58
58
|
* const tools = await readResource('hub://servers/my-mcp-server/tools');
|
|
59
59
|
* ```
|
|
60
60
|
*/
|
|
61
|
-
export declare function readResource(uri: string): Promise<ServerMetadata | Resource[] | string | unknown>;
|
|
61
|
+
export declare function readResource(uri: string, language?: string): Promise<ServerMetadata | Resource[] | string | unknown>;
|
|
62
62
|
//# sourceMappingURL=resource-generator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource-generator.d.ts","sourceRoot":"","sources":["../../../../../src/services/hub-tools/resource-generator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"resource-generator.d.ts","sourceRoot":"","sources":["../../../../../src/services/hub-tools/resource-generator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAmLlE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,IAAI,QAAQ,EAAE,CAqErD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,GAAG,QAAQ,EAAE,GAAG,MAAM,GAAG,OAAO,CAAC,CAyGzD"}
|
|
@@ -104,27 +104,29 @@ function parseHubUri(uri) {
|
|
|
104
104
|
*/
|
|
105
105
|
const __filename = fileURLToPath(import.meta.url);
|
|
106
106
|
const __dirname = dirname(__filename);
|
|
107
|
-
const
|
|
107
|
+
const USE_GUIDE_PATH_ZH = join(__dirname, 'use-guide-zh.md');
|
|
108
|
+
const USE_GUIDE_PATH_EN = join(__dirname, 'use-guide-en.md');
|
|
108
109
|
/**
|
|
109
110
|
* Loads the use guide content from the Markdown file.
|
|
110
111
|
*
|
|
111
|
-
* @
|
|
112
|
+
* @param language - Language code ('zh' for Chinese, defaults to 'en')
|
|
113
|
+
* @returns Markdown formatted use guide content
|
|
112
114
|
*/
|
|
113
|
-
function loadUseGuideContent() {
|
|
115
|
+
function loadUseGuideContent(language) {
|
|
116
|
+
const path = language === 'zh' ? USE_GUIDE_PATH_ZH : USE_GUIDE_PATH_EN;
|
|
114
117
|
try {
|
|
115
|
-
return fs.readFileSync(
|
|
118
|
+
return fs.readFileSync(path, 'utf-8');
|
|
116
119
|
}
|
|
117
120
|
catch {
|
|
118
|
-
// Fallback in case the file can't be read
|
|
119
121
|
return `# MCP Hub Lite Use Guide
|
|
120
122
|
|
|
121
123
|
## Overview
|
|
122
124
|
|
|
123
125
|
MCP Hub Lite is a lightweight MCP (Model Context Protocol) gateway that acts as a unified interface between AI assistants and multiple backend MCP servers.
|
|
124
126
|
|
|
125
|
-
|
|
127
|
+
Use \`resources/list\` to discover servers, then \`list_tools\` / \`get_tool\` / \`call_tool\` to interact with them.
|
|
126
128
|
|
|
127
|
-
The complete use guide is currently unavailable. Please check the
|
|
129
|
+
The complete use guide is currently unavailable. Please check the documentation for more information.
|
|
128
130
|
`;
|
|
129
131
|
}
|
|
130
132
|
}
|
|
@@ -248,14 +250,14 @@ export function generateDynamicResources() {
|
|
|
248
250
|
* const tools = await readResource('hub://servers/my-mcp-server/tools');
|
|
249
251
|
* ```
|
|
250
252
|
*/
|
|
251
|
-
export async function readResource(uri) {
|
|
253
|
+
export async function readResource(uri, language) {
|
|
252
254
|
// Validate URI format
|
|
253
255
|
if (!uri.startsWith('hub://')) {
|
|
254
256
|
throw new Error(`Invalid Hub resource URI: ${uri}. Must start with 'hub://'`);
|
|
255
257
|
}
|
|
256
258
|
// Check for use-guide resource first
|
|
257
259
|
if (uri === USE_GUIDE_URI) {
|
|
258
|
-
return loadUseGuideContent();
|
|
260
|
+
return loadUseGuideContent(language);
|
|
259
261
|
}
|
|
260
262
|
// Parse URI
|
|
261
263
|
const parsed = parseHubUri(uri);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-tool-definitions.d.ts","sourceRoot":"","sources":["../../../../../src/services/hub-tools/system-tool-definitions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAY/D;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,cAAc,IAAI,oBAAoB,EAAE,
|
|
1
|
+
{"version":3,"file":"system-tool-definitions.d.ts","sourceRoot":"","sources":["../../../../../src/services/hub-tools/system-tool-definitions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAY/D;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,cAAc,IAAI,oBAAoB,EAAE,CA+LvD"}
|
|
@@ -185,6 +185,13 @@ export function getSystemTools() {
|
|
|
185
185
|
query: {
|
|
186
186
|
type: 'string',
|
|
187
187
|
description: 'Search query to match against tool names and descriptions'
|
|
188
|
+
},
|
|
189
|
+
limit: {
|
|
190
|
+
type: 'integer',
|
|
191
|
+
description: 'Maximum number of results to return per server (1-10, default 5)',
|
|
192
|
+
minimum: 1,
|
|
193
|
+
maximum: 10,
|
|
194
|
+
default: 5
|
|
188
195
|
}
|
|
189
196
|
},
|
|
190
197
|
required: ['query']
|
|
@@ -202,7 +202,7 @@ export declare class HubToolsService {
|
|
|
202
202
|
* @returns {Promise<Record<string, { description: string; tools: ToolSummary[] }>>}
|
|
203
203
|
* Object mapping server names to their descriptions and matching tools
|
|
204
204
|
*/
|
|
205
|
-
searchTools(query: string): Promise<Record<string, {
|
|
205
|
+
searchTools(query: string, limit?: number): Promise<Record<string, {
|
|
206
206
|
description: string;
|
|
207
207
|
tools: ToolSummary[];
|
|
208
208
|
}>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hub-tools.service.d.ts","sourceRoot":"","sources":["../../../../src/services/hub-tools.service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hub-tools.service.d.ts","sourceRoot":"","sources":["../../../../src/services/hub-tools.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { hubManager } from './hub-manager.service.js';
|
|
2
2
|
import { mcpConnectionManager } from './connection/index.js';
|
|
3
|
+
import { configManager } from '../config/config-manager.js';
|
|
3
4
|
import { eventBus, EventTypes } from './event-bus.service.js';
|
|
4
5
|
import { generateGatewayToolsList } from './gateway/tool-list-generator.js';
|
|
5
6
|
import { logger, LOG_MODULES } from '../utils/logger/index.js';
|
|
6
7
|
import { stringifyForLogging } from '../utils/json-utils.js';
|
|
7
8
|
import { normalizeToolName } from '../utils/name-converter.js';
|
|
9
|
+
import { countMatchingTokens } from '../utils/search-matcher.js';
|
|
8
10
|
import { McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
9
11
|
import { MCP_HUB_LITE_SERVER, LIST_SERVERS_TOOL, LIST_TOOLS_TOOL, GET_TOOL_TOOL, CALL_TOOL_TOOL, UPDATE_SERVER_DESCRIPTION_TOOL, LIST_TAGS_TOOL, SEARCH_TOOLS_TOOL, SYSTEM_TOOL_NAMES } from '../models/system-tools.constants.js';
|
|
10
12
|
import { ToolArgsParser } from '../utils/tool-args-parser.js';
|
|
@@ -600,11 +602,11 @@ export class HubToolsService {
|
|
|
600
602
|
* @returns {Promise<Record<string, { description: string; tools: ToolSummary[] }>>}
|
|
601
603
|
* Object mapping server names to their descriptions and matching tools
|
|
602
604
|
*/
|
|
603
|
-
async searchTools(query) {
|
|
605
|
+
async searchTools(query, limit = 5) {
|
|
604
606
|
if (!query || typeof query !== 'string') {
|
|
605
607
|
throw new Error('query is required and must be a non-empty string');
|
|
606
608
|
}
|
|
607
|
-
const
|
|
609
|
+
const effectiveLimit = Math.min(Math.max(1, limit), 10);
|
|
608
610
|
const servers = hubManager.getAllServers();
|
|
609
611
|
const result = {};
|
|
610
612
|
for (const server of servers) {
|
|
@@ -620,21 +622,26 @@ export class HubToolsService {
|
|
|
620
622
|
if (tools.length === 0) {
|
|
621
623
|
continue;
|
|
622
624
|
}
|
|
623
|
-
const
|
|
624
|
-
.
|
|
625
|
-
const
|
|
626
|
-
|
|
627
|
-
|
|
625
|
+
const scored = tools
|
|
626
|
+
.map((tool) => {
|
|
627
|
+
const matchCount = countMatchingTokens(query, [tool.name, tool.description || '']);
|
|
628
|
+
return {
|
|
629
|
+
tool,
|
|
630
|
+
matchCount,
|
|
631
|
+
summary: {
|
|
632
|
+
name: tool.name,
|
|
633
|
+
description: tool.description,
|
|
634
|
+
serverName: server.name
|
|
635
|
+
}
|
|
636
|
+
};
|
|
628
637
|
})
|
|
629
|
-
.
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
}));
|
|
634
|
-
if (matchingTools.length > 0) {
|
|
638
|
+
.filter((item) => item.matchCount > 0)
|
|
639
|
+
.sort((a, b) => b.matchCount - a.matchCount)
|
|
640
|
+
.slice(0, effectiveLimit);
|
|
641
|
+
if (scored.length > 0) {
|
|
635
642
|
result[server.name] = {
|
|
636
643
|
description,
|
|
637
|
-
tools:
|
|
644
|
+
tools: scored.map((item) => item.summary)
|
|
638
645
|
};
|
|
639
646
|
}
|
|
640
647
|
}
|
|
@@ -668,7 +675,8 @@ export class HubToolsService {
|
|
|
668
675
|
* @throws {Error} If URI format is invalid, server not found, or resource type unknown
|
|
669
676
|
*/
|
|
670
677
|
async readResource(uri) {
|
|
671
|
-
|
|
678
|
+
const language = configManager.getConfig().system.language;
|
|
679
|
+
return readResourceUtil(uri, language);
|
|
672
680
|
}
|
|
673
681
|
}
|
|
674
682
|
export const hubToolsService = new HubToolsService();
|
|
@@ -63,7 +63,7 @@ export class SystemToolHandler {
|
|
|
63
63
|
if (!searchArgs.query) {
|
|
64
64
|
throw new McpError(-32802, 'query is required for search_tools');
|
|
65
65
|
}
|
|
66
|
-
result = await hubToolsService.searchTools(searchArgs.query);
|
|
66
|
+
result = await hubToolsService.searchTools(searchArgs.query, searchArgs.limit);
|
|
67
67
|
break;
|
|
68
68
|
}
|
|
69
69
|
default:
|
|
@@ -25,6 +25,7 @@ type ConfigGetter = () => {
|
|
|
25
25
|
mcpCommDebug: boolean;
|
|
26
26
|
apiDebug: boolean;
|
|
27
27
|
gatewayDebug: boolean;
|
|
28
|
+
showTraceContext?: boolean;
|
|
28
29
|
};
|
|
29
30
|
};
|
|
30
31
|
};
|
|
@@ -72,6 +73,14 @@ export declare function getApiDebugSetting(): boolean;
|
|
|
72
73
|
* @returns boolean indicating whether to enable Gateway debug logging
|
|
73
74
|
*/
|
|
74
75
|
export declare function getGatewayDebugSetting(): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Get the showTraceContext configuration value.
|
|
78
|
+
* Controls whether [SSN]/[TID]/[SID] trace context markers appear in log output.
|
|
79
|
+
* Defaults to true.
|
|
80
|
+
*
|
|
81
|
+
* @returns boolean indicating whether to show trace context in logs
|
|
82
|
+
*/
|
|
83
|
+
export declare function getShowTraceContextSetting(): boolean;
|
|
75
84
|
/**
|
|
76
85
|
* Stringify object for logging with dynamic pretty formatting based on LOG_JSON_PRETTY environment variable
|
|
77
86
|
* @param obj Object to stringify
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-utils.d.ts","sourceRoot":"","sources":["../../../../src/utils/json-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAExD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAiED;;GAEG;AACH,KAAK,YAAY,GAAG,MAAM;IACxB,MAAM,EAAE;QACN,OAAO,EAAE;YACP,UAAU,EAAE,OAAO,CAAC;YACpB,YAAY,EAAE,OAAO,CAAC;YACtB,QAAQ,EAAE,OAAO,CAAC;YAClB,YAAY,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"json-utils.d.ts","sourceRoot":"","sources":["../../../../src/utils/json-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAExD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAiED;;GAEG;AACH,KAAK,YAAY,GAAG,MAAM;IACxB,MAAM,EAAE;QACN,OAAO,EAAE;YACP,UAAU,EAAE,OAAO,CAAC;YACpB,YAAY,EAAE,OAAO,CAAC;YACtB,QAAQ,EAAE,OAAO,CAAC;YAClB,YAAY,EAAE,OAAO,CAAC;YACtB,gBAAgB,CAAC,EAAE,OAAO,CAAC;SAC5B,CAAC;KACH,CAAC;CACH,CAAC;AAQF;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,GAAG,IAAI,CAE3E;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAU/E;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAG1E;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAiB9C;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAUhD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAU5C;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAUhD;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAUpD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAOxD;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,GAAG,EAAE,OAAO,EACZ,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,GAClD,MAAM,CAOR"}
|
|
@@ -198,6 +198,25 @@ export function getGatewayDebugSetting() {
|
|
|
198
198
|
}
|
|
199
199
|
return getDefaultForDevMode(false);
|
|
200
200
|
}
|
|
201
|
+
/**
|
|
202
|
+
* Get the showTraceContext configuration value.
|
|
203
|
+
* Controls whether [SSN]/[TID]/[SID] trace context markers appear in log output.
|
|
204
|
+
* Defaults to true.
|
|
205
|
+
*
|
|
206
|
+
* @returns boolean indicating whether to show trace context in logs
|
|
207
|
+
*/
|
|
208
|
+
export function getShowTraceContextSetting() {
|
|
209
|
+
if (_configGetter) {
|
|
210
|
+
try {
|
|
211
|
+
const config = _configGetter();
|
|
212
|
+
return config.system.logging.showTraceContext ?? true;
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
// Fall through to default if config getter fails
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return true; // default enabled
|
|
219
|
+
}
|
|
201
220
|
/**
|
|
202
221
|
* Stringify object for logging with dynamic pretty formatting based on LOG_JSON_PRETTY environment variable
|
|
203
222
|
* @param obj Object to stringify
|
|
@@ -7,7 +7,7 @@ export { LOG_MODULES } from './log-modules.js';
|
|
|
7
7
|
export type { LogModuleKey, LogModule } from './log-modules.js';
|
|
8
8
|
export { COLORS, getColorCodeForLevel, getResetColor } from './log-colors.js';
|
|
9
9
|
export { formatTimestamp, formatLogLevel, formatPid, createColoredLogMessage, createLogMessage, formatError } from './log-formatter.js';
|
|
10
|
-
export { isToolsListResponse, simplifyToolsListResponse, hasImageContent, simplifyImageContent, formatMcpMessageForLogging, isNotificationMessage, logNotificationMessage } from './log-output.js';
|
|
10
|
+
export { isToolsListResponse, simplifyToolsListResponse, hasImageContent, simplifyImageContent, hasDataUriImage, simplifyDataUriImages, formatMcpMessageForLogging, isNotificationMessage, logNotificationMessage } from './log-output.js';
|
|
11
11
|
export { Logger } from './logger.js';
|
|
12
12
|
import { Logger } from './logger.js';
|
|
13
13
|
export declare const logger: Logger;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/utils/logger/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG/D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGhE,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAG9E,OAAO,EACL,eAAe,EACf,cAAc,EACd,SAAS,EACT,uBAAuB,EACvB,gBAAgB,EAChB,WAAW,EACZ,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,eAAe,EACf,oBAAoB,EACpB,0BAA0B,EAC1B,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,eAAO,MAAM,MAAM,QAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/utils/logger/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG/D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGhE,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAG9E,OAAO,EACL,eAAe,EACf,cAAc,EACd,SAAS,EACT,uBAAuB,EACvB,gBAAgB,EAChB,WAAW,EACZ,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,eAAO,MAAM,MAAM,QAAe,CAAC"}
|
|
@@ -9,7 +9,7 @@ export { COLORS, getColorCodeForLevel, getResetColor } from './log-colors.js';
|
|
|
9
9
|
// Re-export formatter utilities
|
|
10
10
|
export { formatTimestamp, formatLogLevel, formatPid, createColoredLogMessage, createLogMessage, formatError } from './log-formatter.js';
|
|
11
11
|
// Re-export output utilities
|
|
12
|
-
export { isToolsListResponse, simplifyToolsListResponse, hasImageContent, simplifyImageContent, formatMcpMessageForLogging, isNotificationMessage, logNotificationMessage } from './log-output.js';
|
|
12
|
+
export { isToolsListResponse, simplifyToolsListResponse, hasImageContent, simplifyImageContent, hasDataUriImage, simplifyDataUriImages, formatMcpMessageForLogging, isNotificationMessage, logNotificationMessage } from './log-output.js';
|
|
13
13
|
// Re-export main Logger class
|
|
14
14
|
export { Logger } from './logger.js';
|
|
15
15
|
// Create and export the default logger instance
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-context.d.ts","sourceRoot":"","sources":["../../../../../src/utils/logger/log-context.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,KAAK,GAAG,YAAY,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"log-context.d.ts","sourceRoot":"","sources":["../../../../../src/utils/logger/log-context.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,KAAK,GAAG,YAAY,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-formatter.d.ts","sourceRoot":"","sources":["../../../../../src/utils/logger/log-formatter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAE9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"log-formatter.d.ts","sourceRoot":"","sources":["../../../../../src/utils/logger/log-formatter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAE9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAOnD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAsED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,UAAU,SAAI,GAAG,UAAU,GAAG,IAAI,CAQ/D;AA2HD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAK/D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CASlD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAatD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM7C;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,QAAQ,EACf,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,UAAU,GACnB,MAAM,CA2CR;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,MAAM,CAkC/F;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CA4HlD"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { stringifyForLogging } from '../json-utils.js';
|
|
6
6
|
import { getColorCodeForLevel, getResetColor, COLORS } from './log-colors.js';
|
|
7
|
+
import { getShowTraceContextSetting } from '../json-utils.js';
|
|
7
8
|
// PID formatting configuration
|
|
8
9
|
const PID_WIDTH = 8;
|
|
9
10
|
/**
|
|
@@ -272,11 +273,16 @@ export function createColoredLogMessage(level, message, context) {
|
|
|
272
273
|
const callerColor = COLORS.brightBlue;
|
|
273
274
|
const resetColor = getResetColor();
|
|
274
275
|
let result = `${timestampColor}[${timestamp}]${resetColor} ${levelColor}[${formattedLevel}]${resetColor} ${pidColor}[${formattedPid}]${resetColor}`;
|
|
275
|
-
if (
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
276
|
+
if (getShowTraceContextSetting()) {
|
|
277
|
+
if (context?.sessionId) {
|
|
278
|
+
result += ` ${traceColor}[SSN:${context.sessionId}]${resetColor}`;
|
|
279
|
+
}
|
|
280
|
+
if (context?.traceId) {
|
|
281
|
+
result += ` ${traceColor}[TID:${context.traceId}]${resetColor}`;
|
|
282
|
+
}
|
|
283
|
+
if (context?.spanId) {
|
|
284
|
+
result += ` ${traceColor}[SID:${context.spanId}]${resetColor}`;
|
|
285
|
+
}
|
|
280
286
|
}
|
|
281
287
|
result += ` ${serverColor}[${actualServerName}]${resetColor}`;
|
|
282
288
|
if (context?.module) {
|
|
@@ -302,11 +308,16 @@ export function createLogMessage(level, message, context) {
|
|
|
302
308
|
const pidStr = processPid.toString().padStart(PID_WIDTH, ' ');
|
|
303
309
|
const serverIdentifier = context?.serverName || 'mcp-hub';
|
|
304
310
|
let result = `[${timestamp}] [${formattedLevel}] [PID:${pidStr}]`;
|
|
305
|
-
if (
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
311
|
+
if (getShowTraceContextSetting()) {
|
|
312
|
+
if (context?.sessionId) {
|
|
313
|
+
result += ` [SSN:${context.sessionId}]`;
|
|
314
|
+
}
|
|
315
|
+
if (context?.traceId) {
|
|
316
|
+
result += ` [TID:${context.traceId}]`;
|
|
317
|
+
}
|
|
318
|
+
if (context?.spanId) {
|
|
319
|
+
result += ` [SID:${context.spanId}]`;
|
|
320
|
+
}
|
|
310
321
|
}
|
|
311
322
|
result += ` [${serverIdentifier}]`;
|
|
312
323
|
if (context?.module) {
|
|
@@ -336,7 +347,10 @@ export function formatError(error) {
|
|
|
336
347
|
if (typeof element === 'object' &&
|
|
337
348
|
element !== null &&
|
|
338
349
|
!Array.isArray(element) &&
|
|
339
|
-
('module' in element ||
|
|
350
|
+
('module' in element ||
|
|
351
|
+
'traceId' in element ||
|
|
352
|
+
'spanId' in element ||
|
|
353
|
+
'sessionId' in element)) {
|
|
340
354
|
return '';
|
|
341
355
|
}
|
|
342
356
|
// Otherwise format the single element
|