- Unified localStorage key to 'theme-preference' across all components
- Fixed header.tsx using wrong localStorage key ('theme' instead of 'theme-preference')
- Added localStorage hybrid persistence for instant theme changes
- Removed router.refresh() which was causing stale data revert
- Replaced Blue theme with Sepia
- Consolidated auth() calls to prevent race conditions
- Updated UserSettingsData types to include all themes
674 lines
12 KiB
Markdown
674 lines
12 KiB
Markdown
# Keep Notes MCP SSE Server
|
|
|
|
Server-Sent Events (SSE) version of Keep Notes MCP Server for remote N8N access.
|
|
|
|
## 🎯 Purpose
|
|
|
|
This SSE server allows N8N (or other MCP clients) running on **remote machines** to connect to Keep Notes via HTTP/SSE instead of stdio.
|
|
|
|
### stdio vs SSE
|
|
|
|
|| Feature | stdio (`index.js`) | SSE (`index-sse.js`) |
|
|
||---------|-------------------|---------------------|
|
|
|| **Connection** | Local process | Network HTTP |
|
|
|| **Remote access** | ❌ No | ✅ Yes |
|
|
|| **Use case** | Claude Desktop, local tools | N8N on remote machine |
|
|
|| **Port** | N/A | 3001 |
|
|
|| **Version** | 2.0.0 | 2.0.0 |
|
|
|| **Tools** | 19 | 19 |
|
|
|
|
## 🚀 Quick Start
|
|
|
|
### 1. Install Dependencies
|
|
|
|
```bash
|
|
cd mcp-server
|
|
npm install
|
|
```
|
|
|
|
### 2. Start Server
|
|
|
|
**Option A: PowerShell Script (Recommended)**
|
|
|
|
```powershell
|
|
.\start-sse.ps1
|
|
```
|
|
|
|
**Option B: Direct Node**
|
|
|
|
```bash
|
|
npm run start:sse
|
|
# or
|
|
node index-sse.js
|
|
```
|
|
|
|
### 3. Verify Server is Running
|
|
|
|
Open browser to: `http://localhost:3001`
|
|
|
|
You should see:
|
|
|
|
```json
|
|
{
|
|
"name": "Keep Notes MCP SSE Server",
|
|
"version": "2.0.0",
|
|
"status": "running",
|
|
"endpoints": {
|
|
"sse": "/sse",
|
|
"message": "/message"
|
|
}
|
|
}
|
|
```
|
|
|
|
## 🌐 Get Your IP Address
|
|
|
|
### Windows
|
|
|
|
```powershell
|
|
ipconfig
|
|
```
|
|
|
|
Look for "IPv4 Address" (usually 192.168.x.x)
|
|
|
|
### Mac/Linux
|
|
|
|
```bash
|
|
ifconfig
|
|
# or
|
|
ip addr show
|
|
```
|
|
|
|
## 🔌 N8N Configuration
|
|
|
|
### Method 1: MCP Client Community Node
|
|
|
|
If your N8N has MCP Client node installed:
|
|
|
|
1. Open N8N Settings → MCP Access
|
|
2. Add new server:
|
|
```json
|
|
{
|
|
"name": "keep-notes",
|
|
"transport": "sse",
|
|
"url": "http://YOUR_IP:3001/sse"
|
|
}
|
|
```
|
|
Replace `YOUR_IP` with your machine's IP (e.g., `192.168.1.100`)
|
|
|
|
3. Enable "Available in MCP" for your workflow
|
|
4. Use MCP Client node to call tools
|
|
|
|
### Method 2: HTTP Request Nodes (Fallback)
|
|
|
|
Use N8N's standard HTTP Request nodes with the REST API:
|
|
- POST `http://YOUR_IP:3000/api/notes` (Keep Notes REST API)
|
|
|
|
## 🛠️ Available Tools (19)
|
|
|
|
### Notes Tools (9)
|
|
|
|
#### 1. **create_note** - Create new note with full support
|
|
|
|
```json
|
|
{
|
|
"name": "create_note",
|
|
"arguments": {
|
|
"title": "My Note",
|
|
"content": "Note content",
|
|
"color": "blue",
|
|
"type": "text",
|
|
"checkItems": [{"id": "1", "text": "Task", "checked": false}],
|
|
"labels": ["work", "important"],
|
|
"isPinned": false,
|
|
"isArchived": false,
|
|
"images": ["data:image/png;base64,..."],
|
|
"links": ["https://example.com"],
|
|
"reminder": "2026-01-20T10:00:00Z",
|
|
"isReminderDone": false,
|
|
"reminderRecurrence": "daily",
|
|
"reminderLocation": "Office",
|
|
"isMarkdown": false,
|
|
"size": "medium",
|
|
"notebookId": "cuid..."
|
|
}
|
|
}
|
|
```
|
|
|
|
**New Fields (v2.0):**
|
|
- `links` - Note links as array
|
|
- `reminder` - Reminder date/time (ISO 8601)
|
|
- `isReminderDone` - Mark reminder as done
|
|
- `reminderRecurrence` - Reminder recurrence (daily, weekly, monthly, yearly)
|
|
- `reminderLocation` - Reminder location
|
|
- `isMarkdown` - Enable markdown support
|
|
- `size` - Note size (small, medium, large)
|
|
- `notebookId` - Associate note with notebook
|
|
|
|
#### 2. **get_notes** - Get all notes (supports filters)
|
|
|
|
```json
|
|
{
|
|
"name": "get_notes",
|
|
"arguments": {
|
|
"includeArchived": false,
|
|
"search": "optional search query",
|
|
"notebookId": "cuid...",
|
|
"fullDetails": false
|
|
}
|
|
}
|
|
```
|
|
|
|
**New Filters (v2.0):**
|
|
- `notebookId` - Filter by notebook
|
|
- `fullDetails` - Return full details including images (warning: large payload)
|
|
|
|
#### 3. **get_note** - Get specific note by ID
|
|
|
|
```json
|
|
{
|
|
"name": "get_note",
|
|
"arguments": {
|
|
"id": "cuid..."
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 4. **update_note** - Update existing note
|
|
|
|
Supports all fields from create_note. All are optional except `id`.
|
|
|
|
```json
|
|
{
|
|
"name": "update_note",
|
|
"arguments": {
|
|
"id": "cuid...",
|
|
"title": "Updated Title",
|
|
"color": "green",
|
|
"isPinned": true
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 5. **delete_note** - Delete note
|
|
|
|
```json
|
|
{
|
|
"name": "delete_note",
|
|
"arguments": {
|
|
"id": "cuid..."
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 6. **search_notes** - Search notes by query
|
|
|
|
```json
|
|
{
|
|
"name": "search_notes",
|
|
"arguments": {
|
|
"query": "project",
|
|
"notebookId": "cuid..."
|
|
}
|
|
}
|
|
```
|
|
|
|
**New (v2.0):** `notebookId` filter support
|
|
|
|
#### 7. **get_labels** - Get all unique labels (legacy method)
|
|
|
|
```json
|
|
{
|
|
"name": "get_labels",
|
|
"arguments": {}
|
|
}
|
|
```
|
|
|
|
#### 8. **toggle_pin** - Pin/unpin note
|
|
|
|
```json
|
|
{
|
|
"name": "toggle_pin",
|
|
"arguments": {
|
|
"id": "cuid..."
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 9. **toggle_archive** - Archive/unarchive note
|
|
|
|
```json
|
|
{
|
|
"name": "toggle_archive",
|
|
"arguments": {
|
|
"id": "cuid..."
|
|
}
|
|
}
|
|
```
|
|
|
|
### Notebooks Tools (5) - NEW in v2.0
|
|
|
|
#### 10. **create_notebook** - Create new notebook
|
|
|
|
```json
|
|
{
|
|
"name": "create_notebook",
|
|
"arguments": {
|
|
"name": "Work Projects",
|
|
"icon": "💼",
|
|
"color": "#3B82F6",
|
|
"order": 1
|
|
}
|
|
}
|
|
```
|
|
|
|
**Returns:** Notebook with labels and notes count
|
|
|
|
#### 11. **get_notebooks** - Get all notebooks
|
|
|
|
```json
|
|
{
|
|
"name": "get_notebooks",
|
|
"arguments": {}
|
|
}
|
|
```
|
|
|
|
**Returns:** Array of notebooks with labels and notes count
|
|
|
|
#### 12. **get_notebook** - Get notebook with notes
|
|
|
|
```json
|
|
{
|
|
"name": "get_notebook",
|
|
"arguments": {
|
|
"id": "cuid..."
|
|
}
|
|
}
|
|
```
|
|
|
|
**Returns:** Notebook with labels, notes (parsed), and notes count
|
|
|
|
#### 13. **update_notebook** - Update notebook
|
|
|
|
```json
|
|
{
|
|
"name": "update_notebook",
|
|
"arguments": {
|
|
"id": "cuid...",
|
|
"name": "Updated Name",
|
|
"icon": "📁",
|
|
"color": "#10B981"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 14. **delete_notebook** - Delete notebook
|
|
|
|
```json
|
|
{
|
|
"name": "delete_notebook",
|
|
"arguments": {
|
|
"id": "cuid..."
|
|
}
|
|
}
|
|
```
|
|
|
|
**Warning:** Deletes all notes in the notebook
|
|
|
|
### Labels Tools (5) - NEW in v2.0
|
|
|
|
#### 15. **create_label** - Create new label
|
|
|
|
```json
|
|
{
|
|
"name": "create_label",
|
|
"arguments": {
|
|
"name": "Important",
|
|
"color": "red",
|
|
"notebookId": "cuid..."
|
|
}
|
|
}
|
|
```
|
|
|
|
**Required:** `name` and `notebookId`
|
|
|
|
#### 16. **get_labels_detailed** - Get labels with details
|
|
|
|
```json
|
|
{
|
|
"name": "get_labels_detailed",
|
|
"arguments": {
|
|
"notebookId": "cuid..."
|
|
}
|
|
}
|
|
```
|
|
|
|
**Returns:** Labels with notebook information
|
|
|
|
#### 17. **update_label** - Update label
|
|
|
|
```json
|
|
{
|
|
"name": "update_label",
|
|
"arguments": {
|
|
"id": "cuid...",
|
|
"name": "Updated Name",
|
|
"color": "blue"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 18. **delete_label** - Delete label
|
|
|
|
```json
|
|
{
|
|
"name": "delete_label",
|
|
"arguments": {
|
|
"id": "cuid..."
|
|
}
|
|
}
|
|
```
|
|
|
|
## 🧪 Testing the SSE Server
|
|
|
|
### Test 1: Health Check
|
|
|
|
```bash
|
|
curl http://localhost:3001/
|
|
```
|
|
|
|
### Test 2: SSE Connection
|
|
|
|
```bash
|
|
curl -N http://localhost:3001/sse
|
|
```
|
|
|
|
### Test 3: Call a Tool (get_notes)
|
|
|
|
```bash
|
|
curl -X POST http://localhost:3001/message \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"jsonrpc": "2.0",
|
|
"method": "tools/call",
|
|
"params": {
|
|
"name": "get_notes",
|
|
"arguments": {}
|
|
},
|
|
"id": 1
|
|
}'
|
|
```
|
|
|
|
### Test 4: Create Note via MCP
|
|
|
|
```powershell
|
|
$body = @{
|
|
jsonrpc = "2.0"
|
|
method = "tools/call"
|
|
params = @{
|
|
name = "create_note"
|
|
arguments = @{
|
|
content = "Test from MCP SSE"
|
|
title = "SSE Test"
|
|
color = "green"
|
|
}
|
|
}
|
|
id = 1
|
|
} | ConvertTo-Json -Depth 5
|
|
|
|
Invoke-RestMethod -Method POST -Uri "http://localhost:3001/message" `
|
|
-Body $body -ContentType "application/json"
|
|
```
|
|
|
|
### Test 5: Create Notebook
|
|
|
|
```powershell
|
|
$body = @{
|
|
jsonrpc = "2.0"
|
|
method = "tools/call"
|
|
params = @{
|
|
name = "create_notebook"
|
|
arguments = @{
|
|
name = "Test Notebook"
|
|
icon = "📁"
|
|
color = "#3B82F6"
|
|
}
|
|
}
|
|
id = 1
|
|
} | ConvertTo-Json -Depth 5
|
|
|
|
Invoke-RestMethod -Method POST -Uri "http://localhost:3001/message" `
|
|
-Body $body -ContentType "application/json"
|
|
```
|
|
|
|
### Test 6: Create Label
|
|
|
|
```powershell
|
|
$body = @{
|
|
jsonrpc = "2.0"
|
|
method = "tools/call"
|
|
params = @{
|
|
name = "create_label"
|
|
arguments = @{
|
|
name = "Test Label"
|
|
color = "blue"
|
|
notebookId = "YOUR_NOTEBOOK_ID"
|
|
}
|
|
}
|
|
id = 1
|
|
} | ConvertTo-Json -Depth 5
|
|
|
|
Invoke-RestMethod -Method POST -Uri "http://localhost:3001/message" `
|
|
-Body $body -ContentType "application/json"
|
|
```
|
|
|
|
## 🔥 Troubleshooting
|
|
|
|
### Error: Prisma Client not initialized
|
|
|
|
**Solution**: Generate Prisma Client:
|
|
|
|
```bash
|
|
npx prisma generate
|
|
```
|
|
|
|
### Error: Port 3001 already in use
|
|
|
|
**Solution 1:** Change port in `index-sse.js`:
|
|
```javascript
|
|
const PORT = process.env.PORT || 3002;
|
|
```
|
|
|
|
**Solution 2:** Kill existing process:
|
|
```powershell
|
|
Get-Process node | Where-Object {$_.Path -like "*index-sse*"}
|
|
Stop-Process -Id $process.Id
|
|
```
|
|
|
|
### Error: Cannot connect from N8N
|
|
|
|
**Checklist:**
|
|
1. ✅ Server is running (`http://localhost:3001` works locally)
|
|
2. ✅ Firewall allows port 3001
|
|
3. ✅ Using correct IP address (not `localhost`)
|
|
4. ✅ N8N can reach your network
|
|
5. ✅ Using `http://` not `https://`
|
|
|
|
**Test connectivity from N8N machine:**
|
|
```bash
|
|
curl http://YOUR_IP:3001/
|
|
```
|
|
|
|
### SSE Connection Keeps Dropping
|
|
|
|
This is normal! SSE maintains a persistent connection. If it drops:
|
|
- Client should automatically reconnect
|
|
- Check network stability
|
|
- Verify firewall/proxy settings
|
|
|
|
## 🔒 Security Notes
|
|
|
|
⚠️ **This server has NO AUTHENTICATION!**
|
|
|
|
For production use:
|
|
1. Add API key authentication
|
|
2. Use HTTPS with SSL certificates
|
|
3. Restrict CORS origins
|
|
4. Use environment variables for secrets
|
|
5. Deploy behind a reverse proxy (nginx, Caddy)
|
|
|
|
### Add Basic API Key (Example)
|
|
|
|
```javascript
|
|
// In index-sse.js, add middleware:
|
|
app.use((req, res, next) => {
|
|
const apiKey = req.headers['x-api-key'];
|
|
if (apiKey !== process.env.MCP_API_KEY) {
|
|
return res.status(401).json({ error: 'Unauthorized' });
|
|
}
|
|
next();
|
|
});
|
|
```
|
|
|
|
## 📊 Endpoints
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/` | Health check |
|
|
| GET | `/sse` | SSE connection endpoint |
|
|
| POST | `/message` | MCP message handler |
|
|
|
|
## 🆚 Comparison with REST API
|
|
|
|
| Feature | MCP SSE | REST API |
|
|
|---------|---------|----------|
|
|
| **Protocol** | SSE (MCP) | HTTP JSON |
|
|
| **Port** | 3001 | 3000 (Next.js) |
|
|
| **Format** | MCP JSON-RPC | REST JSON |
|
|
| **Use case** | MCP clients | Standard HTTP clients |
|
|
| **Tools** | 19 MCP tools | 4 CRUD endpoints |
|
|
|
|
**Both work!** Use MCP SSE for proper MCP integration, or REST API for simpler HTTP requests.
|
|
|
|
## 🔄 Development Workflow
|
|
|
|
### Running Both Servers
|
|
|
|
**Terminal 1: Next.js + REST API**
|
|
```bash
|
|
cd keep-notes
|
|
npm run dev
|
|
# Runs on http://localhost:3000
|
|
```
|
|
|
|
**Terminal 2: MCP SSE Server**
|
|
```bash
|
|
cd mcp-server
|
|
npm run start:sse
|
|
# Runs on http://localhost:3001
|
|
```
|
|
|
|
**Terminal 3: MCP stdio (for Claude Desktop)**
|
|
```bash
|
|
cd mcp-server
|
|
npm start
|
|
# Runs as stdio process
|
|
```
|
|
|
|
## 📝 Configuration Examples
|
|
|
|
### N8N Workflow (MCP Client)
|
|
|
|
```json
|
|
{
|
|
"nodes": [
|
|
{
|
|
"name": "Get Keep Notes",
|
|
"type": "MCP Client",
|
|
"typeVersion": 1,
|
|
"position": [250, 300],
|
|
"parameters": {
|
|
"server": "keep-notes",
|
|
"tool": "get_notes",
|
|
"arguments": {
|
|
"includeArchived": false
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Create Notebook via MCP
|
|
|
|
```json
|
|
{
|
|
"name": "Create Notebook",
|
|
"type": "MCP Client",
|
|
"parameters": {
|
|
"server": "keep-notes",
|
|
"tool": "create_notebook",
|
|
"arguments": {
|
|
"name": "Work Projects",
|
|
"icon": "💼",
|
|
"color": "#3B82F6"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Create Label via MCP
|
|
|
|
```json
|
|
{
|
|
"name": "Create Label",
|
|
"type": "MCP Client",
|
|
"parameters": {
|
|
"server": "keep-notes",
|
|
"tool": "create_label",
|
|
"arguments": {
|
|
"name": "Important",
|
|
"color": "red",
|
|
"notebookId": "WORKBOOK_ID"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Claude Desktop Config (stdio)
|
|
|
|
Use original `index.js` with stdio:
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"keep-notes": {
|
|
"command": "node",
|
|
"args": ["D:/dev_new_pc/Keep/mcp-server/index.js"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## 🚀 N8N Integration Guide
|
|
|
|
See [N8N-SETUP.md](./N8N-SETUP.md) for complete N8N workflow setup and [N8N-WORKFLOWS.md](./N8N-WORKFLOWS.md) for available workflows.
|
|
|
|
## 📚 Resources
|
|
|
|
- [MCP Protocol Documentation](https://modelcontextprotocol.io)
|
|
- [Server-Sent Events Spec](https://html.spec.whatwg.org/multipage/server-sent-events.html)
|
|
- [N8N MCP Integration Guide](https://community.n8n.io)
|
|
- [Express.js Documentation](https://expressjs.com)
|
|
|
|
## 🤝 Support
|
|
|
|
Issues? Check:
|
|
1. [START-SSE.md](./START-SSE.md) - Quick start guide
|
|
2. [README.md](../README.md) - Main project README
|
|
3. [COMPLETED-FEATURES.md](../COMPLETED-FEATURES.md) - Implementation details
|
|
|
|
---
|
|
|
|
**Version**: 2.0.0
|
|
**Last Updated**: January 18, 2026
|
|
**Status**: ✅ Production Ready
|