@chnxthr/knowledge-mcp 0.0.0-stage → 0.3.1
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 +21 -0
- package/README.md +37 -2
- package/dist/bootstrap.d.ts +1 -0
- package/dist/bootstrap.js +18 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +5 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/auth.d.ts +38 -0
- package/dist/core/auth.js +93 -0
- package/dist/core/auth.js.map +1 -0
- package/dist/core/config.d.ts +259 -0
- package/dist/core/config.js +172 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/context.d.ts +25 -0
- package/dist/core/context.js +37 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/env.d.ts +2 -0
- package/dist/core/env.js +5 -0
- package/dist/core/env.js.map +1 -0
- package/dist/core/log_mask.d.ts +10 -0
- package/dist/core/log_mask.js +88 -0
- package/dist/core/log_mask.js.map +1 -0
- package/dist/core/oauth.d.ts +46 -0
- package/dist/core/oauth.js +507 -0
- package/dist/core/oauth.js.map +1 -0
- package/dist/core/paths.d.ts +5 -0
- package/dist/core/paths.js +47 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/scope.d.ts +28 -0
- package/dist/core/scope.js +54 -0
- package/dist/core/scope.js.map +1 -0
- package/dist/core/upstream.d.ts +30 -0
- package/dist/core/upstream.js +164 -0
- package/dist/core/upstream.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin/define.d.ts +144 -0
- package/dist/plugin/define.js +44 -0
- package/dist/plugin/define.js.map +1 -0
- package/dist/plugin/load.d.ts +2 -0
- package/dist/plugin/load.js +41 -0
- package/dist/plugin/load.js.map +1 -0
- package/dist/plugin/ping.d.ts +9 -0
- package/dist/plugin/ping.js +29 -0
- package/dist/plugin/ping.js.map +1 -0
- package/dist/plugin/registry.d.ts +62 -0
- package/dist/plugin/registry.js +248 -0
- package/dist/plugin/registry.js.map +1 -0
- package/dist/plugin/result.d.ts +20 -0
- package/dist/plugin/result.js +59 -0
- package/dist/plugin/result.js.map +1 -0
- package/dist/plugins/drive/chunker.d.ts +28 -0
- package/dist/plugins/drive/chunker.js +356 -0
- package/dist/plugins/drive/chunker.js.map +1 -0
- package/dist/plugins/drive/clean_text.d.ts +13 -0
- package/dist/plugins/drive/clean_text.js +31 -0
- package/dist/plugins/drive/clean_text.js.map +1 -0
- package/dist/plugins/drive/client.d.ts +94 -0
- package/dist/plugins/drive/client.js +220 -0
- package/dist/plugins/drive/client.js.map +1 -0
- package/dist/plugins/drive/embeddings.d.ts +15 -0
- package/dist/plugins/drive/embeddings.js +118 -0
- package/dist/plugins/drive/embeddings.js.map +1 -0
- package/dist/plugins/drive/exclude.d.ts +11 -0
- package/dist/plugins/drive/exclude.js +36 -0
- package/dist/plugins/drive/exclude.js.map +1 -0
- package/dist/plugins/drive/extract_text.d.ts +26 -0
- package/dist/plugins/drive/extract_text.js +95 -0
- package/dist/plugins/drive/extract_text.js.map +1 -0
- package/dist/plugins/drive/get_token.d.ts +5 -0
- package/dist/plugins/drive/get_token.js +128 -0
- package/dist/plugins/drive/get_token.js.map +1 -0
- package/dist/plugins/drive/index.d.ts +5 -0
- package/dist/plugins/drive/index.js +72 -0
- package/dist/plugins/drive/index.js.map +1 -0
- package/dist/plugins/drive/indexer.d.ts +69 -0
- package/dist/plugins/drive/indexer.js +204 -0
- package/dist/plugins/drive/indexer.js.map +1 -0
- package/dist/plugins/drive/mathpix.d.ts +4 -0
- package/dist/plugins/drive/mathpix.js +102 -0
- package/dist/plugins/drive/mathpix.js.map +1 -0
- package/dist/plugins/drive/ooxml.d.ts +17 -0
- package/dist/plugins/drive/ooxml.js +152 -0
- package/dist/plugins/drive/ooxml.js.map +1 -0
- package/dist/plugins/drive/path.d.ts +40 -0
- package/dist/plugins/drive/path.js +87 -0
- package/dist/plugins/drive/path.js.map +1 -0
- package/dist/plugins/drive/qdrant.d.ts +123 -0
- package/dist/plugins/drive/qdrant.js +148 -0
- package/dist/plugins/drive/qdrant.js.map +1 -0
- package/dist/plugins/drive/reindex.d.ts +2 -0
- package/dist/plugins/drive/reindex.js +263 -0
- package/dist/plugins/drive/reindex.js.map +1 -0
- package/dist/plugins/drive/settings.d.ts +11 -0
- package/dist/plugins/drive/settings.js +13 -0
- package/dist/plugins/drive/settings.js.map +1 -0
- package/dist/plugins/drive/sync.d.ts +16 -0
- package/dist/plugins/drive/sync.js +139 -0
- package/dist/plugins/drive/sync.js.map +1 -0
- package/dist/plugins/drive/sync_state.d.ts +3 -0
- package/dist/plugins/drive/sync_state.js +26 -0
- package/dist/plugins/drive/sync_state.js.map +1 -0
- package/dist/plugins/drive/tools/list_drive_folder.d.ts +104 -0
- package/dist/plugins/drive/tools/list_drive_folder.js +221 -0
- package/dist/plugins/drive/tools/list_drive_folder.js.map +1 -0
- package/dist/plugins/drive/tools/read_drive_file.d.ts +66 -0
- package/dist/plugins/drive/tools/read_drive_file.js +206 -0
- package/dist/plugins/drive/tools/read_drive_file.js.map +1 -0
- package/dist/plugins/drive/tools/search_drive.d.ts +52 -0
- package/dist/plugins/drive/tools/search_drive.js +78 -0
- package/dist/plugins/drive/tools/search_drive.js.map +1 -0
- package/dist/plugins/drive/tools/semantic_search_drive.d.ts +109 -0
- package/dist/plugins/drive/tools/semantic_search_drive.js +228 -0
- package/dist/plugins/drive/tools/semantic_search_drive.js.map +1 -0
- package/dist/plugins/github/index.d.ts +1 -0
- package/dist/plugins/github/index.js +27 -0
- package/dist/plugins/github/index.js.map +1 -0
- package/dist/plugins/github/repo_tree.d.ts +57 -0
- package/dist/plugins/github/repo_tree.js +123 -0
- package/dist/plugins/github/repo_tree.js.map +1 -0
- package/dist/plugins/index.d.ts +11 -0
- package/dist/plugins/index.js +7 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/railway/index.d.ts +1 -0
- package/dist/plugins/railway/index.js +21 -0
- package/dist/plugins/railway/index.js.map +1 -0
- package/dist/plugins/railway/tools.d.ts +114 -0
- package/dist/plugins/railway/tools.js +165 -0
- package/dist/plugins/railway/tools.js.map +1 -0
- package/dist/plugins/slack/api.d.ts +63 -0
- package/dist/plugins/slack/api.js +280 -0
- package/dist/plugins/slack/api.js.map +1 -0
- package/dist/plugins/slack/index.d.ts +1 -0
- package/dist/plugins/slack/index.js +80 -0
- package/dist/plugins/slack/index.js.map +1 -0
- package/dist/plugins/slack/tools/slack_files.d.ts +87 -0
- package/dist/plugins/slack/tools/slack_files.js +204 -0
- package/dist/plugins/slack/tools/slack_files.js.map +1 -0
- package/dist/plugins/slack/tools/slack_list_channels.d.ts +46 -0
- package/dist/plugins/slack/tools/slack_list_channels.js +197 -0
- package/dist/plugins/slack/tools/slack_list_channels.js.map +1 -0
- package/dist/plugins/slack/tools/slack_read_channel.d.ts +56 -0
- package/dist/plugins/slack/tools/slack_read_channel.js +150 -0
- package/dist/plugins/slack/tools/slack_read_channel.js.map +1 -0
- package/dist/plugins/slack/tools/slack_search.d.ts +53 -0
- package/dist/plugins/slack/tools/slack_search.js +132 -0
- package/dist/plugins/slack/tools/slack_search.js.map +1 -0
- package/dist/run.d.ts +8 -0
- package/dist/run.js +270 -0
- package/dist/run.js.map +1 -0
- package/dist/server/http.d.ts +5 -0
- package/dist/server/http.js +406 -0
- package/dist/server/http.js.map +1 -0
- package/dist/server/identity.d.ts +17 -0
- package/dist/server/identity.js +47 -0
- package/dist/server/identity.js.map +1 -0
- package/dist/server/mcp.d.ts +7 -0
- package/dist/server/mcp.js +55 -0
- package/dist/server/mcp.js.map +1 -0
- package/dist/server/stdio.d.ts +2 -0
- package/dist/server/stdio.js +40 -0
- package/dist/server/stdio.js.map +1 -0
- package/dist/store/index.d.ts +11 -0
- package/dist/store/index.js +31 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/keys.d.ts +9 -0
- package/dist/store/keys.js +32 -0
- package/dist/store/keys.js.map +1 -0
- package/dist/store/sqlite.d.ts +38 -0
- package/dist/store/sqlite.js +316 -0
- package/dist/store/sqlite.js.map +1 -0
- package/dist/store/supabase.d.ts +35 -0
- package/dist/store/supabase.js +269 -0
- package/dist/store/supabase.js.map +1 -0
- package/dist/store/supabase_client.d.ts +10 -0
- package/dist/store/supabase_client.js +31 -0
- package/dist/store/supabase_client.js.map +1 -0
- package/dist/store/tool_log.d.ts +12 -0
- package/dist/store/tool_log.js +8 -0
- package/dist/store/tool_log.js.map +1 -0
- package/dist/store/types.d.ts +96 -0
- package/dist/store/types.js +2 -0
- package/dist/store/types.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +11 -0
- package/dist/version.js.map +1 -0
- package/package.json +80 -4
- package/sql/supabase.sql +185 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Store selection. MCP_STORE=sqlite|supabase picks one explicitly. Without it, Supabase is used when
|
|
3
|
+
* SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY are set (installs from before 0.3 keep working), else SQLite.
|
|
4
|
+
*/
|
|
5
|
+
import type { Store } from './types.js';
|
|
6
|
+
export declare function storeKind(): 'sqlite' | 'supabase';
|
|
7
|
+
/** The process-wide store, opened on first use. */
|
|
8
|
+
export declare function getStore(): Promise<Store>;
|
|
9
|
+
/** Tests only: use this store instead of opening one. */
|
|
10
|
+
export declare function setStoreForTesting(store: Store | null): void;
|
|
11
|
+
export type { Store } from './types.js';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
let _store = null;
|
|
2
|
+
export function storeKind() {
|
|
3
|
+
const explicit = (process.env.MCP_STORE ?? '').trim().toLowerCase();
|
|
4
|
+
if (explicit === 'sqlite' || explicit === 'supabase')
|
|
5
|
+
return explicit;
|
|
6
|
+
if (explicit)
|
|
7
|
+
throw new Error(`[store] MCP_STORE must be "sqlite" or "supabase", got "${explicit}"`);
|
|
8
|
+
return process.env.SUPABASE_URL && process.env.SUPABASE_SERVICE_ROLE_KEY ? 'supabase' : 'sqlite';
|
|
9
|
+
}
|
|
10
|
+
/** The process-wide store, opened on first use. */
|
|
11
|
+
export function getStore() {
|
|
12
|
+
if (!_store) {
|
|
13
|
+
_store = (async () => {
|
|
14
|
+
if (storeKind() === 'supabase') {
|
|
15
|
+
const { SupabaseStore } = await import('./supabase.js');
|
|
16
|
+
return new SupabaseStore();
|
|
17
|
+
}
|
|
18
|
+
const { SqliteStore } = await import('./sqlite.js');
|
|
19
|
+
return SqliteStore.open();
|
|
20
|
+
})();
|
|
21
|
+
_store.catch(() => {
|
|
22
|
+
_store = null; // let the next call retry instead of caching the failure
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return _store;
|
|
26
|
+
}
|
|
27
|
+
/** Tests only: use this store instead of opening one. */
|
|
28
|
+
export function setStoreForTesting(store) {
|
|
29
|
+
_store = store ? Promise.resolve(store) : null;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":"AAMA,IAAI,MAAM,GAA0B,IAAI,CAAC;AAEzC,MAAM,UAAU,SAAS;IACvB,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACpE,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,UAAU;QAAE,OAAO,QAAQ,CAAC;IACtE,IAAI,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,0DAA0D,QAAQ,GAAG,CAAC,CAAC;IACrG,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC;AACnG,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,QAAQ;IACtB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE;YACnB,IAAI,SAAS,EAAE,KAAK,UAAU,EAAE,CAAC;gBAC/B,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;gBACxD,OAAO,IAAI,aAAa,EAAE,CAAC;YAC7B,CAAC;YACD,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;YACpD,OAAO,WAAW,CAAC,IAAI,EAAE,CAAC;QAC5B,CAAC,CAAC,EAAE,CAAC;QACL,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;YAChB,MAAM,GAAG,IAAI,CAAC,CAAC,yDAAyD;QAC1E,CAAC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,kBAAkB,CAAC,KAAmB;IACpD,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Role } from '../core/auth.js';
|
|
2
|
+
/** `kmcp_` + 32 random bytes (base64url). The prefix lets log masking and secret scanners spot it. */
|
|
3
|
+
export declare function generateKey(): string;
|
|
4
|
+
/** Hex SHA-256 of the UTF-8 key — same as encode(sha256(convert_to(key,'UTF8')),'hex') in Postgres. */
|
|
5
|
+
export declare function hashKey(key: string): string;
|
|
6
|
+
/** Stored role text → Role. 'engineer' is the pre-0.3 name of 'member'. Unknown values are treated as viewer. */
|
|
7
|
+
export declare function toRole(v: unknown): Role;
|
|
8
|
+
/** "90d", "12h", "30m" or an ISO date → ISO timestamp. */
|
|
9
|
+
export declare function parseExpiry(v: string): string;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** API key format and hashing, shared by both stores (Supabase's validate_mcp_key uses the same hash). */
|
|
2
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
3
|
+
/** `kmcp_` + 32 random bytes (base64url). The prefix lets log masking and secret scanners spot it. */
|
|
4
|
+
export function generateKey() {
|
|
5
|
+
return `kmcp_${randomBytes(32).toString('base64url')}`;
|
|
6
|
+
}
|
|
7
|
+
/** Hex SHA-256 of the UTF-8 key — same as encode(sha256(convert_to(key,'UTF8')),'hex') in Postgres. */
|
|
8
|
+
export function hashKey(key) {
|
|
9
|
+
return createHash('sha256').update(key, 'utf8').digest('hex');
|
|
10
|
+
}
|
|
11
|
+
/** Stored role text → Role. 'engineer' is the pre-0.3 name of 'member'. Unknown values are treated as viewer. */
|
|
12
|
+
export function toRole(v) {
|
|
13
|
+
if (v === 'admin')
|
|
14
|
+
return 'admin';
|
|
15
|
+
if (v === 'member' || v === 'engineer')
|
|
16
|
+
return 'member';
|
|
17
|
+
return 'viewer';
|
|
18
|
+
}
|
|
19
|
+
/** "90d", "12h", "30m" or an ISO date → ISO timestamp. */
|
|
20
|
+
export function parseExpiry(v) {
|
|
21
|
+
const m = /^(\d+)([dhm])$/.exec(v.trim());
|
|
22
|
+
if (m) {
|
|
23
|
+
const n = Number(m[1]);
|
|
24
|
+
const ms = m[2] === 'd' ? n * 86_400_000 : m[2] === 'h' ? n * 3_600_000 : n * 60_000;
|
|
25
|
+
return new Date(Date.now() + ms).toISOString();
|
|
26
|
+
}
|
|
27
|
+
const d = new Date(v);
|
|
28
|
+
if (Number.isNaN(d.getTime()))
|
|
29
|
+
throw new Error(`invalid expiry "${v}" — use 90d, 12h, 30m or a date`);
|
|
30
|
+
return d.toISOString();
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/store/keys.ts"],"names":[],"mappings":"AAAA,0GAA0G;AAC1G,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAGtD,sGAAsG;AACtG,MAAM,UAAU,WAAW;IACzB,OAAO,QAAQ,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;AACzD,CAAC;AAED,uGAAuG;AACvG,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAED,iHAAiH;AACjH,MAAM,UAAU,MAAM,CAAC,CAAU;IAC/B,IAAI,CAAC,KAAK,OAAO;QAAE,OAAO,OAAO,CAAC;IAClC,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,UAAU;QAAE,OAAO,QAAQ,CAAC;IACxD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,WAAW,CAAC,CAAS;IACnC,MAAM,CAAC,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1C,IAAI,CAAC,EAAE,CAAC;QACN,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;QACrF,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACjD,CAAC;IACD,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,iCAAiC,CAAC,CAAC;IACtG,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { OAuthClientInformationFull } from '@modelcontextprotocol/sdk/shared/auth.js';
|
|
2
|
+
import type { KeyCheck, KeyInfo, NewKey, RefreshConsume, SlackChannelPatch, SlackChannelRow, Store, ToolCallRecord, UserRecord } from './types.js';
|
|
3
|
+
export declare class SqliteStore implements Store {
|
|
4
|
+
private readonly db;
|
|
5
|
+
readonly location: string;
|
|
6
|
+
readonly kind: "sqlite";
|
|
7
|
+
private constructor();
|
|
8
|
+
static open(path?: string): Promise<SqliteStore>;
|
|
9
|
+
/** Keep the audit log bounded: MCP_TOOL_LOG_DAYS (default 90) days. */
|
|
10
|
+
private pruneToolCalls;
|
|
11
|
+
close(): void;
|
|
12
|
+
validateKey(rawKey: string): Promise<KeyCheck>;
|
|
13
|
+
createKey(input: NewKey): Promise<{
|
|
14
|
+
id: string;
|
|
15
|
+
key: string;
|
|
16
|
+
}>;
|
|
17
|
+
listKeys(): Promise<KeyInfo[]>;
|
|
18
|
+
revokeKey(id: string): Promise<boolean>;
|
|
19
|
+
getUser(email: string): Promise<UserRecord | null>;
|
|
20
|
+
private userFromRow;
|
|
21
|
+
upsertUser(u: UserRecord): Promise<void>;
|
|
22
|
+
listUsers(): Promise<UserRecord[]>;
|
|
23
|
+
removeUser(email: string): Promise<boolean>;
|
|
24
|
+
logToolCall(row: ToolCallRecord): Promise<void>;
|
|
25
|
+
getOAuthClient(clientId: string): Promise<OAuthClientInformationFull | null>;
|
|
26
|
+
saveOAuthClient(client: OAuthClientInformationFull): Promise<void>;
|
|
27
|
+
touchOAuthClient(clientId: string): Promise<void>;
|
|
28
|
+
recordRefreshToken(jti: string, email: string, clientId: string, expiresAt: string): Promise<void>;
|
|
29
|
+
consumeRefreshToken(jti: string, rotatedTo: string): Promise<RefreshConsume>;
|
|
30
|
+
revokeAllRefreshForEmail(email: string): Promise<void>;
|
|
31
|
+
purgeExpiredRefreshTokens(): Promise<void>;
|
|
32
|
+
getState(namespace: string, key: string): Promise<unknown | null>;
|
|
33
|
+
setState(namespace: string, key: string, value: unknown): Promise<void>;
|
|
34
|
+
deleteState(namespace: string, key: string): Promise<void>;
|
|
35
|
+
listSlackChannels(): Promise<SlackChannelRow[]>;
|
|
36
|
+
insertSlackChannels(rows: Array<Omit<SlackChannelRow, 'id'>>): Promise<void>;
|
|
37
|
+
updateSlackChannel(id: string, patch: SlackChannelPatch): Promise<void>;
|
|
38
|
+
}
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite store — the default. One file (<data dir>/knowledge-mcp.db), no external service.
|
|
3
|
+
*
|
|
4
|
+
* Uses Node's built-in node:sqlite (Node 22.13+), so there is no native module to compile.
|
|
5
|
+
* WAL mode lets the CLI (`knowledge-mcp keys create`) write while the server is running.
|
|
6
|
+
* The file holds key hashes and OAuth client secrets: the directory is created 0700 and the file 0600.
|
|
7
|
+
*/
|
|
8
|
+
import { chmodSync, existsSync, mkdirSync } from 'node:fs';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { randomUUID } from 'node:crypto';
|
|
11
|
+
import { dataDir } from '../core/paths.js';
|
|
12
|
+
import { generateKey, hashKey, toRole } from './keys.js';
|
|
13
|
+
const SCHEMA_SQL = `
|
|
14
|
+
create table if not exists mcp_keys (
|
|
15
|
+
id text primary key,
|
|
16
|
+
key_hash text not null unique,
|
|
17
|
+
org_id text not null default 'org',
|
|
18
|
+
role text not null default 'member',
|
|
19
|
+
email text,
|
|
20
|
+
label text,
|
|
21
|
+
active integer not null default 1,
|
|
22
|
+
expires_at text,
|
|
23
|
+
created_at text not null
|
|
24
|
+
);
|
|
25
|
+
create table if not exists app_users (
|
|
26
|
+
email text primary key,
|
|
27
|
+
role text not null default 'member',
|
|
28
|
+
name text,
|
|
29
|
+
allowed_slack_channels text,
|
|
30
|
+
allowed_drive_folders text,
|
|
31
|
+
allowed_tools text,
|
|
32
|
+
created_at text not null
|
|
33
|
+
);
|
|
34
|
+
create table if not exists mcp_oauth_clients (
|
|
35
|
+
client_id text primary key,
|
|
36
|
+
client_data text not null,
|
|
37
|
+
client_name text,
|
|
38
|
+
created_at text not null,
|
|
39
|
+
last_used_at text
|
|
40
|
+
);
|
|
41
|
+
create table if not exists mcp_refresh_tokens (
|
|
42
|
+
jti text primary key,
|
|
43
|
+
email text not null,
|
|
44
|
+
client_id text not null,
|
|
45
|
+
expires_at text not null,
|
|
46
|
+
revoked_at text,
|
|
47
|
+
rotated_to text,
|
|
48
|
+
created_at text not null
|
|
49
|
+
);
|
|
50
|
+
create index if not exists mcp_refresh_tokens_email_idx on mcp_refresh_tokens (email);
|
|
51
|
+
create table if not exists mcp_plugin_state (
|
|
52
|
+
namespace text not null,
|
|
53
|
+
key text not null,
|
|
54
|
+
value text not null,
|
|
55
|
+
updated_at text not null,
|
|
56
|
+
primary key (namespace, key)
|
|
57
|
+
);
|
|
58
|
+
create table if not exists mcp_tool_calls (
|
|
59
|
+
id integer primary key autoincrement,
|
|
60
|
+
tool text not null,
|
|
61
|
+
email text,
|
|
62
|
+
role text,
|
|
63
|
+
ok integer not null,
|
|
64
|
+
error text,
|
|
65
|
+
duration_ms integer,
|
|
66
|
+
source text,
|
|
67
|
+
created_at text not null
|
|
68
|
+
);
|
|
69
|
+
create index if not exists mcp_tool_calls_created_idx on mcp_tool_calls (created_at);
|
|
70
|
+
create table if not exists slack_channels (
|
|
71
|
+
id text primary key,
|
|
72
|
+
channel_name text not null,
|
|
73
|
+
channel_id text unique,
|
|
74
|
+
purpose text not null default '',
|
|
75
|
+
category text,
|
|
76
|
+
enabled integer not null default 0,
|
|
77
|
+
sort_order integer not null default 100,
|
|
78
|
+
created_at text not null
|
|
79
|
+
);
|
|
80
|
+
`;
|
|
81
|
+
const now = () => new Date().toISOString();
|
|
82
|
+
const arr = (v) => {
|
|
83
|
+
if (typeof v !== 'string' || !v)
|
|
84
|
+
return null;
|
|
85
|
+
try {
|
|
86
|
+
const parsed = JSON.parse(v);
|
|
87
|
+
return Array.isArray(parsed) ? parsed.map(String) : null;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const arrText = (v) => (v && v.length ? JSON.stringify(v) : null);
|
|
94
|
+
const SLACK_PATCH_COLUMNS = new Set(['channel_name', 'channel_id', 'purpose', 'category', 'enabled', 'sort_order']);
|
|
95
|
+
/** Loads node:sqlite without its one-time ExperimentalWarning (stable enough for this use, noisy in every CLI run). */
|
|
96
|
+
async function openDatabase(path) {
|
|
97
|
+
const orig = process.emitWarning;
|
|
98
|
+
process.emitWarning = ((warning, ...rest) => {
|
|
99
|
+
const msg = typeof warning === 'string' ? warning : warning?.message;
|
|
100
|
+
if (msg && msg.includes('SQLite is an experimental feature'))
|
|
101
|
+
return;
|
|
102
|
+
return orig.call(process, warning, ...rest);
|
|
103
|
+
});
|
|
104
|
+
try {
|
|
105
|
+
const { DatabaseSync } = await import('node:sqlite');
|
|
106
|
+
return new DatabaseSync(path);
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
process.emitWarning = orig;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
export class SqliteStore {
|
|
113
|
+
db;
|
|
114
|
+
location;
|
|
115
|
+
kind = 'sqlite';
|
|
116
|
+
constructor(db, location) {
|
|
117
|
+
this.db = db;
|
|
118
|
+
this.location = location;
|
|
119
|
+
}
|
|
120
|
+
static async open(path = join(dataDir(), 'knowledge-mcp.db')) {
|
|
121
|
+
const dir = join(path, '..');
|
|
122
|
+
if (!existsSync(dir))
|
|
123
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
124
|
+
const fresh = !existsSync(path);
|
|
125
|
+
const db = await openDatabase(path);
|
|
126
|
+
if (fresh) {
|
|
127
|
+
try {
|
|
128
|
+
chmodSync(path, 0o600);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
/* not supported on this filesystem */
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
db.exec('pragma journal_mode = wal; pragma busy_timeout = 5000; pragma foreign_keys = on;');
|
|
135
|
+
db.exec(SCHEMA_SQL);
|
|
136
|
+
const store = new SqliteStore(db, path);
|
|
137
|
+
store.pruneToolCalls();
|
|
138
|
+
return store;
|
|
139
|
+
}
|
|
140
|
+
/** Keep the audit log bounded: MCP_TOOL_LOG_DAYS (default 90) days. */
|
|
141
|
+
pruneToolCalls() {
|
|
142
|
+
const days = Number(process.env.MCP_TOOL_LOG_DAYS ?? 90);
|
|
143
|
+
if (!Number.isFinite(days) || days <= 0)
|
|
144
|
+
return;
|
|
145
|
+
const cutoff = new Date(Date.now() - days * 86_400_000).toISOString();
|
|
146
|
+
this.db.prepare('delete from mcp_tool_calls where created_at < ?').run(cutoff);
|
|
147
|
+
}
|
|
148
|
+
close() {
|
|
149
|
+
this.db.close();
|
|
150
|
+
}
|
|
151
|
+
// ── API keys ──
|
|
152
|
+
async validateKey(rawKey) {
|
|
153
|
+
const r = this.db.prepare('select * from mcp_keys where key_hash = ?').get(hashKey(rawKey));
|
|
154
|
+
if (!r)
|
|
155
|
+
return { ok: false, reason: 'key not found' };
|
|
156
|
+
if (!r.active)
|
|
157
|
+
return { ok: false, reason: 'key inactive' };
|
|
158
|
+
if (r.expires_at && String(r.expires_at) < now())
|
|
159
|
+
return { ok: false, reason: 'key expired' };
|
|
160
|
+
return {
|
|
161
|
+
ok: true,
|
|
162
|
+
keyId: String(r.id),
|
|
163
|
+
orgId: String(r.org_id),
|
|
164
|
+
role: toRole(r.role),
|
|
165
|
+
email: r.email ?? null,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
async createKey(input) {
|
|
169
|
+
const id = randomUUID();
|
|
170
|
+
const key = generateKey();
|
|
171
|
+
this.db
|
|
172
|
+
.prepare('insert into mcp_keys (id, key_hash, org_id, role, email, label, active, expires_at, created_at) values (?, ?, ?, ?, ?, ?, 1, ?, ?)')
|
|
173
|
+
.run(id, hashKey(key), input.orgId, input.role ?? 'member', input.email?.toLowerCase() ?? null, input.label ?? null, input.expiresAt ?? null, now());
|
|
174
|
+
return { id, key };
|
|
175
|
+
}
|
|
176
|
+
async listKeys() {
|
|
177
|
+
const rows = this.db.prepare('select * from mcp_keys order by created_at').all();
|
|
178
|
+
return rows.map((r) => ({
|
|
179
|
+
id: String(r.id),
|
|
180
|
+
orgId: String(r.org_id),
|
|
181
|
+
role: toRole(r.role),
|
|
182
|
+
email: r.email ?? null,
|
|
183
|
+
label: r.label ?? null,
|
|
184
|
+
active: !!r.active,
|
|
185
|
+
expiresAt: r.expires_at ?? null,
|
|
186
|
+
createdAt: String(r.created_at),
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
189
|
+
async revokeKey(id) {
|
|
190
|
+
return Number(this.db.prepare('update mcp_keys set active = 0 where id = ? and active = 1').run(id).changes) > 0;
|
|
191
|
+
}
|
|
192
|
+
// ── Users ──
|
|
193
|
+
async getUser(email) {
|
|
194
|
+
const r = this.db.prepare('select * from app_users where email = ?').get(email.toLowerCase());
|
|
195
|
+
return r ? this.userFromRow(r) : null;
|
|
196
|
+
}
|
|
197
|
+
userFromRow(r) {
|
|
198
|
+
return {
|
|
199
|
+
email: String(r.email),
|
|
200
|
+
role: String(r.role),
|
|
201
|
+
name: r.name ?? null,
|
|
202
|
+
allowedSlackChannels: arr(r.allowed_slack_channels),
|
|
203
|
+
allowedDriveFolders: arr(r.allowed_drive_folders),
|
|
204
|
+
allowedTools: arr(r.allowed_tools),
|
|
205
|
+
scopesKnown: true,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
async upsertUser(u) {
|
|
209
|
+
this.db
|
|
210
|
+
.prepare(`insert into app_users (email, role, name, allowed_slack_channels, allowed_drive_folders, allowed_tools, created_at)
|
|
211
|
+
values (?, ?, ?, ?, ?, ?, ?)
|
|
212
|
+
on conflict (email) do update set role = excluded.role, name = excluded.name,
|
|
213
|
+
allowed_slack_channels = excluded.allowed_slack_channels,
|
|
214
|
+
allowed_drive_folders = excluded.allowed_drive_folders, allowed_tools = excluded.allowed_tools`)
|
|
215
|
+
.run(u.email.toLowerCase(), u.role, u.name ?? null, arrText(u.allowedSlackChannels), arrText(u.allowedDriveFolders), arrText(u.allowedTools), now());
|
|
216
|
+
}
|
|
217
|
+
async listUsers() {
|
|
218
|
+
return this.db.prepare('select * from app_users order by email').all().map((r) => this.userFromRow(r));
|
|
219
|
+
}
|
|
220
|
+
async removeUser(email) {
|
|
221
|
+
return Number(this.db.prepare('delete from app_users where email = ?').run(email.toLowerCase()).changes) > 0;
|
|
222
|
+
}
|
|
223
|
+
// ── Audit log ──
|
|
224
|
+
async logToolCall(row) {
|
|
225
|
+
try {
|
|
226
|
+
this.db
|
|
227
|
+
.prepare('insert into mcp_tool_calls (tool, email, role, ok, error, duration_ms, source, created_at) values (?, ?, ?, ?, ?, ?, ?, ?)')
|
|
228
|
+
.run(row.tool, row.email, row.role, row.ok ? 1 : 0, row.error ? row.error.slice(0, 2000) : null, row.durationMs, 'knowledge-mcp', now());
|
|
229
|
+
}
|
|
230
|
+
catch (e) {
|
|
231
|
+
console.error('[tool-log] insert failed:', e instanceof Error ? e.message : e);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// ── OAuth ──
|
|
235
|
+
async getOAuthClient(clientId) {
|
|
236
|
+
const r = this.db.prepare('select client_data from mcp_oauth_clients where client_id = ?').get(clientId);
|
|
237
|
+
return r ? JSON.parse(String(r.client_data)) : null;
|
|
238
|
+
}
|
|
239
|
+
async saveOAuthClient(client) {
|
|
240
|
+
this.db
|
|
241
|
+
.prepare(`insert into mcp_oauth_clients (client_id, client_data, client_name, created_at, last_used_at) values (?, ?, ?, ?, ?)
|
|
242
|
+
on conflict (client_id) do update set client_data = excluded.client_data, client_name = excluded.client_name,
|
|
243
|
+
last_used_at = excluded.last_used_at`)
|
|
244
|
+
.run(client.client_id, JSON.stringify(client), typeof client.client_name === 'string' ? client.client_name : null, now(), now());
|
|
245
|
+
}
|
|
246
|
+
async touchOAuthClient(clientId) {
|
|
247
|
+
this.db.prepare('update mcp_oauth_clients set last_used_at = ? where client_id = ?').run(now(), clientId);
|
|
248
|
+
}
|
|
249
|
+
async recordRefreshToken(jti, email, clientId, expiresAt) {
|
|
250
|
+
this.db
|
|
251
|
+
.prepare('insert into mcp_refresh_tokens (jti, email, client_id, expires_at, created_at) values (?, ?, ?, ?, ?)')
|
|
252
|
+
.run(jti, email.toLowerCase(), clientId, expiresAt, now());
|
|
253
|
+
}
|
|
254
|
+
async consumeRefreshToken(jti, rotatedTo) {
|
|
255
|
+
const t = now();
|
|
256
|
+
// One statement, so two concurrent refreshes with the same token cannot both succeed.
|
|
257
|
+
const changed = this.db
|
|
258
|
+
.prepare('update mcp_refresh_tokens set revoked_at = ?, rotated_to = ? where jti = ? and revoked_at is null and expires_at > ?')
|
|
259
|
+
.run(t, rotatedTo, jti, t).changes;
|
|
260
|
+
if (Number(changed) > 0)
|
|
261
|
+
return 'ok';
|
|
262
|
+
const row = this.db.prepare('select jti from mcp_refresh_tokens where jti = ?').get(jti);
|
|
263
|
+
return row ? 'revoked' : 'unknown';
|
|
264
|
+
}
|
|
265
|
+
async revokeAllRefreshForEmail(email) {
|
|
266
|
+
this.db.prepare('update mcp_refresh_tokens set revoked_at = ? where email = ? and revoked_at is null').run(now(), email.toLowerCase());
|
|
267
|
+
}
|
|
268
|
+
async purgeExpiredRefreshTokens() {
|
|
269
|
+
this.db.prepare('delete from mcp_refresh_tokens where expires_at < ?').run(now());
|
|
270
|
+
}
|
|
271
|
+
// ── Plugin state ──
|
|
272
|
+
async getState(namespace, key) {
|
|
273
|
+
const r = this.db.prepare('select value from mcp_plugin_state where namespace = ? and key = ?').get(namespace, key);
|
|
274
|
+
return r ? JSON.parse(String(r.value)) : null;
|
|
275
|
+
}
|
|
276
|
+
async setState(namespace, key, value) {
|
|
277
|
+
this.db
|
|
278
|
+
.prepare(`insert into mcp_plugin_state (namespace, key, value, updated_at) values (?, ?, ?, ?)
|
|
279
|
+
on conflict (namespace, key) do update set value = excluded.value, updated_at = excluded.updated_at`)
|
|
280
|
+
.run(namespace, key, JSON.stringify(value ?? null), now());
|
|
281
|
+
}
|
|
282
|
+
async deleteState(namespace, key) {
|
|
283
|
+
this.db.prepare('delete from mcp_plugin_state where namespace = ? and key = ?').run(namespace, key);
|
|
284
|
+
}
|
|
285
|
+
// ── Slack channel map ──
|
|
286
|
+
async listSlackChannels() {
|
|
287
|
+
const rows = this.db.prepare('select * from slack_channels order by sort_order, channel_name').all();
|
|
288
|
+
return rows.map((r) => ({
|
|
289
|
+
id: String(r.id),
|
|
290
|
+
channel_name: String(r.channel_name),
|
|
291
|
+
channel_id: r.channel_id ?? null,
|
|
292
|
+
purpose: String(r.purpose ?? ''),
|
|
293
|
+
category: r.category ?? null,
|
|
294
|
+
enabled: !!r.enabled,
|
|
295
|
+
sort_order: Number(r.sort_order),
|
|
296
|
+
}));
|
|
297
|
+
}
|
|
298
|
+
async insertSlackChannels(rows) {
|
|
299
|
+
const stmt = this.db.prepare('insert or ignore into slack_channels (id, channel_name, channel_id, purpose, category, enabled, sort_order, created_at) values (?, ?, ?, ?, ?, ?, ?, ?)');
|
|
300
|
+
for (const r of rows) {
|
|
301
|
+
stmt.run(randomUUID(), r.channel_name, r.channel_id, r.purpose, r.category, r.enabled ? 1 : 0, r.sort_order, now());
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
async updateSlackChannel(id, patch) {
|
|
305
|
+
// Column names go into the SQL text, so only known columns pass.
|
|
306
|
+
const cols = Object.keys(patch).filter((c) => SLACK_PATCH_COLUMNS.has(c));
|
|
307
|
+
if (!cols.length)
|
|
308
|
+
return;
|
|
309
|
+
const values = cols.map((c) => {
|
|
310
|
+
const v = patch[c];
|
|
311
|
+
return typeof v === 'boolean' ? (v ? 1 : 0) : (v ?? null);
|
|
312
|
+
});
|
|
313
|
+
this.db.prepare(`update slack_channels set ${cols.map((c) => `${c} = ?`).join(', ')} where id = ?`).run(...values, id);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
//# sourceMappingURL=sqlite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/store/sqlite.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { OAuthClientInformationFull } from '@modelcontextprotocol/sdk/shared/auth.js';
|
|
2
|
+
import type { KeyCheck, KeyInfo, NewKey, RefreshConsume, SlackChannelPatch, SlackChannelRow, Store, ToolCallRecord, UserRecord } from './types.js';
|
|
3
|
+
export declare class SupabaseStore implements Store {
|
|
4
|
+
readonly kind: "supabase";
|
|
5
|
+
readonly location: string;
|
|
6
|
+
private readonly sb;
|
|
7
|
+
private readonly schema;
|
|
8
|
+
constructor();
|
|
9
|
+
private t;
|
|
10
|
+
validateKey(rawKey: string): Promise<KeyCheck>;
|
|
11
|
+
createKey(input: NewKey): Promise<{
|
|
12
|
+
id: string;
|
|
13
|
+
key: string;
|
|
14
|
+
}>;
|
|
15
|
+
listKeys(): Promise<KeyInfo[]>;
|
|
16
|
+
revokeKey(id: string): Promise<boolean>;
|
|
17
|
+
getUser(email: string): Promise<UserRecord | null>;
|
|
18
|
+
upsertUser(u: UserRecord): Promise<void>;
|
|
19
|
+
listUsers(): Promise<UserRecord[]>;
|
|
20
|
+
removeUser(email: string): Promise<boolean>;
|
|
21
|
+
logToolCall(row: ToolCallRecord): Promise<void>;
|
|
22
|
+
getOAuthClient(clientId: string): Promise<OAuthClientInformationFull | null>;
|
|
23
|
+
saveOAuthClient(client: OAuthClientInformationFull): Promise<void>;
|
|
24
|
+
touchOAuthClient(clientId: string): Promise<void>;
|
|
25
|
+
recordRefreshToken(jti: string, email: string, clientId: string, expiresAt: string): Promise<void>;
|
|
26
|
+
consumeRefreshToken(jti: string, rotatedTo: string): Promise<RefreshConsume>;
|
|
27
|
+
revokeAllRefreshForEmail(email: string): Promise<void>;
|
|
28
|
+
purgeExpiredRefreshTokens(): Promise<void>;
|
|
29
|
+
getState(namespace: string, key: string): Promise<unknown | null>;
|
|
30
|
+
setState(namespace: string, key: string, value: unknown): Promise<void>;
|
|
31
|
+
deleteState(namespace: string, key: string): Promise<void>;
|
|
32
|
+
listSlackChannels(): Promise<SlackChannelRow[]>;
|
|
33
|
+
insertSlackChannels(rows: Array<Omit<SlackChannelRow, 'id'>>): Promise<void>;
|
|
34
|
+
updateSlackChannel(id: string, patch: SlackChannelPatch): Promise<void>;
|
|
35
|
+
}
|