@dinoxx/dinox-cli 1.0.15 → 1.0.16
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/dist/cli.js +6 -0
- package/dist/commands/graph/index.d.ts +2 -0
- package/dist/commands/graph/index.js +98 -0
- package/dist/commands/graph/repo.d.ts +33 -0
- package/dist/commands/graph/repo.js +76 -0
- package/dist/commands/mcp/auth.d.ts +4 -0
- package/dist/commands/mcp/auth.js +75 -0
- package/dist/commands/mcp/index.d.ts +2 -0
- package/dist/commands/mcp/index.js +84 -0
- package/dist/commands/mcp/server.d.ts +30 -0
- package/dist/commands/mcp/server.js +324 -0
- package/dist/commands/mcp/tools.d.ts +2 -0
- package/dist/commands/mcp/tools.js +90 -0
- package/dist/commands/mcp/types.d.ts +24 -0
- package/dist/commands/mcp/types.js +1 -0
- package/dist/daemon/client.d.ts +2 -0
- package/dist/daemon/client.js +86 -0
- package/dist/daemon/ensure.d.ts +1 -0
- package/dist/daemon/ensure.js +23 -0
- package/dist/daemon/index.d.ts +2 -0
- package/dist/daemon/index.js +151 -0
- package/dist/daemon/pid.d.ts +10 -0
- package/dist/daemon/pid.js +55 -0
- package/dist/daemon/server.d.ts +10 -0
- package/dist/daemon/server.js +137 -0
- package/dist/daemon/types.d.ts +19 -0
- package/dist/daemon/types.js +1 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,10 @@ import { Command } from 'commander';
|
|
|
2
2
|
import { registerAuthCommands } from './commands/auth/index.js';
|
|
3
3
|
import { registerBoxesCommand } from './commands/boxes/index.js';
|
|
4
4
|
import { registerConfigCommands } from './commands/config/index.js';
|
|
5
|
+
import { registerDaemonCommands } from './daemon/index.js';
|
|
6
|
+
import { registerGraphCommands } from './commands/graph/index.js';
|
|
5
7
|
import { registerInfoCommand } from './commands/info/index.js';
|
|
8
|
+
import { registerMCPCommands } from './commands/mcp/index.js';
|
|
6
9
|
import { registerNoteCommands } from './commands/notes/index.js';
|
|
7
10
|
import { registerPromptCommands } from './commands/prompt/index.js';
|
|
8
11
|
import { registerSyncCommand } from './commands/sync.js';
|
|
@@ -25,7 +28,10 @@ export function createCli() {
|
|
|
25
28
|
registerAuthCommands(program);
|
|
26
29
|
registerBoxesCommand(program);
|
|
27
30
|
registerConfigCommands(program);
|
|
31
|
+
registerDaemonCommands(program);
|
|
32
|
+
registerGraphCommands(program);
|
|
28
33
|
registerInfoCommand(program);
|
|
34
|
+
registerMCPCommands(program);
|
|
29
35
|
registerSyncCommand(program);
|
|
30
36
|
registerUpdateCommand(program);
|
|
31
37
|
registerPromptCommands(program);
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { printYaml } from '../../utils/output.js';
|
|
2
|
+
import { sendDaemonRequest } from '../../daemon/client.js';
|
|
3
|
+
import { ensureDaemonRunning } from '../../daemon/ensure.js';
|
|
4
|
+
import { DinoxError } from '../../utils/errors.js';
|
|
5
|
+
import { loadConfig } from '../../config/store.js';
|
|
6
|
+
import { resolveConfig } from '../../config/resolve.js';
|
|
7
|
+
import { connectPowerSync } from '../../powersync/runtime.js';
|
|
8
|
+
import { parseSyncTimeoutMs } from '../../utils/syncTimeout.js';
|
|
9
|
+
import { getBacklinks, getOutlinks, getRelatedNotes } from './repo.js';
|
|
10
|
+
function parseDepth(value) {
|
|
11
|
+
if (value === undefined || value === null || value === '') {
|
|
12
|
+
return 2;
|
|
13
|
+
}
|
|
14
|
+
if (typeof value !== 'string') {
|
|
15
|
+
throw new DinoxError('--depth must be a positive integer');
|
|
16
|
+
}
|
|
17
|
+
const trimmed = value.trim();
|
|
18
|
+
if (!/^\d+$/.test(trimmed)) {
|
|
19
|
+
throw new DinoxError('--depth must be a positive integer');
|
|
20
|
+
}
|
|
21
|
+
const parsed = Number(trimmed);
|
|
22
|
+
if (!Number.isFinite(parsed) || parsed <= 0 || parsed > 5) {
|
|
23
|
+
throw new DinoxError('--depth must be between 1 and 5');
|
|
24
|
+
}
|
|
25
|
+
return Math.trunc(parsed);
|
|
26
|
+
}
|
|
27
|
+
async function withOfflineDb(command, fn) {
|
|
28
|
+
const globals = command.optsWithGlobals?.() ?? {};
|
|
29
|
+
const offline = Boolean(globals.offline);
|
|
30
|
+
if (!offline) {
|
|
31
|
+
throw new DinoxError('withOfflineDb called without --offline');
|
|
32
|
+
}
|
|
33
|
+
const config = resolveConfig(await loadConfig());
|
|
34
|
+
const timeoutMs = parseSyncTimeoutMs(globals.syncTimeout) ?? config.sync.timeoutMs;
|
|
35
|
+
const { db } = await connectPowerSync({ config, offline: true, timeoutMs });
|
|
36
|
+
try {
|
|
37
|
+
return await fn(db);
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
await db.close().catch(() => undefined);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function registerGraphCommands(program) {
|
|
44
|
+
const graph = program.command('graph').description('Query knowledge graph');
|
|
45
|
+
graph
|
|
46
|
+
.command('backlinks')
|
|
47
|
+
.description('Get notes that link to this note')
|
|
48
|
+
.argument('<id>', 'note id')
|
|
49
|
+
.action(async (id, _options, command) => {
|
|
50
|
+
const globals = command.optsWithGlobals?.() ?? {};
|
|
51
|
+
const offline = Boolean(globals.offline);
|
|
52
|
+
if (offline) {
|
|
53
|
+
const result = await withOfflineDb(command, (db) => getBacklinks(db, id));
|
|
54
|
+
printYaml(result);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
await ensureDaemonRunning();
|
|
58
|
+
const result = await sendDaemonRequest('graph.backlinks', { id });
|
|
59
|
+
printYaml(result);
|
|
60
|
+
});
|
|
61
|
+
graph
|
|
62
|
+
.command('outlinks')
|
|
63
|
+
.description('Get notes that this note links to')
|
|
64
|
+
.argument('<id>', 'note id')
|
|
65
|
+
.action(async (id, _options, command) => {
|
|
66
|
+
const globals = command.optsWithGlobals?.() ?? {};
|
|
67
|
+
const offline = Boolean(globals.offline);
|
|
68
|
+
if (offline) {
|
|
69
|
+
const result = await withOfflineDb(command, (db) => getOutlinks(db, id));
|
|
70
|
+
printYaml(result);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
await ensureDaemonRunning();
|
|
74
|
+
const result = await sendDaemonRequest('graph.outlinks', { id });
|
|
75
|
+
printYaml(result);
|
|
76
|
+
});
|
|
77
|
+
graph
|
|
78
|
+
.command('related')
|
|
79
|
+
.description('Get related notes within N degrees of separation')
|
|
80
|
+
.argument('<id>', 'note id')
|
|
81
|
+
.option('--depth <n>', 'degrees of separation (1-5, default: 2)')
|
|
82
|
+
.action(async (id, options, command) => {
|
|
83
|
+
const depth = parseDepth(options.depth);
|
|
84
|
+
const globals = command.optsWithGlobals?.() ?? {};
|
|
85
|
+
const offline = Boolean(globals.offline);
|
|
86
|
+
if (offline) {
|
|
87
|
+
const result = await withOfflineDb(command, (db) => getRelatedNotes(db, id, depth));
|
|
88
|
+
printYaml(result);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
await ensureDaemonRunning();
|
|
92
|
+
const result = await sendDaemonRequest('graph.related', { id, depth });
|
|
93
|
+
printYaml(result);
|
|
94
|
+
});
|
|
95
|
+
graph.action((_options, command) => {
|
|
96
|
+
command.outputHelp();
|
|
97
|
+
});
|
|
98
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AbstractPowerSyncDatabase } from '@powersync/common';
|
|
2
|
+
export type NoteLinkRecord = {
|
|
3
|
+
id: string;
|
|
4
|
+
src_note_id: string;
|
|
5
|
+
dst_note_id: string;
|
|
6
|
+
relation: string | null;
|
|
7
|
+
created_at: string;
|
|
8
|
+
};
|
|
9
|
+
export type LinkedNote = {
|
|
10
|
+
note_id: string;
|
|
11
|
+
title: string;
|
|
12
|
+
relation: string | null;
|
|
13
|
+
link_created_at: string;
|
|
14
|
+
};
|
|
15
|
+
export type GraphBacklinksResult = {
|
|
16
|
+
note_id: string;
|
|
17
|
+
backlinks: LinkedNote[];
|
|
18
|
+
count: number;
|
|
19
|
+
};
|
|
20
|
+
export type GraphOutlinksResult = {
|
|
21
|
+
note_id: string;
|
|
22
|
+
outlinks: LinkedNote[];
|
|
23
|
+
count: number;
|
|
24
|
+
};
|
|
25
|
+
export type GraphRelatedResult = {
|
|
26
|
+
note_id: string;
|
|
27
|
+
related: LinkedNote[];
|
|
28
|
+
count: number;
|
|
29
|
+
depth: number;
|
|
30
|
+
};
|
|
31
|
+
export declare function getBacklinks(db: AbstractPowerSyncDatabase, noteId: string): Promise<GraphBacklinksResult>;
|
|
32
|
+
export declare function getOutlinks(db: AbstractPowerSyncDatabase, noteId: string): Promise<GraphOutlinksResult>;
|
|
33
|
+
export declare function getRelatedNotes(db: AbstractPowerSyncDatabase, noteId: string, depth?: number): Promise<GraphRelatedResult>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export async function getBacklinks(db, noteId) {
|
|
2
|
+
const rows = await db.getAll(`SELECT
|
|
3
|
+
l.id,
|
|
4
|
+
l.src_note_id,
|
|
5
|
+
l.dst_note_id,
|
|
6
|
+
l.relation,
|
|
7
|
+
l.created_at,
|
|
8
|
+
n.title
|
|
9
|
+
FROM c_note_link l
|
|
10
|
+
LEFT JOIN c_note n ON l.src_note_id = n.id
|
|
11
|
+
WHERE l.dst_note_id = ? AND l.is_del = 0 AND (n.is_del = 0 OR n.is_del IS NULL)
|
|
12
|
+
ORDER BY l.created_at DESC`, [noteId]);
|
|
13
|
+
const backlinks = rows.map((row) => ({
|
|
14
|
+
note_id: row.src_note_id,
|
|
15
|
+
title: row.title || '',
|
|
16
|
+
relation: row.relation,
|
|
17
|
+
link_created_at: row.created_at,
|
|
18
|
+
}));
|
|
19
|
+
return {
|
|
20
|
+
note_id: noteId,
|
|
21
|
+
backlinks,
|
|
22
|
+
count: backlinks.length,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export async function getOutlinks(db, noteId) {
|
|
26
|
+
const rows = await db.getAll(`SELECT
|
|
27
|
+
l.id,
|
|
28
|
+
l.src_note_id,
|
|
29
|
+
l.dst_note_id,
|
|
30
|
+
l.relation,
|
|
31
|
+
l.created_at,
|
|
32
|
+
n.title
|
|
33
|
+
FROM c_note_link l
|
|
34
|
+
LEFT JOIN c_note n ON l.dst_note_id = n.id
|
|
35
|
+
WHERE l.src_note_id = ? AND l.is_del = 0 AND (n.is_del = 0 OR n.is_del IS NULL)
|
|
36
|
+
ORDER BY l.created_at DESC`, [noteId]);
|
|
37
|
+
const outlinks = rows.map((row) => ({
|
|
38
|
+
note_id: row.dst_note_id,
|
|
39
|
+
title: row.title || '',
|
|
40
|
+
relation: row.relation,
|
|
41
|
+
link_created_at: row.created_at,
|
|
42
|
+
}));
|
|
43
|
+
return {
|
|
44
|
+
note_id: noteId,
|
|
45
|
+
outlinks,
|
|
46
|
+
count: outlinks.length,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export async function getRelatedNotes(db, noteId, depth = 2) {
|
|
50
|
+
const visited = new Set([noteId]);
|
|
51
|
+
const related = new Map();
|
|
52
|
+
async function traverse(currentId, currentDepth) {
|
|
53
|
+
if (currentDepth > depth)
|
|
54
|
+
return;
|
|
55
|
+
const [backlinks, outlinks] = await Promise.all([
|
|
56
|
+
getBacklinks(db, currentId),
|
|
57
|
+
getOutlinks(db, currentId),
|
|
58
|
+
]);
|
|
59
|
+
for (const link of [...backlinks.backlinks, ...outlinks.outlinks]) {
|
|
60
|
+
if (!visited.has(link.note_id)) {
|
|
61
|
+
visited.add(link.note_id);
|
|
62
|
+
related.set(link.note_id, link);
|
|
63
|
+
if (currentDepth < depth) {
|
|
64
|
+
await traverse(link.note_id, currentDepth + 1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
await traverse(noteId, 1);
|
|
70
|
+
return {
|
|
71
|
+
note_id: noteId,
|
|
72
|
+
related: Array.from(related.values()),
|
|
73
|
+
count: related.size,
|
|
74
|
+
depth,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { IncomingHttpHeaders } from 'node:http';
|
|
2
|
+
export declare function isLoopbackHost(host: string): boolean;
|
|
3
|
+
export declare function resolveMCPAuthToken(tokenOption: unknown, envToken?: string | undefined): string | undefined;
|
|
4
|
+
export declare function isAuthorizedMCPRequest(headers: IncomingHttpHeaders, expectedToken?: string): boolean;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { timingSafeEqual } from 'node:crypto';
|
|
2
|
+
import { DinoxError } from '../../utils/errors.js';
|
|
3
|
+
const AUTH_HEADER_RE = /^Bearer\s+(.+)$/i;
|
|
4
|
+
export function isLoopbackHost(host) {
|
|
5
|
+
const normalized = host.trim().toLowerCase();
|
|
6
|
+
return normalized === '127.0.0.1' || normalized === 'localhost' || normalized === '::1';
|
|
7
|
+
}
|
|
8
|
+
export function resolveMCPAuthToken(tokenOption, envToken = process.env.DINOX_MCP_TOKEN) {
|
|
9
|
+
if (tokenOption !== undefined && tokenOption !== null) {
|
|
10
|
+
if (typeof tokenOption !== 'string') {
|
|
11
|
+
throw new DinoxError('--token must be a non-empty string');
|
|
12
|
+
}
|
|
13
|
+
const parsed = tokenOption.trim();
|
|
14
|
+
if (!parsed) {
|
|
15
|
+
throw new DinoxError('--token must be a non-empty string');
|
|
16
|
+
}
|
|
17
|
+
return parsed;
|
|
18
|
+
}
|
|
19
|
+
const fromEnv = envToken?.trim() ?? '';
|
|
20
|
+
return fromEnv || undefined;
|
|
21
|
+
}
|
|
22
|
+
function readHeaderTokenValue(value) {
|
|
23
|
+
if (typeof value === 'string') {
|
|
24
|
+
const parsed = value.trim();
|
|
25
|
+
return parsed || undefined;
|
|
26
|
+
}
|
|
27
|
+
if (!Array.isArray(value)) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
for (const item of value) {
|
|
31
|
+
const parsed = item.trim();
|
|
32
|
+
if (parsed) {
|
|
33
|
+
return parsed;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
function readBearerToken(headers) {
|
|
39
|
+
const authorization = readHeaderTokenValue(headers.authorization);
|
|
40
|
+
if (!authorization) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
const match = authorization.match(AUTH_HEADER_RE);
|
|
44
|
+
if (!match) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
const token = match[1]?.trim() ?? '';
|
|
48
|
+
return token || undefined;
|
|
49
|
+
}
|
|
50
|
+
function readMCPToken(headers) {
|
|
51
|
+
const bearer = readBearerToken(headers);
|
|
52
|
+
if (bearer) {
|
|
53
|
+
return bearer;
|
|
54
|
+
}
|
|
55
|
+
const raw = readHeaderTokenValue(headers['x-dinox-token']);
|
|
56
|
+
return raw?.trim() || undefined;
|
|
57
|
+
}
|
|
58
|
+
function secureTokenEquals(left, right) {
|
|
59
|
+
const leftBuffer = Buffer.from(left);
|
|
60
|
+
const rightBuffer = Buffer.from(right);
|
|
61
|
+
if (leftBuffer.length !== rightBuffer.length) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
return timingSafeEqual(leftBuffer, rightBuffer);
|
|
65
|
+
}
|
|
66
|
+
export function isAuthorizedMCPRequest(headers, expectedToken) {
|
|
67
|
+
if (!expectedToken) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
const provided = readMCPToken(headers);
|
|
71
|
+
if (!provided) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return secureTokenEquals(provided, expectedToken);
|
|
75
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { startMCPServer } from './server.js';
|
|
2
|
+
import { mcpTools } from './tools.js';
|
|
3
|
+
import { isLoopbackHost, resolveMCPAuthToken } from './auth.js';
|
|
4
|
+
import { DinoxError } from '../../utils/errors.js';
|
|
5
|
+
function parsePort(value) {
|
|
6
|
+
if (value === undefined || value === null || value === '') {
|
|
7
|
+
return 3000;
|
|
8
|
+
}
|
|
9
|
+
if (typeof value !== 'string') {
|
|
10
|
+
throw new DinoxError('--port must be a valid port number');
|
|
11
|
+
}
|
|
12
|
+
const trimmed = value.trim();
|
|
13
|
+
if (!/^\d+$/.test(trimmed)) {
|
|
14
|
+
throw new DinoxError('--port must be a valid port number');
|
|
15
|
+
}
|
|
16
|
+
const parsed = Number(trimmed);
|
|
17
|
+
if (!Number.isFinite(parsed) || parsed < 1 || parsed > 65535) {
|
|
18
|
+
throw new DinoxError('--port must be between 1 and 65535');
|
|
19
|
+
}
|
|
20
|
+
return Math.trunc(parsed);
|
|
21
|
+
}
|
|
22
|
+
function parseHost(value) {
|
|
23
|
+
if (value === undefined || value === null || value === '') {
|
|
24
|
+
return '127.0.0.1';
|
|
25
|
+
}
|
|
26
|
+
if (typeof value !== 'string') {
|
|
27
|
+
throw new DinoxError('--host must be a valid hostname or IP address');
|
|
28
|
+
}
|
|
29
|
+
const trimmed = value.trim();
|
|
30
|
+
if (!trimmed) {
|
|
31
|
+
throw new DinoxError('--host must be a valid hostname or IP address');
|
|
32
|
+
}
|
|
33
|
+
return trimmed;
|
|
34
|
+
}
|
|
35
|
+
export function registerMCPCommands(program) {
|
|
36
|
+
const mcp = program.command('mcp').description('MCP (Model Context Protocol) server');
|
|
37
|
+
mcp
|
|
38
|
+
.command('serve')
|
|
39
|
+
.description('Start MCP server for AI agent integration')
|
|
40
|
+
.option('--host <string>', 'bind address (default: 127.0.0.1)')
|
|
41
|
+
.option('--port <number>', 'server port (default: 3000)')
|
|
42
|
+
.option('--token <string>', 'auth token (or DINOX_MCP_TOKEN env var)')
|
|
43
|
+
.action(async (options) => {
|
|
44
|
+
const port = parsePort(options.port);
|
|
45
|
+
const host = parseHost(options.host);
|
|
46
|
+
const token = resolveMCPAuthToken(options.token);
|
|
47
|
+
const loopback = isLoopbackHost(host);
|
|
48
|
+
if (!loopback && !token) {
|
|
49
|
+
throw new DinoxError('--token (or DINOX_MCP_TOKEN) is required when --host is non-loopback');
|
|
50
|
+
}
|
|
51
|
+
console.log('Starting Dinox MCP server...');
|
|
52
|
+
console.log(`Host: ${host}`);
|
|
53
|
+
console.log(`Port: ${port}`);
|
|
54
|
+
console.log(`Auth: ${token ? 'enabled' : 'disabled (loopback only)'}`);
|
|
55
|
+
console.log('Protocol: Model Context Protocol (MCP)');
|
|
56
|
+
if (!loopback) {
|
|
57
|
+
console.log('warning: binding to a non-loopback host may expose your local data; use firewall/auth as needed');
|
|
58
|
+
}
|
|
59
|
+
console.log('');
|
|
60
|
+
console.log('Available tools:');
|
|
61
|
+
for (const tool of mcpTools) {
|
|
62
|
+
console.log(` - ${tool.name}`);
|
|
63
|
+
}
|
|
64
|
+
console.log('');
|
|
65
|
+
const { server, mcpServer } = await startMCPServer(port, host, token);
|
|
66
|
+
let shuttingDown = false;
|
|
67
|
+
const shutdown = async () => {
|
|
68
|
+
if (shuttingDown)
|
|
69
|
+
return;
|
|
70
|
+
shuttingDown = true;
|
|
71
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
72
|
+
await mcpServer.close();
|
|
73
|
+
};
|
|
74
|
+
process.on('SIGINT', () => {
|
|
75
|
+
void shutdown().finally(() => process.exit(0));
|
|
76
|
+
});
|
|
77
|
+
process.on('SIGTERM', () => {
|
|
78
|
+
void shutdown().finally(() => process.exit(0));
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
mcp.action((_options, command) => {
|
|
82
|
+
command.outputHelp();
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { IncomingMessage, Server } from 'node:http';
|
|
2
|
+
type MCPRequest = {
|
|
3
|
+
jsonrpc: '2.0';
|
|
4
|
+
id: string | number;
|
|
5
|
+
method: string;
|
|
6
|
+
params?: any;
|
|
7
|
+
};
|
|
8
|
+
type MCPResponse = {
|
|
9
|
+
jsonrpc: '2.0';
|
|
10
|
+
id: string | number;
|
|
11
|
+
result?: any;
|
|
12
|
+
error?: {
|
|
13
|
+
code: number;
|
|
14
|
+
message: string;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export declare class MCPServer {
|
|
18
|
+
private db;
|
|
19
|
+
initialize(): Promise<void>;
|
|
20
|
+
handleRequest(req: MCPRequest): Promise<MCPResponse>;
|
|
21
|
+
private handleInitialize;
|
|
22
|
+
private handleToolsList;
|
|
23
|
+
private handleToolsCall;
|
|
24
|
+
close(): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
export declare function startMCPServer(port?: number, host?: string, authToken?: string): Promise<{
|
|
27
|
+
server: Server<typeof IncomingMessage, typeof import("http").ServerResponse>;
|
|
28
|
+
mcpServer: MCPServer;
|
|
29
|
+
}>;
|
|
30
|
+
export {};
|