# 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
