remnote-mcp-server 0.1.3 → 0.3.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.
- package/CHANGELOG.md +78 -0
- package/README.md +226 -224
- package/dist/cli.d.ts +14 -0
- package/dist/cli.js +51 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.js +41 -0
- package/dist/config.js.map +1 -0
- package/dist/http-server.d.ts +23 -0
- package/dist/http-server.js +197 -0
- package/dist/http-server.js.map +1 -0
- package/dist/index.js +48 -25
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +20 -0
- package/dist/logger.js +85 -0
- package/dist/logger.js.map +1 -0
- package/dist/tools/index.d.ts +2 -1
- package/dist/tools/index.js +48 -50
- package/dist/tools/index.js.map +1 -1
- package/dist/websocket-server.d.ts +5 -1
- package/dist/websocket-server.js +53 -10
- package/dist/websocket-server.js.map +1 -1
- package/package.json +6 -1
package/dist/cli.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { createRequire } from 'module';
|
|
3
|
+
const require = createRequire(import.meta.url);
|
|
4
|
+
const packageJson = require('../package.json');
|
|
5
|
+
const validLogLevels = ['debug', 'info', 'warn', 'error'];
|
|
6
|
+
/**
|
|
7
|
+
* Parse CLI arguments and return typed options
|
|
8
|
+
*/
|
|
9
|
+
export function parseCliArgs() {
|
|
10
|
+
const program = new Command();
|
|
11
|
+
program
|
|
12
|
+
.name('remnote-mcp-server')
|
|
13
|
+
.description('MCP server bridge for RemNote knowledge base')
|
|
14
|
+
.version(packageJson.version)
|
|
15
|
+
.option('--ws-port <number>', 'WebSocket port (default: 3002, env: REMNOTE_WS_PORT)', parsePort)
|
|
16
|
+
.option('--http-port <number>', 'HTTP MCP port (default: 3001, env: REMNOTE_HTTP_PORT)', parsePort)
|
|
17
|
+
.option('--log-level <level>', `Console log level: ${validLogLevels.join(', ')} (default: info)`, validateLogLevel)
|
|
18
|
+
.option('--log-level-file <level>', `File log level (default: same as --log-level)`, validateLogLevel)
|
|
19
|
+
.option('--verbose', 'Shorthand for --log-level debug')
|
|
20
|
+
.option('--log-file <path>', 'Log to file (default: console only)')
|
|
21
|
+
.option('--request-log <path>', 'Log all WebSocket requests to file (JSON Lines)')
|
|
22
|
+
.option('--response-log <path>', 'Log all WebSocket responses to file (JSON Lines)');
|
|
23
|
+
program.parse();
|
|
24
|
+
const options = program.opts();
|
|
25
|
+
// Validate port conflicts
|
|
26
|
+
if (options.wsPort && options.httpPort && options.wsPort === options.httpPort) {
|
|
27
|
+
console.error('Error: WebSocket port and HTTP port cannot be the same');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
return options;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Parse and validate port number
|
|
34
|
+
*/
|
|
35
|
+
function parsePort(value) {
|
|
36
|
+
const port = parseInt(value, 10);
|
|
37
|
+
if (isNaN(port) || port < 1 || port > 65535) {
|
|
38
|
+
throw new Error(`Invalid port number: ${value}. Must be between 1 and 65535.`);
|
|
39
|
+
}
|
|
40
|
+
return port;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Validate log level string
|
|
44
|
+
*/
|
|
45
|
+
function validateLogLevel(value) {
|
|
46
|
+
if (!validLogLevels.includes(value.toLowerCase())) {
|
|
47
|
+
throw new Error(`Invalid log level: ${value}. Valid levels: ${validLogLevels.join(', ')}`);
|
|
48
|
+
}
|
|
49
|
+
return value.toLowerCase();
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAEvC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAa/C,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAE1D;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,oBAAoB,CAAC;SAC1B,WAAW,CAAC,8CAA8C,CAAC;SAC3D,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;SAC5B,MAAM,CAAC,oBAAoB,EAAE,sDAAsD,EAAE,SAAS,CAAC;SAC/F,MAAM,CACL,sBAAsB,EACtB,uDAAuD,EACvD,SAAS,CACV;SACA,MAAM,CACL,qBAAqB,EACrB,sBAAsB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,EACjE,gBAAgB,CACjB;SACA,MAAM,CACL,0BAA0B,EAC1B,+CAA+C,EAC/C,gBAAgB,CACjB;SACA,MAAM,CAAC,WAAW,EAAE,iCAAiC,CAAC;SACtD,MAAM,CAAC,mBAAmB,EAAE,qCAAqC,CAAC;SAClE,MAAM,CAAC,sBAAsB,EAAE,iDAAiD,CAAC;SACjF,MAAM,CAAC,uBAAuB,EAAE,kDAAkD,CAAC,CAAC;IAEvF,OAAO,CAAC,KAAK,EAAE,CAAC;IAEhB,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;IAE3C,0BAA0B;IAC1B,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC;QAC9E,OAAO,CAAC,KAAK,CAAC,wDAAwD,CAAC,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAAC,KAAa;IAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,wBAAwB,KAAK,gCAAgC,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CAAC,KAAa;IACrC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,sBAAsB,KAAK,mBAAmB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7F,CAAC;IACD,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC;AAC7B,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CliOptions } from './cli.js';
|
|
2
|
+
export interface ServerConfig {
|
|
3
|
+
wsPort: number;
|
|
4
|
+
httpPort: number;
|
|
5
|
+
logLevel: string;
|
|
6
|
+
logLevelFile?: string;
|
|
7
|
+
logFile?: string;
|
|
8
|
+
requestLog?: string;
|
|
9
|
+
responseLog?: string;
|
|
10
|
+
prettyLogs: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Merge CLI options with environment variables and apply defaults
|
|
14
|
+
* Precedence: CLI > Environment Variables > Defaults
|
|
15
|
+
*/
|
|
16
|
+
export declare function getConfig(cliOptions: CliOptions): ServerConfig;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge CLI options with environment variables and apply defaults
|
|
3
|
+
* Precedence: CLI > Environment Variables > Defaults
|
|
4
|
+
*/
|
|
5
|
+
export function getConfig(cliOptions) {
|
|
6
|
+
// Apply verbose flag override
|
|
7
|
+
let logLevel = cliOptions.logLevel || 'info';
|
|
8
|
+
if (cliOptions.verbose) {
|
|
9
|
+
logLevel = 'debug';
|
|
10
|
+
}
|
|
11
|
+
// Validate CLI port ranges before merging
|
|
12
|
+
if (cliOptions.wsPort !== undefined && (cliOptions.wsPort < 1 || cliOptions.wsPort > 65535)) {
|
|
13
|
+
throw new Error(`Invalid WebSocket port: ${cliOptions.wsPort}. Must be between 1 and 65535.`);
|
|
14
|
+
}
|
|
15
|
+
if (cliOptions.httpPort !== undefined &&
|
|
16
|
+
(cliOptions.httpPort < 1 || cliOptions.httpPort > 65535)) {
|
|
17
|
+
throw new Error(`Invalid HTTP port: ${cliOptions.httpPort}. Must be between 1 and 65535.`);
|
|
18
|
+
}
|
|
19
|
+
// Get ports with CLI > env > default precedence
|
|
20
|
+
const wsPort = cliOptions.wsPort || parseInt(process.env.REMNOTE_WS_PORT || '3002', 10);
|
|
21
|
+
const httpPort = cliOptions.httpPort || parseInt(process.env.REMNOTE_HTTP_PORT || '3001', 10);
|
|
22
|
+
// Validate port conflicts
|
|
23
|
+
if (wsPort === httpPort) {
|
|
24
|
+
throw new Error(`WebSocket port and HTTP port cannot be the same (both set to ${wsPort})`);
|
|
25
|
+
}
|
|
26
|
+
// File log level defaults to console log level if not specified
|
|
27
|
+
const logLevelFile = cliOptions.logLevelFile || (cliOptions.logFile ? logLevel : undefined);
|
|
28
|
+
// Pretty logs in development (when using pino-pretty)
|
|
29
|
+
const prettyLogs = process.stdout.isTTY === true;
|
|
30
|
+
return {
|
|
31
|
+
wsPort,
|
|
32
|
+
httpPort,
|
|
33
|
+
logLevel,
|
|
34
|
+
logLevelFile,
|
|
35
|
+
logFile: cliOptions.logFile,
|
|
36
|
+
requestLog: cliOptions.requestLog,
|
|
37
|
+
responseLog: cliOptions.responseLog,
|
|
38
|
+
prettyLogs,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAaA;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,UAAsB;IAC9C,8BAA8B;IAC9B,IAAI,QAAQ,GAAG,UAAU,CAAC,QAAQ,IAAI,MAAM,CAAC;IAC7C,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;QACvB,QAAQ,GAAG,OAAO,CAAC;IACrB,CAAC;IAED,0CAA0C;IAC1C,IAAI,UAAU,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,KAAK,CAAC,EAAE,CAAC;QAC5F,MAAM,IAAI,KAAK,CAAC,2BAA2B,UAAU,CAAC,MAAM,gCAAgC,CAAC,CAAC;IAChG,CAAC;IACD,IACE,UAAU,CAAC,QAAQ,KAAK,SAAS;QACjC,CAAC,UAAU,CAAC,QAAQ,GAAG,CAAC,IAAI,UAAU,CAAC,QAAQ,GAAG,KAAK,CAAC,EACxD,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,sBAAsB,UAAU,CAAC,QAAQ,gCAAgC,CAAC,CAAC;IAC7F,CAAC;IAED,gDAAgD;IAChD,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,IAAI,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;IACxF,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,IAAI,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;IAE9F,0BAA0B;IAC1B,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,gEAAgE,MAAM,GAAG,CAAC,CAAC;IAC7F,CAAC;IAED,gEAAgE;IAChE,MAAM,YAAY,GAAG,UAAU,CAAC,YAAY,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAE5F,sDAAsD;IACtD,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC;IAEjD,OAAO;QACL,MAAM;QACN,QAAQ;QACR,QAAQ;QACR,YAAY;QACZ,OAAO,EAAE,UAAU,CAAC,OAAO;QAC3B,UAAU,EAAE,UAAU,CAAC,UAAU;QACjC,WAAW,EAAE,UAAU,CAAC,WAAW;QACnC,UAAU;KACX,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { WebSocketServer } from './websocket-server.js';
|
|
2
|
+
import type { Logger } from './logger.js';
|
|
3
|
+
interface ServerInfo {
|
|
4
|
+
name: string;
|
|
5
|
+
version: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class HttpMcpServer {
|
|
8
|
+
private app;
|
|
9
|
+
private server;
|
|
10
|
+
private port;
|
|
11
|
+
private wsServer;
|
|
12
|
+
private serverInfo;
|
|
13
|
+
private logger;
|
|
14
|
+
private transports;
|
|
15
|
+
constructor(port: number, wsServer: WebSocketServer, serverInfo: ServerInfo, logger: Logger);
|
|
16
|
+
private setupRoutes;
|
|
17
|
+
private initializeNewSession;
|
|
18
|
+
private handleSessionRequest;
|
|
19
|
+
start(): Promise<void>;
|
|
20
|
+
stop(): Promise<void>;
|
|
21
|
+
getActiveSessionCount(): number;
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
3
|
+
import express from 'express';
|
|
4
|
+
import { randomUUID } from 'crypto';
|
|
5
|
+
import { registerAllTools } from './tools/index.js';
|
|
6
|
+
export class HttpMcpServer {
|
|
7
|
+
app;
|
|
8
|
+
server = null;
|
|
9
|
+
port;
|
|
10
|
+
wsServer;
|
|
11
|
+
serverInfo;
|
|
12
|
+
logger;
|
|
13
|
+
transports = new Map();
|
|
14
|
+
constructor(port, wsServer, serverInfo, logger) {
|
|
15
|
+
this.port = port;
|
|
16
|
+
this.wsServer = wsServer;
|
|
17
|
+
this.serverInfo = serverInfo;
|
|
18
|
+
this.logger = logger.child({ context: 'http-server' });
|
|
19
|
+
// Create Express app with JSON parsing
|
|
20
|
+
this.app = express();
|
|
21
|
+
this.app.use(express.json());
|
|
22
|
+
// Route handlers
|
|
23
|
+
this.setupRoutes();
|
|
24
|
+
}
|
|
25
|
+
setupRoutes() {
|
|
26
|
+
// POST: Handle session initialization and requests
|
|
27
|
+
this.app.post('/mcp', async (req, res) => {
|
|
28
|
+
try {
|
|
29
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
30
|
+
const body = req.body;
|
|
31
|
+
// Check if this is an initialize request
|
|
32
|
+
const isInitializeRequest = body && body.method === 'initialize' && body.jsonrpc === '2.0';
|
|
33
|
+
this.logger.debug({
|
|
34
|
+
sessionId: sessionId || 'none',
|
|
35
|
+
method: body?.method || 'unknown',
|
|
36
|
+
}, 'POST request received');
|
|
37
|
+
if (!sessionId && isInitializeRequest) {
|
|
38
|
+
// New session initialization
|
|
39
|
+
await this.initializeNewSession(req, res, body);
|
|
40
|
+
}
|
|
41
|
+
else if (sessionId) {
|
|
42
|
+
// Existing session request
|
|
43
|
+
await this.handleSessionRequest(sessionId, req, res, body);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// Missing session ID for non-initialize request
|
|
47
|
+
res.status(400).json({
|
|
48
|
+
jsonrpc: '2.0',
|
|
49
|
+
error: {
|
|
50
|
+
code: -32600,
|
|
51
|
+
message: 'Missing mcp-session-id header for non-initialize request',
|
|
52
|
+
},
|
|
53
|
+
id: body?.id ?? null,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
this.logger.error({
|
|
59
|
+
error,
|
|
60
|
+
sessionId: req.headers['mcp-session-id'],
|
|
61
|
+
}, 'Error handling POST request');
|
|
62
|
+
res.status(500).json({
|
|
63
|
+
jsonrpc: '2.0',
|
|
64
|
+
error: {
|
|
65
|
+
code: -32603,
|
|
66
|
+
message: error instanceof Error ? error.message : String(error),
|
|
67
|
+
},
|
|
68
|
+
id: null,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
// GET: SSE stream for session notifications
|
|
73
|
+
this.app.get('/mcp', async (req, res) => {
|
|
74
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
75
|
+
this.logger.debug({ sessionId: sessionId || 'none' }, 'SSE stream opened');
|
|
76
|
+
if (!sessionId) {
|
|
77
|
+
res.status(400).json({ error: 'Missing mcp-session-id header' });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const transport = this.transports.get(sessionId);
|
|
81
|
+
if (!transport) {
|
|
82
|
+
res.status(404).json({ error: `Session not found: ${sessionId}` });
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// Let transport handle SSE stream setup
|
|
86
|
+
await transport.handleRequest(req, res);
|
|
87
|
+
});
|
|
88
|
+
// DELETE: Terminate session
|
|
89
|
+
this.app.delete('/mcp', async (req, res) => {
|
|
90
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
91
|
+
this.logger.debug({ sessionId: sessionId || 'none' }, 'Session termination requested');
|
|
92
|
+
if (!sessionId) {
|
|
93
|
+
res.status(400).json({ error: 'Missing mcp-session-id header' });
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const transport = this.transports.get(sessionId);
|
|
97
|
+
if (!transport) {
|
|
98
|
+
res.status(404).json({ error: `Session not found: ${sessionId}` });
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
// Let transport handle session termination
|
|
102
|
+
await transport.handleRequest(req, res);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
async initializeNewSession(req, res, body) {
|
|
106
|
+
// Create new transport with session ID generator
|
|
107
|
+
const transport = new StreamableHTTPServerTransport({
|
|
108
|
+
sessionIdGenerator: () => randomUUID(),
|
|
109
|
+
onsessioninitialized: (sessionId) => {
|
|
110
|
+
this.transports.set(sessionId, transport);
|
|
111
|
+
this.logger.info({ sessionId }, 'New MCP session initialized');
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
// Set up onclose handler to clean up transport when closed
|
|
115
|
+
transport.onclose = () => {
|
|
116
|
+
const sessionId = transport.sessionId;
|
|
117
|
+
if (sessionId && this.transports.has(sessionId)) {
|
|
118
|
+
this.logger.info({ sessionId }, 'MCP session closed');
|
|
119
|
+
this.transports.delete(sessionId);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
// Create new MCP server instance for this session
|
|
123
|
+
const server = new Server(this.serverInfo, {
|
|
124
|
+
capabilities: {
|
|
125
|
+
tools: {},
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
// Register all tools with the shared WebSocket server
|
|
129
|
+
registerAllTools(server, this.wsServer, this.logger);
|
|
130
|
+
// Connect server to transport
|
|
131
|
+
await server.connect(transport);
|
|
132
|
+
// Handle the initialize request
|
|
133
|
+
await transport.handleRequest(req, res, body);
|
|
134
|
+
}
|
|
135
|
+
async handleSessionRequest(sessionId, req, res, body) {
|
|
136
|
+
const transport = this.transports.get(sessionId);
|
|
137
|
+
if (!transport) {
|
|
138
|
+
res.status(400).json({
|
|
139
|
+
jsonrpc: '2.0',
|
|
140
|
+
error: {
|
|
141
|
+
code: -32600,
|
|
142
|
+
message: `Invalid session ID: ${sessionId}`,
|
|
143
|
+
},
|
|
144
|
+
id: body?.id ?? null,
|
|
145
|
+
});
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
await transport.handleRequest(req, res, body);
|
|
149
|
+
}
|
|
150
|
+
async start() {
|
|
151
|
+
return new Promise((resolve, reject) => {
|
|
152
|
+
try {
|
|
153
|
+
this.server = this.app.listen(this.port, () => {
|
|
154
|
+
this.logger.info({ port: this.port }, 'HTTP server started');
|
|
155
|
+
resolve();
|
|
156
|
+
});
|
|
157
|
+
this.server.on('error', (error) => {
|
|
158
|
+
this.logger.error({ error }, 'HTTP server error');
|
|
159
|
+
reject(error);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
reject(error);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
async stop() {
|
|
168
|
+
// Close all active transports
|
|
169
|
+
for (const [sessionId, transport] of this.transports.entries()) {
|
|
170
|
+
try {
|
|
171
|
+
this.logger.debug({ sessionId }, 'Closing MCP session');
|
|
172
|
+
await transport.close();
|
|
173
|
+
this.transports.delete(sessionId);
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
this.logger.error({ sessionId, error }, 'Error closing session');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Close HTTP server
|
|
180
|
+
return new Promise((resolve) => {
|
|
181
|
+
if (this.server) {
|
|
182
|
+
this.server.close(() => {
|
|
183
|
+
this.logger.info('HTTP server stopped');
|
|
184
|
+
this.server = null;
|
|
185
|
+
resolve();
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
resolve();
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
getActiveSessionCount() {
|
|
194
|
+
return this.transports.size;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=http-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,51 +1,74 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
2
|
import { createRequire } from 'module';
|
|
5
3
|
import { WebSocketServer } from './websocket-server.js';
|
|
6
|
-
import {
|
|
4
|
+
import { HttpMcpServer } from './http-server.js';
|
|
5
|
+
import { parseCliArgs } from './cli.js';
|
|
6
|
+
import { getConfig } from './config.js';
|
|
7
|
+
import { createLogger, ensureLogDirectory, createRequestResponseLogger } from './logger.js';
|
|
7
8
|
const require = createRequire(import.meta.url);
|
|
8
9
|
const packageJson = require('../package.json');
|
|
9
|
-
const WS_PORT = parseInt(process.env.REMNOTE_WS_PORT || '3002', 10);
|
|
10
10
|
async function main() {
|
|
11
|
-
//
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
// Parse CLI arguments and merge with environment variables
|
|
12
|
+
const cliOptions = parseCliArgs();
|
|
13
|
+
const config = getConfig(cliOptions);
|
|
14
|
+
// Ensure log directories exist
|
|
15
|
+
if (config.logFile) {
|
|
16
|
+
await ensureLogDirectory(config.logFile);
|
|
17
|
+
}
|
|
18
|
+
if (config.requestLog) {
|
|
19
|
+
await ensureLogDirectory(config.requestLog);
|
|
20
|
+
}
|
|
21
|
+
if (config.responseLog) {
|
|
22
|
+
await ensureLogDirectory(config.responseLog);
|
|
23
|
+
}
|
|
24
|
+
// Create logger
|
|
25
|
+
const logger = createLogger({
|
|
26
|
+
consoleLevel: config.logLevel,
|
|
27
|
+
fileLevel: config.logLevelFile,
|
|
28
|
+
filePath: config.logFile,
|
|
29
|
+
pretty: config.prettyLogs,
|
|
19
30
|
});
|
|
31
|
+
// Create request/response loggers if configured
|
|
32
|
+
const requestLogger = config.requestLog
|
|
33
|
+
? createRequestResponseLogger(config.requestLog)
|
|
34
|
+
: undefined;
|
|
35
|
+
const responseLogger = config.responseLog
|
|
36
|
+
? createRequestResponseLogger(config.responseLog)
|
|
37
|
+
: undefined;
|
|
20
38
|
// Initialize WebSocket server for RemNote plugin
|
|
21
|
-
const wsServer = new WebSocketServer(
|
|
22
|
-
// Log connection status
|
|
39
|
+
const wsServer = new WebSocketServer(config.wsPort, logger, requestLogger, responseLogger);
|
|
40
|
+
// Log connection status
|
|
23
41
|
wsServer.onClientConnect(() => {
|
|
24
|
-
|
|
42
|
+
logger.info('RemNote plugin connected');
|
|
25
43
|
});
|
|
26
44
|
wsServer.onClientDisconnect(() => {
|
|
27
|
-
|
|
45
|
+
logger.info('RemNote plugin disconnected');
|
|
28
46
|
});
|
|
29
47
|
// Start WebSocket server
|
|
30
48
|
await wsServer.start();
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
await
|
|
37
|
-
|
|
49
|
+
// Initialize HTTP MCP server
|
|
50
|
+
const httpServer = new HttpMcpServer(config.httpPort, wsServer, {
|
|
51
|
+
name: 'remnote-mcp-server',
|
|
52
|
+
version: packageJson.version,
|
|
53
|
+
}, logger);
|
|
54
|
+
await httpServer.start();
|
|
55
|
+
// Log startup message
|
|
56
|
+
logger.info({
|
|
57
|
+
wsPort: config.wsPort,
|
|
58
|
+
httpPort: config.httpPort,
|
|
59
|
+
}, `RemNote MCP Server v${packageJson.version} listening`);
|
|
38
60
|
// Graceful shutdown
|
|
39
61
|
const shutdown = async () => {
|
|
40
|
-
|
|
62
|
+
logger.info('Shutting down');
|
|
63
|
+
await httpServer.stop();
|
|
41
64
|
await wsServer.stop();
|
|
42
|
-
await mcpServer.close();
|
|
43
65
|
process.exit(0);
|
|
44
66
|
};
|
|
45
67
|
process.on('SIGINT', shutdown);
|
|
46
68
|
process.on('SIGTERM', shutdown);
|
|
47
69
|
}
|
|
48
70
|
main().catch((error) => {
|
|
71
|
+
// Pre-logger error handling
|
|
49
72
|
console.error('[MCP Server] Fatal error:', error);
|
|
50
73
|
process.exit(1);
|
|
51
74
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
export type { Logger } from 'pino';
|
|
3
|
+
export interface LoggerConfig {
|
|
4
|
+
consoleLevel: string;
|
|
5
|
+
fileLevel?: string;
|
|
6
|
+
filePath?: string;
|
|
7
|
+
pretty?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Create a Pino logger with the specified configuration
|
|
11
|
+
*/
|
|
12
|
+
export declare function createLogger(config: LoggerConfig): pino.Logger;
|
|
13
|
+
/**
|
|
14
|
+
* Create a logger for request/response logging (JSON Lines format)
|
|
15
|
+
*/
|
|
16
|
+
export declare function createRequestResponseLogger(filePath: string): pino.Logger;
|
|
17
|
+
/**
|
|
18
|
+
* Ensure directory exists for log file
|
|
19
|
+
*/
|
|
20
|
+
export declare function ensureLogDirectory(filePath: string): Promise<void>;
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
import { mkdir } from 'fs/promises';
|
|
3
|
+
import { dirname } from 'path';
|
|
4
|
+
/**
|
|
5
|
+
* Create a Pino logger with the specified configuration
|
|
6
|
+
*/
|
|
7
|
+
export function createLogger(config) {
|
|
8
|
+
const targets = [];
|
|
9
|
+
// Console transport
|
|
10
|
+
if (config.pretty) {
|
|
11
|
+
targets.push({
|
|
12
|
+
level: config.consoleLevel,
|
|
13
|
+
target: 'pino-pretty',
|
|
14
|
+
options: {
|
|
15
|
+
colorize: true,
|
|
16
|
+
translateTime: 'HH:MM:ss.l',
|
|
17
|
+
ignore: 'pid,hostname',
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
targets.push({
|
|
23
|
+
level: config.consoleLevel,
|
|
24
|
+
target: 'pino/file',
|
|
25
|
+
options: { destination: 2 }, // stderr
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
// File transport (if configured)
|
|
29
|
+
if (config.filePath && config.fileLevel) {
|
|
30
|
+
targets.push({
|
|
31
|
+
level: config.fileLevel,
|
|
32
|
+
target: 'pino/file',
|
|
33
|
+
options: { destination: config.filePath },
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return pino({
|
|
37
|
+
level: getMinLevel(config.consoleLevel, config.fileLevel),
|
|
38
|
+
transport: {
|
|
39
|
+
targets,
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Create a logger for request/response logging (JSON Lines format)
|
|
45
|
+
*/
|
|
46
|
+
export function createRequestResponseLogger(filePath) {
|
|
47
|
+
return pino({
|
|
48
|
+
level: 'info',
|
|
49
|
+
timestamp: pino.stdTimeFunctions.isoTime,
|
|
50
|
+
}, pino.destination(filePath));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Ensure directory exists for log file
|
|
54
|
+
*/
|
|
55
|
+
export async function ensureLogDirectory(filePath) {
|
|
56
|
+
try {
|
|
57
|
+
const dir = dirname(filePath);
|
|
58
|
+
await mkdir(dir, { recursive: true });
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
throw new Error(`Failed to create log directory for ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get minimum log level between console and file
|
|
66
|
+
*/
|
|
67
|
+
function getMinLevel(consoleLevel, fileLevel) {
|
|
68
|
+
const levels = {
|
|
69
|
+
debug: 20,
|
|
70
|
+
info: 30,
|
|
71
|
+
warn: 40,
|
|
72
|
+
error: 50,
|
|
73
|
+
};
|
|
74
|
+
const consoleLevelNum = levels[consoleLevel] || 30;
|
|
75
|
+
const fileLevelNum = fileLevel ? levels[fileLevel] || 30 : Infinity;
|
|
76
|
+
const minLevelNum = Math.min(consoleLevelNum, fileLevelNum);
|
|
77
|
+
// Return level name for minimum level number
|
|
78
|
+
for (const [name, num] of Object.entries(levels)) {
|
|
79
|
+
if (num === minLevelNum) {
|
|
80
|
+
return name;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return 'info';
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
2
|
import { WebSocketServer } from '../websocket-server.js';
|
|
3
|
+
import type { Logger } from '../logger.js';
|
|
3
4
|
export declare const CREATE_NOTE_TOOL: {
|
|
4
5
|
name: string;
|
|
5
6
|
description: string;
|
|
@@ -131,4 +132,4 @@ export declare const STATUS_TOOL: {
|
|
|
131
132
|
properties: {};
|
|
132
133
|
};
|
|
133
134
|
};
|
|
134
|
-
export declare function registerAllTools(server: Server, wsServer: WebSocketServer): void;
|
|
135
|
+
export declare function registerAllTools(server: Server, wsServer: WebSocketServer, logger: Logger): void;
|