@contorium/mcp 0.8.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/README.md +97 -0
- package/bin/contorium-mcp.js +34 -0
- package/dist/autoContext.d.ts +2 -0
- package/dist/autoContext.js +2 -0
- package/dist/bootstrapCli.d.ts +2 -0
- package/dist/bootstrapCli.js +21 -0
- package/dist/conflicts.d.ts +19 -0
- package/dist/conflicts.js +49 -0
- package/dist/dashboardEnsure.d.ts +10 -0
- package/dist/dashboardEnsure.js +41 -0
- package/dist/intelligence.d.ts +16 -0
- package/dist/intelligence.js +38 -0
- package/dist/intentGraph.d.ts +20 -0
- package/dist/intentGraph.js +51 -0
- package/dist/mcpBootstrap.d.ts +8 -0
- package/dist/mcpBootstrap.js +81 -0
- package/dist/memoryStore.d.ts +18 -0
- package/dist/memoryStore.js +57 -0
- package/dist/paths.d.ts +12 -0
- package/dist/paths.js +66 -0
- package/dist/runtimeState.d.ts +14 -0
- package/dist/runtimeState.js +36 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +567 -0
- package/dist/stateBuilder.d.ts +16 -0
- package/dist/stateBuilder.js +40 -0
- package/dist/understanding.d.ts +1 -0
- package/dist/understanding.js +1 -0
- package/dist/workspace.d.ts +12 -0
- package/dist/workspace.js +40 -0
- package/dist/workspaceConfig.d.ts +14 -0
- package/dist/workspaceConfig.js +80 -0
- package/node_modules/@contora/state-core/dist/adapterSync.d.ts +29 -0
- package/node_modules/@contora/state-core/dist/adapterSync.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/adapterSync.js +142 -0
- package/node_modules/@contora/state-core/dist/adapters.d.ts +20 -0
- package/node_modules/@contora/state-core/dist/adapters.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/adapters.js +24 -0
- package/node_modules/@contora/state-core/dist/bootstrap/bootstrapState.d.ts +6 -0
- package/node_modules/@contora/state-core/dist/bootstrap/bootstrapState.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/bootstrap/bootstrapState.js +116 -0
- package/node_modules/@contora/state-core/dist/bootstrapArtifacts.d.ts +18 -0
- package/node_modules/@contora/state-core/dist/bootstrapArtifacts.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/bootstrapArtifacts.js +43 -0
- package/node_modules/@contora/state-core/dist/bootstrapState.d.ts +6 -0
- package/node_modules/@contora/state-core/dist/bootstrapState.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/bootstrapState.js +60 -0
- package/node_modules/@contora/state-core/dist/dashboardActivity.d.ts +12 -0
- package/node_modules/@contora/state-core/dist/dashboardActivity.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/dashboardActivity.js +58 -0
- package/node_modules/@contora/state-core/dist/dualMode.d.ts +11 -0
- package/node_modules/@contora/state-core/dist/dualMode.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/dualMode.js +38 -0
- package/node_modules/@contora/state-core/dist/gitScan.d.ts +7 -0
- package/node_modules/@contora/state-core/dist/gitScan.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/gitScan.js +39 -0
- package/node_modules/@contora/state-core/dist/index.d.ts +44 -0
- package/node_modules/@contora/state-core/dist/index.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/index.js +141 -0
- package/node_modules/@contora/state-core/dist/minimalSnapshot.d.ts +4 -0
- package/node_modules/@contora/state-core/dist/minimalSnapshot.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/minimalSnapshot.js +60 -0
- package/node_modules/@contora/state-core/dist/scanner/gitScan.d.ts +7 -0
- package/node_modules/@contora/state-core/dist/scanner/gitScan.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/scanner/gitScan.js +42 -0
- package/node_modules/@contora/state-core/dist/scanner/workspaceScanner.d.ts +4 -0
- package/node_modules/@contora/state-core/dist/scanner/workspaceScanner.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/scanner/workspaceScanner.js +148 -0
- package/node_modules/@contora/state-core/dist/semiAutoHandoff.d.ts +46 -0
- package/node_modules/@contora/state-core/dist/semiAutoHandoff.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/semiAutoHandoff.js +227 -0
- package/node_modules/@contora/state-core/dist/sourceMetadata.d.ts +4 -0
- package/node_modules/@contora/state-core/dist/sourceMetadata.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/sourceMetadata.js +27 -0
- package/node_modules/@contora/state-core/dist/state-builder/buildFromScan.d.ts +5 -0
- package/node_modules/@contora/state-core/dist/state-builder/buildFromScan.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/state-builder/buildFromScan.js +33 -0
- package/node_modules/@contora/state-core/dist/state-builder/normalization.d.ts +5 -0
- package/node_modules/@contora/state-core/dist/state-builder/normalization.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/state-builder/normalization.js +107 -0
- package/node_modules/@contora/state-core/dist/state-builder/rebuildFromScan.d.ts +4 -0
- package/node_modules/@contora/state-core/dist/state-builder/rebuildFromScan.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/state-builder/rebuildFromScan.js +22 -0
- package/node_modules/@contora/state-core/dist/state-builder/snapshot.d.ts +5 -0
- package/node_modules/@contora/state-core/dist/state-builder/snapshot.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/state-builder/snapshot.js +53 -0
- package/node_modules/@contora/state-core/dist/state-builder/store.d.ts +7 -0
- package/node_modules/@contora/state-core/dist/state-builder/store.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/state-builder/store.js +99 -0
- package/node_modules/@contora/state-core/dist/state-builder/types.d.ts +18 -0
- package/node_modules/@contora/state-core/dist/state-builder/types.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/state-builder/types.js +20 -0
- package/node_modules/@contora/state-core/dist/types.d.ts +42 -0
- package/node_modules/@contora/state-core/dist/types.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/types.js +3 -0
- package/node_modules/@contora/state-core/dist/understanding/buildUnderstanding.d.ts +22 -0
- package/node_modules/@contora/state-core/dist/understanding/buildUnderstanding.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/buildUnderstanding.js +87 -0
- package/node_modules/@contora/state-core/dist/understanding/changeDetector.d.ts +7 -0
- package/node_modules/@contora/state-core/dist/understanding/changeDetector.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/changeDetector.js +68 -0
- package/node_modules/@contora/state-core/dist/understanding/chpHandoff.d.ts +49 -0
- package/node_modules/@contora/state-core/dist/understanding/chpHandoff.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/chpHandoff.js +214 -0
- package/node_modules/@contora/state-core/dist/understanding/extractor.d.ts +21 -0
- package/node_modules/@contora/state-core/dist/understanding/extractor.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/extractor.js +173 -0
- package/node_modules/@contora/state-core/dist/understanding/formatCanonicalExport.d.ts +30 -0
- package/node_modules/@contora/state-core/dist/understanding/formatCanonicalExport.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/formatCanonicalExport.js +363 -0
- package/node_modules/@contora/state-core/dist/understanding/formatHandoff.d.ts +20 -0
- package/node_modules/@contora/state-core/dist/understanding/formatHandoff.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/formatHandoff.js +57 -0
- package/node_modules/@contora/state-core/dist/understanding/graphBuilder.d.ts +9 -0
- package/node_modules/@contora/state-core/dist/understanding/graphBuilder.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/graphBuilder.js +107 -0
- package/node_modules/@contora/state-core/dist/understanding/handoffBuilder.d.ts +12 -0
- package/node_modules/@contora/state-core/dist/understanding/handoffBuilder.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/handoffBuilder.js +101 -0
- package/node_modules/@contora/state-core/dist/understanding/impactAnalyzer.d.ts +5 -0
- package/node_modules/@contora/state-core/dist/understanding/impactAnalyzer.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/impactAnalyzer.js +58 -0
- package/node_modules/@contora/state-core/dist/understanding/intentFusion.d.ts +9 -0
- package/node_modules/@contora/state-core/dist/understanding/intentFusion.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/intentFusion.js +54 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/closureConstants.d.ts +24 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/closureConstants.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/closureConstants.js +33 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/confidence.d.ts +20 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/confidence.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/confidence.js +53 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/gitFrequency.d.ts +5 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/gitFrequency.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/gitFrequency.js +19 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/hotspotBuilder.d.ts +13 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/hotspotBuilder.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/hotspotBuilder.js +101 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/intentFunctionMapper.d.ts +22 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/intentFunctionMapper.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/intentFunctionMapper.js +106 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/knowledgeGraphBuilder.d.ts +23 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/knowledgeGraphBuilder.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/knowledgeGraphBuilder.js +415 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/normalize.d.ts +11 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/normalize.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/normalize.js +136 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/rebuildTrigger.d.ts +13 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/rebuildTrigger.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/rebuildTrigger.js +34 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/snapshotBuilder.d.ts +17 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/snapshotBuilder.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/snapshotBuilder.js +73 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/store.d.ts +7 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/store.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/store.js +127 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/types.d.ts +116 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/types.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/types.js +6 -0
- package/node_modules/@contora/state-core/dist/understanding/miniGraph.d.ts +4 -0
- package/node_modules/@contora/state-core/dist/understanding/miniGraph.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/miniGraph.js +18 -0
- package/node_modules/@contora/state-core/dist/understanding/store.d.ts +24 -0
- package/node_modules/@contora/state-core/dist/understanding/store.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/store.js +243 -0
- package/node_modules/@contora/state-core/dist/understanding/symbolValidator.d.ts +9 -0
- package/node_modules/@contora/state-core/dist/understanding/symbolValidator.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/symbolValidator.js +51 -0
- package/node_modules/@contora/state-core/dist/understanding/timelineTracker.d.ts +3 -0
- package/node_modules/@contora/state-core/dist/understanding/timelineTracker.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/timelineTracker.js +129 -0
- package/node_modules/@contora/state-core/dist/understanding/treeSitterParser.d.ts +24 -0
- package/node_modules/@contora/state-core/dist/understanding/treeSitterParser.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/treeSitterParser.js +56 -0
- package/node_modules/@contora/state-core/dist/understanding/types.d.ts +136 -0
- package/node_modules/@contora/state-core/dist/understanding/types.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/types.js +5 -0
- package/node_modules/@contora/state-core/dist/understanding/understandingGraphBuilder.d.ts +23 -0
- package/node_modules/@contora/state-core/dist/understanding/understandingGraphBuilder.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/understandingGraphBuilder.js +67 -0
- package/node_modules/@contora/state-core/dist/version.d.ts +3 -0
- package/node_modules/@contora/state-core/dist/version.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/version.js +21 -0
- package/node_modules/@contora/state-core/dist/workspaceScanner.d.ts +4 -0
- package/node_modules/@contora/state-core/dist/workspaceScanner.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/workspaceScanner.js +112 -0
- package/node_modules/@contora/state-core/package.json +49 -0
- package/package.json +61 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface RuntimeStateSnapshot {
|
|
2
|
+
workspaceRoot: string;
|
|
3
|
+
bootstrap?: Record<string, unknown>;
|
|
4
|
+
dashboard?: Record<string, unknown>;
|
|
5
|
+
session?: Record<string, unknown>;
|
|
6
|
+
stateSummary?: {
|
|
7
|
+
mode: string;
|
|
8
|
+
currentTask: string;
|
|
9
|
+
lastWriter?: string;
|
|
10
|
+
eventCount: number;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/** Standard MCP tool: worker / session / bootstrap view (read-only). */
|
|
14
|
+
export declare function readRuntimeState(workspaceRoot: string): Promise<RuntimeStateSnapshot>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { readStateJson, readWorkspaceStatus } from './understanding.js';
|
|
4
|
+
async function readJsonFile(filePath) {
|
|
5
|
+
try {
|
|
6
|
+
const raw = await fs.readFile(filePath, 'utf8');
|
|
7
|
+
return JSON.parse(raw);
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** Standard MCP tool: worker / session / bootstrap view (read-only). */
|
|
14
|
+
export async function readRuntimeState(workspaceRoot) {
|
|
15
|
+
const root = path.resolve(workspaceRoot);
|
|
16
|
+
const contora = path.join(root, '.contora');
|
|
17
|
+
const [bootstrap, dashboard, session, status, state] = await Promise.all([
|
|
18
|
+
readJsonFile(path.join(contora, 'runtime.bootstrap.json')),
|
|
19
|
+
readJsonFile(path.join(contora, 'dashboard.status.json')),
|
|
20
|
+
readJsonFile(path.join(contora, 'dashboard.session.json')),
|
|
21
|
+
readWorkspaceStatus(root),
|
|
22
|
+
readStateJson(root),
|
|
23
|
+
]);
|
|
24
|
+
return {
|
|
25
|
+
workspaceRoot: root,
|
|
26
|
+
bootstrap,
|
|
27
|
+
dashboard,
|
|
28
|
+
session,
|
|
29
|
+
stateSummary: {
|
|
30
|
+
mode: status.mode,
|
|
31
|
+
currentTask: status.currentTask,
|
|
32
|
+
lastWriter: state?.source?.lastWriter,
|
|
33
|
+
eventCount: status.eventCount,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
package/dist/server.d.ts
ADDED
package/dist/server.js
ADDED
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { getMemory, searchMemory, storeMemory } from './memoryStore.js';
|
|
9
|
+
import { loadProjectIntelligence } from './intelligence.js';
|
|
10
|
+
import { activeIntentNodes, loadIntentGraph } from './intentGraph.js';
|
|
11
|
+
import { loadStateConflicts } from './conflicts.js';
|
|
12
|
+
import { loadProjectBuiltState, loadProjectSnapshotMarkdown } from './stateBuilder.js';
|
|
13
|
+
import { readChangeArtifact, readHandoffArtifact, readImpactArtifact, readIntentArtifact, readProjectGraph, readProjectKnowledgeGraph, readKnowledgeSnapshot, readProjectTimeline, readUnderstandingGraph, filterMappingsByConfidence, getProjectHandoff, } from './understanding.js';
|
|
14
|
+
import { findWorkspaceRoot, initWorkspaceFromArgv, resolveWorkspaceRoot } from './paths.js';
|
|
15
|
+
import { ensureWorkspaceBootstrapped, startMcpLightSync } from './mcpBootstrap.js';
|
|
16
|
+
import { scheduleMcpRuntimeBootstrap } from './dashboardEnsure.js';
|
|
17
|
+
import { readMcpAutoContext } from './autoContext.js';
|
|
18
|
+
import { confirmHandoffInjection, prepareHandoffInjection, readHandoffInjectionState, skipHandoffInjection, syncInjectionWithRuntime, } from '@contora/state-core';
|
|
19
|
+
import { loadWorkspaceSnapshot } from './workspace.js';
|
|
20
|
+
import { readRuntimeState } from './runtimeState.js';
|
|
21
|
+
import { resolveMcpStartupConfig } from './workspaceConfig.js';
|
|
22
|
+
function mcpPackageVersion() {
|
|
23
|
+
const pkgPath = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'package.json');
|
|
24
|
+
return JSON.parse(readFileSync(pkgPath, 'utf8')).version;
|
|
25
|
+
}
|
|
26
|
+
async function workspaceRootForTools() {
|
|
27
|
+
const hint = resolveWorkspaceRoot();
|
|
28
|
+
return findWorkspaceRoot(hint);
|
|
29
|
+
}
|
|
30
|
+
function textResult(data) {
|
|
31
|
+
return {
|
|
32
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const MCP_SERVER_INSTRUCTIONS = `Contorium MCP — persistent project memory for AI coding.
|
|
36
|
+
|
|
37
|
+
On every NEW chat when a runtime is active:
|
|
38
|
+
1. Call get_handoff_injection_status first.
|
|
39
|
+
2. If pending is true, ask the user: "Contorium has active project context. Inject it? (Y/n)"
|
|
40
|
+
3. On Y → confirm_handoff_injection. On N → skip_handoff_injection.
|
|
41
|
+
Do NOT inject without user confirmation.
|
|
42
|
+
|
|
43
|
+
For ongoing work use get_project_handoff, get_understanding_graph, get_recent_changes.`;
|
|
44
|
+
const server = new McpServer({
|
|
45
|
+
name: 'contorium',
|
|
46
|
+
version: mcpPackageVersion(),
|
|
47
|
+
}, { instructions: MCP_SERVER_INSTRUCTIONS });
|
|
48
|
+
const workspaceRootSchema = z.object({
|
|
49
|
+
workspaceRoot: z.string().optional().describe('Override workspace root; default auto-detect'),
|
|
50
|
+
});
|
|
51
|
+
server.registerTool('store_memory', {
|
|
52
|
+
description: 'Store important coding context into Contorium memory (persisted under .contora/mcp/).',
|
|
53
|
+
inputSchema: z.object({
|
|
54
|
+
key: z.string().min(1).describe('Unique memory key'),
|
|
55
|
+
value: z.string().describe('Memory content'),
|
|
56
|
+
type: z.enum(['note', 'decision', 'architecture']).optional().describe('Memory category'),
|
|
57
|
+
}),
|
|
58
|
+
}, async ({ key, value, type }) => {
|
|
59
|
+
const root = await workspaceRootForTools();
|
|
60
|
+
const result = await storeMemory(root, key, value, type ?? 'note');
|
|
61
|
+
return textResult({ ...result, workspaceRoot: root });
|
|
62
|
+
});
|
|
63
|
+
server.registerTool('search_memory', {
|
|
64
|
+
description: 'Search Contorium MCP memory entries by keyword.',
|
|
65
|
+
inputSchema: z.object({
|
|
66
|
+
query: z.string().min(1).describe('Search text matched against keys and values'),
|
|
67
|
+
}),
|
|
68
|
+
}, async ({ query }) => {
|
|
69
|
+
const root = await workspaceRootForTools();
|
|
70
|
+
const results = await searchMemory(root, query);
|
|
71
|
+
return textResult({ workspaceRoot: root, results });
|
|
72
|
+
});
|
|
73
|
+
server.registerTool('get_memory', {
|
|
74
|
+
description: 'Get a Contorium MCP memory entry by exact key.',
|
|
75
|
+
inputSchema: z.object({
|
|
76
|
+
key: z.string().min(1).describe('Memory key'),
|
|
77
|
+
}),
|
|
78
|
+
}, async ({ key }) => {
|
|
79
|
+
const root = await workspaceRootForTools();
|
|
80
|
+
const entry = await getMemory(root, key);
|
|
81
|
+
return textResult({ workspaceRoot: root, key, entry });
|
|
82
|
+
});
|
|
83
|
+
server.registerTool('get_workspace_context', {
|
|
84
|
+
description: 'Read Contorium workspace snapshot from .contora/state.json (current focus, notes, files, Git) written by the VS Code/Cursor extension.',
|
|
85
|
+
inputSchema: z.object({
|
|
86
|
+
workspaceRoot: z.string().optional().describe('Override workspace root; default auto-detect'),
|
|
87
|
+
}),
|
|
88
|
+
}, async ({ workspaceRoot: override }) => {
|
|
89
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
90
|
+
await ensureWorkspaceBootstrapped(root);
|
|
91
|
+
const snapshot = await loadWorkspaceSnapshot(root);
|
|
92
|
+
const injection = await readHandoffInjectionState(root);
|
|
93
|
+
const confirmedContext = await readMcpAutoContext(root);
|
|
94
|
+
if (!snapshot) {
|
|
95
|
+
return textResult({
|
|
96
|
+
workspaceRoot: root,
|
|
97
|
+
found: false,
|
|
98
|
+
hint: 'Workspace scan bootstrap failed — check workspace path and permissions.',
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return textResult({
|
|
102
|
+
workspaceRoot: root,
|
|
103
|
+
found: true,
|
|
104
|
+
snapshot,
|
|
105
|
+
handoffInjection: injection ?? undefined,
|
|
106
|
+
confirmedContext: confirmedContext ?? undefined,
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
server.registerTool('get_project_intelligence', {
|
|
110
|
+
description: 'Read Contorium v0.7 derived project understanding from .contora/intelligence/state-summary.json (written by the extension cognition layer).',
|
|
111
|
+
inputSchema: z.object({
|
|
112
|
+
workspaceRoot: z.string().optional().describe('Override workspace root; default auto-detect'),
|
|
113
|
+
}),
|
|
114
|
+
}, async ({ workspaceRoot: override }) => {
|
|
115
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
116
|
+
const intelligence = await loadProjectIntelligence(root);
|
|
117
|
+
if (!intelligence) {
|
|
118
|
+
return textResult({
|
|
119
|
+
workspaceRoot: root,
|
|
120
|
+
found: false,
|
|
121
|
+
hint: 'Open the workspace with Contorium extension active to generate state-summary.json.',
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return textResult({ workspaceRoot: root, found: true, intelligence });
|
|
125
|
+
});
|
|
126
|
+
server.registerTool('get_intent_graph', {
|
|
127
|
+
description: 'Read the full Contorium intent graph from .contora/intent-graph/graph.json (multi-intent cognition layer).',
|
|
128
|
+
inputSchema: z.object({
|
|
129
|
+
workspaceRoot: z.string().optional().describe('Override workspace root; default auto-detect'),
|
|
130
|
+
}),
|
|
131
|
+
}, async ({ workspaceRoot: override }) => {
|
|
132
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
133
|
+
const graph = await loadIntentGraph(root);
|
|
134
|
+
if (!graph) {
|
|
135
|
+
return textResult({
|
|
136
|
+
workspaceRoot: root,
|
|
137
|
+
found: false,
|
|
138
|
+
hint: 'Intent graph not generated yet — use Contorium extension in this workspace.',
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return textResult({ workspaceRoot: root, found: true, graph });
|
|
142
|
+
});
|
|
143
|
+
server.registerTool('get_active_intents', {
|
|
144
|
+
description: 'Return ACTIVE / WEAKENING / PARTIAL intent nodes from the Contorium intent graph (compact summary for agents).',
|
|
145
|
+
inputSchema: z.object({
|
|
146
|
+
workspaceRoot: z.string().optional().describe('Override workspace root; default auto-detect'),
|
|
147
|
+
max: z.number().int().min(1).max(24).optional().describe('Max intent nodes (default 8)'),
|
|
148
|
+
}),
|
|
149
|
+
}, async ({ workspaceRoot: override, max }) => {
|
|
150
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
151
|
+
const graph = await loadIntentGraph(root);
|
|
152
|
+
if (!graph) {
|
|
153
|
+
return textResult({
|
|
154
|
+
workspaceRoot: root,
|
|
155
|
+
found: false,
|
|
156
|
+
intents: [],
|
|
157
|
+
hint: 'Intent graph not generated yet.',
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
const intents = activeIntentNodes(graph, max ?? 8);
|
|
161
|
+
return textResult({ workspaceRoot: root, found: true, intents, graphUpdatedAt: graph.updatedAt });
|
|
162
|
+
});
|
|
163
|
+
server.registerTool('get_project_state', {
|
|
164
|
+
description: 'Read Contorium State Builder structured project state from .contora/state-builder/project-state.json (goal, stage, decisions, problems, next actions).',
|
|
165
|
+
inputSchema: z.object({
|
|
166
|
+
workspaceRoot: z.string().optional().describe('Override workspace root; default auto-detect'),
|
|
167
|
+
}),
|
|
168
|
+
}, async ({ workspaceRoot: override }) => {
|
|
169
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
170
|
+
const projectState = await loadProjectBuiltState(root);
|
|
171
|
+
if (!projectState) {
|
|
172
|
+
return textResult({
|
|
173
|
+
workspaceRoot: root,
|
|
174
|
+
found: false,
|
|
175
|
+
hint: 'State Builder not generated yet — use Contorium extension in this workspace.',
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
return textResult({ workspaceRoot: root, found: true, projectState });
|
|
179
|
+
});
|
|
180
|
+
server.registerTool('get_project_snapshot', {
|
|
181
|
+
description: 'Read Contorium PROJECT SNAPSHOT markdown from .contora/state-builder/project-snapshot.md for cross-AI project continuity.',
|
|
182
|
+
inputSchema: z.object({
|
|
183
|
+
workspaceRoot: z.string().optional().describe('Override workspace root; default auto-detect'),
|
|
184
|
+
format: z.enum(['markdown', 'json']).optional().describe('Return markdown (default) or structured JSON state'),
|
|
185
|
+
}),
|
|
186
|
+
}, async ({ workspaceRoot: override, format }) => {
|
|
187
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
188
|
+
const projectState = await loadProjectBuiltState(root);
|
|
189
|
+
const markdown = await loadProjectSnapshotMarkdown(root);
|
|
190
|
+
if (!projectState && !markdown) {
|
|
191
|
+
return textResult({
|
|
192
|
+
workspaceRoot: root,
|
|
193
|
+
found: false,
|
|
194
|
+
hint: 'Project snapshot not generated yet.',
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
if (format === 'json') {
|
|
198
|
+
return textResult({ workspaceRoot: root, found: true, projectState });
|
|
199
|
+
}
|
|
200
|
+
return textResult({
|
|
201
|
+
workspaceRoot: root,
|
|
202
|
+
found: true,
|
|
203
|
+
markdown: markdown ?? '',
|
|
204
|
+
projectState,
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
server.registerTool('get_state_conflicts', {
|
|
208
|
+
description: 'Read Contorium v2 unresolved state conflicts from .contora/state-engine/conflicts.json (audit only — system does not auto-resolve).',
|
|
209
|
+
inputSchema: z.object({
|
|
210
|
+
workspaceRoot: z.string().optional().describe('Override workspace root; default auto-detect'),
|
|
211
|
+
}),
|
|
212
|
+
}, async ({ workspaceRoot: override }) => {
|
|
213
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
214
|
+
const artifact = await loadStateConflicts(root);
|
|
215
|
+
if (!artifact || !artifact.conflicts.length) {
|
|
216
|
+
return textResult({
|
|
217
|
+
workspaceRoot: root,
|
|
218
|
+
found: false,
|
|
219
|
+
conflicts: [],
|
|
220
|
+
hint: 'No unresolved conflicts — or cognition pipeline has not run yet.',
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
return textResult({
|
|
224
|
+
workspaceRoot: root,
|
|
225
|
+
found: true,
|
|
226
|
+
count: artifact.conflicts.length,
|
|
227
|
+
generatedAt: artifact.generatedAt,
|
|
228
|
+
conflicts: artifact.conflicts,
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
server.registerTool('get_project_change', {
|
|
232
|
+
description: 'Read Contorium V3.1 change semantics from .contora/change.json (changed files + key symbol changes).',
|
|
233
|
+
inputSchema: z.object({
|
|
234
|
+
workspaceRoot: z.string().optional().describe('Override workspace root; default auto-detect'),
|
|
235
|
+
}),
|
|
236
|
+
}, async ({ workspaceRoot: override }) => {
|
|
237
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
238
|
+
const change = await readChangeArtifact(root);
|
|
239
|
+
if (!change) {
|
|
240
|
+
return textResult({
|
|
241
|
+
workspaceRoot: root,
|
|
242
|
+
found: false,
|
|
243
|
+
hint: 'Change artifact not generated yet — save code changes or run Contorium sync.',
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
return textResult({ workspaceRoot: root, found: true, change });
|
|
247
|
+
});
|
|
248
|
+
server.registerTool('get_project_graph', {
|
|
249
|
+
description: 'Read Contorium V3 change-neighborhood project graph from .contora/graph.json (functions, classes, imports around recent changes).',
|
|
250
|
+
inputSchema: z.object({
|
|
251
|
+
workspaceRoot: z.string().optional().describe('Override workspace root; default auto-detect'),
|
|
252
|
+
}),
|
|
253
|
+
}, async ({ workspaceRoot: override }) => {
|
|
254
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
255
|
+
const graph = await readProjectGraph(root);
|
|
256
|
+
if (!graph) {
|
|
257
|
+
return textResult({
|
|
258
|
+
workspaceRoot: root,
|
|
259
|
+
found: false,
|
|
260
|
+
hint: 'Project graph not generated yet — save code changes or run Contorium sync.',
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
return textResult({ workspaceRoot: root, found: true, graph });
|
|
264
|
+
});
|
|
265
|
+
server.registerTool('get_project_knowledge_graph', {
|
|
266
|
+
description: 'Read Contorium V3.1 Project Knowledge Graph from .contora/graph/knowledge.json (Intent → Module → File → Function + intent mappings).',
|
|
267
|
+
inputSchema: z.object({
|
|
268
|
+
workspaceRoot: z.string().optional().describe('Override workspace root; default auto-detect'),
|
|
269
|
+
minConfidence: z
|
|
270
|
+
.number()
|
|
271
|
+
.min(0)
|
|
272
|
+
.max(1)
|
|
273
|
+
.optional()
|
|
274
|
+
.describe('Optional filter — omit intent mappings below this confidence (default: 0.7 canonical threshold)'),
|
|
275
|
+
includeInference: z
|
|
276
|
+
.boolean()
|
|
277
|
+
.optional()
|
|
278
|
+
.describe('Include Cortex-only inferenceMappings (confidence < 0.7). Default false.'),
|
|
279
|
+
}),
|
|
280
|
+
}, async ({ workspaceRoot: override, minConfidence, includeInference }) => {
|
|
281
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
282
|
+
const knowledge = await readProjectKnowledgeGraph(root);
|
|
283
|
+
if (!knowledge) {
|
|
284
|
+
return textResult({
|
|
285
|
+
workspaceRoot: root,
|
|
286
|
+
found: false,
|
|
287
|
+
hint: 'Knowledge graph not generated yet — save code changes or run Contorium sync.',
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
const threshold = minConfidence ?? 0.7;
|
|
291
|
+
const { inferenceMappings, ...canonical } = knowledge;
|
|
292
|
+
const payload = {
|
|
293
|
+
...canonical,
|
|
294
|
+
intentMappings: filterMappingsByConfidence(knowledge.intentMappings, threshold),
|
|
295
|
+
...(includeInference ? { inferenceMappings } : {}),
|
|
296
|
+
};
|
|
297
|
+
return textResult({ workspaceRoot: root, found: true, knowledge: payload });
|
|
298
|
+
});
|
|
299
|
+
server.registerTool('get_project_graph_snapshot', {
|
|
300
|
+
description: 'Read Contorium V3.1 cognitive snapshot from .contora/graph/snapshot.json — compact summary for AI Handoff (top intents, hotspots, functions).',
|
|
301
|
+
inputSchema: z.object({
|
|
302
|
+
workspaceRoot: z.string().optional().describe('Override workspace root; default auto-detect'),
|
|
303
|
+
}),
|
|
304
|
+
}, async ({ workspaceRoot: override }) => {
|
|
305
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
306
|
+
const snapshot = await readKnowledgeSnapshot(root);
|
|
307
|
+
if (!snapshot) {
|
|
308
|
+
return textResult({
|
|
309
|
+
workspaceRoot: root,
|
|
310
|
+
found: false,
|
|
311
|
+
hint: 'Graph snapshot not generated yet — save code changes or run Contorium sync.',
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
return textResult({ workspaceRoot: root, found: true, snapshot });
|
|
315
|
+
});
|
|
316
|
+
server.registerTool('get_project_impact', {
|
|
317
|
+
description: '[Deprecated V3.1] Impact merged into handoff.json — returns impact_summary from handoff or legacy impact.json.',
|
|
318
|
+
inputSchema: z.object({
|
|
319
|
+
workspaceRoot: z.string().optional().describe('Override workspace root; default auto-detect'),
|
|
320
|
+
}),
|
|
321
|
+
}, async ({ workspaceRoot: override }) => {
|
|
322
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
323
|
+
const impact = await readImpactArtifact(root);
|
|
324
|
+
if (!impact) {
|
|
325
|
+
return textResult({
|
|
326
|
+
workspaceRoot: root,
|
|
327
|
+
found: false,
|
|
328
|
+
hint: 'Impact not available — run cognition sync or use get_project_handoff.',
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
return textResult({
|
|
332
|
+
workspaceRoot: root,
|
|
333
|
+
found: true,
|
|
334
|
+
impact,
|
|
335
|
+
deprecated: true,
|
|
336
|
+
prefer: 'get_project_handoff',
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
server.registerTool('get_project_intent', {
|
|
340
|
+
description: '[Deprecated V3.1] Intent merged into handoff.json — returns current_focus from handoff or legacy intent.json.',
|
|
341
|
+
inputSchema: z.object({
|
|
342
|
+
workspaceRoot: z.string().optional().describe('Override workspace root; default auto-detect'),
|
|
343
|
+
}),
|
|
344
|
+
}, async ({ workspaceRoot: override }) => {
|
|
345
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
346
|
+
const intent = await readIntentArtifact(root);
|
|
347
|
+
if (!intent) {
|
|
348
|
+
return textResult({
|
|
349
|
+
workspaceRoot: root,
|
|
350
|
+
found: false,
|
|
351
|
+
hint: 'Intent not available — use get_project_handoff.',
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
return textResult({
|
|
355
|
+
workspaceRoot: root,
|
|
356
|
+
found: true,
|
|
357
|
+
intent,
|
|
358
|
+
deprecated: true,
|
|
359
|
+
prefer: 'get_project_handoff',
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
server.registerTool('get_handoff_injection_status', {
|
|
363
|
+
description: 'At the START of each new chat: check if Contorium runtime is active and user should be asked to inject context. Call automatically — no CLI command needed.',
|
|
364
|
+
inputSchema: workspaceRootSchema,
|
|
365
|
+
}, async ({ workspaceRoot: override }) => {
|
|
366
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
367
|
+
await syncInjectionWithRuntime(root);
|
|
368
|
+
const prep = await prepareHandoffInjection(root);
|
|
369
|
+
const state = await readHandoffInjectionState(root);
|
|
370
|
+
const confirmedContext = await readMcpAutoContext(root);
|
|
371
|
+
return textResult({
|
|
372
|
+
workspaceRoot: root,
|
|
373
|
+
pending: prep.shouldPrompt,
|
|
374
|
+
alreadyInjected: prep.alreadyInjected,
|
|
375
|
+
prompt: prep.prompt,
|
|
376
|
+
compact: prep.compact,
|
|
377
|
+
state,
|
|
378
|
+
confirmedContext: confirmedContext ? true : false,
|
|
379
|
+
next: prep.shouldPrompt
|
|
380
|
+
? 'Ask the user, then call confirm_handoff_injection (Y) or skip_handoff_injection (N).'
|
|
381
|
+
: prep.alreadyInjected
|
|
382
|
+
? 'Context already injected for this runtime — read .contora/mcp.auto-context.md or get_project_handoff.'
|
|
383
|
+
: 'No active runtime or user skipped injection.',
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
server.registerTool('confirm_handoff_injection', {
|
|
387
|
+
description: 'After user confirms (Y), write .contora/mcp.auto-context.md and mark runtime handoff as injected for this session.',
|
|
388
|
+
inputSchema: z.object({
|
|
389
|
+
workspaceRoot: z.string().optional().describe('Override workspace root; default auto-detect'),
|
|
390
|
+
format: z
|
|
391
|
+
.enum(['json', 'markdown', 'compact'])
|
|
392
|
+
.optional()
|
|
393
|
+
.describe('Handoff format written to mcp.auto-context.md (default markdown)'),
|
|
394
|
+
}),
|
|
395
|
+
}, async ({ workspaceRoot: override, format }) => {
|
|
396
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
397
|
+
const result = await confirmHandoffInjection(root, format ?? 'markdown');
|
|
398
|
+
if (!result.ok) {
|
|
399
|
+
return textResult({ workspaceRoot: root, ok: false, hint: result.hint });
|
|
400
|
+
}
|
|
401
|
+
return textResult({
|
|
402
|
+
workspaceRoot: root,
|
|
403
|
+
ok: true,
|
|
404
|
+
filePath: result.filePath,
|
|
405
|
+
contextFile: `.contora/mcp.auto-context.md`,
|
|
406
|
+
hint: 'Injected — AI can read the context file or call get_project_handoff.',
|
|
407
|
+
preview: result.text?.slice(0, 400),
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
server.registerTool('skip_handoff_injection', {
|
|
411
|
+
description: 'User declined runtime handoff injection for the current runtime session (N).',
|
|
412
|
+
inputSchema: workspaceRootSchema,
|
|
413
|
+
}, async ({ workspaceRoot: override }) => {
|
|
414
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
415
|
+
const result = await skipHandoffInjection(root);
|
|
416
|
+
return textResult({
|
|
417
|
+
workspaceRoot: root,
|
|
418
|
+
ok: result.ok,
|
|
419
|
+
hint: 'Skipped — start chat without injected context; get_project_handoff remains available.',
|
|
420
|
+
});
|
|
421
|
+
});
|
|
422
|
+
server.registerTool('get_project_handoff', {
|
|
423
|
+
description: 'CHP v1 get_handoff — read unified AI handoff from Contorium Runtime (.contora/handoff.json + state). For new chats prefer get_handoff_injection_status → user confirm → confirm_handoff_injection.',
|
|
424
|
+
inputSchema: z.object({
|
|
425
|
+
workspaceRoot: z.string().optional().describe('Override workspace root; default auto-detect'),
|
|
426
|
+
format: z
|
|
427
|
+
.enum(['json', 'markdown', 'compact'])
|
|
428
|
+
.optional()
|
|
429
|
+
.describe('Output format: compact (default), markdown (AI chat), json (systems)'),
|
|
430
|
+
filter: z.string().optional().describe('Optional symbol/file filter'),
|
|
431
|
+
}),
|
|
432
|
+
}, async ({ workspaceRoot: override, format, filter }) => {
|
|
433
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
434
|
+
const handoff = await readHandoffArtifact(root);
|
|
435
|
+
const result = await getProjectHandoff(root, format ?? 'compact', filter);
|
|
436
|
+
if (!result.found) {
|
|
437
|
+
return textResult({
|
|
438
|
+
workspaceRoot: root,
|
|
439
|
+
found: false,
|
|
440
|
+
hint: 'Handoff artifact not generated yet — save code changes or run contorium sync.',
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
if (format === 'markdown' || format === 'compact') {
|
|
444
|
+
return textResult({
|
|
445
|
+
workspaceRoot: root,
|
|
446
|
+
found: true,
|
|
447
|
+
format,
|
|
448
|
+
text: result.text,
|
|
449
|
+
state: result.state,
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
if (format === 'json') {
|
|
453
|
+
return textResult({ workspaceRoot: root, found: true, chp: result.state });
|
|
454
|
+
}
|
|
455
|
+
return textResult({
|
|
456
|
+
workspaceRoot: root,
|
|
457
|
+
found: true,
|
|
458
|
+
handoff,
|
|
459
|
+
chp: result.state,
|
|
460
|
+
compact: result.text,
|
|
461
|
+
});
|
|
462
|
+
});
|
|
463
|
+
server.registerTool('get_project_timeline', {
|
|
464
|
+
description: 'Read Contorium V3.1 code evolution timeline from .contora/timeline.json (recent commits + symbol changes).',
|
|
465
|
+
inputSchema: z.object({
|
|
466
|
+
workspaceRoot: z.string().optional().describe('Override workspace root; default auto-detect'),
|
|
467
|
+
}),
|
|
468
|
+
}, async ({ workspaceRoot: override }) => {
|
|
469
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
470
|
+
const timeline = await readProjectTimeline(root);
|
|
471
|
+
if (!timeline) {
|
|
472
|
+
return textResult({
|
|
473
|
+
workspaceRoot: root,
|
|
474
|
+
found: false,
|
|
475
|
+
hint: 'Timeline not generated yet — requires git history and recent code changes.',
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
return textResult({ workspaceRoot: root, found: true, timeline });
|
|
479
|
+
});
|
|
480
|
+
// ── MCP v1 standard tools (aliases + runtime graph) ──────────────────────────
|
|
481
|
+
server.registerTool('get_recent_changes', {
|
|
482
|
+
description: '[MCP v1 standard] Recent file/function changes from .contora/change.json — alias of get_project_change.',
|
|
483
|
+
inputSchema: workspaceRootSchema,
|
|
484
|
+
}, async ({ workspaceRoot: override }) => {
|
|
485
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
486
|
+
const change = await readChangeArtifact(root);
|
|
487
|
+
if (!change) {
|
|
488
|
+
return textResult({
|
|
489
|
+
workspaceRoot: root,
|
|
490
|
+
found: false,
|
|
491
|
+
hint: 'No recent changes — save code or run: contorium sync',
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
return textResult({ workspaceRoot: root, found: true, recent_changes: change });
|
|
495
|
+
});
|
|
496
|
+
server.registerTool('get_understanding_graph', {
|
|
497
|
+
description: '[MCP v1 standard] Runtime understanding graph — call chains + impact from .contora/understanding_graph.json.',
|
|
498
|
+
inputSchema: workspaceRootSchema,
|
|
499
|
+
}, async ({ workspaceRoot: override }) => {
|
|
500
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
501
|
+
const graph = await readUnderstandingGraph(root);
|
|
502
|
+
if (!graph) {
|
|
503
|
+
return textResult({
|
|
504
|
+
workspaceRoot: root,
|
|
505
|
+
found: false,
|
|
506
|
+
hint: 'Understanding graph pending — save code changes or run contorium sync.',
|
|
507
|
+
fallback: 'Try get_project_graph for change-neighborhood graph.json',
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
return textResult({ workspaceRoot: root, found: true, understanding_graph: graph });
|
|
511
|
+
});
|
|
512
|
+
server.registerTool('get_runtime_state', {
|
|
513
|
+
description: '[MCP v1 standard] Runtime session view — bootstrap, dashboard worker, session marker (read-only).',
|
|
514
|
+
inputSchema: workspaceRootSchema,
|
|
515
|
+
}, async ({ workspaceRoot: override }) => {
|
|
516
|
+
const root = override ? path.resolve(override) : await workspaceRootForTools();
|
|
517
|
+
const runtime = await readRuntimeState(root);
|
|
518
|
+
return textResult({ workspaceRoot: root, found: true, runtime });
|
|
519
|
+
});
|
|
520
|
+
/** Standard MCP server startup — used by bin/contorium-mcp.js and direct server.js entry. */
|
|
521
|
+
export async function startMcpServer(argv = process.argv.slice(2)) {
|
|
522
|
+
const startup = resolveMcpStartupConfig(argv);
|
|
523
|
+
initWorkspaceFromArgv(argv);
|
|
524
|
+
console.error(`[contorium-mcp] workspace: ${startup.workspaceHint}`);
|
|
525
|
+
try {
|
|
526
|
+
const root = await workspaceRootForTools();
|
|
527
|
+
const boot = await ensureWorkspaceBootstrapped(root);
|
|
528
|
+
startMcpLightSync(root);
|
|
529
|
+
scheduleMcpRuntimeBootstrap(root);
|
|
530
|
+
console.error(`[contorium-mcp] runtime bootstrap scheduled (mode: ${boot.mode})`);
|
|
531
|
+
setTimeout(() => {
|
|
532
|
+
void (async () => {
|
|
533
|
+
await syncInjectionWithRuntime(root);
|
|
534
|
+
const prep = await prepareHandoffInjection(root, { newChat: true });
|
|
535
|
+
if (prep.shouldPrompt && prep.prompt) {
|
|
536
|
+
console.error('[contorium-mcp:handoff] ── New chat · semi-auto injection ──');
|
|
537
|
+
for (const line of prep.prompt.split('\n')) {
|
|
538
|
+
console.error(`[contorium-mcp:handoff] ${line}`);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
else if (prep.alreadyInjected) {
|
|
542
|
+
console.error('[contorium-mcp:handoff] Context already confirmed for this chat.');
|
|
543
|
+
}
|
|
544
|
+
})();
|
|
545
|
+
}, 1200);
|
|
546
|
+
}
|
|
547
|
+
catch (err) {
|
|
548
|
+
console.error('[contorium-mcp] bootstrap skipped:', err instanceof Error ? err.message : err);
|
|
549
|
+
}
|
|
550
|
+
const transport = new StdioServerTransport();
|
|
551
|
+
await server.connect(transport);
|
|
552
|
+
console.error('[contorium-mcp] ready on stdio');
|
|
553
|
+
}
|
|
554
|
+
function isDirectServerEntry() {
|
|
555
|
+
const entry = process.argv[1];
|
|
556
|
+
if (!entry) {
|
|
557
|
+
return false;
|
|
558
|
+
}
|
|
559
|
+
const base = path.basename(entry);
|
|
560
|
+
return base === 'server.js' || base === 'server.ts';
|
|
561
|
+
}
|
|
562
|
+
if (isDirectServerEntry()) {
|
|
563
|
+
startMcpServer().catch((err) => {
|
|
564
|
+
console.error('[contorium-mcp] fatal:', err);
|
|
565
|
+
process.exit(1);
|
|
566
|
+
});
|
|
567
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface McpProjectBuiltState {
|
|
2
|
+
version: number;
|
|
3
|
+
engine_version?: number;
|
|
4
|
+
generatedAt: number;
|
|
5
|
+
task_anchor?: string;
|
|
6
|
+
project_goal: string;
|
|
7
|
+
current_stage: string;
|
|
8
|
+
active_modules: string[];
|
|
9
|
+
recent_decisions: string[];
|
|
10
|
+
open_problems: string[];
|
|
11
|
+
completed_milestones: string[];
|
|
12
|
+
next_actions: string[];
|
|
13
|
+
confidence: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function loadProjectBuiltState(workspaceRoot: string): Promise<McpProjectBuiltState | null>;
|
|
16
|
+
export declare function loadProjectSnapshotMarkdown(workspaceRoot: string): Promise<string | null>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import { projectSnapshotFile, projectStateFile } from './paths.js';
|
|
3
|
+
export async function loadProjectBuiltState(workspaceRoot) {
|
|
4
|
+
const fp = projectStateFile(workspaceRoot);
|
|
5
|
+
try {
|
|
6
|
+
const text = await fs.readFile(fp, 'utf8');
|
|
7
|
+
const o = JSON.parse(text);
|
|
8
|
+
if (!o || typeof o !== 'object' || o.version !== 1) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
const strList = (v) => Array.isArray(v) ? v.filter((x) => typeof x === 'string') : [];
|
|
12
|
+
return {
|
|
13
|
+
version: 1,
|
|
14
|
+
engine_version: typeof o.engine_version === 'number' ? o.engine_version : undefined,
|
|
15
|
+
generatedAt: typeof o.generatedAt === 'number' ? o.generatedAt : 0,
|
|
16
|
+
task_anchor: typeof o.task_anchor === 'string' ? o.task_anchor : undefined,
|
|
17
|
+
project_goal: typeof o.project_goal === 'string' ? o.project_goal : '',
|
|
18
|
+
current_stage: typeof o.current_stage === 'string' ? o.current_stage : '',
|
|
19
|
+
active_modules: strList(o.active_modules),
|
|
20
|
+
recent_decisions: strList(o.recent_decisions),
|
|
21
|
+
open_problems: strList(o.open_problems),
|
|
22
|
+
completed_milestones: strList(o.completed_milestones),
|
|
23
|
+
next_actions: strList(o.next_actions),
|
|
24
|
+
confidence: typeof o.confidence === 'number' ? o.confidence : 0,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export async function loadProjectSnapshotMarkdown(workspaceRoot) {
|
|
32
|
+
const fp = projectSnapshotFile(workspaceRoot);
|
|
33
|
+
try {
|
|
34
|
+
const text = (await fs.readFile(fp, 'utf8')).trim();
|
|
35
|
+
return text.length ? text : null;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { readChangeArtifact, readHandoffArtifact, readImpactArtifact, readIntentArtifact, readProjectGraph, readProjectKnowledgeGraph, readKnowledgeSnapshot, readProjectTimeline, readUnderstandingGraph, readStateJson, readWorkspaceStatus, filterMappingsByConfidence, getProjectHandoff, type ChpHandoffFormat, } from '@contora/state-core';
|