remnote-mcp-server 0.1.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 ADDED
@@ -0,0 +1,90 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic
6
+ Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.2] - 2026-02-07
11
+
12
+ ### Added
13
+
14
+ - Documentation of multi-agent limitations in README.md
15
+ - Explains 1:1:1 architecture constraint (one AI agent ↔ one server ↔ one RemNote connection)
16
+ - Details three architectural constraints: stdio point-to-point transport, single-client WebSocket, port binding
17
+ - Provides practical implications and alternative approaches for users needing multiple agents
18
+ - Notes planned migration to HTTP transport (SSE) which would enable multi-agent support
19
+ - Comprehensive testing infrastructure with Vitest (95 tests)
20
+ - Unit tests for WebSocketServer, tools, schemas
21
+ - Coverage thresholds enforced (80% lines/functions/statements, 75% branches)
22
+ - Code quality tools
23
+ - ESLint with TypeScript-specific rules
24
+ - Prettier for consistent code formatting
25
+ - `./code-quality.sh` script for unified quality checks
26
+ - CI/CD integration
27
+ - GitHub Actions workflow running all quality checks on push/PR
28
+ - CI status badge in README
29
+ - npm scripts for testing, linting, and formatting
30
+ - Test helpers and mock implementations for isolated testing
31
+
32
+ ### Changed
33
+
34
+ - MCP server version is now dynamically read from package.json instead of being hardcoded in src/index.ts
35
+
36
+ ## [0.1.1] - 2026-02-07
37
+
38
+ ### Added
39
+
40
+ - README.md now includes explanation of stdio transport architecture and its implications (lifecycle management, message
41
+ protocol, logging constraints)
42
+ - AGENTS.md now references `.agents/dev-documentation.md` for documentation guidelines
43
+ - AGENTS.md now includes critical reminder to read `.agents/dev-workflow.md` before writing code or docs
44
+ - README.md now includes inline verification step for `npm link` using `which` command with concise explanation of what
45
+ npm link creates
46
+ - README.md now explains Node.js environment requirement for Claude Code CLI to execute the `remnote-mcp-server` command
47
+ - LICENSE file (MIT License)
48
+ - Repository, homepage, and bugs fields in package.json for npm registry
49
+ - Files field in package.json to explicitly control published files
50
+ - prepublishOnly script to ensure build before publishing
51
+ - Additional keywords for improved npm discoverability
52
+ - Coauthorship policy documented in CLAUDE.md
53
+ - Publishing documentation in docs/publishing.md for maintainers
54
+
55
+ ### Fixed
56
+
57
+ - Version mismatch between package.json (0.1.0) and MCP server declaration (was 1.0.0)
58
+ - Corrected critical configuration error in all documentation files that would prevent users from successfully setting
59
+ up the server
60
+
61
+ ### Changed
62
+
63
+ - **BREAKING**: Documentation now shows correct Claude Code configuration format using `~/.claude.json` with
64
+ `mcpServers` key instead of deprecated `~/.claude/.mcp.json` format
65
+ - Completely rewrote README.md for better user experience with comprehensive installation, verification,
66
+ troubleshooting, and usage examples
67
+ - Updated AGENTS.md with correct configuration format and deprecation notices
68
+ - Updated IMPLEMENTATION.md with correct configuration examples
69
+
70
+ ### Removed
71
+
72
+ - Deleted CLAUDE_CODE_CONFIG.md (content consolidated into README.md and AGENTS.md to eliminate redundancy)
73
+
74
+ ## [0.1.0] - 2026-02-06
75
+
76
+ ### Added
77
+
78
+ - Initial release: RemNote MCP Server
79
+ - WebSocket server for RemNote plugin bridge
80
+ - MCP stdio transport for Claude Code integration
81
+ - Six RemNote tools: create_note, search, read_note, update_note, append_journal, status
82
+ - Request/response correlation with UUID tracking
83
+ - 5-second request timeout handling
84
+ - Heartbeat support (ping/pong)
85
+ - Single-client connection model
86
+ - Graceful shutdown handling (SIGINT/SIGTERM)
87
+ - Zod schema validation for all tool parameters
88
+ - TypeScript strict mode compilation
89
+ - Development mode with hot reload
90
+ - Global npm linking support
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 nightingale7 nightingale7@gmail.com
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,506 @@
1
+ # RemNote MCP Server
2
+
3
+ [![CI](https://github.com/robert7/remnote-mcp-server/actions/workflows/ci.yml/badge.svg)](https://github.com/robert7/remnote-mcp-server/actions/workflows/ci.yml)
4
+
5
+ MCP server that bridges Claude Code (and other MCP clients) to [RemNote](https://remnote.com/) via the [RemNote MCP
6
+ Bridge plugin](https://github.com/robert7/remnote-mcp-bridge).
7
+
8
+ ## What is This?
9
+
10
+ The RemNote MCP Server enables AI assistants like Claude Code to interact directly with your RemNote knowledge base
11
+ through the Model Context Protocol (MCP). This allows you to create notes, search your knowledge base, update existing
12
+ notes, and maintain your daily journal—all through conversational commands.
13
+
14
+ **Architecture:**
15
+
16
+ ```text
17
+ AI agent (e.g. Claude Code, MCP Client) ↔ MCP Server (stdio) ↔ WebSocket Server :3002 ↔ RemNote Plugin ↔ RemNote
18
+ ```
19
+
20
+ The server acts as a bridge:
21
+
22
+ - Communicates with Claude Code via stdio transport (MCP protocol)
23
+ - Runs a WebSocket server (port 3002) that the RemNote browser plugin connects to
24
+ - Translates MCP tool calls into RemNote API actions
25
+
26
+ ## Features
27
+
28
+ - **Create Notes** - Create new notes with optional parent hierarchy and tags
29
+ - **Search Knowledge Base** - Full-text search with configurable result limits
30
+ - **Read Notes** - Retrieve note content with configurable child depth
31
+ - **Update Notes** - Modify titles, append content, add/remove tags
32
+ - **Journal Entries** - Append timestamped entries to daily documents
33
+ - **Connection Status** - Check server and plugin connection health
34
+
35
+ ## Important Limitations
36
+
37
+ **This MCP server enforces a strict 1:1:1 relationship:** one AI agent ↔ one MCP server instance ↔ one RemNote plugin
38
+ connection.
39
+
40
+ ### Multi-Agent Constraints
41
+
42
+ You **cannot** use multiple AI agents (e.g., two Claude Code sessions) with the same RemNote knowledge base
43
+ simultaneously. Three architectural constraints prevent this:
44
+
45
+ 1. **stdio transport is point-to-point** - Each MCP server process communicates with exactly one AI agent via
46
+ stdin/stdout. The transport protocol doesn't support multiple clients.
47
+ 2. **WebSocket enforces single-client** - The server explicitly rejects multiple RemNote plugin connections. Only one
48
+ plugin instance can connect to port 3002 at a time (connection code: 1008).
49
+ 3. **Port binding conflict** - Multiple server instances attempting to use the default port 3002 will fail with
50
+ `EADDRINUSE`.
51
+
52
+ ### Practical Implications
53
+
54
+ - **One agent at a time** - Close one Claude Code session before starting another if both need RemNote access
55
+ - **No concurrent access** - Cannot have multiple AI assistants modifying your RemNote knowledge base simultaneously
56
+ - **Separate workspaces don't help** - Even with different ports, only one plugin instance can connect to RemNote at a
57
+ time
58
+
59
+ ### Alternative Approach
60
+
61
+ If you need multiple AI agents with separate note-taking systems, use separate RemNote accounts/workspaces and configure
62
+ each with its own MCP server instance on different ports.
63
+
64
+ ### Future Plans
65
+
66
+ **HTTP transport migration planned** - The single-agent limitation is a temporary architectural constraint. A future
67
+ version will migrate from stdio transport to HTTP transport (SSE), which would allow multiple AI agents to connect
68
+ to the same MCP server instance simultaneously. This would remove constraint #1 above while maintaining the existing
69
+ WebSocket bridge to RemNote.
70
+
71
+ ## Prerequisites
72
+
73
+ - **Node.js** >= 18.0.0
74
+ - **RemNote app** with [RemNote MCP Bridge plugin](https://github.com/robert7/remnote-mcp-bridge) installed
75
+ - **Claude Code CLI** installed and configured
76
+
77
+ ## Installation
78
+
79
+ ### 1. Install the MCP Server
80
+
81
+ **From source (recommended for development):**
82
+
83
+ ```bash
84
+ git clone https://github.com/robert7/remnote-mcp-server.git
85
+ cd remnote-mcp-server
86
+ npm install
87
+ npm run build
88
+
89
+ # Creates global symlink: makes remnote-mcp-server command available system-wide
90
+ npm link
91
+
92
+ # Verify it worked
93
+ which remnote-mcp-server
94
+ # Should output e.g.: /Users/<username>/.nvm/versions/node/<version>/bin/remnote-mcp-server
95
+ ```
96
+
97
+ **What npm link does:** Creates a symbolic link from your global `node_modules` bin directory to this project's
98
+ executable, allowing Claude Code to launch `remnote-mcp-server` from anywhere without publishing to npm.
99
+
100
+ **Important:** Claude Code CLI must have access to the same Node.js environment where you ran `npm link`. If Claude Code
101
+ uses a different Node.js version or environment (e.g., different shell PATH), it won't find the command. Ensure your
102
+ shell configuration (`.bashrc`, `.zshrc`) properly exposes your Node.js environment.
103
+
104
+ **About stdio transport**
105
+
106
+ This MCP server uses [stdio transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#stdio),
107
+ the preferred communication mechanism for MCP. In stdio transport, Claude Code launches the server as a subprocess and
108
+ exchanges JSON-RPC messages via standard input/output streams.
109
+
110
+ **Key characteristics:**
111
+
112
+ - **Lifecycle management**: Claude Code automatically starts the server when it launches and stops it on exit. The
113
+ server is launched as a subprocess, not a standalone service.
114
+ - **Message protocol**: Communication uses newline-delimited JSON-RPC messages on stdin (client → server) and stdout
115
+ (server → client). No HTTP/REST endpoints are exposed.
116
+ - **Logging constraint**: stdout is reserved exclusively for MCP protocol messages. All logging must go to stderr, which
117
+ is why the codebase uses `console.error()` for logs.
118
+
119
+ This architecture provides tight integration with Claude Code while maintaining process isolation and security
120
+ boundaries. For technical details, see the [MCP
121
+ specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports).
122
+
123
+ ### 2. Install RemNote MCP Bridge Plugin
124
+
125
+ Install the [RemNote MCP Bridge plugin](https://github.com/robert7/remnote-mcp-bridge) in your RemNote app:
126
+
127
+ 1. Open RemNote
128
+ 2. Navigate to plugin installation (see plugin repository for instructions)
129
+ 3. Configure WebSocket URL: `ws://127.0.0.1:3002`
130
+ 4. Enable auto-reconnect
131
+
132
+ ### 3. Configure Claude Code CLI
133
+
134
+ MCP servers are configured in `~/.claude.json` under the `mcpServers` key within project-specific sections.
135
+
136
+ **Add to your `~/.claude.json`:**
137
+
138
+ ```json
139
+ {
140
+ "projects": {
141
+ "/Users/username": {
142
+ "mcpServers": {
143
+ "remnote": {
144
+ "type": "stdio",
145
+ "command": "remnote-mcp-server",
146
+ "args": [],
147
+ "env": {
148
+ "REMNOTE_WS_PORT": "3002"
149
+ }
150
+ }
151
+ }
152
+ }
153
+ }
154
+ }
155
+ ```
156
+
157
+ **Configuration Notes:**
158
+
159
+ - **Global availability:** Use your home directory path (`/Users/username`) to make RemNote tools available in all
160
+ projects
161
+ - **Project-specific:** Use a specific project path to limit availability to that project
162
+ - **Multiple projects:** Add `mcpServers` configuration under each project path as needed
163
+
164
+ **Example with multiple projects:**
165
+
166
+ ```json
167
+ {
168
+ "projects": {
169
+ "/Users/username": {
170
+ "mcpServers": {
171
+ "remnote": {
172
+ "type": "stdio",
173
+ "command": "remnote-mcp-server",
174
+ "args": [],
175
+ "env": {
176
+ "REMNOTE_WS_PORT": "3002"
177
+ }
178
+ }
179
+ }
180
+ },
181
+ "/Users/username/Projects/my-project": {
182
+ "mcpServers": {
183
+ "remnote": {
184
+ "type": "stdio",
185
+ "command": "remnote-mcp-server",
186
+ "args": [],
187
+ "env": {
188
+ "REMNOTE_WS_PORT": "3002"
189
+ }
190
+ }
191
+ }
192
+ }
193
+ }
194
+ }
195
+ ```
196
+
197
+ ### 4. Restart Claude Code
198
+
199
+ Restart Claude Code completely to load the MCP server configuration. The server will start automatically when Claude
200
+ Code launches.
201
+
202
+ ## Verification
203
+
204
+ ### Check Server is Running
205
+
206
+ After Claude Code restarts, verify the server started:
207
+
208
+ ```bash
209
+ # Check process is running
210
+ ps aux | grep remnote-mcp-server
211
+
212
+ # Check WebSocket port is listening
213
+ lsof -i :3002
214
+ ```
215
+
216
+ You should see the `remnote-mcp-server` process running.
217
+
218
+ ### Check RemNote Plugin Connection
219
+
220
+ Open RemNote with the MCP Bridge plugin installed. The plugin control panel should show:
221
+
222
+ - **Status:** "Connected" (green)
223
+ - **Server:** ws://127.0.0.1:3002
224
+ - Connection timestamp
225
+
226
+ ### Test in Claude Code
227
+
228
+ In any Claude Code session, try:
229
+
230
+ ```
231
+ Use remnote_status to check the connection
232
+ ```
233
+
234
+ Expected response:
235
+
236
+ ```json
237
+ {
238
+ "connected": true,
239
+ "actionsProcessed": 0,
240
+ "pluginVersion": "1.1.0",
241
+ "timestamp": "2026-02-07T..."
242
+ }
243
+ ```
244
+
245
+ ### Test RemNote Integration
246
+
247
+ Try creating a note:
248
+
249
+ ```
250
+ Create a RemNote note titled "MCP Test" with content "Testing the bridge"
251
+ ```
252
+
253
+ This should use the `remnote_create_note` tool and create a new note in your RemNote knowledge base.
254
+
255
+ ## Available Tools
256
+
257
+ | Tool | Description | Parameters |
258
+ |------|-------------|------------|
259
+ | `remnote_create_note` | Create a new note with optional parent and tags | `title`, `content`, `parentId`, `tags` |
260
+ | `remnote_search` | Search knowledge base | `query`, `limit`, `includeContent` |
261
+ | `remnote_read_note` | Read note by RemNote ID | `remId`, `depth` |
262
+ | `remnote_update_note` | Update title, append content, or modify tags | `remId`, `title`, `appendContent`, `addTags`, `removeTags` |
263
+ | `remnote_append_journal` | Append to today's daily document | `content`, `timestamp` |
264
+ | `remnote_status` | Check connection status and statistics | _(no parameters)_ |
265
+
266
+ ## Example Usage
267
+
268
+ ### Conversational Commands
269
+
270
+ Claude Code will automatically select the appropriate tool based on your natural language commands:
271
+
272
+ **Create notes:**
273
+ ```
274
+ Create a note about "Project Ideas" with content:
275
+ - AI-powered note taking
276
+ - Personal knowledge management
277
+ ```
278
+
279
+ **Search:**
280
+ ```
281
+ Search my RemNote for notes about "machine learning"
282
+ ```
283
+
284
+ **Read specific notes:**
285
+ ```
286
+ Read the note with ID abc123
287
+ ```
288
+
289
+ **Update notes:**
290
+ ```
291
+ Add a tag "important" to note abc123
292
+ ```
293
+
294
+ **Journal entries:**
295
+ ```
296
+ Add to my journal: "Completed the RemNote MCP integration"
297
+ ```
298
+
299
+ **Check status:**
300
+ ```
301
+ Check if RemNote is connected
302
+ ```
303
+
304
+ ## Configuration
305
+
306
+ ### Environment Variables
307
+
308
+ - `REMNOTE_WS_PORT` - WebSocket server port (default: 3002)
309
+
310
+ **Example with custom port:**
311
+
312
+ ```json
313
+ {
314
+ "projects": {
315
+ "/Users/username": {
316
+ "mcpServers": {
317
+ "remnote": {
318
+ "type": "stdio",
319
+ "command": "remnote-mcp-server",
320
+ "args": [],
321
+ "env": {
322
+ "REMNOTE_WS_PORT": "3003"
323
+ }
324
+ }
325
+ }
326
+ }
327
+ }
328
+ }
329
+ ```
330
+
331
+ **Note:** If you change the port, you must also update the WebSocket URL in the RemNote MCP Bridge plugin settings.
332
+
333
+ ### RemNote Plugin Settings
334
+
335
+ Configure in the plugin control panel:
336
+
337
+ - **WebSocket URL:** `ws://127.0.0.1:3002` (or your custom port)
338
+ - **Auto-reconnect:** Enabled (recommended)
339
+
340
+ ## Troubleshooting
341
+
342
+ ### Server Not Starting
343
+
344
+ 1. **Check if globally linked:**
345
+ ```bash
346
+ which remnote-mcp-server
347
+ ```
348
+ Should return a path to the executable.
349
+
350
+ 2. **Re-link if needed:**
351
+ ```bash
352
+ cd ~/Projects/_private/remnote-mcp-server
353
+ npm link
354
+ ```
355
+
356
+ 3. **Check Claude Code logs:**
357
+ ```bash
358
+ tail -f ~/.claude/debug/mcp-*.log
359
+ ```
360
+
361
+ ### Port 3002 Already in Use
362
+
363
+ If you see "EADDRINUSE" error:
364
+
365
+ ```bash
366
+ # Find what's using the port
367
+ lsof -i :3002
368
+
369
+ # Kill the process if needed
370
+ kill -9 <PID>
371
+ ```
372
+
373
+ Alternatively, configure a different port in both `~/.claude.json` and the RemNote plugin settings.
374
+
375
+ ### Plugin Won't Connect
376
+
377
+ 1. **Verify plugin settings in RemNote:**
378
+ - WebSocket URL: `ws://127.0.0.1:3002`
379
+ - Auto-reconnect: Enabled
380
+ 2. **Check plugin console (RemNote Developer Tools):**
381
+ ```
382
+ Cmd+Option+I (macOS)
383
+ Ctrl+Shift+I (Windows/Linux)
384
+ ```
385
+
386
+ 3. **Restart RemNote** after changing settings
387
+ 4. **Check server logs** for connection messages
388
+
389
+ ### Tools Not Appearing in Claude Code
390
+
391
+ 1. **Verify configuration in `~/.claude.json`:**
392
+ ```bash
393
+ cat ~/.claude.json | grep -A 10 mcpServers
394
+ ```
395
+
396
+ 2. **Ensure configuration is under correct project path** (use home directory for global)
397
+ 3. **Restart Claude Code completely** (not just reload)
398
+ 4. **Check MCP logs:**
399
+ ```bash
400
+ tail -f ~/.claude/debug/mcp-*.log
401
+ ```
402
+
403
+ ### Configuration Not Working
404
+
405
+ **Common issue:** Using the old `~/.claude/.mcp.json` file format
406
+
407
+ ❌ **Old format (deprecated):**
408
+ ```json
409
+ // File: ~/.claude/.mcp.json
410
+ {
411
+ "remnote": { ... }
412
+ }
413
+ ```
414
+
415
+ ✅ **Correct format:**
416
+ ```json
417
+ // File: ~/.claude.json
418
+ {
419
+ "projects": {
420
+ "/Users/username": {
421
+ "mcpServers": {
422
+ "remnote": { ... }
423
+ }
424
+ }
425
+ }
426
+ }
427
+ ```
428
+
429
+ The `enabledMcpjsonServers` setting in `~/.claude/settings.json` is also deprecated and no longer needed.
430
+
431
+ ## Development
432
+
433
+ ### Setup
434
+
435
+ ```bash
436
+ npm install
437
+ npm run build
438
+ npm link # Make command globally available
439
+ ```
440
+
441
+ ### Development Workflow
442
+
443
+ ```bash
444
+ npm run dev # Watch mode with hot reload
445
+ npm run typecheck # Type checking only
446
+ npm run build # Production build
447
+ ```
448
+
449
+ ### Testing
450
+
451
+ ```bash
452
+ npm test # Run all tests
453
+ npm run test:watch # Watch mode
454
+ npm run test:coverage # With coverage report
455
+ ```
456
+
457
+ ### Code Quality
458
+
459
+ ```bash
460
+ ./code-quality.sh # Run all checks
461
+ npm run lint # ESLint only
462
+ npm run format # Format code
463
+ ```
464
+
465
+ ### Before Committing
466
+
467
+ Run `./code-quality.sh` to ensure all checks pass.
468
+
469
+ ### Manual Testing
470
+
471
+ To test the server independently (without Claude Code):
472
+
473
+ ```bash
474
+ # Stop Claude Code first to free port 3002
475
+ cd ~/Projects/_private/remnote-mcp-server
476
+ npm run dev
477
+ ```
478
+
479
+ Expected output:
480
+ ```
481
+ [WebSocket Server] Listening on port 3002
482
+ [MCP Server] Server started on stdio
483
+ ```
484
+
485
+ When the RemNote plugin connects:
486
+ ```
487
+ [WebSocket Server] Client connected
488
+ [RemNote Bridge] RemNote plugin connected
489
+ ```
490
+
491
+ Press Ctrl+C to stop.
492
+
493
+ ### Development Documentation
494
+
495
+ - **[IMPLEMENTATION.md](./IMPLEMENTATION.md)** - Technical implementation details
496
+ - **[AGENTS.md](./AGENTS.md)** - AI agent and developer guidance
497
+ - **[CHANGELOG.md](./CHANGELOG.md)** - Version history
498
+
499
+ ## Related Projects
500
+
501
+ - [RemNote MCP Bridge Plugin](https://github.com/robert7/remnote-mcp-bridge) - Browser plugin for RemNote integration
502
+ - [Model Context Protocol](https://modelcontextprotocol.io/) - Open protocol for AI-application integration
503
+
504
+ ## License
505
+
506
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { createRequire } from 'module';
5
+ import { WebSocketServer } from './websocket-server.js';
6
+ import { registerAllTools } from './tools/index.js';
7
+ const require = createRequire(import.meta.url);
8
+ const packageJson = require('../package.json');
9
+ const WS_PORT = parseInt(process.env.REMNOTE_WS_PORT || '3002', 10);
10
+ async function main() {
11
+ // Initialize MCP server
12
+ const mcpServer = new Server({
13
+ name: 'remnote-mcp-server',
14
+ version: packageJson.version,
15
+ }, {
16
+ capabilities: {
17
+ tools: {},
18
+ },
19
+ });
20
+ // Initialize WebSocket server for RemNote plugin
21
+ const wsServer = new WebSocketServer(WS_PORT);
22
+ // Log connection status to stderr (stdio reserved for MCP)
23
+ wsServer.onClientConnect(() => {
24
+ console.error('[RemNote Bridge] RemNote plugin connected');
25
+ });
26
+ wsServer.onClientDisconnect(() => {
27
+ console.error('[RemNote Bridge] RemNote plugin disconnected');
28
+ });
29
+ // Start WebSocket server
30
+ await wsServer.start();
31
+ console.error(`[WebSocket Server] Listening on port ${WS_PORT}`);
32
+ // Register all RemNote MCP tools
33
+ registerAllTools(mcpServer, wsServer);
34
+ // Set up stdio transport for MCP
35
+ const transport = new StdioServerTransport();
36
+ await mcpServer.connect(transport);
37
+ console.error('[MCP Server] Server started on stdio');
38
+ // Graceful shutdown
39
+ const shutdown = async () => {
40
+ console.error('[MCP Server] Shutting down...');
41
+ await wsServer.stop();
42
+ await mcpServer.close();
43
+ process.exit(0);
44
+ };
45
+ process.on('SIGINT', shutdown);
46
+ process.on('SIGTERM', shutdown);
47
+ }
48
+ main().catch((error) => {
49
+ console.error('[MCP Server] Fatal error:', error);
50
+ process.exit(1);
51
+ });
52
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAE/C,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;AAEpE,KAAK,UAAU,IAAI;IACjB,wBAAwB;IACxB,MAAM,SAAS,GAAG,IAAI,MAAM,CAC1B;QACE,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,WAAW,CAAC,OAAO;KAC7B,EACD;QACE,YAAY,EAAE;YACZ,KAAK,EAAE,EAAE;SACV;KACF,CACF,CAAC;IAEF,iDAAiD;IACjD,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,OAAO,CAAC,CAAC;IAE9C,2DAA2D;IAC3D,QAAQ,CAAC,eAAe,CAAC,GAAG,EAAE;QAC5B,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kBAAkB,CAAC,GAAG,EAAE;QAC/B,OAAO,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,yBAAyB;IACzB,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC;IACvB,OAAO,CAAC,KAAK,CAAC,wCAAwC,OAAO,EAAE,CAAC,CAAC;IAEjE,iCAAiC;IACjC,gBAAgB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAEtC,iCAAiC;IACjC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEnC,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAEtD,oBAAoB;IACpB,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;QAC/C,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACtB,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;IAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { z } from 'zod';
2
+ export declare const CreateNoteSchema: z.ZodObject<{
3
+ title: z.ZodString;
4
+ content: z.ZodOptional<z.ZodString>;
5
+ parentId: z.ZodOptional<z.ZodString>;
6
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
7
+ }, z.core.$strip>;
8
+ export declare const SearchSchema: z.ZodObject<{
9
+ query: z.ZodString;
10
+ limit: z.ZodDefault<z.ZodNumber>;
11
+ includeContent: z.ZodDefault<z.ZodBoolean>;
12
+ }, z.core.$strip>;
13
+ export declare const ReadNoteSchema: z.ZodObject<{
14
+ remId: z.ZodString;
15
+ depth: z.ZodDefault<z.ZodNumber>;
16
+ }, z.core.$strip>;
17
+ export declare const UpdateNoteSchema: z.ZodObject<{
18
+ remId: z.ZodString;
19
+ title: z.ZodOptional<z.ZodString>;
20
+ appendContent: z.ZodOptional<z.ZodString>;
21
+ addTags: z.ZodOptional<z.ZodArray<z.ZodString>>;
22
+ removeTags: z.ZodOptional<z.ZodArray<z.ZodString>>;
23
+ }, z.core.$strip>;
24
+ export declare const AppendJournalSchema: z.ZodObject<{
25
+ content: z.ZodString;
26
+ timestamp: z.ZodDefault<z.ZodBoolean>;
27
+ }, z.core.$strip>;
@@ -0,0 +1,28 @@
1
+ import { z } from 'zod';
2
+ export const CreateNoteSchema = z.object({
3
+ title: z.string().describe('The title of the note'),
4
+ content: z.string().optional().describe('Content as child bullets (newline-separated)'),
5
+ parentId: z.string().optional().describe('Parent Rem ID'),
6
+ tags: z.array(z.string()).optional().describe('Tags to apply'),
7
+ });
8
+ export const SearchSchema = z.object({
9
+ query: z.string().describe('Search query text'),
10
+ limit: z.number().int().min(1).max(100).default(20).describe('Maximum results'),
11
+ includeContent: z.boolean().default(false).describe('Include child content'),
12
+ });
13
+ export const ReadNoteSchema = z.object({
14
+ remId: z.string().describe('The Rem ID to read'),
15
+ depth: z.number().int().min(0).max(10).default(3).describe('Depth of children'),
16
+ });
17
+ export const UpdateNoteSchema = z.object({
18
+ remId: z.string().describe('The Rem ID to update'),
19
+ title: z.string().optional().describe('New title'),
20
+ appendContent: z.string().optional().describe('Content to append as children'),
21
+ addTags: z.array(z.string()).optional().describe('Tags to add'),
22
+ removeTags: z.array(z.string()).optional().describe('Tags to remove'),
23
+ });
24
+ export const AppendJournalSchema = z.object({
25
+ content: z.string().describe("Content to append to today's daily document"),
26
+ timestamp: z.boolean().default(true).describe('Include timestamp'),
27
+ });
28
+ //# sourceMappingURL=remnote-schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remnote-schemas.js","sourceRoot":"","sources":["../../src/schemas/remnote-schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;IACnD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;IACvF,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;IACzD,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;CAC/D,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IAC/E,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,uBAAuB,CAAC;CAC7E,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oBAAoB,CAAC;IAChD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC;CAChF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;IAClD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;IAClD,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;IAC9E,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;IAC/D,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;CACtE,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6CAA6C,CAAC;IAC3E,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC;CACnE,CAAC,CAAC"}
@@ -0,0 +1,134 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { WebSocketServer } from '../websocket-server.js';
3
+ export declare const CREATE_NOTE_TOOL: {
4
+ name: string;
5
+ description: string;
6
+ inputSchema: {
7
+ type: "object";
8
+ properties: {
9
+ title: {
10
+ type: string;
11
+ description: string;
12
+ };
13
+ content: {
14
+ type: string;
15
+ description: string;
16
+ };
17
+ parentId: {
18
+ type: string;
19
+ description: string;
20
+ };
21
+ tags: {
22
+ type: string;
23
+ items: {
24
+ type: string;
25
+ };
26
+ description: string;
27
+ };
28
+ };
29
+ required: string[];
30
+ };
31
+ };
32
+ export declare const SEARCH_TOOL: {
33
+ name: string;
34
+ description: string;
35
+ inputSchema: {
36
+ type: "object";
37
+ properties: {
38
+ query: {
39
+ type: string;
40
+ description: string;
41
+ };
42
+ limit: {
43
+ type: string;
44
+ description: string;
45
+ };
46
+ includeContent: {
47
+ type: string;
48
+ description: string;
49
+ };
50
+ };
51
+ required: string[];
52
+ };
53
+ };
54
+ export declare const READ_NOTE_TOOL: {
55
+ name: string;
56
+ description: string;
57
+ inputSchema: {
58
+ type: "object";
59
+ properties: {
60
+ remId: {
61
+ type: string;
62
+ description: string;
63
+ };
64
+ depth: {
65
+ type: string;
66
+ description: string;
67
+ };
68
+ };
69
+ required: string[];
70
+ };
71
+ };
72
+ export declare const UPDATE_NOTE_TOOL: {
73
+ name: string;
74
+ description: string;
75
+ inputSchema: {
76
+ type: "object";
77
+ properties: {
78
+ remId: {
79
+ type: string;
80
+ description: string;
81
+ };
82
+ title: {
83
+ type: string;
84
+ description: string;
85
+ };
86
+ appendContent: {
87
+ type: string;
88
+ description: string;
89
+ };
90
+ addTags: {
91
+ type: string;
92
+ items: {
93
+ type: string;
94
+ };
95
+ description: string;
96
+ };
97
+ removeTags: {
98
+ type: string;
99
+ items: {
100
+ type: string;
101
+ };
102
+ description: string;
103
+ };
104
+ };
105
+ required: string[];
106
+ };
107
+ };
108
+ export declare const APPEND_JOURNAL_TOOL: {
109
+ name: string;
110
+ description: string;
111
+ inputSchema: {
112
+ type: "object";
113
+ properties: {
114
+ content: {
115
+ type: string;
116
+ description: string;
117
+ };
118
+ timestamp: {
119
+ type: string;
120
+ description: string;
121
+ };
122
+ };
123
+ required: string[];
124
+ };
125
+ };
126
+ export declare const STATUS_TOOL: {
127
+ name: string;
128
+ description: string;
129
+ inputSchema: {
130
+ type: "object";
131
+ properties: {};
132
+ };
133
+ };
134
+ export declare function registerAllTools(server: Server, wsServer: WebSocketServer): void;
@@ -0,0 +1,171 @@
1
+ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
2
+ import { CreateNoteSchema } from '../schemas/remnote-schemas.js';
3
+ import { SearchSchema } from '../schemas/remnote-schemas.js';
4
+ import { ReadNoteSchema } from '../schemas/remnote-schemas.js';
5
+ import { UpdateNoteSchema } from '../schemas/remnote-schemas.js';
6
+ import { AppendJournalSchema } from '../schemas/remnote-schemas.js';
7
+ export const CREATE_NOTE_TOOL = {
8
+ name: 'remnote_create_note',
9
+ description: 'Create a new note in RemNote with optional content, parent, and tags',
10
+ inputSchema: {
11
+ type: 'object',
12
+ properties: {
13
+ title: { type: 'string', description: 'The title of the note' },
14
+ content: { type: 'string', description: 'Content as child bullets (newline-separated)' },
15
+ parentId: { type: 'string', description: 'Parent Rem ID' },
16
+ tags: { type: 'array', items: { type: 'string' }, description: 'Tags to apply' },
17
+ },
18
+ required: ['title'],
19
+ },
20
+ };
21
+ export const SEARCH_TOOL = {
22
+ name: 'remnote_search',
23
+ description: 'Search the RemNote knowledge base for notes matching a query',
24
+ inputSchema: {
25
+ type: 'object',
26
+ properties: {
27
+ query: { type: 'string', description: 'Search query text' },
28
+ limit: { type: 'number', description: 'Maximum results (1-100, default: 20)' },
29
+ includeContent: { type: 'boolean', description: 'Include child content (default: false)' },
30
+ },
31
+ required: ['query'],
32
+ },
33
+ };
34
+ export const READ_NOTE_TOOL = {
35
+ name: 'remnote_read_note',
36
+ description: 'Read a specific note from RemNote by its Rem ID',
37
+ inputSchema: {
38
+ type: 'object',
39
+ properties: {
40
+ remId: { type: 'string', description: 'The Rem ID to read' },
41
+ depth: { type: 'number', description: 'Depth of children to include (0-10, default: 3)' },
42
+ },
43
+ required: ['remId'],
44
+ },
45
+ };
46
+ export const UPDATE_NOTE_TOOL = {
47
+ name: 'remnote_update_note',
48
+ description: 'Update an existing note in RemNote (change title, append content, or modify tags)',
49
+ inputSchema: {
50
+ type: 'object',
51
+ properties: {
52
+ remId: { type: 'string', description: 'The Rem ID to update' },
53
+ title: { type: 'string', description: 'New title' },
54
+ appendContent: { type: 'string', description: 'Content to append as children' },
55
+ addTags: { type: 'array', items: { type: 'string' }, description: 'Tags to add' },
56
+ removeTags: { type: 'array', items: { type: 'string' }, description: 'Tags to remove' },
57
+ },
58
+ required: ['remId'],
59
+ },
60
+ };
61
+ export const APPEND_JOURNAL_TOOL = {
62
+ name: 'remnote_append_journal',
63
+ description: "Append content to today's daily document in RemNote",
64
+ inputSchema: {
65
+ type: 'object',
66
+ properties: {
67
+ content: { type: 'string', description: "Content to append to today's daily document" },
68
+ timestamp: { type: 'boolean', description: 'Include timestamp (default: true)' },
69
+ },
70
+ required: ['content'],
71
+ },
72
+ };
73
+ export const STATUS_TOOL = {
74
+ name: 'remnote_status',
75
+ description: 'Check the connection status and statistics of the RemNote MCP bridge',
76
+ inputSchema: {
77
+ type: 'object',
78
+ properties: {},
79
+ },
80
+ };
81
+ export function registerAllTools(server, wsServer) {
82
+ // Single CallTool handler for all tools
83
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
84
+ try {
85
+ switch (request.params.name) {
86
+ case 'remnote_create_note': {
87
+ const args = CreateNoteSchema.parse(request.params.arguments);
88
+ const result = await wsServer.sendRequest('create_note', args);
89
+ return {
90
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
91
+ };
92
+ }
93
+ case 'remnote_search': {
94
+ const args = SearchSchema.parse(request.params.arguments);
95
+ const result = await wsServer.sendRequest('search', args);
96
+ return {
97
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
98
+ };
99
+ }
100
+ case 'remnote_read_note': {
101
+ const args = ReadNoteSchema.parse(request.params.arguments);
102
+ const result = await wsServer.sendRequest('read_note', args);
103
+ return {
104
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
105
+ };
106
+ }
107
+ case 'remnote_update_note': {
108
+ const args = UpdateNoteSchema.parse(request.params.arguments);
109
+ const result = await wsServer.sendRequest('update_note', args);
110
+ return {
111
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
112
+ };
113
+ }
114
+ case 'remnote_append_journal': {
115
+ const args = AppendJournalSchema.parse(request.params.arguments);
116
+ const result = await wsServer.sendRequest('append_journal', args);
117
+ return {
118
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
119
+ };
120
+ }
121
+ case 'remnote_status': {
122
+ const connected = wsServer.isConnected();
123
+ if (!connected) {
124
+ return {
125
+ content: [
126
+ {
127
+ type: 'text',
128
+ text: JSON.stringify({ connected: false, message: 'RemNote plugin not connected' }, null, 2),
129
+ },
130
+ ],
131
+ };
132
+ }
133
+ const result = await wsServer.sendRequest('status', {});
134
+ return {
135
+ content: [
136
+ {
137
+ type: 'text',
138
+ text: JSON.stringify({ connected: true, ...(typeof result === 'object' ? result : {}) }, null, 2),
139
+ },
140
+ ],
141
+ };
142
+ }
143
+ default:
144
+ throw new Error(`Unknown tool: ${request.params.name}`);
145
+ }
146
+ }
147
+ catch (error) {
148
+ return {
149
+ content: [
150
+ {
151
+ type: 'text',
152
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`,
153
+ },
154
+ ],
155
+ isError: true,
156
+ };
157
+ }
158
+ });
159
+ // Register list_tools handler
160
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
161
+ tools: [
162
+ CREATE_NOTE_TOOL,
163
+ SEARCH_TOOL,
164
+ READ_NOTE_TOOL,
165
+ UPDATE_NOTE_TOOL,
166
+ APPEND_JOURNAL_TOOL,
167
+ STATUS_TOOL,
168
+ ],
169
+ }));
170
+ }
171
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Request sent TO RemNote plugin
3
+ */
4
+ export interface BridgeRequest {
5
+ id: string;
6
+ action: string;
7
+ payload: Record<string, unknown>;
8
+ }
9
+ /**
10
+ * Response received FROM RemNote plugin
11
+ */
12
+ export interface BridgeResponse {
13
+ id: string;
14
+ result?: unknown;
15
+ error?: string;
16
+ }
17
+ /**
18
+ * Heartbeat messages
19
+ */
20
+ export interface HeartbeatPing {
21
+ type: 'ping';
22
+ }
23
+ export interface HeartbeatPong {
24
+ type: 'pong';
25
+ }
26
+ export type BridgeMessage = BridgeRequest | BridgeResponse | HeartbeatPing | HeartbeatPong;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/types/bridge.ts"],"names":[],"mappings":""}
@@ -0,0 +1,16 @@
1
+ export declare class WebSocketServer {
2
+ private wss;
3
+ private client;
4
+ private port;
5
+ private pendingRequests;
6
+ private connectCallbacks;
7
+ private disconnectCallbacks;
8
+ constructor(port: number);
9
+ start(): Promise<void>;
10
+ stop(): Promise<void>;
11
+ sendRequest(action: string, payload: Record<string, unknown>): Promise<unknown>;
12
+ isConnected(): boolean;
13
+ onClientConnect(callback: () => void): void;
14
+ onClientDisconnect(callback: () => void): void;
15
+ private handleMessage;
16
+ }
@@ -0,0 +1,143 @@
1
+ import { WebSocketServer as WSServer, WebSocket } from 'ws';
2
+ import { randomUUID } from 'crypto';
3
+ export class WebSocketServer {
4
+ wss = null;
5
+ client = null;
6
+ port;
7
+ pendingRequests = new Map();
8
+ connectCallbacks = [];
9
+ disconnectCallbacks = [];
10
+ constructor(port) {
11
+ this.port = port;
12
+ }
13
+ async start() {
14
+ return new Promise((resolve, reject) => {
15
+ this.wss = new WSServer({ port: this.port }, () => {
16
+ resolve();
17
+ });
18
+ this.wss.on('error', (error) => {
19
+ console.error('[WebSocket Server] Error:', error);
20
+ reject(error);
21
+ });
22
+ this.wss.on('connection', (ws) => {
23
+ // Only allow single client connection
24
+ if (this.client && this.client.readyState === WebSocket.OPEN) {
25
+ console.error('[WebSocket Server] Rejecting connection: client already connected');
26
+ ws.close(1008, 'Only one client allowed');
27
+ return;
28
+ }
29
+ this.client = ws;
30
+ console.error('[WebSocket Server] Client connected');
31
+ this.connectCallbacks.forEach((cb) => cb());
32
+ ws.on('message', (data) => {
33
+ try {
34
+ this.handleMessage(data.toString());
35
+ }
36
+ catch (error) {
37
+ console.error('[WebSocket Server] Error handling message:', error);
38
+ }
39
+ });
40
+ ws.on('close', () => {
41
+ console.error('[WebSocket Server] Client disconnected');
42
+ this.client = null;
43
+ // Reject all pending requests
44
+ for (const [_id, pending] of this.pendingRequests.entries()) {
45
+ clearTimeout(pending.timeout);
46
+ pending.reject(new Error('Connection lost'));
47
+ }
48
+ this.pendingRequests.clear();
49
+ this.disconnectCallbacks.forEach((cb) => cb());
50
+ });
51
+ ws.on('error', (error) => {
52
+ console.error('[WebSocket Server] Client error:', error);
53
+ });
54
+ });
55
+ });
56
+ }
57
+ async stop() {
58
+ return new Promise((resolve) => {
59
+ if (this.client) {
60
+ this.client.close();
61
+ this.client = null;
62
+ }
63
+ if (this.wss) {
64
+ this.wss.close(() => {
65
+ this.wss = null;
66
+ resolve();
67
+ });
68
+ }
69
+ else {
70
+ resolve();
71
+ }
72
+ });
73
+ }
74
+ async sendRequest(action, payload) {
75
+ if (!this.client || this.client.readyState !== WebSocket.OPEN) {
76
+ throw new Error('RemNote plugin not connected. Please ensure the plugin is installed and running.');
77
+ }
78
+ const id = randomUUID();
79
+ const request = { id, action, payload };
80
+ return new Promise((resolve, reject) => {
81
+ const timeout = setTimeout(() => {
82
+ this.pendingRequests.delete(id);
83
+ reject(new Error(`Request timeout: ${action}`));
84
+ }, 5000);
85
+ this.pendingRequests.set(id, { resolve, reject, timeout });
86
+ try {
87
+ this.client.send(JSON.stringify(request));
88
+ }
89
+ catch (error) {
90
+ clearTimeout(timeout);
91
+ this.pendingRequests.delete(id);
92
+ reject(error);
93
+ }
94
+ });
95
+ }
96
+ isConnected() {
97
+ return this.client !== null && this.client.readyState === WebSocket.OPEN;
98
+ }
99
+ onClientConnect(callback) {
100
+ this.connectCallbacks.push(callback);
101
+ }
102
+ onClientDisconnect(callback) {
103
+ this.disconnectCallbacks.push(callback);
104
+ }
105
+ handleMessage(data) {
106
+ try {
107
+ const message = JSON.parse(data);
108
+ // Handle pong response to ping
109
+ if ('type' in message && message.type === 'pong') {
110
+ return;
111
+ }
112
+ // Handle ping - respond with pong
113
+ if ('type' in message && message.type === 'ping') {
114
+ if (this.client && this.client.readyState === WebSocket.OPEN) {
115
+ this.client.send(JSON.stringify({ type: 'pong' }));
116
+ }
117
+ return;
118
+ }
119
+ // Handle response to our request
120
+ if ('id' in message) {
121
+ const response = message;
122
+ const pending = this.pendingRequests.get(response.id);
123
+ if (pending) {
124
+ clearTimeout(pending.timeout);
125
+ this.pendingRequests.delete(response.id);
126
+ if (response.error) {
127
+ pending.reject(new Error(response.error));
128
+ }
129
+ else {
130
+ pending.resolve(response.result);
131
+ }
132
+ }
133
+ else {
134
+ console.error('[WebSocket Server] Received response for unknown request ID:', response.id);
135
+ }
136
+ }
137
+ }
138
+ catch (error) {
139
+ console.error('[WebSocket Server] Error parsing message:', error);
140
+ }
141
+ }
142
+ }
143
+ //# sourceMappingURL=websocket-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket-server.js","sourceRoot":"","sources":["../src/websocket-server.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "remnote-mcp-server",
3
+ "version": "0.1.2",
4
+ "description": "MCP server bridge for RemNote knowledge base",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "remnote-mcp-server": "dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsx watch src/index.ts",
13
+ "start": "node dist/index.js",
14
+ "typecheck": "tsc --noEmit",
15
+ "prepublishOnly": "npm run build",
16
+ "test": "vitest run",
17
+ "test:watch": "vitest",
18
+ "test:coverage": "vitest run --coverage",
19
+ "test:ui": "vitest --ui",
20
+ "lint": "eslint src test --ext .ts",
21
+ "lint:fix": "eslint src test --ext .ts --fix",
22
+ "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
23
+ "format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
24
+ "quality": "./code-quality.sh",
25
+ "precommit": "./code-quality.sh"
26
+ },
27
+ "keywords": [
28
+ "mcp",
29
+ "remnote",
30
+ "model-context-protocol",
31
+ "knowledge-base",
32
+ "note-taking",
33
+ "ai",
34
+ "assistant",
35
+ "websocket",
36
+ "bridge"
37
+ ],
38
+ "author": "nightingale7 <nightingale7@gmail.com>",
39
+ "license": "MIT",
40
+ "files": [
41
+ "dist/",
42
+ "README.md",
43
+ "LICENSE",
44
+ "CHANGELOG.md"
45
+ ],
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "git+https://github.com/robert7/remnote-mcp-server.git"
49
+ },
50
+ "bugs": {
51
+ "url": "https://github.com/robert7/remnote-mcp-server/issues"
52
+ },
53
+ "homepage": "https://github.com/robert7/remnote-mcp-server#readme",
54
+ "dependencies": {
55
+ "@modelcontextprotocol/sdk": "^1.26.0",
56
+ "ws": "^8.19.0",
57
+ "zod": "^4.3.6"
58
+ },
59
+ "devDependencies": {
60
+ "@types/node": "^25.2.1",
61
+ "@types/ws": "^8.18.1",
62
+ "@typescript-eslint/eslint-plugin": "^6.21.0",
63
+ "@typescript-eslint/parser": "^6.21.0",
64
+ "@vitest/coverage-v8": "^1.6.1",
65
+ "@vitest/ui": "^1.6.1",
66
+ "eslint": "^8.57.1",
67
+ "eslint-config-prettier": "^9.1.2",
68
+ "prettier": "^3.8.1",
69
+ "tsx": "^4.21.0",
70
+ "typescript": "^5.9.3",
71
+ "vitest": "^1.6.1"
72
+ },
73
+ "engines": {
74
+ "node": ">=18.0.0"
75
+ }
76
+ }