remnote-mcp-server 0.2.1 → 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 +30 -0
- package/README.md +60 -90
- 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 +3 -1
- package/dist/http-server.js +21 -10
- package/dist/http-server.js.map +1 -1
- package/dist/index.js +42 -9
- 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 +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,36 @@ Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.3.0] - 2026-02-12
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Comprehensive logging infrastructure with Pino logger
|
|
15
|
+
- CLI argument parsing with Commander for server configuration
|
|
16
|
+
- Configurable log levels (debug, info, warn, error) for console and file output
|
|
17
|
+
- Optional file logging with separate log level control
|
|
18
|
+
- Optional request/response logging to JSON Lines files for debugging
|
|
19
|
+
- Verbose mode (`--verbose`) for quick debug logging enablement
|
|
20
|
+
- CLI flags for port configuration (`--ws-port`, `--http-port`)
|
|
21
|
+
- Structured logging throughout the application with contextual information
|
|
22
|
+
- Debug-level logging for detailed troubleshooting
|
|
23
|
+
- Request timing and duration tracking in logs
|
|
24
|
+
- Graceful error handling with comprehensive error logging
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- Startup message now includes version number and port information
|
|
29
|
+
- All console.error calls replaced with structured Pino logging
|
|
30
|
+
- Server startup sequence now validates configuration before starting services
|
|
31
|
+
- Environment variable configuration now validated with better error messages
|
|
32
|
+
- Port validation moved earlier in startup process for faster failure feedback
|
|
33
|
+
|
|
34
|
+
### Dependencies
|
|
35
|
+
|
|
36
|
+
- Added `pino@^9.6.0` for structured logging
|
|
37
|
+
- Added `commander@^13.0.0` for CLI argument parsing
|
|
38
|
+
- Added `pino-pretty@^11.0.0` (dev) for human-readable development logs
|
|
39
|
+
|
|
10
40
|
## [0.2.1] - 2026-02-11
|
|
11
41
|
|
|
12
42
|
### Added
|
package/README.md
CHANGED
|
@@ -41,6 +41,25 @@ The server acts as a bridge:
|
|
|
41
41
|
- WebSocket server (port 3002) connects to the RemNote browser plugin
|
|
42
42
|
- Translates MCP tool calls into RemNote API actions
|
|
43
43
|
|
|
44
|
+
**About Streamable HTTP Transport**
|
|
45
|
+
|
|
46
|
+
This MCP server uses [Streamable HTTP
|
|
47
|
+
transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#http-with-sse), a communication
|
|
48
|
+
mechanism for MCP that supports multiple concurrent clients.
|
|
49
|
+
|
|
50
|
+
**Key characteristics:**
|
|
51
|
+
|
|
52
|
+
- **Lifecycle management**: You must start the server independently (`npm start` or `npm run dev`). Claude Code connects
|
|
53
|
+
to the running server via HTTP.
|
|
54
|
+
- **Message protocol**: Communication uses JSON-RPC over HTTP POST for requests and Server-Sent Events (SSE) for
|
|
55
|
+
notifications.
|
|
56
|
+
- **Multi-client support**: Multiple AI agents can connect simultaneously, each with their own MCP session.
|
|
57
|
+
- **Session management**: Server tracks sessions via `mcp-session-id` headers and UUID-based request correlation.
|
|
58
|
+
|
|
59
|
+
This architecture enables multiple Claude Code windows to access RemNote concurrently while maintaining process
|
|
60
|
+
isolation and security boundaries. For technical details, see the [MCP
|
|
61
|
+
specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports).
|
|
62
|
+
|
|
44
63
|
## Features
|
|
45
64
|
|
|
46
65
|
- **Create Notes** - Create new notes with optional parent hierarchy and tags
|
|
@@ -82,6 +101,8 @@ The WebSocket bridge still enforces a **single RemNote plugin connection**. This
|
|
|
82
101
|
|
|
83
102
|
**From npm (recommended for most users):**
|
|
84
103
|
|
|
104
|
+
See [MCP Server npm Package](https://www.npmjs.com/package/remnote-mcp-server).
|
|
105
|
+
|
|
85
106
|
```bash
|
|
86
107
|
# Install globally
|
|
87
108
|
npm install -g remnote-mcp-server
|
|
@@ -104,82 +125,59 @@ npm uninstall -g remnote-mcp-server
|
|
|
104
125
|
git clone https://github.com/robert7/remnote-mcp-server.git
|
|
105
126
|
cd remnote-mcp-server
|
|
106
127
|
npm install
|
|
107
|
-
npm run build
|
|
108
|
-
|
|
109
|
-
# Creates global symlink: makes remnote-mcp-server command available system-wide
|
|
110
|
-
npm link
|
|
111
|
-
|
|
112
|
-
# Verify it worked
|
|
113
|
-
which remnote-mcp-server
|
|
114
|
-
# Should output e.g.: /Users/<username>/.nvm/versions/node/<version>/bin/remnote-mcp-server
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
**What npm link does:** Creates a symbolic link from your global `node_modules` bin directory to this project's
|
|
118
|
-
executable, allowing Claude Code to launch `remnote-mcp-server` from anywhere without publishing to npm.
|
|
119
|
-
|
|
120
|
-
**Important:** Claude Code CLI must have access to the same Node.js environment where you ran `npm link`. If Claude Code
|
|
121
|
-
uses a different Node.js version or environment (e.g., different shell PATH), it won't find the command. Ensure your
|
|
122
|
-
shell configuration (`.bashrc`, `.zshrc`) properly exposes your Node.js environment.
|
|
123
|
-
|
|
124
|
-
**Unlinking the source installation:**
|
|
125
|
-
|
|
126
|
-
When you no longer want the global `remnote-mcp-server` command to point to your local repository:
|
|
127
|
-
|
|
128
|
-
```bash
|
|
129
|
-
# Remove the global symlink
|
|
130
|
-
npm unlink -g remnote-mcp-server
|
|
131
|
-
|
|
132
|
-
# Verify it's removed
|
|
133
|
-
which remnote-mcp-server
|
|
134
|
-
# Should output nothing if successfully unlinked
|
|
135
128
|
```
|
|
136
129
|
|
|
137
|
-
After unlinking, you can install the published npm package globally with `npm install -g remnote-mcp-server` if needed.
|
|
138
|
-
|
|
139
|
-
**About Streamable HTTP Transport**
|
|
140
|
-
|
|
141
|
-
This MCP server uses [Streamable HTTP
|
|
142
|
-
transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#http-with-sse), a communication
|
|
143
|
-
mechanism for MCP that supports multiple concurrent clients.
|
|
144
|
-
|
|
145
|
-
**Key characteristics:**
|
|
146
|
-
|
|
147
|
-
- **Lifecycle management**: You must start the server independently (`npm start` or `npm run dev`). Claude Code connects
|
|
148
|
-
to the running server via HTTP.
|
|
149
|
-
- **Message protocol**: Communication uses JSON-RPC over HTTP POST for requests and Server-Sent Events (SSE) for
|
|
150
|
-
notifications.
|
|
151
|
-
- **Multi-client support**: Multiple AI agents can connect simultaneously, each with their own MCP session.
|
|
152
|
-
- **Session management**: Server tracks sessions via `mcp-session-id` headers and UUID-based request correlation.
|
|
153
|
-
|
|
154
|
-
This architecture enables multiple Claude Code windows to access RemNote concurrently while maintaining process
|
|
155
|
-
isolation and security boundaries. For technical details, see the [MCP
|
|
156
|
-
specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports).
|
|
157
|
-
|
|
158
130
|
### 2. Install RemNote MCP Bridge Plugin
|
|
159
131
|
|
|
160
132
|
Install the [RemNote MCP Bridge plugin](https://github.com/robert7/remnote-mcp-bridge) in your RemNote app:
|
|
161
133
|
|
|
162
134
|
1. Open RemNote
|
|
163
135
|
2. Navigate to plugin installation (see plugin repository for instructions)
|
|
164
|
-
3. Configure WebSocket URL: `ws://127.0.0.1:3002`
|
|
165
|
-
4. Enable auto-reconnect
|
|
166
136
|
|
|
167
137
|
### 3. Start the Server
|
|
168
138
|
|
|
169
139
|
**IMPORTANT:** You must start the server before using it with Claude Code.
|
|
170
140
|
|
|
171
141
|
```bash
|
|
172
|
-
#
|
|
173
|
-
|
|
142
|
+
# Start with default settings
|
|
143
|
+
remnote-mcp-server
|
|
144
|
+
|
|
145
|
+
# With custom ports
|
|
146
|
+
remnote-mcp-server --ws-port 4002 --http-port 4001
|
|
147
|
+
|
|
148
|
+
# With verbose logging
|
|
149
|
+
remnote-mcp-server --verbose
|
|
150
|
+
|
|
151
|
+
# With file logging
|
|
152
|
+
remnote-mcp-server --log-file /tmp/remnote-mcp.log --log-level-file debug
|
|
174
153
|
|
|
175
154
|
# OR development mode (with hot reload)
|
|
176
155
|
npm run dev
|
|
156
|
+
# you can also pass CLI options after `--`, e.g.
|
|
157
|
+
npm run dev -- -h
|
|
177
158
|
```
|
|
178
159
|
|
|
160
|
+
**CLI Options:**
|
|
161
|
+
|
|
162
|
+
Server Configuration:
|
|
163
|
+
- `--ws-port <number>` - WebSocket port (default: 3002, env: REMNOTE_WS_PORT)
|
|
164
|
+
- `--http-port <number>` - HTTP MCP port (default: 3001, env: REMNOTE_HTTP_PORT)
|
|
165
|
+
|
|
166
|
+
Logging Configuration:
|
|
167
|
+
- `--log-level <level>` - Console log level: debug, info, warn, error (default: info)
|
|
168
|
+
- `--log-level-file <level>` - File log level (default: same as --log-level)
|
|
169
|
+
- `--verbose` - Shorthand for --log-level debug
|
|
170
|
+
- `--log-file <path>` - Log to file (default: console only)
|
|
171
|
+
- `--request-log <path>` - Log all WebSocket requests to file (JSON Lines)
|
|
172
|
+
- `--response-log <path>` - Log all WebSocket responses to file (JSON Lines)
|
|
173
|
+
|
|
174
|
+
Information:
|
|
175
|
+
- `-h, --help` - Display help message
|
|
176
|
+
- `-v, --version` - Display version number
|
|
177
|
+
|
|
179
178
|
Expected output:
|
|
180
179
|
```
|
|
181
|
-
|
|
182
|
-
[HTTP Server] Listening on port 3001
|
|
180
|
+
RemNote MCP Server v0.2.1 listening { wsPort: 3002, httpPort: 3001 }
|
|
183
181
|
```
|
|
184
182
|
|
|
185
183
|
Keep this terminal running. The server must be running for Claude Code to connect.
|
|
@@ -317,12 +315,11 @@ Use remnote_status to check the connection
|
|
|
317
315
|
Expected response:
|
|
318
316
|
|
|
319
317
|
```json
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
}
|
|
318
|
+
⏺ remnote - remnote_status (MCP)
|
|
319
|
+
⎿ {
|
|
320
|
+
"connected": true,
|
|
321
|
+
"pluginVersion": "0.3.2"
|
|
322
|
+
}
|
|
326
323
|
```
|
|
327
324
|
|
|
328
325
|
### Test RemNote Integration
|
|
@@ -398,6 +395,8 @@ Check if RemNote is connected
|
|
|
398
395
|
export REMNOTE_HTTP_PORT=3003
|
|
399
396
|
export REMNOTE_WS_PORT=3004
|
|
400
397
|
npm start
|
|
398
|
+
# you can pass CLI options after `--`, e.g.
|
|
399
|
+
npm start -- -h
|
|
401
400
|
```
|
|
402
401
|
|
|
403
402
|
Then update your `~/.claude.json` and RemNote plugin settings to use the new ports.
|
|
@@ -538,35 +537,6 @@ npm run lint # ESLint only
|
|
|
538
537
|
npm run format # Format code
|
|
539
538
|
```
|
|
540
539
|
|
|
541
|
-
### Before Committing
|
|
542
|
-
|
|
543
|
-
Run `./code-quality.sh` to ensure all checks pass.
|
|
544
|
-
|
|
545
|
-
### Manual Testing
|
|
546
|
-
|
|
547
|
-
To test the server:
|
|
548
|
-
|
|
549
|
-
```bash
|
|
550
|
-
cd ~/Projects/_private/remnote-mcp-server
|
|
551
|
-
npm run dev
|
|
552
|
-
```
|
|
553
|
-
|
|
554
|
-
Expected output:
|
|
555
|
-
```
|
|
556
|
-
[WebSocket Server] Listening on port 3002
|
|
557
|
-
[HTTP Server] Listening on port 3001
|
|
558
|
-
```
|
|
559
|
-
|
|
560
|
-
When the RemNote plugin connects:
|
|
561
|
-
```
|
|
562
|
-
[WebSocket Server] Client connected
|
|
563
|
-
[RemNote Bridge] RemNote plugin connected
|
|
564
|
-
```
|
|
565
|
-
|
|
566
|
-
When Claude Code connects, you'll see HTTP requests in the logs.
|
|
567
|
-
|
|
568
|
-
Press Ctrl+C to stop.
|
|
569
|
-
|
|
570
540
|
### Development Documentation
|
|
571
541
|
|
|
572
542
|
- **[docs/architecture.md](./docs/architecture.md)** - Architecture and design rationale
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface CliOptions {
|
|
2
|
+
wsPort?: number;
|
|
3
|
+
httpPort?: number;
|
|
4
|
+
logLevel?: string;
|
|
5
|
+
logLevelFile?: string;
|
|
6
|
+
verbose?: boolean;
|
|
7
|
+
logFile?: string;
|
|
8
|
+
requestLog?: string;
|
|
9
|
+
responseLog?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Parse CLI arguments and return typed options
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseCliArgs(): CliOptions;
|
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"}
|
package/dist/http-server.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { WebSocketServer } from './websocket-server.js';
|
|
2
|
+
import type { Logger } from './logger.js';
|
|
2
3
|
interface ServerInfo {
|
|
3
4
|
name: string;
|
|
4
5
|
version: string;
|
|
@@ -9,8 +10,9 @@ export declare class HttpMcpServer {
|
|
|
9
10
|
private port;
|
|
10
11
|
private wsServer;
|
|
11
12
|
private serverInfo;
|
|
13
|
+
private logger;
|
|
12
14
|
private transports;
|
|
13
|
-
constructor(port: number, wsServer: WebSocketServer, serverInfo: ServerInfo);
|
|
15
|
+
constructor(port: number, wsServer: WebSocketServer, serverInfo: ServerInfo, logger: Logger);
|
|
14
16
|
private setupRoutes;
|
|
15
17
|
private initializeNewSession;
|
|
16
18
|
private handleSessionRequest;
|
package/dist/http-server.js
CHANGED
|
@@ -9,11 +9,13 @@ export class HttpMcpServer {
|
|
|
9
9
|
port;
|
|
10
10
|
wsServer;
|
|
11
11
|
serverInfo;
|
|
12
|
+
logger;
|
|
12
13
|
transports = new Map();
|
|
13
|
-
constructor(port, wsServer, serverInfo) {
|
|
14
|
+
constructor(port, wsServer, serverInfo, logger) {
|
|
14
15
|
this.port = port;
|
|
15
16
|
this.wsServer = wsServer;
|
|
16
17
|
this.serverInfo = serverInfo;
|
|
18
|
+
this.logger = logger.child({ context: 'http-server' });
|
|
17
19
|
// Create Express app with JSON parsing
|
|
18
20
|
this.app = express();
|
|
19
21
|
this.app.use(express.json());
|
|
@@ -28,6 +30,10 @@ export class HttpMcpServer {
|
|
|
28
30
|
const body = req.body;
|
|
29
31
|
// Check if this is an initialize request
|
|
30
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');
|
|
31
37
|
if (!sessionId && isInitializeRequest) {
|
|
32
38
|
// New session initialization
|
|
33
39
|
await this.initializeNewSession(req, res, body);
|
|
@@ -49,7 +55,10 @@ export class HttpMcpServer {
|
|
|
49
55
|
}
|
|
50
56
|
}
|
|
51
57
|
catch (error) {
|
|
52
|
-
|
|
58
|
+
this.logger.error({
|
|
59
|
+
error,
|
|
60
|
+
sessionId: req.headers['mcp-session-id'],
|
|
61
|
+
}, 'Error handling POST request');
|
|
53
62
|
res.status(500).json({
|
|
54
63
|
jsonrpc: '2.0',
|
|
55
64
|
error: {
|
|
@@ -63,6 +72,7 @@ export class HttpMcpServer {
|
|
|
63
72
|
// GET: SSE stream for session notifications
|
|
64
73
|
this.app.get('/mcp', async (req, res) => {
|
|
65
74
|
const sessionId = req.headers['mcp-session-id'];
|
|
75
|
+
this.logger.debug({ sessionId: sessionId || 'none' }, 'SSE stream opened');
|
|
66
76
|
if (!sessionId) {
|
|
67
77
|
res.status(400).json({ error: 'Missing mcp-session-id header' });
|
|
68
78
|
return;
|
|
@@ -78,6 +88,7 @@ export class HttpMcpServer {
|
|
|
78
88
|
// DELETE: Terminate session
|
|
79
89
|
this.app.delete('/mcp', async (req, res) => {
|
|
80
90
|
const sessionId = req.headers['mcp-session-id'];
|
|
91
|
+
this.logger.debug({ sessionId: sessionId || 'none' }, 'Session termination requested');
|
|
81
92
|
if (!sessionId) {
|
|
82
93
|
res.status(400).json({ error: 'Missing mcp-session-id header' });
|
|
83
94
|
return;
|
|
@@ -97,14 +108,14 @@ export class HttpMcpServer {
|
|
|
97
108
|
sessionIdGenerator: () => randomUUID(),
|
|
98
109
|
onsessioninitialized: (sessionId) => {
|
|
99
110
|
this.transports.set(sessionId, transport);
|
|
100
|
-
|
|
111
|
+
this.logger.info({ sessionId }, 'New MCP session initialized');
|
|
101
112
|
},
|
|
102
113
|
});
|
|
103
114
|
// Set up onclose handler to clean up transport when closed
|
|
104
115
|
transport.onclose = () => {
|
|
105
116
|
const sessionId = transport.sessionId;
|
|
106
117
|
if (sessionId && this.transports.has(sessionId)) {
|
|
107
|
-
|
|
118
|
+
this.logger.info({ sessionId }, 'MCP session closed');
|
|
108
119
|
this.transports.delete(sessionId);
|
|
109
120
|
}
|
|
110
121
|
};
|
|
@@ -115,7 +126,7 @@ export class HttpMcpServer {
|
|
|
115
126
|
},
|
|
116
127
|
});
|
|
117
128
|
// Register all tools with the shared WebSocket server
|
|
118
|
-
registerAllTools(server, this.wsServer);
|
|
129
|
+
registerAllTools(server, this.wsServer, this.logger);
|
|
119
130
|
// Connect server to transport
|
|
120
131
|
await server.connect(transport);
|
|
121
132
|
// Handle the initialize request
|
|
@@ -140,11 +151,11 @@ export class HttpMcpServer {
|
|
|
140
151
|
return new Promise((resolve, reject) => {
|
|
141
152
|
try {
|
|
142
153
|
this.server = this.app.listen(this.port, () => {
|
|
143
|
-
|
|
154
|
+
this.logger.info({ port: this.port }, 'HTTP server started');
|
|
144
155
|
resolve();
|
|
145
156
|
});
|
|
146
157
|
this.server.on('error', (error) => {
|
|
147
|
-
|
|
158
|
+
this.logger.error({ error }, 'HTTP server error');
|
|
148
159
|
reject(error);
|
|
149
160
|
});
|
|
150
161
|
}
|
|
@@ -157,19 +168,19 @@ export class HttpMcpServer {
|
|
|
157
168
|
// Close all active transports
|
|
158
169
|
for (const [sessionId, transport] of this.transports.entries()) {
|
|
159
170
|
try {
|
|
160
|
-
|
|
171
|
+
this.logger.debug({ sessionId }, 'Closing MCP session');
|
|
161
172
|
await transport.close();
|
|
162
173
|
this.transports.delete(sessionId);
|
|
163
174
|
}
|
|
164
175
|
catch (error) {
|
|
165
|
-
|
|
176
|
+
this.logger.error({ sessionId, error }, 'Error closing session');
|
|
166
177
|
}
|
|
167
178
|
}
|
|
168
179
|
// Close HTTP server
|
|
169
180
|
return new Promise((resolve) => {
|
|
170
181
|
if (this.server) {
|
|
171
182
|
this.server.close(() => {
|
|
172
|
-
|
|
183
|
+
this.logger.info('HTTP server stopped');
|
|
173
184
|
this.server = null;
|
|
174
185
|
resolve();
|
|
175
186
|
});
|
package/dist/http-server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,OAAsD,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -2,32 +2,64 @@
|
|
|
2
2
|
import { createRequire } from 'module';
|
|
3
3
|
import { WebSocketServer } from './websocket-server.js';
|
|
4
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';
|
|
5
8
|
const require = createRequire(import.meta.url);
|
|
6
9
|
const packageJson = require('../package.json');
|
|
7
|
-
const WS_PORT = parseInt(process.env.REMNOTE_WS_PORT || '3002', 10);
|
|
8
|
-
const HTTP_PORT = parseInt(process.env.REMNOTE_HTTP_PORT || '3001', 10);
|
|
9
10
|
async function main() {
|
|
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,
|
|
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;
|
|
10
38
|
// Initialize WebSocket server for RemNote plugin
|
|
11
|
-
const wsServer = new WebSocketServer(
|
|
39
|
+
const wsServer = new WebSocketServer(config.wsPort, logger, requestLogger, responseLogger);
|
|
12
40
|
// Log connection status
|
|
13
41
|
wsServer.onClientConnect(() => {
|
|
14
|
-
|
|
42
|
+
logger.info('RemNote plugin connected');
|
|
15
43
|
});
|
|
16
44
|
wsServer.onClientDisconnect(() => {
|
|
17
|
-
|
|
45
|
+
logger.info('RemNote plugin disconnected');
|
|
18
46
|
});
|
|
19
47
|
// Start WebSocket server
|
|
20
48
|
await wsServer.start();
|
|
21
|
-
console.error(`[WebSocket Server] Listening on port ${WS_PORT}`);
|
|
22
49
|
// Initialize HTTP MCP server
|
|
23
|
-
const httpServer = new HttpMcpServer(
|
|
50
|
+
const httpServer = new HttpMcpServer(config.httpPort, wsServer, {
|
|
24
51
|
name: 'remnote-mcp-server',
|
|
25
52
|
version: packageJson.version,
|
|
26
|
-
});
|
|
53
|
+
}, logger);
|
|
27
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`);
|
|
28
60
|
// Graceful shutdown
|
|
29
61
|
const shutdown = async () => {
|
|
30
|
-
|
|
62
|
+
logger.info('Shutting down');
|
|
31
63
|
await httpServer.stop();
|
|
32
64
|
await wsServer.stop();
|
|
33
65
|
process.exit(0);
|
|
@@ -36,6 +68,7 @@ async function main() {
|
|
|
36
68
|
process.on('SIGTERM', shutdown);
|
|
37
69
|
}
|
|
38
70
|
main().catch((error) => {
|
|
71
|
+
// Pre-logger error handling
|
|
39
72
|
console.error('[MCP Server] Fatal error:', error);
|
|
40
73
|
process.exit(1);
|
|
41
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,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
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;
|
package/dist/tools/index.js
CHANGED
|
@@ -78,73 +78,68 @@ export const STATUS_TOOL = {
|
|
|
78
78
|
properties: {},
|
|
79
79
|
},
|
|
80
80
|
};
|
|
81
|
-
export function registerAllTools(server, wsServer) {
|
|
81
|
+
export function registerAllTools(server, wsServer, logger) {
|
|
82
|
+
const toolLogger = logger.child({ context: 'tools' });
|
|
82
83
|
// Single CallTool handler for all tools
|
|
83
84
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
85
|
+
const toolName = request.params.name;
|
|
86
|
+
const startTime = Date.now();
|
|
87
|
+
toolLogger.debug({ tool: toolName, args: request.params.arguments }, 'Executing tool');
|
|
84
88
|
try {
|
|
85
|
-
|
|
89
|
+
let result;
|
|
90
|
+
switch (toolName) {
|
|
86
91
|
case 'remnote_create_note': {
|
|
87
92
|
const args = CreateNoteSchema.parse(request.params.arguments);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
91
|
-
};
|
|
93
|
+
result = await wsServer.sendRequest('create_note', args);
|
|
94
|
+
break;
|
|
92
95
|
}
|
|
93
96
|
case 'remnote_search': {
|
|
94
97
|
const args = SearchSchema.parse(request.params.arguments);
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
98
|
-
};
|
|
98
|
+
result = await wsServer.sendRequest('search', args);
|
|
99
|
+
break;
|
|
99
100
|
}
|
|
100
101
|
case 'remnote_read_note': {
|
|
101
102
|
const args = ReadNoteSchema.parse(request.params.arguments);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
105
|
-
};
|
|
103
|
+
result = await wsServer.sendRequest('read_note', args);
|
|
104
|
+
break;
|
|
106
105
|
}
|
|
107
106
|
case 'remnote_update_note': {
|
|
108
107
|
const args = UpdateNoteSchema.parse(request.params.arguments);
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
112
|
-
};
|
|
108
|
+
result = await wsServer.sendRequest('update_note', args);
|
|
109
|
+
break;
|
|
113
110
|
}
|
|
114
111
|
case 'remnote_append_journal': {
|
|
115
112
|
const args = AppendJournalSchema.parse(request.params.arguments);
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
119
|
-
};
|
|
113
|
+
result = await wsServer.sendRequest('append_journal', args);
|
|
114
|
+
break;
|
|
120
115
|
}
|
|
121
116
|
case 'remnote_status': {
|
|
122
117
|
const connected = wsServer.isConnected();
|
|
123
118
|
if (!connected) {
|
|
124
|
-
|
|
125
|
-
content: [
|
|
126
|
-
{
|
|
127
|
-
type: 'text',
|
|
128
|
-
text: JSON.stringify({ connected: false, message: 'RemNote plugin not connected' }, null, 2),
|
|
129
|
-
},
|
|
130
|
-
],
|
|
131
|
-
};
|
|
119
|
+
result = { connected: false, message: 'RemNote plugin not connected' };
|
|
132
120
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
text: JSON.stringify({ connected: true, ...(typeof result === 'object' ? result : {}) }, null, 2),
|
|
139
|
-
},
|
|
140
|
-
],
|
|
141
|
-
};
|
|
121
|
+
else {
|
|
122
|
+
const statusResult = await wsServer.sendRequest('get_status', {});
|
|
123
|
+
result = { connected: true, ...(typeof statusResult === 'object' ? statusResult : {}) };
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
142
126
|
}
|
|
143
127
|
default:
|
|
144
|
-
throw new Error(`Unknown tool: ${
|
|
128
|
+
throw new Error(`Unknown tool: ${toolName}`);
|
|
145
129
|
}
|
|
130
|
+
toolLogger.debug({
|
|
131
|
+
tool: toolName,
|
|
132
|
+
duration_ms: Date.now() - startTime,
|
|
133
|
+
}, 'Tool completed');
|
|
134
|
+
return {
|
|
135
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
136
|
+
};
|
|
146
137
|
}
|
|
147
138
|
catch (error) {
|
|
139
|
+
toolLogger.error({
|
|
140
|
+
tool: toolName,
|
|
141
|
+
error: error instanceof Error ? error.message : String(error),
|
|
142
|
+
}, 'Tool failed');
|
|
148
143
|
return {
|
|
149
144
|
content: [
|
|
150
145
|
{
|
|
@@ -157,15 +152,18 @@ export function registerAllTools(server, wsServer) {
|
|
|
157
152
|
}
|
|
158
153
|
});
|
|
159
154
|
// Register list_tools handler
|
|
160
|
-
server.setRequestHandler(ListToolsRequestSchema, async () =>
|
|
161
|
-
tools
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
155
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
156
|
+
toolLogger.debug('Listing available tools');
|
|
157
|
+
return {
|
|
158
|
+
tools: [
|
|
159
|
+
CREATE_NOTE_TOOL,
|
|
160
|
+
SEARCH_TOOL,
|
|
161
|
+
READ_NOTE_TOOL,
|
|
162
|
+
UPDATE_NOTE_TOOL,
|
|
163
|
+
APPEND_JOURNAL_TOOL,
|
|
164
|
+
STATUS_TOOL,
|
|
165
|
+
],
|
|
166
|
+
};
|
|
167
|
+
});
|
|
170
168
|
}
|
|
171
169
|
//# sourceMappingURL=index.js.map
|
package/dist/tools/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAEnG,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
+
import type { Logger } from './logger.js';
|
|
1
2
|
export declare class WebSocketServer {
|
|
2
3
|
private wss;
|
|
3
4
|
private client;
|
|
4
5
|
private port;
|
|
6
|
+
private logger;
|
|
7
|
+
private requestLogger;
|
|
8
|
+
private responseLogger;
|
|
5
9
|
private pendingRequests;
|
|
6
10
|
private connectCallbacks;
|
|
7
11
|
private disconnectCallbacks;
|
|
8
|
-
constructor(port: number);
|
|
12
|
+
constructor(port: number, logger: Logger, requestLogger?: Logger, responseLogger?: Logger);
|
|
9
13
|
start(): Promise<void>;
|
|
10
14
|
stop(): Promise<void>;
|
|
11
15
|
sendRequest(action: string, payload: Record<string, unknown>): Promise<unknown>;
|
package/dist/websocket-server.js
CHANGED
|
@@ -4,41 +4,48 @@ export class WebSocketServer {
|
|
|
4
4
|
wss = null;
|
|
5
5
|
client = null;
|
|
6
6
|
port;
|
|
7
|
+
logger;
|
|
8
|
+
requestLogger = null;
|
|
9
|
+
responseLogger = null;
|
|
7
10
|
pendingRequests = new Map();
|
|
8
11
|
connectCallbacks = [];
|
|
9
12
|
disconnectCallbacks = [];
|
|
10
|
-
constructor(port) {
|
|
13
|
+
constructor(port, logger, requestLogger, responseLogger) {
|
|
11
14
|
this.port = port;
|
|
15
|
+
this.logger = logger.child({ context: 'websocket-server' });
|
|
16
|
+
this.requestLogger = requestLogger || null;
|
|
17
|
+
this.responseLogger = responseLogger || null;
|
|
12
18
|
}
|
|
13
19
|
async start() {
|
|
14
20
|
return new Promise((resolve, reject) => {
|
|
15
21
|
this.wss = new WSServer({ port: this.port }, () => {
|
|
22
|
+
this.logger.debug({ port: this.port }, 'WebSocket server started');
|
|
16
23
|
resolve();
|
|
17
24
|
});
|
|
18
25
|
this.wss.on('error', (error) => {
|
|
19
|
-
|
|
26
|
+
this.logger.error({ error }, 'WebSocket server error');
|
|
20
27
|
reject(error);
|
|
21
28
|
});
|
|
22
29
|
this.wss.on('connection', (ws) => {
|
|
23
30
|
// Only allow single client connection
|
|
24
31
|
if (this.client && this.client.readyState === WebSocket.OPEN) {
|
|
25
|
-
|
|
32
|
+
this.logger.warn('Rejecting connection: client already connected');
|
|
26
33
|
ws.close(1008, 'Only one client allowed');
|
|
27
34
|
return;
|
|
28
35
|
}
|
|
29
36
|
this.client = ws;
|
|
30
|
-
|
|
37
|
+
this.logger.info('WebSocket client connected');
|
|
31
38
|
this.connectCallbacks.forEach((cb) => cb());
|
|
32
39
|
ws.on('message', (data) => {
|
|
33
40
|
try {
|
|
34
41
|
this.handleMessage(data.toString());
|
|
35
42
|
}
|
|
36
43
|
catch (error) {
|
|
37
|
-
|
|
44
|
+
this.logger.error({ error }, 'Error handling message');
|
|
38
45
|
}
|
|
39
46
|
});
|
|
40
47
|
ws.on('close', () => {
|
|
41
|
-
|
|
48
|
+
this.logger.info('WebSocket client disconnected');
|
|
42
49
|
this.client = null;
|
|
43
50
|
// Reject all pending requests
|
|
44
51
|
for (const [_id, pending] of this.pendingRequests.entries()) {
|
|
@@ -49,7 +56,7 @@ export class WebSocketServer {
|
|
|
49
56
|
this.disconnectCallbacks.forEach((cb) => cb());
|
|
50
57
|
});
|
|
51
58
|
ws.on('error', (error) => {
|
|
52
|
-
|
|
59
|
+
this.logger.error({ error }, 'WebSocket client error');
|
|
53
60
|
});
|
|
54
61
|
});
|
|
55
62
|
});
|
|
@@ -62,6 +69,7 @@ export class WebSocketServer {
|
|
|
62
69
|
}
|
|
63
70
|
if (this.wss) {
|
|
64
71
|
this.wss.close(() => {
|
|
72
|
+
this.logger.debug('WebSocket server stopped');
|
|
65
73
|
this.wss = null;
|
|
66
74
|
resolve();
|
|
67
75
|
});
|
|
@@ -77,12 +85,44 @@ export class WebSocketServer {
|
|
|
77
85
|
}
|
|
78
86
|
const id = randomUUID();
|
|
79
87
|
const request = { id, action, payload };
|
|
88
|
+
const startTime = Date.now();
|
|
89
|
+
this.logger.debug({ id, action }, 'Sending request');
|
|
90
|
+
// Log request if configured
|
|
91
|
+
if (this.requestLogger) {
|
|
92
|
+
this.requestLogger.info({ type: 'request', id, action, payload });
|
|
93
|
+
}
|
|
80
94
|
return new Promise((resolve, reject) => {
|
|
81
95
|
const timeout = setTimeout(() => {
|
|
82
96
|
this.pendingRequests.delete(id);
|
|
83
97
|
reject(new Error(`Request timeout: ${action}`));
|
|
84
98
|
}, 5000);
|
|
85
|
-
this.pendingRequests.set(id, {
|
|
99
|
+
this.pendingRequests.set(id, {
|
|
100
|
+
resolve: (result) => {
|
|
101
|
+
// Log response if configured
|
|
102
|
+
if (this.responseLogger) {
|
|
103
|
+
this.responseLogger.info({
|
|
104
|
+
type: 'response',
|
|
105
|
+
id,
|
|
106
|
+
duration_ms: Date.now() - startTime,
|
|
107
|
+
error: null,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
resolve(result);
|
|
111
|
+
},
|
|
112
|
+
reject: (error) => {
|
|
113
|
+
// Log error response if configured
|
|
114
|
+
if (this.responseLogger) {
|
|
115
|
+
this.responseLogger.info({
|
|
116
|
+
type: 'response',
|
|
117
|
+
id,
|
|
118
|
+
duration_ms: Date.now() - startTime,
|
|
119
|
+
error: error.message,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
reject(error);
|
|
123
|
+
},
|
|
124
|
+
timeout,
|
|
125
|
+
});
|
|
86
126
|
try {
|
|
87
127
|
this.client.send(JSON.stringify(request));
|
|
88
128
|
}
|
|
@@ -105,6 +145,9 @@ export class WebSocketServer {
|
|
|
105
145
|
handleMessage(data) {
|
|
106
146
|
try {
|
|
107
147
|
const message = JSON.parse(data);
|
|
148
|
+
this.logger.debug({
|
|
149
|
+
type: 'type' in message ? message.type : 'response',
|
|
150
|
+
}, 'Received message');
|
|
108
151
|
// Handle pong response to ping
|
|
109
152
|
if ('type' in message && message.type === 'pong') {
|
|
110
153
|
return;
|
|
@@ -131,12 +174,12 @@ export class WebSocketServer {
|
|
|
131
174
|
}
|
|
132
175
|
}
|
|
133
176
|
else {
|
|
134
|
-
|
|
177
|
+
this.logger.warn({ id: response.id }, 'Unknown request ID');
|
|
135
178
|
}
|
|
136
179
|
}
|
|
137
180
|
}
|
|
138
181
|
catch (error) {
|
|
139
|
-
|
|
182
|
+
this.logger.error({ error }, 'Error parsing message');
|
|
140
183
|
}
|
|
141
184
|
}
|
|
142
185
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-server.js","sourceRoot":"","sources":["../src/websocket-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,IAAI,QAAQ,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"websocket-server.js","sourceRoot":"","sources":["../src/websocket-server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "remnote-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "MCP server bridge for RemNote knowledge base",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -53,7 +53,9 @@
|
|
|
53
53
|
"homepage": "https://github.com/robert7/remnote-mcp-server#readme",
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
56
|
+
"commander": "^13.0.0",
|
|
56
57
|
"express": "^5.2.0",
|
|
58
|
+
"pino": "^9.6.0",
|
|
57
59
|
"ws": "^8.19.0",
|
|
58
60
|
"zod": "^4.3.6"
|
|
59
61
|
},
|
|
@@ -67,6 +69,7 @@
|
|
|
67
69
|
"@vitest/ui": "^1.6.1",
|
|
68
70
|
"eslint": "^8.57.1",
|
|
69
71
|
"eslint-config-prettier": "^9.1.2",
|
|
72
|
+
"pino-pretty": "^11.0.0",
|
|
70
73
|
"prettier": "^3.8.1",
|
|
71
74
|
"tsx": "^4.21.0",
|
|
72
75
|
"typescript": "^5.9.3",
|