cprime-supergateway 3.4.4 → 3.4.6
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/dist/gateways/stdioToSse.js +29 -31
- package/dist/services/logService.js +24 -0
- package/package.json +1 -1
- package/src/gateways/stdioToSse.ts +38 -41
- package/src/lib/mcpServerLogRepository.ts +1 -1
- package/src/services/logService.ts +43 -0
- /package/dist/services/{EncryptionService.js → encryptionService.js} +0 -0
|
@@ -10,15 +10,21 @@ import { serializeCorsOrigin } from '../lib/serializeCorsOrigin.js';
|
|
|
10
10
|
import { EncryptionService } from '../services/encryptionService.js';
|
|
11
11
|
import { initMongoClient } from '../lib/initMongoClient.js';
|
|
12
12
|
import { McpServerLogRepository } from '../lib/mcpServerLogRepository.js';
|
|
13
|
+
import { LogService } from '../services/logService.js';
|
|
13
14
|
const encryptionService = new EncryptionService('env');
|
|
14
|
-
const
|
|
15
|
+
const mongoClient = initMongoClient();
|
|
16
|
+
const mcpServerLogRepository = new McpServerLogRepository(mongoClient, process.env.MONGO_DB ?? 'localhost', process.env.LOGS_COLLECTION ?? 'mcp_server_logs');
|
|
17
|
+
const logService = new LogService(mcpServerLogRepository);
|
|
15
18
|
let decryptedEnvs = {};
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
if (process.env.ENCRYPTED_ENV) {
|
|
20
|
+
const plaintext = await encryptionService.decryptText(process.env.ENCRYPTED_ENV, process.env.AAD_JSON ? JSON.parse(process.env.AAD_JSON) : {});
|
|
21
|
+
try {
|
|
22
|
+
const asObj = JSON.parse(plaintext);
|
|
23
|
+
decryptedEnvs = asObj;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
console.error('Failed to parse decrypted envs', plaintext);
|
|
27
|
+
}
|
|
22
28
|
}
|
|
23
29
|
const setResponseHeaders = ({ res, headers, }) => Object.entries(headers).forEach(([key, value]) => {
|
|
24
30
|
res.setHeader(key, value);
|
|
@@ -36,8 +42,6 @@ export async function stdioToSse(args) {
|
|
|
36
42
|
logger.info(` - CORS: ${corsOrigin ? `enabled (${serializeCorsOrigin({ corsOrigin })})` : 'disabled'}`);
|
|
37
43
|
logger.info(` - Health endpoints: ${healthEndpoints.length ? healthEndpoints.join(', ') : '(none)'}`);
|
|
38
44
|
onSignals({ logger });
|
|
39
|
-
const mongoClient = initMongoClient();
|
|
40
|
-
const mcpServerLogRepository = new McpServerLogRepository(mongoClient, process.env.MONGO_DB ?? 'localhost', process.env.LOGS_COLLECTION ?? 'mcp_server_logs');
|
|
41
45
|
const child = spawn(stdioCmd, {
|
|
42
46
|
shell: true,
|
|
43
47
|
env: { ...process.env, ...decryptedEnvs },
|
|
@@ -85,18 +89,9 @@ export async function stdioToSse(args) {
|
|
|
85
89
|
}
|
|
86
90
|
sseTransport.onmessage = (msg) => {
|
|
87
91
|
logger.info(`SSE → Child (session ${sessionId}): ${JSON.stringify(msg)}`);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
ip: req.ip ?? '',
|
|
91
|
-
userId: req.query.userId ?? '',
|
|
92
|
+
logService.log(msg, 'request-rpc', logger, {
|
|
93
|
+
...sessions[sessionId],
|
|
92
94
|
sessionId,
|
|
93
|
-
type: 'rpc',
|
|
94
|
-
data: msg,
|
|
95
|
-
createdAt: new Date(),
|
|
96
|
-
updatedAt: new Date(),
|
|
97
|
-
})
|
|
98
|
-
.catch((err) => {
|
|
99
|
-
logger.error(`Failed to insert log:`, JSON.stringify(err));
|
|
100
95
|
});
|
|
101
96
|
child.stdin.write(JSON.stringify(msg) + '\n');
|
|
102
97
|
};
|
|
@@ -151,18 +146,9 @@ export async function stdioToSse(args) {
|
|
|
151
146
|
for (const [sid, session] of Object.entries(sessions)) {
|
|
152
147
|
try {
|
|
153
148
|
session.transport.send(jsonMsg);
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
ip: session.ip,
|
|
157
|
-
userId: session.userId,
|
|
149
|
+
logService.log(jsonMsg, 'response-rpc', logger, {
|
|
150
|
+
...session,
|
|
158
151
|
sessionId: sid,
|
|
159
|
-
type: 'system',
|
|
160
|
-
data: line,
|
|
161
|
-
createdAt: new Date(),
|
|
162
|
-
updatedAt: new Date(),
|
|
163
|
-
})
|
|
164
|
-
.catch((err) => {
|
|
165
|
-
logger.error(`Failed to insert log:`, JSON.stringify(err));
|
|
166
152
|
});
|
|
167
153
|
}
|
|
168
154
|
catch (err) {
|
|
@@ -173,10 +159,22 @@ export async function stdioToSse(args) {
|
|
|
173
159
|
}
|
|
174
160
|
catch {
|
|
175
161
|
logger.error(`Child non-JSON: ${line}`);
|
|
162
|
+
for (const [sid, session] of Object.entries(sessions)) {
|
|
163
|
+
logService.log(line.toString(), 'system', logger, {
|
|
164
|
+
...session,
|
|
165
|
+
sessionId: sid,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
176
168
|
}
|
|
177
169
|
});
|
|
178
170
|
});
|
|
179
171
|
child.stderr.on('data', (chunk) => {
|
|
180
172
|
logger.error(`Child stderr: ${chunk.toString('utf8')}`);
|
|
173
|
+
for (const [sid, session] of Object.entries(sessions)) {
|
|
174
|
+
logService.log(chunk.toString('utf8'), 'system', logger, {
|
|
175
|
+
...session,
|
|
176
|
+
sessionId: sid,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
181
179
|
});
|
|
182
180
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export class LogService {
|
|
2
|
+
repository;
|
|
3
|
+
constructor(repository) {
|
|
4
|
+
this.repository = repository;
|
|
5
|
+
}
|
|
6
|
+
async log(data, type, logger, session) {
|
|
7
|
+
const logDto = {
|
|
8
|
+
ip: session.ip,
|
|
9
|
+
userId: session.userId,
|
|
10
|
+
sessionId: session.sessionId,
|
|
11
|
+
type: type,
|
|
12
|
+
data: data,
|
|
13
|
+
createdAt: new Date(),
|
|
14
|
+
updatedAt: new Date(),
|
|
15
|
+
};
|
|
16
|
+
// Insert to MongoDB with error handling
|
|
17
|
+
try {
|
|
18
|
+
await this.repository.insert(logDto);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
logger.error(`Failed to insert log:`, JSON.stringify(err));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
package/package.json
CHANGED
|
@@ -12,6 +12,7 @@ import { serializeCorsOrigin } from '../lib/serializeCorsOrigin.js'
|
|
|
12
12
|
import { EncryptionService } from '../services/encryptionService.js'
|
|
13
13
|
import { initMongoClient } from '../lib/initMongoClient.js'
|
|
14
14
|
import { McpServerLogRepository } from '../lib/mcpServerLogRepository.js'
|
|
15
|
+
import { ILogService, LogService } from '../services/logService.js'
|
|
15
16
|
|
|
16
17
|
export interface StdioToSseArgs {
|
|
17
18
|
stdioCmd: string
|
|
@@ -26,16 +27,25 @@ export interface StdioToSseArgs {
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
const encryptionService = new EncryptionService('env')
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
const mongoClient = initMongoClient()
|
|
31
|
+
const mcpServerLogRepository = new McpServerLogRepository(
|
|
32
|
+
mongoClient,
|
|
33
|
+
process.env.MONGO_DB ?? 'localhost',
|
|
34
|
+
process.env.LOGS_COLLECTION ?? 'mcp_server_logs',
|
|
32
35
|
)
|
|
36
|
+
const logService: ILogService = new LogService(mcpServerLogRepository)
|
|
33
37
|
let decryptedEnvs = {}
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
if (process.env.ENCRYPTED_ENV) {
|
|
39
|
+
const plaintext = await encryptionService.decryptText(
|
|
40
|
+
process.env.ENCRYPTED_ENV,
|
|
41
|
+
process.env.AAD_JSON ? JSON.parse(process.env.AAD_JSON) : {},
|
|
42
|
+
)
|
|
43
|
+
try {
|
|
44
|
+
const asObj = JSON.parse(plaintext)
|
|
45
|
+
decryptedEnvs = asObj
|
|
46
|
+
} catch {
|
|
47
|
+
console.error('Failed to parse decrypted envs', plaintext)
|
|
48
|
+
}
|
|
39
49
|
}
|
|
40
50
|
|
|
41
51
|
const setResponseHeaders = ({
|
|
@@ -82,13 +92,6 @@ export async function stdioToSse(args: StdioToSseArgs) {
|
|
|
82
92
|
|
|
83
93
|
onSignals({ logger })
|
|
84
94
|
|
|
85
|
-
const mongoClient = initMongoClient()
|
|
86
|
-
const mcpServerLogRepository = new McpServerLogRepository(
|
|
87
|
-
mongoClient,
|
|
88
|
-
process.env.MONGO_DB ?? 'localhost',
|
|
89
|
-
process.env.LOGS_COLLECTION ?? 'mcp_server_logs',
|
|
90
|
-
)
|
|
91
|
-
|
|
92
95
|
const child: ChildProcessWithoutNullStreams = spawn(stdioCmd, {
|
|
93
96
|
shell: true,
|
|
94
97
|
env: { ...process.env, ...decryptedEnvs },
|
|
@@ -157,19 +160,10 @@ export async function stdioToSse(args: StdioToSseArgs) {
|
|
|
157
160
|
|
|
158
161
|
sseTransport.onmessage = (msg: JSONRPCMessage) => {
|
|
159
162
|
logger.info(`SSE → Child (session ${sessionId}): ${JSON.stringify(msg)}`)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
sessionId,
|
|
165
|
-
type: 'rpc',
|
|
166
|
-
data: msg,
|
|
167
|
-
createdAt: new Date(),
|
|
168
|
-
updatedAt: new Date(),
|
|
169
|
-
})
|
|
170
|
-
.catch((err) => {
|
|
171
|
-
logger.error(`Failed to insert log:`, JSON.stringify(err))
|
|
172
|
-
})
|
|
163
|
+
logService.log(msg, 'request-rpc', logger, {
|
|
164
|
+
...sessions[sessionId],
|
|
165
|
+
sessionId,
|
|
166
|
+
})
|
|
173
167
|
child.stdin.write(JSON.stringify(msg) + '\n')
|
|
174
168
|
}
|
|
175
169
|
|
|
@@ -230,19 +224,10 @@ export async function stdioToSse(args: StdioToSseArgs) {
|
|
|
230
224
|
for (const [sid, session] of Object.entries(sessions)) {
|
|
231
225
|
try {
|
|
232
226
|
session.transport.send(jsonMsg)
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
sessionId: sid,
|
|
238
|
-
type: 'system',
|
|
239
|
-
data: line,
|
|
240
|
-
createdAt: new Date(),
|
|
241
|
-
updatedAt: new Date(),
|
|
242
|
-
})
|
|
243
|
-
.catch((err) => {
|
|
244
|
-
logger.error(`Failed to insert log:`, JSON.stringify(err))
|
|
245
|
-
})
|
|
227
|
+
logService.log(jsonMsg, 'response-rpc', logger, {
|
|
228
|
+
...session,
|
|
229
|
+
sessionId: sid,
|
|
230
|
+
})
|
|
246
231
|
} catch (err) {
|
|
247
232
|
logger.error(`Failed to send to session ${sid}:`, err)
|
|
248
233
|
delete sessions[sid]
|
|
@@ -250,11 +235,23 @@ export async function stdioToSse(args: StdioToSseArgs) {
|
|
|
250
235
|
}
|
|
251
236
|
} catch {
|
|
252
237
|
logger.error(`Child non-JSON: ${line}`)
|
|
238
|
+
for (const [sid, session] of Object.entries(sessions)) {
|
|
239
|
+
logService.log(line.toString(), 'system', logger, {
|
|
240
|
+
...session,
|
|
241
|
+
sessionId: sid,
|
|
242
|
+
})
|
|
243
|
+
}
|
|
253
244
|
}
|
|
254
245
|
})
|
|
255
246
|
})
|
|
256
247
|
|
|
257
248
|
child.stderr.on('data', (chunk: Buffer) => {
|
|
258
249
|
logger.error(`Child stderr: ${chunk.toString('utf8')}`)
|
|
250
|
+
for (const [sid, session] of Object.entries(sessions)) {
|
|
251
|
+
logService.log(chunk.toString('utf8'), 'system', logger, {
|
|
252
|
+
...session,
|
|
253
|
+
sessionId: sid,
|
|
254
|
+
})
|
|
255
|
+
}
|
|
259
256
|
})
|
|
260
257
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Logger } from '../types.js'
|
|
2
|
+
import {
|
|
3
|
+
McpServerLogRepository,
|
|
4
|
+
type McpServerLogDto,
|
|
5
|
+
} from '../lib/mcpServerLogRepository.js'
|
|
6
|
+
import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js'
|
|
7
|
+
|
|
8
|
+
export interface ILogService {
|
|
9
|
+
log(
|
|
10
|
+
data: string | object,
|
|
11
|
+
type: string,
|
|
12
|
+
logger: Logger,
|
|
13
|
+
session: { ip: string; userId: string; sessionId: string },
|
|
14
|
+
): Promise<void>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class LogService implements ILogService {
|
|
18
|
+
constructor(private readonly repository: McpServerLogRepository) {}
|
|
19
|
+
|
|
20
|
+
async log(
|
|
21
|
+
data: string | object,
|
|
22
|
+
type: string,
|
|
23
|
+
logger: Logger,
|
|
24
|
+
session: { ip: string; userId: string; sessionId: string },
|
|
25
|
+
): Promise<void> {
|
|
26
|
+
const logDto: McpServerLogDto = {
|
|
27
|
+
ip: session.ip,
|
|
28
|
+
userId: session.userId,
|
|
29
|
+
sessionId: session.sessionId,
|
|
30
|
+
type: type as McpServerLogDto['type'],
|
|
31
|
+
data: data as JSONRPCMessage | string,
|
|
32
|
+
createdAt: new Date(),
|
|
33
|
+
updatedAt: new Date(),
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Insert to MongoDB with error handling
|
|
37
|
+
try {
|
|
38
|
+
await this.repository.insert(logDto)
|
|
39
|
+
} catch (err) {
|
|
40
|
+
logger.error(`Failed to insert log:`, JSON.stringify(err))
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
File without changes
|