@steno-ai/mcp 0.1.10 → 0.1.11
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/init.js +159 -28
- package/dist/init.js.map +1 -1
- package/package.json +6 -3
- package/src/init.ts +160 -21
package/dist/init.js
CHANGED
|
@@ -73,7 +73,7 @@ const MIGRATIONS = [
|
|
|
73
73
|
input_size INTEGER,
|
|
74
74
|
scope TEXT NOT NULL,
|
|
75
75
|
scope_id TEXT NOT NULL,
|
|
76
|
-
session_id
|
|
76
|
+
session_id TEXT,
|
|
77
77
|
tier_used TEXT,
|
|
78
78
|
llm_model TEXT,
|
|
79
79
|
facts_created INTEGER NOT NULL DEFAULT 0,
|
|
@@ -96,7 +96,7 @@ const MIGRATIONS = [
|
|
|
96
96
|
tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
|
|
97
97
|
scope TEXT NOT NULL CHECK (scope IN ('user','agent','session','hive')),
|
|
98
98
|
scope_id TEXT NOT NULL,
|
|
99
|
-
session_id
|
|
99
|
+
session_id TEXT,
|
|
100
100
|
content TEXT NOT NULL,
|
|
101
101
|
embedding VECTOR(2000),
|
|
102
102
|
embedding_model TEXT,
|
|
@@ -276,6 +276,133 @@ const MIGRATIONS = [
|
|
|
276
276
|
AND f.search_vector @@ plainto_tsquery('english', search_query)
|
|
277
277
|
ORDER BY ts_rank(f.search_vector, plainto_tsquery('english', search_query)) DESC LIMIT match_count);
|
|
278
278
|
END; $$;`,
|
|
279
|
+
// Usage records unique constraint (required by increment_usage)
|
|
280
|
+
`ALTER TABLE usage_records ADD CONSTRAINT IF NOT EXISTS usage_records_tenant_period_unique UNIQUE (tenant_id, period_start);`,
|
|
281
|
+
// Extraction hash unique index
|
|
282
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_extractions_hash ON extractions(tenant_id, input_hash);`,
|
|
283
|
+
// match_facts RPC
|
|
284
|
+
`CREATE OR REPLACE FUNCTION match_facts(
|
|
285
|
+
query_embedding TEXT, match_tenant_id UUID, match_scope TEXT,
|
|
286
|
+
match_scope_id TEXT, match_count INT, min_similarity FLOAT DEFAULT 0,
|
|
287
|
+
match_as_of TIMESTAMPTZ DEFAULT NULL
|
|
288
|
+
) RETURNS TABLE (
|
|
289
|
+
id UUID, tenant_id UUID, scope TEXT, scope_id TEXT, session_id TEXT,
|
|
290
|
+
content TEXT, embedding_model TEXT, embedding_dim INT, version INT,
|
|
291
|
+
lineage_id UUID, valid_from TIMESTAMPTZ, valid_until TIMESTAMPTZ,
|
|
292
|
+
operation TEXT, parent_id UUID, importance NUMERIC, frequency INT,
|
|
293
|
+
last_accessed TIMESTAMPTZ, decay_score NUMERIC, contradiction_status TEXT,
|
|
294
|
+
contradicts_id UUID, source_type TEXT, source_ref JSONB, confidence NUMERIC,
|
|
295
|
+
original_content TEXT, extraction_id UUID, extraction_tier TEXT,
|
|
296
|
+
modality TEXT, tags TEXT[], metadata JSONB,
|
|
297
|
+
event_date TIMESTAMPTZ, document_date TIMESTAMPTZ, source_chunk TEXT,
|
|
298
|
+
created_at TIMESTAMPTZ, similarity FLOAT
|
|
299
|
+
) LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT
|
|
300
|
+
f.id, f.tenant_id, f.scope, f.scope_id, f.session_id,
|
|
301
|
+
f.content, f.embedding_model, f.embedding_dim, f.version, f.lineage_id,
|
|
302
|
+
f.valid_from, f.valid_until, f.operation, f.parent_id, f.importance, f.frequency,
|
|
303
|
+
f.last_accessed, f.decay_score, f.contradiction_status, f.contradicts_id,
|
|
304
|
+
f.source_type, f.source_ref, f.confidence, f.original_content, f.extraction_id,
|
|
305
|
+
f.extraction_tier, f.modality, f.tags, f.metadata,
|
|
306
|
+
f.event_date, f.document_date, f.source_chunk, f.created_at,
|
|
307
|
+
(1 - (f.embedding <=> query_embedding::vector)) AS similarity
|
|
308
|
+
FROM facts f WHERE f.tenant_id = match_tenant_id AND f.scope = match_scope
|
|
309
|
+
AND f.scope_id = match_scope_id
|
|
310
|
+
AND (CASE WHEN match_as_of IS NOT NULL THEN f.valid_from <= match_as_of AND (f.valid_until IS NULL OR f.valid_until > match_as_of) ELSE f.valid_until IS NULL END)
|
|
311
|
+
AND (1 - (f.embedding <=> query_embedding::vector)) >= min_similarity
|
|
312
|
+
ORDER BY f.embedding <=> query_embedding::vector LIMIT match_count; END; $$;`,
|
|
313
|
+
// increment_usage RPC
|
|
314
|
+
`CREATE OR REPLACE FUNCTION increment_usage(p_tenant_id UUID, p_tokens INT, p_queries INT, p_extractions INT, p_cost_usd FLOAT)
|
|
315
|
+
RETURNS VOID LANGUAGE plpgsql AS $$ DECLARE p_start DATE := date_trunc('month', CURRENT_DATE)::date;
|
|
316
|
+
p_end DATE := (date_trunc('month', CURRENT_DATE) + interval '1 month' - interval '1 day')::date;
|
|
317
|
+
BEGIN INSERT INTO usage_records (id, tenant_id, period_start, period_end, tokens_used, queries_used, extractions_count, cost_usd)
|
|
318
|
+
VALUES (gen_random_uuid(), p_tenant_id, p_start, p_end, p_tokens, p_queries, p_extractions, p_cost_usd)
|
|
319
|
+
ON CONFLICT (tenant_id, period_start) DO UPDATE SET
|
|
320
|
+
tokens_used = usage_records.tokens_used + EXCLUDED.tokens_used,
|
|
321
|
+
queries_used = usage_records.queries_used + EXCLUDED.queries_used,
|
|
322
|
+
extractions_count = usage_records.extractions_count + EXCLUDED.extractions_count,
|
|
323
|
+
cost_usd = usage_records.cost_usd + EXCLUDED.cost_usd, updated_at = NOW(); END; $$;`,
|
|
324
|
+
// match_entities RPC
|
|
325
|
+
`CREATE OR REPLACE FUNCTION match_entities(query_embedding TEXT, match_tenant_id UUID, match_count INT DEFAULT 10, min_similarity FLOAT DEFAULT 0.3)
|
|
326
|
+
RETURNS TABLE (id UUID, tenant_id UUID, name TEXT, entity_type TEXT, canonical_name TEXT, properties JSONB,
|
|
327
|
+
embedding_model TEXT, embedding_dim INT, merge_target_id UUID, created_at TIMESTAMPTZ, updated_at TIMESTAMPTZ, similarity FLOAT)
|
|
328
|
+
LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT e.id, e.tenant_id, e.name, e.entity_type, e.canonical_name,
|
|
329
|
+
e.properties, e.embedding_model, e.embedding_dim, e.merge_target_id, e.created_at, e.updated_at,
|
|
330
|
+
(1 - (e.embedding <=> query_embedding::vector))::float AS similarity
|
|
331
|
+
FROM entities e WHERE e.tenant_id = match_tenant_id AND e.embedding IS NOT NULL
|
|
332
|
+
AND (1 - (e.embedding <=> query_embedding::vector)) >= min_similarity
|
|
333
|
+
ORDER BY e.embedding <=> query_embedding::vector LIMIT match_count; END; $$;`,
|
|
334
|
+
// graph_traverse RPC
|
|
335
|
+
`CREATE OR REPLACE FUNCTION graph_traverse(match_tenant_id UUID, seed_entity_ids UUID[], max_depth INT DEFAULT 3, max_entities INT DEFAULT 200, match_as_of TIMESTAMPTZ DEFAULT NULL)
|
|
336
|
+
RETURNS TABLE (entity_id UUID, entity_name TEXT, entity_type TEXT, canonical_name TEXT, properties JSONB, hop_depth INT,
|
|
337
|
+
edge_id UUID, edge_source_id UUID, edge_target_id UUID, edge_relation TEXT, edge_type TEXT, edge_weight FLOAT,
|
|
338
|
+
edge_valid_from TIMESTAMPTZ, edge_valid_until TIMESTAMPTZ, edge_confidence FLOAT)
|
|
339
|
+
LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY WITH RECURSIVE traversal AS (
|
|
340
|
+
SELECT e.id AS entity_id, e.name AS entity_name, e.entity_type, e.canonical_name, e.properties, 0 AS hop_depth,
|
|
341
|
+
NULL::UUID AS edge_id, NULL::UUID AS edge_source_id, NULL::UUID AS edge_target_id, NULL::TEXT AS edge_relation,
|
|
342
|
+
NULL::TEXT AS edge_type, NULL::FLOAT AS edge_weight, NULL::TIMESTAMPTZ AS edge_valid_from,
|
|
343
|
+
NULL::TIMESTAMPTZ AS edge_valid_until, NULL::FLOAT AS edge_confidence, ARRAY[e.id] AS visited_ids
|
|
344
|
+
FROM entities e WHERE e.id = ANY(seed_entity_ids) AND e.tenant_id = match_tenant_id
|
|
345
|
+
UNION ALL
|
|
346
|
+
SELECT e2.id, e2.name, e2.entity_type, e2.canonical_name, e2.properties, t.hop_depth + 1,
|
|
347
|
+
ed.id, ed.source_id, ed.target_id, ed.relation, ed.edge_type, ed.weight, ed.valid_from, ed.valid_until, ed.confidence,
|
|
348
|
+
t.visited_ids || e2.id
|
|
349
|
+
FROM traversal t JOIN edges ed ON (ed.source_id = t.entity_id OR ed.target_id = t.entity_id) AND ed.tenant_id = match_tenant_id
|
|
350
|
+
AND (CASE WHEN match_as_of IS NOT NULL THEN ed.valid_from <= match_as_of AND (ed.valid_until IS NULL OR ed.valid_until > match_as_of) ELSE ed.valid_until IS NULL END)
|
|
351
|
+
JOIN entities e2 ON e2.id = CASE WHEN ed.source_id = t.entity_id THEN ed.target_id ELSE ed.source_id END AND e2.tenant_id = match_tenant_id
|
|
352
|
+
WHERE t.hop_depth < max_depth AND e2.id != ALL(t.visited_ids)
|
|
353
|
+
) SELECT traversal.entity_id, traversal.entity_name, traversal.entity_type, traversal.canonical_name, traversal.properties,
|
|
354
|
+
traversal.hop_depth, traversal.edge_id, traversal.edge_source_id, traversal.edge_target_id, traversal.edge_relation,
|
|
355
|
+
traversal.edge_type, traversal.edge_weight, traversal.edge_valid_from, traversal.edge_valid_until, traversal.edge_confidence
|
|
356
|
+
FROM traversal LIMIT max_entities; END; $$;`,
|
|
357
|
+
// get_facts_for_entities RPC
|
|
358
|
+
`CREATE OR REPLACE FUNCTION get_facts_for_entities(match_tenant_id UUID, entity_ids UUID[], per_entity_limit INT DEFAULT 20)
|
|
359
|
+
RETURNS TABLE (entity_id UUID, fact_id UUID, tenant_id UUID, scope TEXT, scope_id TEXT, session_id TEXT,
|
|
360
|
+
content TEXT, embedding_model TEXT, embedding_dim INTEGER, version INTEGER, lineage_id UUID,
|
|
361
|
+
valid_from TIMESTAMPTZ, valid_until TIMESTAMPTZ, operation TEXT, parent_id UUID,
|
|
362
|
+
importance NUMERIC, frequency INTEGER, last_accessed TIMESTAMPTZ, decay_score NUMERIC,
|
|
363
|
+
contradiction_status TEXT, contradicts_id UUID, source_type TEXT, source_ref JSONB, confidence NUMERIC,
|
|
364
|
+
original_content TEXT, extraction_id UUID, extraction_tier TEXT, modality TEXT, tags TEXT[], metadata JSONB,
|
|
365
|
+
event_date TIMESTAMPTZ, document_date TIMESTAMPTZ, source_chunk TEXT, created_at TIMESTAMPTZ)
|
|
366
|
+
LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT ranked.entity_id, ranked.fact_id, ranked.tenant_id, ranked.scope,
|
|
367
|
+
ranked.scope_id, ranked.session_id, ranked.content, ranked.embedding_model, ranked.embedding_dim, ranked.version,
|
|
368
|
+
ranked.lineage_id, ranked.valid_from, ranked.valid_until, ranked.operation, ranked.parent_id, ranked.importance,
|
|
369
|
+
ranked.frequency, ranked.last_accessed, ranked.decay_score, ranked.contradiction_status, ranked.contradicts_id,
|
|
370
|
+
ranked.source_type, ranked.source_ref, ranked.confidence, ranked.original_content, ranked.extraction_id,
|
|
371
|
+
ranked.extraction_tier, ranked.modality, ranked.tags, ranked.metadata,
|
|
372
|
+
ranked.event_date, ranked.document_date, ranked.source_chunk, ranked.created_at
|
|
373
|
+
FROM (SELECT fe.entity_id, f.id AS fact_id, f.tenant_id, f.scope, f.scope_id, f.session_id, f.content,
|
|
374
|
+
f.embedding_model, f.embedding_dim, f.version, f.lineage_id, f.valid_from, f.valid_until, f.operation,
|
|
375
|
+
f.parent_id, f.importance, f.frequency, f.last_accessed, f.decay_score, f.contradiction_status, f.contradicts_id,
|
|
376
|
+
f.source_type, f.source_ref, f.confidence, f.original_content, f.extraction_id, f.extraction_tier, f.modality,
|
|
377
|
+
f.tags, f.metadata, f.event_date, f.document_date, f.source_chunk, f.created_at,
|
|
378
|
+
ROW_NUMBER() OVER (PARTITION BY fe.entity_id ORDER BY f.importance DESC, f.created_at DESC) AS rn
|
|
379
|
+
FROM fact_entities fe JOIN facts f ON f.id = fe.fact_id WHERE fe.entity_id = ANY(entity_ids)
|
|
380
|
+
AND f.tenant_id = match_tenant_id AND f.valid_until IS NULL AND NOT ('raw_chunk' = ANY(f.tags))) ranked
|
|
381
|
+
WHERE ranked.rn <= per_entity_limit; END; $$;`,
|
|
382
|
+
// keyword_search_facts RPC
|
|
383
|
+
`CREATE OR REPLACE FUNCTION keyword_search_facts(search_query TEXT, match_tenant_id UUID, match_scope TEXT,
|
|
384
|
+
match_scope_id TEXT, match_count INT, match_as_of TIMESTAMPTZ DEFAULT NULL)
|
|
385
|
+
RETURNS TABLE (id UUID, tenant_id UUID, scope TEXT, scope_id TEXT, session_id TEXT,
|
|
386
|
+
content TEXT, embedding_model TEXT, embedding_dim INT, version INT, lineage_id UUID,
|
|
387
|
+
valid_from TIMESTAMPTZ, valid_until TIMESTAMPTZ, operation TEXT, parent_id UUID,
|
|
388
|
+
importance NUMERIC, frequency INT, last_accessed TIMESTAMPTZ, decay_score NUMERIC,
|
|
389
|
+
contradiction_status TEXT, contradicts_id UUID, source_type TEXT, source_ref JSONB, confidence NUMERIC,
|
|
390
|
+
original_content TEXT, extraction_id UUID, extraction_tier TEXT, modality TEXT, tags TEXT[], metadata JSONB,
|
|
391
|
+
event_date TIMESTAMPTZ, document_date TIMESTAMPTZ, source_chunk TEXT, created_at TIMESTAMPTZ, rank_score FLOAT)
|
|
392
|
+
LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT f.id, f.tenant_id, f.scope, f.scope_id, f.session_id,
|
|
393
|
+
f.content, f.embedding_model, f.embedding_dim, f.version, f.lineage_id, f.valid_from, f.valid_until,
|
|
394
|
+
f.operation, f.parent_id, f.importance, f.frequency, f.last_accessed, f.decay_score, f.contradiction_status,
|
|
395
|
+
f.contradicts_id, f.source_type, f.source_ref, f.confidence, f.original_content, f.extraction_id,
|
|
396
|
+
f.extraction_tier, f.modality, f.tags, f.metadata, f.event_date, f.document_date, f.source_chunk, f.created_at,
|
|
397
|
+
ts_rank(f.search_vector, plainto_tsquery('english', search_query)) AS rank_score
|
|
398
|
+
FROM facts f WHERE f.tenant_id = match_tenant_id AND f.scope = match_scope AND f.scope_id = match_scope_id
|
|
399
|
+
AND (CASE WHEN match_as_of IS NOT NULL THEN f.valid_from <= match_as_of AND (f.valid_until IS NULL OR f.valid_until > match_as_of) ELSE f.valid_until IS NULL END)
|
|
400
|
+
AND f.search_vector @@ plainto_tsquery('english', search_query)
|
|
401
|
+
ORDER BY rank_score DESC LIMIT match_count; END; $$;`,
|
|
402
|
+
// increment_trigger_fired RPC
|
|
403
|
+
`CREATE OR REPLACE FUNCTION increment_trigger_fired(p_tenant_id UUID, p_trigger_id UUID)
|
|
404
|
+
RETURNS VOID LANGUAGE plpgsql AS $$ BEGIN UPDATE triggers SET times_fired = times_fired + 1,
|
|
405
|
+
last_fired_at = NOW(), updated_at = NOW() WHERE tenant_id = p_tenant_id AND id = p_trigger_id; END; $$;`,
|
|
279
406
|
// Default tenant
|
|
280
407
|
`INSERT INTO tenants (id, name, slug, plan) VALUES ('00000000-0000-0000-0000-000000000001', 'Default', 'default', 'enterprise') ON CONFLICT DO NOTHING;`,
|
|
281
408
|
];
|
|
@@ -293,34 +420,38 @@ async function main() {
|
|
|
293
420
|
// 2. Run migrations
|
|
294
421
|
console.log('\n Running database migrations...');
|
|
295
422
|
const supabase = createClient(supabaseUrl, supabaseKey);
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
else {
|
|
312
|
-
skipped++;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
else {
|
|
316
|
-
success++;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
catch {
|
|
320
|
-
skipped++;
|
|
423
|
+
// Try running migrations via Supabase Management API (requires service role key)
|
|
424
|
+
// If that fails, write SQL to a file for manual execution
|
|
425
|
+
const allSql = MIGRATIONS.join('\n\n');
|
|
426
|
+
const sqlPath = path.join(process.cwd(), 'steno-migrations.sql');
|
|
427
|
+
// Attempt automatic migration via Supabase SQL endpoint
|
|
428
|
+
let autoMigrated = false;
|
|
429
|
+
try {
|
|
430
|
+
const res = await fetch(`${supabaseUrl}/rest/v1/rpc/exec_sql`, {
|
|
431
|
+
method: 'POST',
|
|
432
|
+
headers: { 'apikey': supabaseKey, 'Authorization': `Bearer ${supabaseKey}`, 'Content-Type': 'application/json' },
|
|
433
|
+
body: JSON.stringify({ query: allSql }),
|
|
434
|
+
});
|
|
435
|
+
if (res.ok) {
|
|
436
|
+
autoMigrated = true;
|
|
437
|
+
console.log(' ✓ All migrations applied automatically');
|
|
321
438
|
}
|
|
322
439
|
}
|
|
323
|
-
|
|
440
|
+
catch { /* RPC not available */ }
|
|
441
|
+
if (!autoMigrated) {
|
|
442
|
+
// Write SQL file for manual execution
|
|
443
|
+
fs.writeFileSync(sqlPath, allSql);
|
|
444
|
+
console.log(`
|
|
445
|
+
⚠️ Could not run migrations automatically.
|
|
446
|
+
|
|
447
|
+
Please run the SQL manually:
|
|
448
|
+
1. Open your Supabase dashboard → SQL Editor
|
|
449
|
+
2. Paste the contents of: ${sqlPath}
|
|
450
|
+
3. Click "Run"
|
|
451
|
+
4. Come back here and press Enter to continue
|
|
452
|
+
`);
|
|
453
|
+
await ask(' Press Enter after running the SQL... ');
|
|
454
|
+
}
|
|
324
455
|
// 3. Write Claude Desktop config
|
|
325
456
|
const configDir = path.join(os.homedir(), 'Library', 'Application Support', 'Claude');
|
|
326
457
|
const configPath = path.join(configDir, 'claude_desktop_config.json');
|
package/dist/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAC;AAErC,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AACtF,MAAM,GAAG,GAAG,CAAC,CAAS,EAAmB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAEhF,0BAA0B;AAC1B,MAAM,UAAU,GAAG;IACjB,6CAA6C;IAC7C,0CAA0C;IAC1C,2CAA2C;IAC3C,UAAU;IACV;;;;;;;;;;;;;KAaG;IACH,WAAW;IACX;;;;;;;;;;;KAWG;IACH,WAAW;IACX;;;;;;;;;;;;;KAaG;IACH,cAAc;IACd;;;;;;;;;;;;;;;;;;;;;;;;;;KA0BG;IACH,QAAQ;IACR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAoCG;IACH,eAAe;IACf;;;sGAGoG;IACpG,oBAAoB;IACpB,4IAA4I;IAC5I,WAAW;IACX;;;;;;;;;;;;;;gHAc8G;IAC9G,uBAAuB;IACvB;;;;;;KAMG;IACH,QAAQ;IACR;;;;;;;;;;;;;;;;8EAgB4E;IAC5E,WAAW;IACX;;;;;;;;;;;;;;KAcG;IACH,kBAAkB;IAClB;;;;;;;;;;;;;;KAcG;IACH,gBAAgB;IAChB;;;;;;;;;;;KAWG;IACH,WAAW;IACX;;;;;;;;;KASG;IACH,sBAAsB;IACtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAyCS;IACT,iBAAiB;IACjB,wJAAwJ;CACzJ,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;IAEpD,cAAc;IACd,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAClD,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAClD,MAAM,aAAa,GAAG,MAAM,GAAG,CAAC,wDAAwD,CAAC,CAAC;IAE1F,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW,IAAI,CAAC,SAAS,EAAE,CAAC;QAC/C,OAAO,CAAC,KAAK,CAAC,sEAAsE,CAAC,CAAC;QACtF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,oBAAoB;IACpB,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAExD,
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@steno-ai/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "MCP server for Claude Code, Claude Desktop, and other MCP clients",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
"directory": "packages/mcp-server"
|
|
10
10
|
},
|
|
11
11
|
"type": "module",
|
|
12
|
-
"bin":
|
|
12
|
+
"bin": {
|
|
13
|
+
"steno-mcp": "./dist/cli.js",
|
|
14
|
+
"steno-mcp-init": "./dist/init.js"
|
|
15
|
+
},
|
|
13
16
|
"exports": {
|
|
14
17
|
".": {
|
|
15
18
|
"import": "./dist/index.js",
|
|
@@ -28,7 +31,7 @@
|
|
|
28
31
|
"@supabase/supabase-js": "^2.49.0",
|
|
29
32
|
"openai": "^4.0.0",
|
|
30
33
|
"zod": "^3.25",
|
|
31
|
-
"@steno-ai/engine": "0.1.
|
|
34
|
+
"@steno-ai/engine": "0.1.8",
|
|
32
35
|
"@steno-ai/openai-adapter": "0.1.2",
|
|
33
36
|
"@steno-ai/supabase-adapter": "0.1.4"
|
|
34
37
|
},
|
package/src/init.ts
CHANGED
|
@@ -75,7 +75,7 @@ const MIGRATIONS = [
|
|
|
75
75
|
input_size INTEGER,
|
|
76
76
|
scope TEXT NOT NULL,
|
|
77
77
|
scope_id TEXT NOT NULL,
|
|
78
|
-
session_id
|
|
78
|
+
session_id TEXT,
|
|
79
79
|
tier_used TEXT,
|
|
80
80
|
llm_model TEXT,
|
|
81
81
|
facts_created INTEGER NOT NULL DEFAULT 0,
|
|
@@ -98,7 +98,7 @@ const MIGRATIONS = [
|
|
|
98
98
|
tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
|
|
99
99
|
scope TEXT NOT NULL CHECK (scope IN ('user','agent','session','hive')),
|
|
100
100
|
scope_id TEXT NOT NULL,
|
|
101
|
-
session_id
|
|
101
|
+
session_id TEXT,
|
|
102
102
|
content TEXT NOT NULL,
|
|
103
103
|
embedding VECTOR(2000),
|
|
104
104
|
embedding_model TEXT,
|
|
@@ -278,6 +278,133 @@ const MIGRATIONS = [
|
|
|
278
278
|
AND f.search_vector @@ plainto_tsquery('english', search_query)
|
|
279
279
|
ORDER BY ts_rank(f.search_vector, plainto_tsquery('english', search_query)) DESC LIMIT match_count);
|
|
280
280
|
END; $$;`,
|
|
281
|
+
// Usage records unique constraint (required by increment_usage)
|
|
282
|
+
`ALTER TABLE usage_records ADD CONSTRAINT IF NOT EXISTS usage_records_tenant_period_unique UNIQUE (tenant_id, period_start);`,
|
|
283
|
+
// Extraction hash unique index
|
|
284
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_extractions_hash ON extractions(tenant_id, input_hash);`,
|
|
285
|
+
// match_facts RPC
|
|
286
|
+
`CREATE OR REPLACE FUNCTION match_facts(
|
|
287
|
+
query_embedding TEXT, match_tenant_id UUID, match_scope TEXT,
|
|
288
|
+
match_scope_id TEXT, match_count INT, min_similarity FLOAT DEFAULT 0,
|
|
289
|
+
match_as_of TIMESTAMPTZ DEFAULT NULL
|
|
290
|
+
) RETURNS TABLE (
|
|
291
|
+
id UUID, tenant_id UUID, scope TEXT, scope_id TEXT, session_id TEXT,
|
|
292
|
+
content TEXT, embedding_model TEXT, embedding_dim INT, version INT,
|
|
293
|
+
lineage_id UUID, valid_from TIMESTAMPTZ, valid_until TIMESTAMPTZ,
|
|
294
|
+
operation TEXT, parent_id UUID, importance NUMERIC, frequency INT,
|
|
295
|
+
last_accessed TIMESTAMPTZ, decay_score NUMERIC, contradiction_status TEXT,
|
|
296
|
+
contradicts_id UUID, source_type TEXT, source_ref JSONB, confidence NUMERIC,
|
|
297
|
+
original_content TEXT, extraction_id UUID, extraction_tier TEXT,
|
|
298
|
+
modality TEXT, tags TEXT[], metadata JSONB,
|
|
299
|
+
event_date TIMESTAMPTZ, document_date TIMESTAMPTZ, source_chunk TEXT,
|
|
300
|
+
created_at TIMESTAMPTZ, similarity FLOAT
|
|
301
|
+
) LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT
|
|
302
|
+
f.id, f.tenant_id, f.scope, f.scope_id, f.session_id,
|
|
303
|
+
f.content, f.embedding_model, f.embedding_dim, f.version, f.lineage_id,
|
|
304
|
+
f.valid_from, f.valid_until, f.operation, f.parent_id, f.importance, f.frequency,
|
|
305
|
+
f.last_accessed, f.decay_score, f.contradiction_status, f.contradicts_id,
|
|
306
|
+
f.source_type, f.source_ref, f.confidence, f.original_content, f.extraction_id,
|
|
307
|
+
f.extraction_tier, f.modality, f.tags, f.metadata,
|
|
308
|
+
f.event_date, f.document_date, f.source_chunk, f.created_at,
|
|
309
|
+
(1 - (f.embedding <=> query_embedding::vector)) AS similarity
|
|
310
|
+
FROM facts f WHERE f.tenant_id = match_tenant_id AND f.scope = match_scope
|
|
311
|
+
AND f.scope_id = match_scope_id
|
|
312
|
+
AND (CASE WHEN match_as_of IS NOT NULL THEN f.valid_from <= match_as_of AND (f.valid_until IS NULL OR f.valid_until > match_as_of) ELSE f.valid_until IS NULL END)
|
|
313
|
+
AND (1 - (f.embedding <=> query_embedding::vector)) >= min_similarity
|
|
314
|
+
ORDER BY f.embedding <=> query_embedding::vector LIMIT match_count; END; $$;`,
|
|
315
|
+
// increment_usage RPC
|
|
316
|
+
`CREATE OR REPLACE FUNCTION increment_usage(p_tenant_id UUID, p_tokens INT, p_queries INT, p_extractions INT, p_cost_usd FLOAT)
|
|
317
|
+
RETURNS VOID LANGUAGE plpgsql AS $$ DECLARE p_start DATE := date_trunc('month', CURRENT_DATE)::date;
|
|
318
|
+
p_end DATE := (date_trunc('month', CURRENT_DATE) + interval '1 month' - interval '1 day')::date;
|
|
319
|
+
BEGIN INSERT INTO usage_records (id, tenant_id, period_start, period_end, tokens_used, queries_used, extractions_count, cost_usd)
|
|
320
|
+
VALUES (gen_random_uuid(), p_tenant_id, p_start, p_end, p_tokens, p_queries, p_extractions, p_cost_usd)
|
|
321
|
+
ON CONFLICT (tenant_id, period_start) DO UPDATE SET
|
|
322
|
+
tokens_used = usage_records.tokens_used + EXCLUDED.tokens_used,
|
|
323
|
+
queries_used = usage_records.queries_used + EXCLUDED.queries_used,
|
|
324
|
+
extractions_count = usage_records.extractions_count + EXCLUDED.extractions_count,
|
|
325
|
+
cost_usd = usage_records.cost_usd + EXCLUDED.cost_usd, updated_at = NOW(); END; $$;`,
|
|
326
|
+
// match_entities RPC
|
|
327
|
+
`CREATE OR REPLACE FUNCTION match_entities(query_embedding TEXT, match_tenant_id UUID, match_count INT DEFAULT 10, min_similarity FLOAT DEFAULT 0.3)
|
|
328
|
+
RETURNS TABLE (id UUID, tenant_id UUID, name TEXT, entity_type TEXT, canonical_name TEXT, properties JSONB,
|
|
329
|
+
embedding_model TEXT, embedding_dim INT, merge_target_id UUID, created_at TIMESTAMPTZ, updated_at TIMESTAMPTZ, similarity FLOAT)
|
|
330
|
+
LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT e.id, e.tenant_id, e.name, e.entity_type, e.canonical_name,
|
|
331
|
+
e.properties, e.embedding_model, e.embedding_dim, e.merge_target_id, e.created_at, e.updated_at,
|
|
332
|
+
(1 - (e.embedding <=> query_embedding::vector))::float AS similarity
|
|
333
|
+
FROM entities e WHERE e.tenant_id = match_tenant_id AND e.embedding IS NOT NULL
|
|
334
|
+
AND (1 - (e.embedding <=> query_embedding::vector)) >= min_similarity
|
|
335
|
+
ORDER BY e.embedding <=> query_embedding::vector LIMIT match_count; END; $$;`,
|
|
336
|
+
// graph_traverse RPC
|
|
337
|
+
`CREATE OR REPLACE FUNCTION graph_traverse(match_tenant_id UUID, seed_entity_ids UUID[], max_depth INT DEFAULT 3, max_entities INT DEFAULT 200, match_as_of TIMESTAMPTZ DEFAULT NULL)
|
|
338
|
+
RETURNS TABLE (entity_id UUID, entity_name TEXT, entity_type TEXT, canonical_name TEXT, properties JSONB, hop_depth INT,
|
|
339
|
+
edge_id UUID, edge_source_id UUID, edge_target_id UUID, edge_relation TEXT, edge_type TEXT, edge_weight FLOAT,
|
|
340
|
+
edge_valid_from TIMESTAMPTZ, edge_valid_until TIMESTAMPTZ, edge_confidence FLOAT)
|
|
341
|
+
LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY WITH RECURSIVE traversal AS (
|
|
342
|
+
SELECT e.id AS entity_id, e.name AS entity_name, e.entity_type, e.canonical_name, e.properties, 0 AS hop_depth,
|
|
343
|
+
NULL::UUID AS edge_id, NULL::UUID AS edge_source_id, NULL::UUID AS edge_target_id, NULL::TEXT AS edge_relation,
|
|
344
|
+
NULL::TEXT AS edge_type, NULL::FLOAT AS edge_weight, NULL::TIMESTAMPTZ AS edge_valid_from,
|
|
345
|
+
NULL::TIMESTAMPTZ AS edge_valid_until, NULL::FLOAT AS edge_confidence, ARRAY[e.id] AS visited_ids
|
|
346
|
+
FROM entities e WHERE e.id = ANY(seed_entity_ids) AND e.tenant_id = match_tenant_id
|
|
347
|
+
UNION ALL
|
|
348
|
+
SELECT e2.id, e2.name, e2.entity_type, e2.canonical_name, e2.properties, t.hop_depth + 1,
|
|
349
|
+
ed.id, ed.source_id, ed.target_id, ed.relation, ed.edge_type, ed.weight, ed.valid_from, ed.valid_until, ed.confidence,
|
|
350
|
+
t.visited_ids || e2.id
|
|
351
|
+
FROM traversal t JOIN edges ed ON (ed.source_id = t.entity_id OR ed.target_id = t.entity_id) AND ed.tenant_id = match_tenant_id
|
|
352
|
+
AND (CASE WHEN match_as_of IS NOT NULL THEN ed.valid_from <= match_as_of AND (ed.valid_until IS NULL OR ed.valid_until > match_as_of) ELSE ed.valid_until IS NULL END)
|
|
353
|
+
JOIN entities e2 ON e2.id = CASE WHEN ed.source_id = t.entity_id THEN ed.target_id ELSE ed.source_id END AND e2.tenant_id = match_tenant_id
|
|
354
|
+
WHERE t.hop_depth < max_depth AND e2.id != ALL(t.visited_ids)
|
|
355
|
+
) SELECT traversal.entity_id, traversal.entity_name, traversal.entity_type, traversal.canonical_name, traversal.properties,
|
|
356
|
+
traversal.hop_depth, traversal.edge_id, traversal.edge_source_id, traversal.edge_target_id, traversal.edge_relation,
|
|
357
|
+
traversal.edge_type, traversal.edge_weight, traversal.edge_valid_from, traversal.edge_valid_until, traversal.edge_confidence
|
|
358
|
+
FROM traversal LIMIT max_entities; END; $$;`,
|
|
359
|
+
// get_facts_for_entities RPC
|
|
360
|
+
`CREATE OR REPLACE FUNCTION get_facts_for_entities(match_tenant_id UUID, entity_ids UUID[], per_entity_limit INT DEFAULT 20)
|
|
361
|
+
RETURNS TABLE (entity_id UUID, fact_id UUID, tenant_id UUID, scope TEXT, scope_id TEXT, session_id TEXT,
|
|
362
|
+
content TEXT, embedding_model TEXT, embedding_dim INTEGER, version INTEGER, lineage_id UUID,
|
|
363
|
+
valid_from TIMESTAMPTZ, valid_until TIMESTAMPTZ, operation TEXT, parent_id UUID,
|
|
364
|
+
importance NUMERIC, frequency INTEGER, last_accessed TIMESTAMPTZ, decay_score NUMERIC,
|
|
365
|
+
contradiction_status TEXT, contradicts_id UUID, source_type TEXT, source_ref JSONB, confidence NUMERIC,
|
|
366
|
+
original_content TEXT, extraction_id UUID, extraction_tier TEXT, modality TEXT, tags TEXT[], metadata JSONB,
|
|
367
|
+
event_date TIMESTAMPTZ, document_date TIMESTAMPTZ, source_chunk TEXT, created_at TIMESTAMPTZ)
|
|
368
|
+
LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT ranked.entity_id, ranked.fact_id, ranked.tenant_id, ranked.scope,
|
|
369
|
+
ranked.scope_id, ranked.session_id, ranked.content, ranked.embedding_model, ranked.embedding_dim, ranked.version,
|
|
370
|
+
ranked.lineage_id, ranked.valid_from, ranked.valid_until, ranked.operation, ranked.parent_id, ranked.importance,
|
|
371
|
+
ranked.frequency, ranked.last_accessed, ranked.decay_score, ranked.contradiction_status, ranked.contradicts_id,
|
|
372
|
+
ranked.source_type, ranked.source_ref, ranked.confidence, ranked.original_content, ranked.extraction_id,
|
|
373
|
+
ranked.extraction_tier, ranked.modality, ranked.tags, ranked.metadata,
|
|
374
|
+
ranked.event_date, ranked.document_date, ranked.source_chunk, ranked.created_at
|
|
375
|
+
FROM (SELECT fe.entity_id, f.id AS fact_id, f.tenant_id, f.scope, f.scope_id, f.session_id, f.content,
|
|
376
|
+
f.embedding_model, f.embedding_dim, f.version, f.lineage_id, f.valid_from, f.valid_until, f.operation,
|
|
377
|
+
f.parent_id, f.importance, f.frequency, f.last_accessed, f.decay_score, f.contradiction_status, f.contradicts_id,
|
|
378
|
+
f.source_type, f.source_ref, f.confidence, f.original_content, f.extraction_id, f.extraction_tier, f.modality,
|
|
379
|
+
f.tags, f.metadata, f.event_date, f.document_date, f.source_chunk, f.created_at,
|
|
380
|
+
ROW_NUMBER() OVER (PARTITION BY fe.entity_id ORDER BY f.importance DESC, f.created_at DESC) AS rn
|
|
381
|
+
FROM fact_entities fe JOIN facts f ON f.id = fe.fact_id WHERE fe.entity_id = ANY(entity_ids)
|
|
382
|
+
AND f.tenant_id = match_tenant_id AND f.valid_until IS NULL AND NOT ('raw_chunk' = ANY(f.tags))) ranked
|
|
383
|
+
WHERE ranked.rn <= per_entity_limit; END; $$;`,
|
|
384
|
+
// keyword_search_facts RPC
|
|
385
|
+
`CREATE OR REPLACE FUNCTION keyword_search_facts(search_query TEXT, match_tenant_id UUID, match_scope TEXT,
|
|
386
|
+
match_scope_id TEXT, match_count INT, match_as_of TIMESTAMPTZ DEFAULT NULL)
|
|
387
|
+
RETURNS TABLE (id UUID, tenant_id UUID, scope TEXT, scope_id TEXT, session_id TEXT,
|
|
388
|
+
content TEXT, embedding_model TEXT, embedding_dim INT, version INT, lineage_id UUID,
|
|
389
|
+
valid_from TIMESTAMPTZ, valid_until TIMESTAMPTZ, operation TEXT, parent_id UUID,
|
|
390
|
+
importance NUMERIC, frequency INT, last_accessed TIMESTAMPTZ, decay_score NUMERIC,
|
|
391
|
+
contradiction_status TEXT, contradicts_id UUID, source_type TEXT, source_ref JSONB, confidence NUMERIC,
|
|
392
|
+
original_content TEXT, extraction_id UUID, extraction_tier TEXT, modality TEXT, tags TEXT[], metadata JSONB,
|
|
393
|
+
event_date TIMESTAMPTZ, document_date TIMESTAMPTZ, source_chunk TEXT, created_at TIMESTAMPTZ, rank_score FLOAT)
|
|
394
|
+
LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY SELECT f.id, f.tenant_id, f.scope, f.scope_id, f.session_id,
|
|
395
|
+
f.content, f.embedding_model, f.embedding_dim, f.version, f.lineage_id, f.valid_from, f.valid_until,
|
|
396
|
+
f.operation, f.parent_id, f.importance, f.frequency, f.last_accessed, f.decay_score, f.contradiction_status,
|
|
397
|
+
f.contradicts_id, f.source_type, f.source_ref, f.confidence, f.original_content, f.extraction_id,
|
|
398
|
+
f.extraction_tier, f.modality, f.tags, f.metadata, f.event_date, f.document_date, f.source_chunk, f.created_at,
|
|
399
|
+
ts_rank(f.search_vector, plainto_tsquery('english', search_query)) AS rank_score
|
|
400
|
+
FROM facts f WHERE f.tenant_id = match_tenant_id AND f.scope = match_scope AND f.scope_id = match_scope_id
|
|
401
|
+
AND (CASE WHEN match_as_of IS NOT NULL THEN f.valid_from <= match_as_of AND (f.valid_until IS NULL OR f.valid_until > match_as_of) ELSE f.valid_until IS NULL END)
|
|
402
|
+
AND f.search_vector @@ plainto_tsquery('english', search_query)
|
|
403
|
+
ORDER BY rank_score DESC LIMIT match_count; END; $$;`,
|
|
404
|
+
// increment_trigger_fired RPC
|
|
405
|
+
`CREATE OR REPLACE FUNCTION increment_trigger_fired(p_tenant_id UUID, p_trigger_id UUID)
|
|
406
|
+
RETURNS VOID LANGUAGE plpgsql AS $$ BEGIN UPDATE triggers SET times_fired = times_fired + 1,
|
|
407
|
+
last_fired_at = NOW(), updated_at = NOW() WHERE tenant_id = p_tenant_id AND id = p_trigger_id; END; $$;`,
|
|
281
408
|
// Default tenant
|
|
282
409
|
`INSERT INTO tenants (id, name, slug, plan) VALUES ('00000000-0000-0000-0000-000000000001', 'Default', 'default', 'enterprise') ON CONFLICT DO NOTHING;`,
|
|
283
410
|
];
|
|
@@ -300,27 +427,39 @@ async function main() {
|
|
|
300
427
|
console.log('\n Running database migrations...');
|
|
301
428
|
const supabase = createClient(supabaseUrl, supabaseKey);
|
|
302
429
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
} catch {
|
|
320
|
-
skipped++;
|
|
430
|
+
// Try running migrations via Supabase Management API (requires service role key)
|
|
431
|
+
// If that fails, write SQL to a file for manual execution
|
|
432
|
+
const allSql = MIGRATIONS.join('\n\n');
|
|
433
|
+
const sqlPath = path.join(process.cwd(), 'steno-migrations.sql');
|
|
434
|
+
|
|
435
|
+
// Attempt automatic migration via Supabase SQL endpoint
|
|
436
|
+
let autoMigrated = false;
|
|
437
|
+
try {
|
|
438
|
+
const res = await fetch(`${supabaseUrl}/rest/v1/rpc/exec_sql`, {
|
|
439
|
+
method: 'POST',
|
|
440
|
+
headers: { 'apikey': supabaseKey, 'Authorization': `Bearer ${supabaseKey}`, 'Content-Type': 'application/json' },
|
|
441
|
+
body: JSON.stringify({ query: allSql }),
|
|
442
|
+
});
|
|
443
|
+
if (res.ok) {
|
|
444
|
+
autoMigrated = true;
|
|
445
|
+
console.log(' ✓ All migrations applied automatically');
|
|
321
446
|
}
|
|
447
|
+
} catch { /* RPC not available */ }
|
|
448
|
+
|
|
449
|
+
if (!autoMigrated) {
|
|
450
|
+
// Write SQL file for manual execution
|
|
451
|
+
fs.writeFileSync(sqlPath, allSql);
|
|
452
|
+
console.log(`
|
|
453
|
+
⚠️ Could not run migrations automatically.
|
|
454
|
+
|
|
455
|
+
Please run the SQL manually:
|
|
456
|
+
1. Open your Supabase dashboard → SQL Editor
|
|
457
|
+
2. Paste the contents of: ${sqlPath}
|
|
458
|
+
3. Click "Run"
|
|
459
|
+
4. Come back here and press Enter to continue
|
|
460
|
+
`);
|
|
461
|
+
await ask(' Press Enter after running the SQL... ');
|
|
322
462
|
}
|
|
323
|
-
console.log(` ✓ ${success} migrations applied, ${skipped} skipped (may already exist)`);
|
|
324
463
|
|
|
325
464
|
// 3. Write Claude Desktop config
|
|
326
465
|
const configDir = path.join(os.homedir(), 'Library', 'Application Support', 'Claude');
|