@ainote/mcp 1.3.2 → 1.3.3
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/LICENSE +20 -20
- package/README-ko.md +374 -374
- package/README.md +800 -800
- package/index.js +61 -61
- package/lib/auth/device-flow.js +285 -274
- package/lib/auth/mcp-key.js +40 -40
- package/lib/auth/oauth.js +18 -18
- package/lib/auth/refresh.js +78 -78
- package/lib/auth/strategy-factory.js +31 -31
- package/lib/auth/token-store.js +302 -286
- package/lib/cli/call.js +211 -211
- package/lib/cli/login.js +238 -238
- package/lib/cli/logout.js +39 -39
- package/lib/cli/signup.js +118 -118
- package/lib/cli/whoami.js +77 -77
- package/lib/core/api-client.js +1 -1
- package/lib/core/config-manager.js +106 -106
- package/lib/core/config.js +1 -1
- package/lib/core/mcp-server.js +2 -2
- package/lib/core/server-factory.js +82 -82
- package/lib/core/tool-registry.js +31 -31
- package/lib/tools/chatgpt-tools.js +93 -93
- package/lib/tools/dev-doc-tools.js +643 -643
- package/lib/tools/index.js +5 -5
- package/lib/tools/internal/claude-scanner.js +150 -150
- package/lib/tools/internal/encryption.js +88 -88
- package/lib/tools/internal/formatters.js +80 -80
- package/lib/tools/internal/keychain.js +98 -98
- package/lib/tools/internal/path-mapper.js +221 -221
- package/lib/tools/onboarding-tools.js +124 -124
- package/lib/tools/shared-tools.js +280 -280
- package/lib/utils/api-client.js +152 -152
- package/package.json +101 -101
- package/server.js +99 -99
|
@@ -1,82 +1,82 @@
|
|
|
1
|
-
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
-
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
-
import { ToolRegistry } from './tool-registry.js';
|
|
4
|
-
import { getConfig } from './config-manager.js';
|
|
5
|
-
import { createApiClient } from '../utils/api-client.js';
|
|
6
|
-
import { getSharedTools } from '../tools/shared-tools.js';
|
|
7
|
-
import { getChatGptTools } from '../tools/chatgpt-tools.js';
|
|
8
|
-
import { getDevDocTools } from '../tools/dev-doc-tools.js';
|
|
9
|
-
import { getOnboardingTools } from '../tools/onboarding-tools.js';
|
|
10
|
-
import { toErrorContent } from '../tools/internal/formatters.js';
|
|
11
|
-
|
|
12
|
-
function buildServerInfo(profile) {
|
|
13
|
-
return {
|
|
14
|
-
name: `ainote-mcp-${profile}`,
|
|
15
|
-
version: '1.1.0'
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function registerTools(registry, { includeChatGpt }) {
|
|
20
|
-
// Onboarding tools are always registered (work without API key)
|
|
21
|
-
registry.registerMany(getOnboardingTools());
|
|
22
|
-
registry.registerMany(getSharedTools());
|
|
23
|
-
registry.registerMany(getDevDocTools());
|
|
24
|
-
|
|
25
|
-
if (includeChatGpt) {
|
|
26
|
-
registry.registerMany(getChatGptTools());
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function createServer({ profile, defaultAuthContext } = {}) {
|
|
31
|
-
const config = getConfig();
|
|
32
|
-
const includeChatGpt = profile === 'chatgpt' && config.features.chatgptSupport;
|
|
33
|
-
const registry = new ToolRegistry();
|
|
34
|
-
|
|
35
|
-
registerTools(registry, { includeChatGpt });
|
|
36
|
-
|
|
37
|
-
const server = new Server(buildServerInfo(profile), {
|
|
38
|
-
capabilities: {
|
|
39
|
-
tools: {}
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
44
|
-
tools: registry.listDefinitions()
|
|
45
|
-
}));
|
|
46
|
-
|
|
47
|
-
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
48
|
-
try {
|
|
49
|
-
const { name, arguments: args } = request.params;
|
|
50
|
-
console.error(`[MCP] Calling tool: ${name}`, JSON.stringify(args));
|
|
51
|
-
|
|
52
|
-
const authContext = extra?.authInfo ?? defaultAuthContext;
|
|
53
|
-
const apiClient = createApiClient(authContext);
|
|
54
|
-
|
|
55
|
-
const result = await registry.execute(name, args, {
|
|
56
|
-
apiClient,
|
|
57
|
-
request,
|
|
58
|
-
extra
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
console.error(`[MCP] Tool ${name} completed successfully`);
|
|
62
|
-
return result;
|
|
63
|
-
} catch (error) {
|
|
64
|
-
console.error(`[MCP] Tool error:`, error);
|
|
65
|
-
return toErrorContent(error);
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
return { server, registry };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function createClaudeServer(options = {}) {
|
|
73
|
-
return createServer({ profile: 'claude', ...options });
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function createChatGptServer(options = {}) {
|
|
77
|
-
return createServer({ profile: 'chatgpt', ...options });
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function createServerForProfile(profile, options = {}) {
|
|
81
|
-
return createServer({ profile, ...options });
|
|
82
|
-
}
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import { ToolRegistry } from './tool-registry.js';
|
|
4
|
+
import { getConfig } from './config-manager.js';
|
|
5
|
+
import { createApiClient } from '../utils/api-client.js';
|
|
6
|
+
import { getSharedTools } from '../tools/shared-tools.js';
|
|
7
|
+
import { getChatGptTools } from '../tools/chatgpt-tools.js';
|
|
8
|
+
import { getDevDocTools } from '../tools/dev-doc-tools.js';
|
|
9
|
+
import { getOnboardingTools } from '../tools/onboarding-tools.js';
|
|
10
|
+
import { toErrorContent } from '../tools/internal/formatters.js';
|
|
11
|
+
|
|
12
|
+
function buildServerInfo(profile) {
|
|
13
|
+
return {
|
|
14
|
+
name: `ainote-mcp-${profile}`,
|
|
15
|
+
version: '1.1.0'
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function registerTools(registry, { includeChatGpt }) {
|
|
20
|
+
// Onboarding tools are always registered (work without API key)
|
|
21
|
+
registry.registerMany(getOnboardingTools());
|
|
22
|
+
registry.registerMany(getSharedTools());
|
|
23
|
+
registry.registerMany(getDevDocTools());
|
|
24
|
+
|
|
25
|
+
if (includeChatGpt) {
|
|
26
|
+
registry.registerMany(getChatGptTools());
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function createServer({ profile, defaultAuthContext } = {}) {
|
|
31
|
+
const config = getConfig();
|
|
32
|
+
const includeChatGpt = profile === 'chatgpt' && config.features.chatgptSupport;
|
|
33
|
+
const registry = new ToolRegistry();
|
|
34
|
+
|
|
35
|
+
registerTools(registry, { includeChatGpt });
|
|
36
|
+
|
|
37
|
+
const server = new Server(buildServerInfo(profile), {
|
|
38
|
+
capabilities: {
|
|
39
|
+
tools: {}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
44
|
+
tools: registry.listDefinitions()
|
|
45
|
+
}));
|
|
46
|
+
|
|
47
|
+
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
48
|
+
try {
|
|
49
|
+
const { name, arguments: args } = request.params;
|
|
50
|
+
console.error(`[MCP] Calling tool: ${name}`, JSON.stringify(args));
|
|
51
|
+
|
|
52
|
+
const authContext = extra?.authInfo ?? defaultAuthContext;
|
|
53
|
+
const apiClient = createApiClient(authContext);
|
|
54
|
+
|
|
55
|
+
const result = await registry.execute(name, args, {
|
|
56
|
+
apiClient,
|
|
57
|
+
request,
|
|
58
|
+
extra
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
console.error(`[MCP] Tool ${name} completed successfully`);
|
|
62
|
+
return result;
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error(`[MCP] Tool error:`, error);
|
|
65
|
+
return toErrorContent(error);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
return { server, registry };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function createClaudeServer(options = {}) {
|
|
73
|
+
return createServer({ profile: 'claude', ...options });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function createChatGptServer(options = {}) {
|
|
77
|
+
return createServer({ profile: 'chatgpt', ...options });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function createServerForProfile(profile, options = {}) {
|
|
81
|
+
return createServer({ profile, ...options });
|
|
82
|
+
}
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
export class ToolRegistry {
|
|
2
|
-
constructor() {
|
|
3
|
-
this.tools = new Map();
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
register(tool) {
|
|
7
|
-
if (!tool?.definition?.name) {
|
|
8
|
-
throw new Error('Invalid tool registration: missing tool name');
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
this.tools.set(tool.definition.name, tool);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
registerMany(tools = []) {
|
|
15
|
-
tools.forEach((tool) => this.register(tool));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
listDefinitions() {
|
|
19
|
-
return Array.from(this.tools.values()).map((tool) => tool.definition);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async execute(name, args, context) {
|
|
23
|
-
const tool = this.tools.get(name);
|
|
24
|
-
|
|
25
|
-
if (!tool) {
|
|
26
|
-
throw new Error(`Unknown tool: ${name}`);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return tool.handler(args ?? {}, context ?? {});
|
|
30
|
-
}
|
|
31
|
-
}
|
|
1
|
+
export class ToolRegistry {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.tools = new Map();
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
register(tool) {
|
|
7
|
+
if (!tool?.definition?.name) {
|
|
8
|
+
throw new Error('Invalid tool registration: missing tool name');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
this.tools.set(tool.definition.name, tool);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
registerMany(tools = []) {
|
|
15
|
+
tools.forEach((tool) => this.register(tool));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
listDefinitions() {
|
|
19
|
+
return Array.from(this.tools.values()).map((tool) => tool.definition);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async execute(name, args, context) {
|
|
23
|
+
const tool = this.tools.get(name);
|
|
24
|
+
|
|
25
|
+
if (!tool) {
|
|
26
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return tool.handler(args ?? {}, context ?? {});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -1,93 +1,93 @@
|
|
|
1
|
-
import { toSuccessContent } from './internal/formatters.js';
|
|
2
|
-
|
|
3
|
-
const MAX_RESULTS = 20;
|
|
4
|
-
|
|
5
|
-
function searchDefinition() {
|
|
6
|
-
return {
|
|
7
|
-
name: 'search',
|
|
8
|
-
description: 'Search tasks and categories in AI Note',
|
|
9
|
-
inputSchema: {
|
|
10
|
-
type: 'object',
|
|
11
|
-
properties: {
|
|
12
|
-
query: {
|
|
13
|
-
type: 'string',
|
|
14
|
-
description: 'Search query for tasks content, categories, or due dates'
|
|
15
|
-
},
|
|
16
|
-
limit: {
|
|
17
|
-
type: 'number',
|
|
18
|
-
description: 'Maximum number of search results (default: 20)'
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
required: ['query']
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function fetchDefinition() {
|
|
27
|
-
return {
|
|
28
|
-
name: 'fetch',
|
|
29
|
-
description: 'Fetch detailed information about a specific task',
|
|
30
|
-
inputSchema: {
|
|
31
|
-
type: 'object',
|
|
32
|
-
properties: {
|
|
33
|
-
id: {
|
|
34
|
-
type: 'string',
|
|
35
|
-
description: 'Task ID to fetch detailed information'
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
required: ['id']
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function getChatGptTools() {
|
|
44
|
-
return [
|
|
45
|
-
{
|
|
46
|
-
definition: searchDefinition(),
|
|
47
|
-
handler: async (args, { apiClient }) => {
|
|
48
|
-
const limit = typeof args.limit === 'number' ? Math.min(args.limit, MAX_RESULTS) : MAX_RESULTS;
|
|
49
|
-
const response = await apiClient.get('/api/mcp/tasks', {
|
|
50
|
-
params: {
|
|
51
|
-
search: args.query,
|
|
52
|
-
limit
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
const results = Array.isArray(response.data?.tasks)
|
|
57
|
-
? response.data.tasks.map((task) => ({
|
|
58
|
-
id: task.id,
|
|
59
|
-
title: task.content,
|
|
60
|
-
due_date: task.due_date,
|
|
61
|
-
is_important: task.is_important,
|
|
62
|
-
url: task.url ?? `https://app.ainote.dev/tasks/${task.id}`,
|
|
63
|
-
category: task.category
|
|
64
|
-
}))
|
|
65
|
-
: response.data;
|
|
66
|
-
|
|
67
|
-
return toSuccessContent({
|
|
68
|
-
results,
|
|
69
|
-
meta: {
|
|
70
|
-
source: 'ai-note',
|
|
71
|
-
query: args.query,
|
|
72
|
-
limit
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
definition: fetchDefinition(),
|
|
79
|
-
handler: async (args, { apiClient }) => {
|
|
80
|
-
const response = await apiClient.get(`/api/mcp/tasks/${args.id}`);
|
|
81
|
-
const task = response.data?.task ?? response.data;
|
|
82
|
-
|
|
83
|
-
return toSuccessContent({
|
|
84
|
-
task,
|
|
85
|
-
meta: {
|
|
86
|
-
source: 'ai-note',
|
|
87
|
-
fetched_at: new Date().toISOString()
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
];
|
|
93
|
-
}
|
|
1
|
+
import { toSuccessContent } from './internal/formatters.js';
|
|
2
|
+
|
|
3
|
+
const MAX_RESULTS = 20;
|
|
4
|
+
|
|
5
|
+
function searchDefinition() {
|
|
6
|
+
return {
|
|
7
|
+
name: 'search',
|
|
8
|
+
description: 'Search tasks and categories in AI Note',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
query: {
|
|
13
|
+
type: 'string',
|
|
14
|
+
description: 'Search query for tasks content, categories, or due dates'
|
|
15
|
+
},
|
|
16
|
+
limit: {
|
|
17
|
+
type: 'number',
|
|
18
|
+
description: 'Maximum number of search results (default: 20)'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
required: ['query']
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function fetchDefinition() {
|
|
27
|
+
return {
|
|
28
|
+
name: 'fetch',
|
|
29
|
+
description: 'Fetch detailed information about a specific task',
|
|
30
|
+
inputSchema: {
|
|
31
|
+
type: 'object',
|
|
32
|
+
properties: {
|
|
33
|
+
id: {
|
|
34
|
+
type: 'string',
|
|
35
|
+
description: 'Task ID to fetch detailed information'
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
required: ['id']
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function getChatGptTools() {
|
|
44
|
+
return [
|
|
45
|
+
{
|
|
46
|
+
definition: searchDefinition(),
|
|
47
|
+
handler: async (args, { apiClient }) => {
|
|
48
|
+
const limit = typeof args.limit === 'number' ? Math.min(args.limit, MAX_RESULTS) : MAX_RESULTS;
|
|
49
|
+
const response = await apiClient.get('/api/mcp/tasks', {
|
|
50
|
+
params: {
|
|
51
|
+
search: args.query,
|
|
52
|
+
limit
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const results = Array.isArray(response.data?.tasks)
|
|
57
|
+
? response.data.tasks.map((task) => ({
|
|
58
|
+
id: task.id,
|
|
59
|
+
title: task.content,
|
|
60
|
+
due_date: task.due_date,
|
|
61
|
+
is_important: task.is_important,
|
|
62
|
+
url: task.url ?? `https://app.ainote.dev/tasks/${task.id}`,
|
|
63
|
+
category: task.category
|
|
64
|
+
}))
|
|
65
|
+
: response.data;
|
|
66
|
+
|
|
67
|
+
return toSuccessContent({
|
|
68
|
+
results,
|
|
69
|
+
meta: {
|
|
70
|
+
source: 'ai-note',
|
|
71
|
+
query: args.query,
|
|
72
|
+
limit
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
definition: fetchDefinition(),
|
|
79
|
+
handler: async (args, { apiClient }) => {
|
|
80
|
+
const response = await apiClient.get(`/api/mcp/tasks/${args.id}`);
|
|
81
|
+
const task = response.data?.task ?? response.data;
|
|
82
|
+
|
|
83
|
+
return toSuccessContent({
|
|
84
|
+
task,
|
|
85
|
+
meta: {
|
|
86
|
+
source: 'ai-note',
|
|
87
|
+
fetched_at: new Date().toISOString()
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
];
|
|
93
|
+
}
|