@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 CHANGED
@@ -3,15 +3,19 @@
3
3
  [![npm version](https://badge.fury.io/js/%40ainote%2Fmcp-server.svg)](https://badge.fury.io/js/%40ainote%2Fmcp-server)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- A Model Context Protocol (MCP) server that connects Claude Desktop to your AI Note task management system. This server allows Claude to directly interact with your AI Note tasks, enabling task creation, updates, and management through natural language conversations.
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 Search**: Search tasks by content, status, and more
58
+ - 🔍 **Advanced Filtering**: 18+ filter options including date ranges, location, overdue tasks
27
59
  - ⭐ **Priority Management**: Mark tasks as important
28
- - 📅 **Due Date Support**: Set and manage task due dates
29
- - 🔒 **Secure API Integration**: Uses API key authentication for secure access
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 >= 16.0.0
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
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
- import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
5
- import axios from 'axios';
6
-
7
- const API_KEY = process.env.AINOTE_API_KEY;
8
- const API_URL = process.env.AINOTE_API_URL || 'https://api.ainote.dev';
9
-
10
- // Create axios instance with default config
11
- const api = axios.create({
12
- baseURL: API_URL,
13
- headers: {
14
- 'Authorization': `McpKey ${API_KEY}`,
15
- 'Content-Type': 'application/json'
16
- }
17
- });
18
-
19
- // Create MCP server
20
- const server = new Server(
21
- {
22
- name: 'ainote-mcp',
23
- version: '1.0.0',
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
- // Start the server
226
- const transport = new StdioServerTransport();
227
- await server.connect(transport);
27
+ const { server } = createClaudeServer({ defaultAuthContext });
228
28
 
229
- console.error('AI Note MCP proxy server started');
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
+ }