@ainote/mcp 1.0.2 → 1.1.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/README.md +313 -8
- package/index.js +27 -225
- package/lib/auth/mcp-key.js +14 -0
- package/lib/auth/oauth.js +18 -0
- package/lib/auth/strategy-factory.js +31 -0
- package/lib/cli/signup.js +118 -0
- package/lib/core/api-client.js +1 -0
- package/lib/core/config-manager.js +67 -0
- package/lib/core/config.js +1 -0
- package/lib/core/mcp-server.js +2 -0
- package/lib/core/server-factory.js +82 -0
- package/lib/core/tool-registry.js +31 -0
- package/lib/tools/chatgpt-tools.js +93 -0
- package/lib/tools/dev-doc-tools.js +166 -0
- package/lib/tools/index.js +5 -0
- package/lib/tools/internal/formatters.js +80 -0
- package/lib/tools/onboarding-tools.js +124 -0
- package/lib/tools/shared-tools.js +246 -0
- package/lib/utils/api-client.js +79 -0
- package/package.json +48 -6
- package/server.js +99 -0
package/README.md
CHANGED
|
@@ -3,15 +3,19 @@
|
|
|
3
3
|
[](https://badge.fury.io/js/%40ainote%2Fmcp-server)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
A Model Context Protocol (MCP) server that connects
|
|
6
|
+
A Model Context Protocol (MCP) server that connects AI assistants to your AI Note task management system. This package enables direct interaction with your AI Note tasks through natural language conversations in Claude Desktop and other MCP-compatible platforms.
|
|
7
|
+
|
|
8
|
+
> 📚 **[Complete Project Guide](../docs/PROJECT_GUIDE.md)** - 전체 프로젝트 가이드 및 아키텍처 정보
|
|
7
9
|
|
|
8
10
|
## Table of Contents
|
|
9
11
|
|
|
12
|
+
- [Access Methods](#access-methods)
|
|
10
13
|
- [Features](#features)
|
|
11
14
|
- [Prerequisites](#prerequisites)
|
|
12
15
|
- [Installation](#installation)
|
|
13
16
|
- [Configuration](#configuration)
|
|
14
17
|
- [Usage](#usage)
|
|
18
|
+
- [HTTP Endpoint](#http-endpoint)
|
|
15
19
|
- [Available Tools](#available-tools)
|
|
16
20
|
- [API Reference](#api-reference)
|
|
17
21
|
- [Development](#development)
|
|
@@ -19,20 +23,115 @@ A Model Context Protocol (MCP) server that connects Claude Desktop to your AI No
|
|
|
19
23
|
- [Contributing](#contributing)
|
|
20
24
|
- [License](#license)
|
|
21
25
|
|
|
26
|
+
## Access Methods
|
|
27
|
+
|
|
28
|
+
AI Note MCP server is available through three transport options to cover different integration scenarios:
|
|
29
|
+
|
|
30
|
+
### 1. **stdio Mode (This Package)** - For Personal Use
|
|
31
|
+
- **Installation**: `npm install -g @ainote/mcp`
|
|
32
|
+
- **Usage**: Claude Desktop and other stdio-based MCP clients
|
|
33
|
+
- **Setup**: Local installation with API key configuration
|
|
34
|
+
- **Best for**: Individual users connecting their personal AI Note account to Claude Desktop
|
|
35
|
+
|
|
36
|
+
### 2. **Local SSE Bridge (ChatGPT / MCP Apps)**
|
|
37
|
+
- **Command**: `ainote-mcp-http`
|
|
38
|
+
- **Protocol**: Server-Sent Events (SSE) + JSON-RPC over HTTP POST
|
|
39
|
+
- **Usage**: ChatGPT Model Context Protocol connectors, other SSE-capable MCP clients
|
|
40
|
+
- **Setup**: Run locally alongside your browser; supports API key or (optional) OAuth bearer tokens
|
|
41
|
+
- **Best for**: Users wanting to expose AI Note tools to ChatGPT without deploying infrastructure
|
|
42
|
+
|
|
43
|
+
### 3. **Hosted HTTP Endpoint** - For Platform Integration
|
|
44
|
+
- **URL**: `https://api.ainote.dev/mcp`
|
|
45
|
+
- **Protocol**: JSON-RPC 2.0 over HTTP
|
|
46
|
+
- **Usage**: Platform integrations (Kakao PlayMCP, etc.)
|
|
47
|
+
- **Setup**: No installation required, direct API access
|
|
48
|
+
- **Best for**: Third-party platforms and services integrating AI Note functionality
|
|
49
|
+
|
|
50
|
+
All transports expose the same tool catalog. Choose the option that matches your hosting model and client capabilities.
|
|
51
|
+
|
|
22
52
|
## Features
|
|
23
53
|
|
|
24
54
|
- 📝 **Task Management**: Create, update, delete, and list tasks directly from Claude Desktop
|
|
55
|
+
- 📄 **Dev Docs**: Manage CLAUDE.md, Cursor rules, Windsurf rules, and dev documents centrally via MCP
|
|
56
|
+
- 🗂️ **Dev Category Hierarchy**: Auto-organized under `dev/` with subcategories (claude, cursor, windsurf, copilot, docs)
|
|
25
57
|
- 🏷️ **Category Support**: Organize tasks with categories
|
|
26
|
-
- 🔍 **Advanced
|
|
58
|
+
- 🔍 **Advanced Filtering**: 18+ filter options including date ranges, location, overdue tasks
|
|
27
59
|
- ⭐ **Priority Management**: Mark tasks as important
|
|
28
|
-
- 📅 **Due
|
|
29
|
-
- 🔒 **
|
|
60
|
+
- 📅 **Smart Due Dates**: Human-readable format with relative time (e.g., `'26.1.25 14:30 - 오늘`)
|
|
61
|
+
- 🔒 **Dual Authentication**: Support for both User API Key (24-char) and MCP Key (64-char)
|
|
62
|
+
- 📊 **Usage Tracking**: Automatic API usage statistics per MCP key
|
|
63
|
+
- 🌊 **Streaming API**: Real-time streaming for bulk operations and large datasets
|
|
64
|
+
- 🤖 **Bot Integration**: Telegram bot support via Clawdbot + mcporter
|
|
65
|
+
|
|
66
|
+
## Quick Start (No Account Needed)
|
|
67
|
+
|
|
68
|
+
You can start using AI Note MCP **without an existing account**. The MCP server includes onboarding tools that let you sign up and get an API key directly from Claude:
|
|
69
|
+
|
|
70
|
+
### 1. Add to your MCP config (no API key yet)
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"mcpServers": {
|
|
75
|
+
"ainote": {
|
|
76
|
+
"command": "npx",
|
|
77
|
+
"args": ["-y", "@ainote/mcp"]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 2. Restart Claude Desktop
|
|
84
|
+
|
|
85
|
+
### 3. Ask Claude to sign you up
|
|
86
|
+
|
|
87
|
+
> "Sign me up for AI Note with email user@example.com and password mypassword123"
|
|
88
|
+
|
|
89
|
+
Claude will call the `signup_and_get_key` tool and return your MCP API key.
|
|
90
|
+
|
|
91
|
+
### 4. Add the API key to your config
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"mcpServers": {
|
|
96
|
+
"ainote": {
|
|
97
|
+
"command": "npx",
|
|
98
|
+
"args": ["-y", "@ainote/mcp"],
|
|
99
|
+
"env": {
|
|
100
|
+
"AINOTE_API_KEY": "<your-key-from-step-3>"
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 5. Restart Claude Desktop again
|
|
108
|
+
|
|
109
|
+
Now all tools (tasks, dev docs, etc.) are available.
|
|
110
|
+
|
|
111
|
+
### CLI Signup
|
|
112
|
+
|
|
113
|
+
You can also sign up directly from the terminal:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
npx @ainote/mcp signup
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
This will interactively ask for email, password, and name, then return your MCP API key.
|
|
120
|
+
|
|
121
|
+
### Onboarding MCP Tools
|
|
122
|
+
|
|
123
|
+
These tools also work inside Claude (no API key needed):
|
|
124
|
+
|
|
125
|
+
| Tool | Description |
|
|
126
|
+
|------|-------------|
|
|
127
|
+
| `signup_and_get_key` | Create account + get MCP key |
|
|
128
|
+
| `login_and_get_key` | Login + get MCP key (existing account) |
|
|
129
|
+
| `get_setup_guide` | Setup instructions |
|
|
30
130
|
|
|
31
131
|
## Prerequisites
|
|
32
132
|
|
|
33
|
-
- Node.js >=
|
|
133
|
+
- Node.js >= 18.0.0
|
|
34
134
|
- npm or yarn
|
|
35
|
-
- AI Note API access (API key required)
|
|
36
135
|
- Claude Desktop with MCP support enabled
|
|
37
136
|
|
|
38
137
|
## Installation
|
|
@@ -139,16 +238,148 @@ You: "Mark task ID 123 as completed"
|
|
|
139
238
|
Claude: I'll mark that task as completed...
|
|
140
239
|
```
|
|
141
240
|
|
|
241
|
+
## HTTP Endpoint
|
|
242
|
+
|
|
243
|
+
For platform integrations and services that prefer HTTP over stdio, AI Note provides a direct HTTP endpoint:
|
|
244
|
+
|
|
245
|
+
### Endpoint URL
|
|
246
|
+
```
|
|
247
|
+
POST https://api.ainote.dev/mcp
|
|
248
|
+
Content-Type: application/json
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Authentication
|
|
252
|
+
```http
|
|
253
|
+
Authorization: Bearer YOUR_API_KEY
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Request Format (JSON-RPC 2.0)
|
|
257
|
+
```json
|
|
258
|
+
{
|
|
259
|
+
"jsonrpc": "2.0",
|
|
260
|
+
"method": "tools/list",
|
|
261
|
+
"id": 1
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Response Format
|
|
266
|
+
```json
|
|
267
|
+
{
|
|
268
|
+
"jsonrpc": "2.0",
|
|
269
|
+
"result": {
|
|
270
|
+
"tools": [...]
|
|
271
|
+
},
|
|
272
|
+
"id": 1
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Supported Methods
|
|
277
|
+
- `ping` - Health check
|
|
278
|
+
- `capabilities` - Server capabilities
|
|
279
|
+
- `tools/list` - List available tools
|
|
280
|
+
- `tools/call` - Execute a specific tool
|
|
281
|
+
|
|
282
|
+
### Platform Integration Examples
|
|
283
|
+
- **Kakao PlayMCP**: Use the HTTP endpoint for seamless integration
|
|
284
|
+
- **Custom Applications**: Build your own MCP client using the HTTP API
|
|
285
|
+
- **Enterprise Solutions**: Direct server-to-server communication
|
|
286
|
+
|
|
287
|
+
This HTTP endpoint provides identical functionality to the stdio version, making AI Note MCP accessible to a broader range of platforms and integration scenarios.
|
|
288
|
+
|
|
289
|
+
### 4. **Streaming API** - For Large Data Operations
|
|
290
|
+
- **URL**: `POST https://api.ainote.dev/mcp/stream`
|
|
291
|
+
- **Protocol**: Server-Sent Events (SSE)
|
|
292
|
+
- **Usage**: Bulk operations, large task lists, real-time progress
|
|
293
|
+
- **Best for**: Applications that need to handle large datasets or show progress indicators
|
|
294
|
+
|
|
295
|
+
#### Streaming Methods
|
|
296
|
+
| Method | Description |
|
|
297
|
+
|--------|-------------|
|
|
298
|
+
| `tasks/list` | Stream task list with filters |
|
|
299
|
+
| `tasks/create` | Create single task with progress |
|
|
300
|
+
| `tasks/analyze` | Get task statistics and insights |
|
|
301
|
+
| `tasks/bulk_update` | Update multiple tasks with progress |
|
|
302
|
+
| `tasks/bulk_create` | Create up to 1000 tasks at once |
|
|
303
|
+
|
|
304
|
+
#### Streaming Events
|
|
305
|
+
```
|
|
306
|
+
event: progress
|
|
307
|
+
data: {"status": "starting", "total": 100}
|
|
308
|
+
|
|
309
|
+
event: data
|
|
310
|
+
data: {"type": "task", "data": {...}}
|
|
311
|
+
|
|
312
|
+
event: result
|
|
313
|
+
data: {"status": "success", "count": 100}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### 5. **Telegram Bot Integration** - Via Clawdbot
|
|
317
|
+
- **Setup Guide**: [CLAWDBOT_SETUP.md](./CLAWDBOT_SETUP.md)
|
|
318
|
+
- **Tool**: mcporter for MCP server bridging
|
|
319
|
+
- **Usage**: Natural language task management in Telegram
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
# Quick setup
|
|
323
|
+
npm install -g mcporter
|
|
324
|
+
mcporter call ainote.list_tasks
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Local Development Bridge (`ainote-mcp-http`)
|
|
328
|
+
|
|
329
|
+
Run the bundled HTTP/SSE bridge when you need a local endpoint for ChatGPT or other MCP clients that speak SSE:
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
ainote-mcp-http
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
By default the server listens on `http://localhost:3030` and exposes two endpoints:
|
|
336
|
+
|
|
337
|
+
- `GET /sse` – establishes the SSE stream and returns the `sessionId`
|
|
338
|
+
- `POST /messages?sessionId=...` – receives JSON-RPC payloads from the client
|
|
339
|
+
- `GET /health` – simple health probe for monitoring
|
|
340
|
+
|
|
341
|
+
#### Configuration
|
|
342
|
+
|
|
343
|
+
Environment variable | Description | Default
|
|
344
|
+
---|---|---
|
|
345
|
+
`AINOTE_API_KEY` | API key used for MCP key authentication | **required**
|
|
346
|
+
`AINOTE_API_URL` | Target AI Note API base URL | `https://ainote-5muq.onrender.com`
|
|
347
|
+
`AINOTE_MCP_HTTP_PORT` | Local port for the SSE server | `3030`
|
|
348
|
+
`AINOTE_MCP_ALLOWED_ORIGINS` | Comma-separated list of allowed browser origins | _any_
|
|
349
|
+
`AINOTE_MCP_ALLOWED_HOSTS` | Comma-separated list of allowed `Host` headers | _any_
|
|
350
|
+
`AINOTE_ENABLE_OAUTH_AUTH` | Set to `true` to allow Bearer tokens (OAuth) | `false`
|
|
351
|
+
|
|
352
|
+
When OAuth is enabled the server expects `Authorization: Bearer ...` headers from the client and forwards them to the AI Note API.
|
|
353
|
+
|
|
142
354
|
## Available Tools
|
|
143
355
|
|
|
144
356
|
### list_tasks
|
|
145
357
|
|
|
146
|
-
List tasks from AI Note with filtering options.
|
|
358
|
+
List tasks from AI Note with advanced filtering options.
|
|
147
359
|
|
|
148
|
-
**Parameters:**
|
|
360
|
+
**Basic Parameters:**
|
|
149
361
|
- `status` (optional): Filter by status - "pending" or "completed"
|
|
150
362
|
- `limit` (optional): Maximum number of tasks (default: 25, max: 500)
|
|
151
363
|
- `search` (optional): Search keyword in task content
|
|
364
|
+
- `is_important` (optional): Filter important tasks only
|
|
365
|
+
|
|
366
|
+
**Location & Category:**
|
|
367
|
+
- `location` (optional): Filter by location (partial match, e.g., "여의도")
|
|
368
|
+
- `category_id` (optional): Filter by category UUID
|
|
369
|
+
|
|
370
|
+
**Date Range Filters:**
|
|
371
|
+
- `due_date_start` / `due_date_end`: Filter by due date range
|
|
372
|
+
- `completed_date_start` / `completed_date_end`: Filter by completion date
|
|
373
|
+
- `created_date_start` / `created_date_end`: Filter by creation date
|
|
374
|
+
|
|
375
|
+
**Special Filters:**
|
|
376
|
+
- `overdue` (optional): Filter overdue incomplete tasks
|
|
377
|
+
- `due_today` (optional): Filter tasks due today
|
|
378
|
+
- `has_notification` (optional): Filter by notification status
|
|
379
|
+
|
|
380
|
+
**Sorting:**
|
|
381
|
+
- `sort_by` (optional): Sort field - "due_date", "created_at", "completed_at", "updated_at", "is_important"
|
|
382
|
+
- `sort_order` (optional): Sort direction - "asc" or "desc"
|
|
152
383
|
|
|
153
384
|
### create_task
|
|
154
385
|
|
|
@@ -183,6 +414,80 @@ List all available categories.
|
|
|
183
414
|
|
|
184
415
|
**Parameters:** None
|
|
185
416
|
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
### Dev Doc Tools (v1.1.0+)
|
|
420
|
+
|
|
421
|
+
Manage AI coding tool configuration files and dev documents centrally. All docs are organized under the `dev/` category hierarchy.
|
|
422
|
+
|
|
423
|
+
#### list_dev_docs
|
|
424
|
+
|
|
425
|
+
List dev documents with optional filtering.
|
|
426
|
+
|
|
427
|
+
**Parameters:**
|
|
428
|
+
- `category` (optional): Subcategory filter (claude, cursor, windsurf, copilot, docs)
|
|
429
|
+
- `search` (optional): Search keyword in document title
|
|
430
|
+
- `content_type` (optional): Filter by type - "markdown", "json", "yaml", "text"
|
|
431
|
+
|
|
432
|
+
#### get_dev_doc
|
|
433
|
+
|
|
434
|
+
Get a single dev document by title or id.
|
|
435
|
+
|
|
436
|
+
**Parameters:**
|
|
437
|
+
- `title` or `id` (one required): Document identifier
|
|
438
|
+
- `category` (optional): Subcategory to disambiguate title
|
|
439
|
+
- `include_versions` (optional): Include version history
|
|
440
|
+
|
|
441
|
+
#### create_dev_doc
|
|
442
|
+
|
|
443
|
+
Create a new dev document under `dev/` category.
|
|
444
|
+
|
|
445
|
+
**Parameters:**
|
|
446
|
+
- `title` (required): Document title (e.g., "project-a-claude.md")
|
|
447
|
+
- `content` (required): Document content
|
|
448
|
+
- `category` (optional): Subcategory (default: "docs")
|
|
449
|
+
- `content_type` (optional): Auto-detected from title extension
|
|
450
|
+
|
|
451
|
+
#### update_dev_doc
|
|
452
|
+
|
|
453
|
+
Update a dev document with replace, append, or prepend modes.
|
|
454
|
+
|
|
455
|
+
**Parameters:**
|
|
456
|
+
- `title` or `id` (one required): Document identifier
|
|
457
|
+
- `content` (required): New content
|
|
458
|
+
- `mode` (optional): "replace" (default), "append", or "prepend"
|
|
459
|
+
|
|
460
|
+
#### delete_dev_doc
|
|
461
|
+
|
|
462
|
+
Soft delete a dev document.
|
|
463
|
+
|
|
464
|
+
**Parameters:**
|
|
465
|
+
- `title` or `id` (one required): Document identifier
|
|
466
|
+
|
|
467
|
+
#### list_dev_categories
|
|
468
|
+
|
|
469
|
+
List all subcategories under `dev/` with document counts.
|
|
470
|
+
|
|
471
|
+
**Parameters:** None
|
|
472
|
+
|
|
473
|
+
#### Example: Store CLAUDE.md in ainote
|
|
474
|
+
|
|
475
|
+
```
|
|
476
|
+
You: "Save this project's CLAUDE.md content to ainote"
|
|
477
|
+
Claude: I'll create a dev doc in the claude category...
|
|
478
|
+
→ create_dev_doc(title: "myproject-claude.md", content: "...", category: "claude")
|
|
479
|
+
|
|
480
|
+
You: "Update my cursor rules in ainote"
|
|
481
|
+
Claude: I'll update the cursor rules doc...
|
|
482
|
+
→ update_dev_doc(title: "api-rules.mdc", category: "cursor", content: "...")
|
|
483
|
+
|
|
484
|
+
You: "Show me all my dev docs"
|
|
485
|
+
Claude: I'll list all documents under dev/...
|
|
486
|
+
→ list_dev_docs()
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
186
491
|
## API Reference
|
|
187
492
|
|
|
188
493
|
The MCP server communicates with the AI Note API using the following endpoints:
|
package/index.js
CHANGED
|
@@ -1,229 +1,31 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
{
|
|
26
|
-
capabilities: {
|
|
27
|
-
tools: {},
|
|
28
|
-
},
|
|
29
|
-
}
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
// Define available tools
|
|
33
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
34
|
-
return {
|
|
35
|
-
tools: [
|
|
36
|
-
{
|
|
37
|
-
name: 'list_tasks',
|
|
38
|
-
description: 'List tasks from AI Note',
|
|
39
|
-
inputSchema: {
|
|
40
|
-
type: 'object',
|
|
41
|
-
properties: {
|
|
42
|
-
status: {
|
|
43
|
-
type: 'string',
|
|
44
|
-
enum: ['pending', 'completed'],
|
|
45
|
-
description: 'Filter by task status'
|
|
46
|
-
},
|
|
47
|
-
limit: {
|
|
48
|
-
type: 'number',
|
|
49
|
-
description: 'Maximum number of tasks to return (default: 25, max: 500)'
|
|
50
|
-
},
|
|
51
|
-
search: {
|
|
52
|
-
type: 'string',
|
|
53
|
-
description: 'Search keyword in task content'
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
name: 'create_task',
|
|
60
|
-
description: 'Create a new task in AI Note',
|
|
61
|
-
inputSchema: {
|
|
62
|
-
type: 'object',
|
|
63
|
-
properties: {
|
|
64
|
-
content: {
|
|
65
|
-
type: 'string',
|
|
66
|
-
description: 'Task content'
|
|
67
|
-
},
|
|
68
|
-
is_important: {
|
|
69
|
-
type: 'boolean',
|
|
70
|
-
description: 'Mark task as important'
|
|
71
|
-
},
|
|
72
|
-
due_date: {
|
|
73
|
-
type: 'string',
|
|
74
|
-
description: 'Due date in ISO format'
|
|
75
|
-
},
|
|
76
|
-
category_id: {
|
|
77
|
-
type: 'string',
|
|
78
|
-
description: 'Category ID'
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
required: ['content']
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
name: 'update_task',
|
|
86
|
-
description: 'Update an existing task',
|
|
87
|
-
inputSchema: {
|
|
88
|
-
type: 'object',
|
|
89
|
-
properties: {
|
|
90
|
-
id: {
|
|
91
|
-
type: 'string',
|
|
92
|
-
description: 'Task ID'
|
|
93
|
-
},
|
|
94
|
-
content: {
|
|
95
|
-
type: 'string',
|
|
96
|
-
description: 'New task content'
|
|
97
|
-
},
|
|
98
|
-
is_important: {
|
|
99
|
-
type: 'boolean',
|
|
100
|
-
description: 'Update important status'
|
|
101
|
-
},
|
|
102
|
-
completed_at: {
|
|
103
|
-
type: 'string',
|
|
104
|
-
description: 'Mark as completed (ISO format) or null to uncomplete'
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
|
-
required: ['id']
|
|
108
|
-
}
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
name: 'delete_task',
|
|
112
|
-
description: 'Delete a task (soft delete)',
|
|
113
|
-
inputSchema: {
|
|
114
|
-
type: 'object',
|
|
115
|
-
properties: {
|
|
116
|
-
id: {
|
|
117
|
-
type: 'string',
|
|
118
|
-
description: 'Task ID to delete'
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
required: ['id']
|
|
122
|
-
}
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
name: 'list_categories',
|
|
126
|
-
description: 'List all categories',
|
|
127
|
-
inputSchema: {
|
|
128
|
-
type: 'object',
|
|
129
|
-
properties: {}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
]
|
|
133
|
-
};
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
// Handle tool calls
|
|
137
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
138
|
-
const { name, arguments: args } = request.params;
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
switch (name) {
|
|
142
|
-
case 'list_tasks': {
|
|
143
|
-
const response = await api.get('/api/mcp/tasks', {
|
|
144
|
-
params: args
|
|
145
|
-
});
|
|
146
|
-
return {
|
|
147
|
-
content: [
|
|
148
|
-
{
|
|
149
|
-
type: 'text',
|
|
150
|
-
text: JSON.stringify(response.data, null, 2)
|
|
151
|
-
}
|
|
152
|
-
]
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
case 'create_task': {
|
|
157
|
-
const response = await api.post('/api/mcp/tasks', {
|
|
158
|
-
task: args
|
|
159
|
-
});
|
|
160
|
-
return {
|
|
161
|
-
content: [
|
|
162
|
-
{
|
|
163
|
-
type: 'text',
|
|
164
|
-
text: JSON.stringify(response.data, null, 2)
|
|
165
|
-
}
|
|
166
|
-
]
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
case 'update_task': {
|
|
171
|
-
const { id, ...updateData } = args;
|
|
172
|
-
const response = await api.put(`/api/mcp/tasks/${id}`, {
|
|
173
|
-
task: updateData
|
|
174
|
-
});
|
|
175
|
-
return {
|
|
176
|
-
content: [
|
|
177
|
-
{
|
|
178
|
-
type: 'text',
|
|
179
|
-
text: JSON.stringify(response.data, null, 2)
|
|
180
|
-
}
|
|
181
|
-
]
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
case 'delete_task': {
|
|
186
|
-
const response = await api.delete(`/api/mcp/tasks/${args.id}`);
|
|
187
|
-
return {
|
|
188
|
-
content: [
|
|
189
|
-
{
|
|
190
|
-
type: 'text',
|
|
191
|
-
text: JSON.stringify(response.data, null, 2)
|
|
192
|
-
}
|
|
193
|
-
]
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
case 'list_categories': {
|
|
198
|
-
const response = await api.get('/api/mcp/categories');
|
|
199
|
-
return {
|
|
200
|
-
content: [
|
|
201
|
-
{
|
|
202
|
-
type: 'text',
|
|
203
|
-
text: JSON.stringify(response.data, null, 2)
|
|
204
|
-
}
|
|
205
|
-
]
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
default:
|
|
210
|
-
throw new Error(`Unknown tool: ${name}`);
|
|
211
|
-
}
|
|
212
|
-
} catch (error) {
|
|
213
|
-
return {
|
|
214
|
-
content: [
|
|
215
|
-
{
|
|
216
|
-
type: 'text',
|
|
217
|
-
text: `Error: ${error.message}\n${error.response?.data ? JSON.stringify(error.response.data, null, 2) : ''}`
|
|
218
|
-
}
|
|
219
|
-
],
|
|
220
|
-
isError: true
|
|
221
|
-
};
|
|
2
|
+
/**
|
|
3
|
+
* AI Note MCP Server - Claude Desktop Integration (stdio transport)
|
|
4
|
+
* Also supports CLI subcommands: signup
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const subcommand = process.argv[2];
|
|
8
|
+
|
|
9
|
+
if (subcommand === 'signup') {
|
|
10
|
+
const { runSignup } = await import('./lib/cli/signup.js');
|
|
11
|
+
await runSignup();
|
|
12
|
+
} else {
|
|
13
|
+
// Default: start MCP stdio server
|
|
14
|
+
const { StdioServerTransport } = await import('@modelcontextprotocol/sdk/server/stdio.js');
|
|
15
|
+
const { resolveAuthContext } = await import('./lib/auth/strategy-factory.js');
|
|
16
|
+
const { createClaudeServer } = await import('./lib/core/server-factory.js');
|
|
17
|
+
|
|
18
|
+
const transport = new StdioServerTransport();
|
|
19
|
+
const defaultAuthContext = resolveAuthContext('stdio');
|
|
20
|
+
|
|
21
|
+
if (defaultAuthContext.type === 'anonymous') {
|
|
22
|
+
console.error('[ainote-mcp] No AINOTE_API_KEY found. Starting in onboarding mode.');
|
|
23
|
+
console.error('[ainote-mcp] Use signup_and_get_key or login_and_get_key to get started.');
|
|
24
|
+
console.error('[ainote-mcp] Or run: npx @ainote/mcp signup');
|
|
222
25
|
}
|
|
223
|
-
});
|
|
224
26
|
|
|
225
|
-
|
|
226
|
-
const transport = new StdioServerTransport();
|
|
227
|
-
await server.connect(transport);
|
|
27
|
+
const { server } = createClaudeServer({ defaultAuthContext });
|
|
228
28
|
|
|
229
|
-
|
|
29
|
+
await server.connect(transport);
|
|
30
|
+
console.error('AI Note MCP stdio server started (Claude Desktop compatible)');
|
|
31
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getConfig } from '../core/config.js';
|
|
2
|
+
|
|
3
|
+
export function authenticateWithMcpKey() {
|
|
4
|
+
const config = getConfig();
|
|
5
|
+
|
|
6
|
+
if (!config.api.key) {
|
|
7
|
+
throw new Error('AINOTE_API_KEY is required to authenticate MCP requests');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
type: 'mcpKey',
|
|
12
|
+
apiKey: config.api.key
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function authenticateWithOAuth(headers = {}) {
|
|
2
|
+
const authHeader = headers['authorization'] || headers['Authorization'];
|
|
3
|
+
|
|
4
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
5
|
+
throw new Error('Missing or invalid Bearer token for OAuth authentication');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const token = authHeader.substring('Bearer '.length).trim();
|
|
9
|
+
|
|
10
|
+
if (!token) {
|
|
11
|
+
throw new Error('Bearer token is empty');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
type: 'oauth',
|
|
16
|
+
token
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { authenticateWithMcpKey } from './mcp-key.js';
|
|
2
|
+
import { authenticateWithOAuth } from './oauth.js';
|
|
3
|
+
import { getFeatureFlags } from '../core/config.js';
|
|
4
|
+
|
|
5
|
+
export function resolveAuthContext(transportType, headers = {}) {
|
|
6
|
+
if (transportType === 'stdio') {
|
|
7
|
+
try {
|
|
8
|
+
return authenticateWithMcpKey();
|
|
9
|
+
} catch {
|
|
10
|
+
// No API key configured — allow anonymous mode for onboarding tools
|
|
11
|
+
return { type: 'anonymous' };
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const features = getFeatureFlags();
|
|
16
|
+
|
|
17
|
+
if (transportType === 'sse' && features.oauthAuth) {
|
|
18
|
+
try {
|
|
19
|
+
return authenticateWithOAuth(headers);
|
|
20
|
+
} catch {
|
|
21
|
+
// Fall through to MCP key or anonymous
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Default fallback to MCP key, then anonymous for onboarding
|
|
26
|
+
try {
|
|
27
|
+
return authenticateWithMcpKey();
|
|
28
|
+
} catch {
|
|
29
|
+
return { type: 'anonymous' };
|
|
30
|
+
}
|
|
31
|
+
}
|