context-gatekeeper 0.3.0
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 +774 -0
- package/README.zh.md +765 -0
- package/bin/context-gatekeeper-cli.js +60 -0
- package/dist/api/gdpr.d.ts +104 -0
- package/dist/api/gdpr.d.ts.map +1 -0
- package/dist/api/gdpr.js +229 -0
- package/dist/api/gdpr.js.map +1 -0
- package/dist/api/health-check.d.ts +13 -0
- package/dist/api/health-check.d.ts.map +1 -0
- package/dist/api/health-check.js +2 -0
- package/dist/api/health-check.js.map +1 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +8 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/observability.d.ts +39 -0
- package/dist/api/observability.d.ts.map +1 -0
- package/dist/api/observability.js +132 -0
- package/dist/api/observability.js.map +1 -0
- package/dist/api/session-manager.d.ts +41 -0
- package/dist/api/session-manager.d.ts.map +1 -0
- package/dist/api/session-manager.js +129 -0
- package/dist/api/session-manager.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +8 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +613 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/configure-llm.d.ts +26 -0
- package/dist/mcp/tools/configure-llm.d.ts.map +1 -0
- package/dist/mcp/tools/configure-llm.js +32 -0
- package/dist/mcp/tools/configure-llm.js.map +1 -0
- package/dist/mcp/tools/context-compress.d.ts +15 -0
- package/dist/mcp/tools/context-compress.d.ts.map +1 -0
- package/dist/mcp/tools/context-compress.js +15 -0
- package/dist/mcp/tools/context-compress.js.map +1 -0
- package/dist/mcp/tools/dual-mode-execute.d.ts +78 -0
- package/dist/mcp/tools/dual-mode-execute.d.ts.map +1 -0
- package/dist/mcp/tools/dual-mode-execute.js +299 -0
- package/dist/mcp/tools/dual-mode-execute.js.map +1 -0
- package/dist/mcp/tools/index.d.ts +19 -0
- package/dist/mcp/tools/index.d.ts.map +1 -0
- package/dist/mcp/tools/index.js +20 -0
- package/dist/mcp/tools/index.js.map +1 -0
- package/dist/mcp/tools/intelligent-recall.d.ts +67 -0
- package/dist/mcp/tools/intelligent-recall.d.ts.map +1 -0
- package/dist/mcp/tools/intelligent-recall.js +208 -0
- package/dist/mcp/tools/intelligent-recall.js.map +1 -0
- package/dist/mcp/tools/memory-anchor.d.ts +13 -0
- package/dist/mcp/tools/memory-anchor.d.ts.map +1 -0
- package/dist/mcp/tools/memory-anchor.js +16 -0
- package/dist/mcp/tools/memory-anchor.js.map +1 -0
- package/dist/mcp/tools/memory-delete-batch.d.ts +16 -0
- package/dist/mcp/tools/memory-delete-batch.d.ts.map +1 -0
- package/dist/mcp/tools/memory-delete-batch.js +26 -0
- package/dist/mcp/tools/memory-delete-batch.js.map +1 -0
- package/dist/mcp/tools/memory-extract.d.ts +68 -0
- package/dist/mcp/tools/memory-extract.d.ts.map +1 -0
- package/dist/mcp/tools/memory-extract.js +280 -0
- package/dist/mcp/tools/memory-extract.js.map +1 -0
- package/dist/mcp/tools/memory-recall.d.ts +42 -0
- package/dist/mcp/tools/memory-recall.d.ts.map +1 -0
- package/dist/mcp/tools/memory-recall.js +37 -0
- package/dist/mcp/tools/memory-recall.js.map +1 -0
- package/dist/mcp/tools/memory-report-usage.d.ts +17 -0
- package/dist/mcp/tools/memory-report-usage.d.ts.map +1 -0
- package/dist/mcp/tools/memory-report-usage.js +15 -0
- package/dist/mcp/tools/memory-report-usage.js.map +1 -0
- package/dist/mcp/tools/memory-search.d.ts +43 -0
- package/dist/mcp/tools/memory-search.d.ts.map +1 -0
- package/dist/mcp/tools/memory-search.js +38 -0
- package/dist/mcp/tools/memory-search.js.map +1 -0
- package/dist/mcp/tools/memory-session.d.ts +118 -0
- package/dist/mcp/tools/memory-session.d.ts.map +1 -0
- package/dist/mcp/tools/memory-session.js +113 -0
- package/dist/mcp/tools/memory-session.js.map +1 -0
- package/dist/mcp/tools/memory-stats.d.ts +10 -0
- package/dist/mcp/tools/memory-stats.d.ts.map +1 -0
- package/dist/mcp/tools/memory-stats.js +35 -0
- package/dist/mcp/tools/memory-stats.js.map +1 -0
- package/dist/mcp/tools/memory-store-batch.d.ts +49 -0
- package/dist/mcp/tools/memory-store-batch.d.ts.map +1 -0
- package/dist/mcp/tools/memory-store-batch.js +48 -0
- package/dist/mcp/tools/memory-store-batch.js.map +1 -0
- package/dist/mcp/tools/memory-store.d.ts +37 -0
- package/dist/mcp/tools/memory-store.d.ts.map +1 -0
- package/dist/mcp/tools/memory-store.js +34 -0
- package/dist/mcp/tools/memory-store.js.map +1 -0
- package/dist/mcp/tools/project-create.d.ts +16 -0
- package/dist/mcp/tools/project-create.d.ts.map +1 -0
- package/dist/mcp/tools/project-create.js +14 -0
- package/dist/mcp/tools/project-create.js.map +1 -0
- package/dist/models/types.d.ts +88 -0
- package/dist/models/types.d.ts.map +1 -0
- package/dist/models/types.js +19 -0
- package/dist/models/types.js.map +1 -0
- package/dist/schema/compression.d.ts +7 -0
- package/dist/schema/compression.d.ts.map +1 -0
- package/dist/schema/compression.js +66 -0
- package/dist/schema/compression.js.map +1 -0
- package/dist/schema/fulltext-search.d.ts +10 -0
- package/dist/schema/fulltext-search.d.ts.map +1 -0
- package/dist/schema/fulltext-search.js +73 -0
- package/dist/schema/fulltext-search.js.map +1 -0
- package/dist/schema/index.d.ts +9 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +9 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/knowledge-graph.d.ts +108 -0
- package/dist/schema/knowledge-graph.d.ts.map +1 -0
- package/dist/schema/knowledge-graph.js +372 -0
- package/dist/schema/knowledge-graph.js.map +1 -0
- package/dist/schema/memory-session.d.ts +62 -0
- package/dist/schema/memory-session.d.ts.map +1 -0
- package/dist/schema/memory-session.js +258 -0
- package/dist/schema/memory-session.js.map +1 -0
- package/dist/schema/memory.d.ts +84 -0
- package/dist/schema/memory.d.ts.map +1 -0
- package/dist/schema/memory.js +622 -0
- package/dist/schema/memory.js.map +1 -0
- package/dist/schema/project.d.ts +8 -0
- package/dist/schema/project.d.ts.map +1 -0
- package/dist/schema/project.js +68 -0
- package/dist/schema/project.js.map +1 -0
- package/dist/schema/schema-init.d.ts +2 -0
- package/dist/schema/schema-init.d.ts.map +1 -0
- package/dist/schema/schema-init.js +199 -0
- package/dist/schema/schema-init.js.map +1 -0
- package/dist/schema/vector-index.d.ts +28 -0
- package/dist/schema/vector-index.d.ts.map +1 -0
- package/dist/schema/vector-index.js +179 -0
- package/dist/schema/vector-index.js.map +1 -0
- package/dist/scripts/agents/base.d.ts +89 -0
- package/dist/scripts/agents/base.d.ts.map +1 -0
- package/dist/scripts/agents/base.js +148 -0
- package/dist/scripts/agents/base.js.map +1 -0
- package/dist/scripts/agents/base.ts +193 -0
- package/dist/scripts/agents/claude-code.d.ts +21 -0
- package/dist/scripts/agents/claude-code.d.ts.map +1 -0
- package/dist/scripts/agents/claude-code.js +33 -0
- package/dist/scripts/agents/claude-code.js.map +1 -0
- package/dist/scripts/agents/claude-code.ts +36 -0
- package/dist/scripts/agents/claude-desktop.d.ts +25 -0
- package/dist/scripts/agents/claude-desktop.d.ts.map +1 -0
- package/dist/scripts/agents/claude-desktop.js +36 -0
- package/dist/scripts/agents/claude-desktop.js.map +1 -0
- package/dist/scripts/agents/claude-desktop.ts +39 -0
- package/dist/scripts/agents/cline.d.ts +22 -0
- package/dist/scripts/agents/cline.d.ts.map +1 -0
- package/dist/scripts/agents/cline.js +35 -0
- package/dist/scripts/agents/cline.js.map +1 -0
- package/dist/scripts/agents/cline.ts +38 -0
- package/dist/scripts/agents/continue.d.ts +20 -0
- package/dist/scripts/agents/continue.d.ts.map +1 -0
- package/dist/scripts/agents/continue.js +35 -0
- package/dist/scripts/agents/continue.js.map +1 -0
- package/dist/scripts/agents/continue.ts +38 -0
- package/dist/scripts/agents/cursor.d.ts +27 -0
- package/dist/scripts/agents/cursor.d.ts.map +1 -0
- package/dist/scripts/agents/cursor.js +38 -0
- package/dist/scripts/agents/cursor.js.map +1 -0
- package/dist/scripts/agents/cursor.ts +41 -0
- package/dist/scripts/cli/config-gen.d.ts +59 -0
- package/dist/scripts/cli/config-gen.d.ts.map +1 -0
- package/dist/scripts/cli/config-gen.js +156 -0
- package/dist/scripts/cli/config-gen.js.map +1 -0
- package/dist/scripts/cli/config-gen.ts +164 -0
- package/dist/scripts/cli/detect.d.ts +42 -0
- package/dist/scripts/cli/detect.d.ts.map +1 -0
- package/dist/scripts/cli/detect.js +131 -0
- package/dist/scripts/cli/detect.js.map +1 -0
- package/dist/scripts/cli/detect.ts +162 -0
- package/dist/scripts/cli/install.d.ts +31 -0
- package/dist/scripts/cli/install.d.ts.map +1 -0
- package/dist/scripts/cli/install.js +125 -0
- package/dist/scripts/cli/install.js.map +1 -0
- package/dist/scripts/cli/install.ts +157 -0
- package/dist/scripts/cli/status.d.ts +8 -0
- package/dist/scripts/cli/status.d.ts.map +1 -0
- package/dist/scripts/cli/status.js +39 -0
- package/dist/scripts/cli/status.js.map +1 -0
- package/dist/scripts/cli/status.ts +48 -0
- package/dist/scripts/cli/uninstall.d.ts +22 -0
- package/dist/scripts/cli/uninstall.d.ts.map +1 -0
- package/dist/scripts/cli/uninstall.js +141 -0
- package/dist/scripts/cli/uninstall.js.map +1 -0
- package/dist/scripts/cli/uninstall.ts +157 -0
- package/dist/scripts/cli.d.ts +23 -0
- package/dist/scripts/cli.d.ts.map +1 -0
- package/dist/scripts/cli.js +166 -0
- package/dist/scripts/cli.js.map +1 -0
- package/dist/scripts/cli.ts +173 -0
- package/dist/services/classifier/index.d.ts +36 -0
- package/dist/services/classifier/index.d.ts.map +1 -0
- package/dist/services/classifier/index.js +104 -0
- package/dist/services/classifier/index.js.map +1 -0
- package/dist/services/classifier/llm.d.ts +37 -0
- package/dist/services/classifier/llm.d.ts.map +1 -0
- package/dist/services/classifier/llm.js +119 -0
- package/dist/services/classifier/llm.js.map +1 -0
- package/dist/services/classifier/rules.d.ts +22 -0
- package/dist/services/classifier/rules.d.ts.map +1 -0
- package/dist/services/classifier/rules.js +98 -0
- package/dist/services/classifier/rules.js.map +1 -0
- package/dist/services/compressor/index.d.ts +3 -0
- package/dist/services/compressor/index.d.ts.map +1 -0
- package/dist/services/compressor/index.js +3 -0
- package/dist/services/compressor/index.js.map +1 -0
- package/dist/services/compressor/threshold.d.ts +35 -0
- package/dist/services/compressor/threshold.d.ts.map +1 -0
- package/dist/services/compressor/threshold.js +60 -0
- package/dist/services/compressor/threshold.js.map +1 -0
- package/dist/services/compressor/trigger.d.ts +24 -0
- package/dist/services/compressor/trigger.d.ts.map +1 -0
- package/dist/services/compressor/trigger.js +91 -0
- package/dist/services/compressor/trigger.js.map +1 -0
- package/dist/services/constraint-extractor.d.ts +25 -0
- package/dist/services/constraint-extractor.d.ts.map +1 -0
- package/dist/services/constraint-extractor.js +97 -0
- package/dist/services/constraint-extractor.js.map +1 -0
- package/dist/services/database-health.d.ts +22 -0
- package/dist/services/database-health.d.ts.map +1 -0
- package/dist/services/database-health.js +122 -0
- package/dist/services/database-health.js.map +1 -0
- package/dist/services/embedding-fixed.d.ts +9 -0
- package/dist/services/embedding-fixed.d.ts.map +1 -0
- package/dist/services/embedding-fixed.js +70 -0
- package/dist/services/embedding-fixed.js.map +1 -0
- package/dist/services/embedding-provider.d.ts +79 -0
- package/dist/services/embedding-provider.d.ts.map +1 -0
- package/dist/services/embedding-provider.js +229 -0
- package/dist/services/embedding-provider.js.map +1 -0
- package/dist/services/embedding.d.ts +17 -0
- package/dist/services/embedding.d.ts.map +1 -0
- package/dist/services/embedding.js +99 -0
- package/dist/services/embedding.js.map +1 -0
- package/dist/services/hnsw-index.d.ts +76 -0
- package/dist/services/hnsw-index.d.ts.map +1 -0
- package/dist/services/hnsw-index.js +301 -0
- package/dist/services/hnsw-index.js.map +1 -0
- package/dist/services/llm.d.ts +39 -0
- package/dist/services/llm.d.ts.map +1 -0
- package/dist/services/llm.js +207 -0
- package/dist/services/llm.js.map +1 -0
- package/dist/services/memory-tiers.d.ts +75 -0
- package/dist/services/memory-tiers.d.ts.map +1 -0
- package/dist/services/memory-tiers.js +275 -0
- package/dist/services/memory-tiers.js.map +1 -0
- package/dist/services/memory.d.ts +33 -0
- package/dist/services/memory.d.ts.map +1 -0
- package/dist/services/memory.js +209 -0
- package/dist/services/memory.js.map +1 -0
- package/dist/services/multi-agent-sharing.d.ts +83 -0
- package/dist/services/multi-agent-sharing.d.ts.map +1 -0
- package/dist/services/multi-agent-sharing.js +278 -0
- package/dist/services/multi-agent-sharing.js.map +1 -0
- package/dist/services/reranker.d.ts +88 -0
- package/dist/services/reranker.d.ts.map +1 -0
- package/dist/services/reranker.js +234 -0
- package/dist/services/reranker.js.map +1 -0
- package/dist/services/triple-extractor.d.ts +35 -0
- package/dist/services/triple-extractor.d.ts.map +1 -0
- package/dist/services/triple-extractor.js +293 -0
- package/dist/services/triple-extractor.js.map +1 -0
- package/dist/services/vector-provider.d.ts +40 -0
- package/dist/services/vector-provider.d.ts.map +1 -0
- package/dist/services/vector-provider.js +225 -0
- package/dist/services/vector-provider.js.map +1 -0
- package/dist/utils/after-chain-executor.d.ts +26 -0
- package/dist/utils/after-chain-executor.d.ts.map +1 -0
- package/dist/utils/after-chain-executor.js +135 -0
- package/dist/utils/after-chain-executor.js.map +1 -0
- package/dist/utils/after-chain.d.ts +94 -0
- package/dist/utils/after-chain.d.ts.map +1 -0
- package/dist/utils/after-chain.js +155 -0
- package/dist/utils/after-chain.js.map +1 -0
- package/dist/utils/db.d.ts +29 -0
- package/dist/utils/db.d.ts.map +1 -0
- package/dist/utils/db.js +201 -0
- package/dist/utils/db.js.map +1 -0
- package/dist/utils/encryption.d.ts +87 -0
- package/dist/utils/encryption.d.ts.map +1 -0
- package/dist/utils/encryption.js +175 -0
- package/dist/utils/encryption.js.map +1 -0
- package/dist/utils/errors.d.ts +35 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +56 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/logger.d.ts +27 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +177 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/priority.d.ts +26 -0
- package/dist/utils/priority.d.ts.map +1 -0
- package/dist/utils/priority.js +43 -0
- package/dist/utils/priority.js.map +1 -0
- package/dist/utils/watchdog.d.ts +57 -0
- package/dist/utils/watchdog.d.ts.map +1 -0
- package/dist/utils/watchdog.js +164 -0
- package/dist/utils/watchdog.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,613 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { z } from 'zod/v4';
|
|
4
|
+
import { logger } from '../utils/logger.js';
|
|
5
|
+
import { initDatabase } from '../utils/db.js';
|
|
6
|
+
import { executeAfterChain, recordConversationTurn } from '../utils/after-chain-executor.js';
|
|
7
|
+
import { getAfterChainRegistry } from '../utils/after-chain.js';
|
|
8
|
+
import { initSchema } from '../schema/index.js';
|
|
9
|
+
import { getWatchdogTokenManager, checkPermission, READ_ONLY_TOOLS, READ_WRITE_TOOLS, WatchdogTokenManager, TOOL_PERMISSIONS, } from '../utils/watchdog.js';
|
|
10
|
+
import { memoryStoreTool, memoryRecallTool, memoryAnchorTool, memoryReportUsageTool, contextCompressTool, projectCreateTool, memoryStoreBatchTool, memoryDeleteBatchTool, memorySearchTool, configureLLMTool, memoryStatsTool, memoryExtractTool, intelligentRecallTool, dualModeExecuteTool } from './tools/index.js';
|
|
11
|
+
const mcpServer = new McpServer({
|
|
12
|
+
name: 'context-gatekeeper',
|
|
13
|
+
version: '0.2.1'
|
|
14
|
+
});
|
|
15
|
+
// Initialize database asynchronously
|
|
16
|
+
async function initialize() {
|
|
17
|
+
try {
|
|
18
|
+
await initDatabase();
|
|
19
|
+
initSchema();
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
logger.error('Failed to initialize database', { error });
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Main entry point - start the MCP server
|
|
28
|
+
*/
|
|
29
|
+
mcpServer.registerTool('memory_store', {
|
|
30
|
+
description: 'Store a new memory with automatic embedding and deduplication',
|
|
31
|
+
inputSchema: {
|
|
32
|
+
content: z.string().min(1).describe('The memory content'),
|
|
33
|
+
priority: z.enum(['anchored', 'constraint', 'decision', 'preference', 'fact']).describe('Priority level'),
|
|
34
|
+
project_tags: z.array(z.string()).optional().describe('Project tags for filtering'),
|
|
35
|
+
anchored: z.boolean().optional().describe('Whether this memory is anchored (permanent)'),
|
|
36
|
+
expires_in_hours: z.number().positive().optional().describe('TTL in hours'),
|
|
37
|
+
updated_by: z.string().optional().describe('Source that updated this memory'),
|
|
38
|
+
user_id: z.string().optional().default('default').describe('User ID for storage isolation'),
|
|
39
|
+
agent_id: z.string().optional().default('default').describe('Agent ID for storage isolation'),
|
|
40
|
+
project_id: z.string().optional().default('default').describe('Project ID for storage isolation'),
|
|
41
|
+
token: z.string().optional().describe('Watchdog token for write operations')
|
|
42
|
+
}
|
|
43
|
+
}, async ({ content, priority, project_tags, anchored, expires_in_hours, updated_by, user_id, agent_id, project_id, token }) => {
|
|
44
|
+
const start = performance.now();
|
|
45
|
+
try {
|
|
46
|
+
const permission = checkPermission('memory_store', token || '');
|
|
47
|
+
if (!permission.allowed) {
|
|
48
|
+
const latencyMs = Math.round(performance.now() - start);
|
|
49
|
+
logger.warn('Tool permission denied', { tool: 'memory_store', latencyMs, reason: permission.reason });
|
|
50
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'Permission denied', reason: permission.reason }) }] };
|
|
51
|
+
}
|
|
52
|
+
const result = await memoryStoreTool({ content, priority, project_tags, anchored, expires_in_hours, updated_by, user_id, agent_id, project_id });
|
|
53
|
+
executeAfterChain('memory_store', { content, priority }, result).catch(() => { });
|
|
54
|
+
const latencyMs = Math.round(performance.now() - start);
|
|
55
|
+
logger.info('Tool completed', { tool: 'memory_store', latencyMs, success: true });
|
|
56
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
const latencyMs = Math.round(performance.now() - start);
|
|
60
|
+
logger.error('Tool failed', { tool: 'memory_store', latencyMs, success: false, error });
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
// Tool: memory_recall
|
|
65
|
+
mcpServer.registerTool('memory_recall', {
|
|
66
|
+
description: 'Recall memories with automatic search mode detection',
|
|
67
|
+
inputSchema: {
|
|
68
|
+
query: z.string().describe('Search query for memories'),
|
|
69
|
+
project_tags: z.array(z.string()).optional().describe('Filter by project tags'),
|
|
70
|
+
limit: z.number().int().positive().optional().default(10).describe('Maximum results'),
|
|
71
|
+
search_mode: z.enum(['keyword', 'semantic', 'hybrid', 'auto']).optional().default('auto').describe('Search mode'),
|
|
72
|
+
user_id: z.string().optional().default('default').describe('User ID for storage isolation'),
|
|
73
|
+
agent_id: z.string().optional().default('default').describe('Agent ID for storage isolation'),
|
|
74
|
+
project_id: z.string().optional().default('default').describe('Project ID for storage isolation')
|
|
75
|
+
}
|
|
76
|
+
}, async ({ query, project_tags, limit, search_mode, user_id, agent_id, project_id }) => {
|
|
77
|
+
const result = await memoryRecallTool({ query, project_tags, limit, search_mode, user_id, agent_id, project_id });
|
|
78
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
79
|
+
});
|
|
80
|
+
// Tool: memory_anchor
|
|
81
|
+
mcpServer.registerTool('memory_anchor', {
|
|
82
|
+
description: 'Anchor a memory to make it permanent (never compressed)',
|
|
83
|
+
inputSchema: {
|
|
84
|
+
memory_id: z.string().uuid().describe('The memory ID to anchor'),
|
|
85
|
+
token: z.string().optional().describe('Watchdog token for write operations')
|
|
86
|
+
}
|
|
87
|
+
}, async ({ memory_id, token }) => {
|
|
88
|
+
const permission = checkPermission('memory_anchor', token || '');
|
|
89
|
+
if (!permission.allowed) {
|
|
90
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'Permission denied', reason: permission.reason }) }] };
|
|
91
|
+
}
|
|
92
|
+
const result = await memoryAnchorTool({ memory_id });
|
|
93
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
94
|
+
});
|
|
95
|
+
// Tool: memory_report_usage
|
|
96
|
+
mcpServer.registerTool('memory_report_usage', {
|
|
97
|
+
description: 'Report token usage and get compression recommendation',
|
|
98
|
+
inputSchema: {
|
|
99
|
+
used_tokens: z.number().min(0).describe('Current token usage'),
|
|
100
|
+
max_tokens: z.number().min(1).describe('Maximum token limit')
|
|
101
|
+
}
|
|
102
|
+
}, async ({ used_tokens, max_tokens }) => {
|
|
103
|
+
const result = await memoryReportUsageTool({ used_tokens, max_tokens });
|
|
104
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
105
|
+
});
|
|
106
|
+
// Tool: context_compress
|
|
107
|
+
mcpServer.registerTool('context_compress', {
|
|
108
|
+
description: 'Compress low-priority memories to reduce context size',
|
|
109
|
+
inputSchema: {
|
|
110
|
+
target_ratio: z.number().min(0).max(1).optional().describe('Target compression ratio (0-1)'),
|
|
111
|
+
token: z.string().optional().describe('Watchdog token for write operations')
|
|
112
|
+
}
|
|
113
|
+
}, async ({ target_ratio, token }) => {
|
|
114
|
+
const permission = checkPermission('context_compress', token || '');
|
|
115
|
+
if (!permission.allowed) {
|
|
116
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'Permission denied', reason: permission.reason }) }] };
|
|
117
|
+
}
|
|
118
|
+
const result = await contextCompressTool({ target_ratio });
|
|
119
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
120
|
+
});
|
|
121
|
+
// Tool: project_create
|
|
122
|
+
mcpServer.registerTool('project_create', {
|
|
123
|
+
description: 'Create a new project for organizing memories',
|
|
124
|
+
inputSchema: {
|
|
125
|
+
name: z.string().min(1).describe('Project name'),
|
|
126
|
+
root_path: z.string().optional().describe('Root path of the project'),
|
|
127
|
+
token: z.string().optional().describe('Watchdog token for write operations')
|
|
128
|
+
}
|
|
129
|
+
}, async ({ name, root_path, token }) => {
|
|
130
|
+
const permission = checkPermission('project_create', token || '');
|
|
131
|
+
if (!permission.allowed) {
|
|
132
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'Permission denied', reason: permission.reason }) }] };
|
|
133
|
+
}
|
|
134
|
+
const result = await projectCreateTool({ name, root_path });
|
|
135
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
136
|
+
});
|
|
137
|
+
// Tool: memory_store_batch
|
|
138
|
+
mcpServer.registerTool('memory_store_batch', {
|
|
139
|
+
description: 'Store multiple memories in one call (up to 100)',
|
|
140
|
+
inputSchema: {
|
|
141
|
+
memories: z.array(z.object({
|
|
142
|
+
content: z.string().min(1).describe('Memory content'),
|
|
143
|
+
priority: z.enum(['anchored', 'constraint', 'decision', 'preference', 'fact']).describe('Priority'),
|
|
144
|
+
project_tags: z.array(z.string()).optional().describe('Project tags'),
|
|
145
|
+
anchored: z.boolean().optional().describe('Anchored'),
|
|
146
|
+
expires_in_hours: z.number().positive().optional().describe('TTL in hours')
|
|
147
|
+
})).min(1).max(100).describe('Array of memories to store'),
|
|
148
|
+
token: z.string().optional().describe('Watchdog token for write operations')
|
|
149
|
+
}
|
|
150
|
+
}, async ({ memories, token }) => {
|
|
151
|
+
const permission = checkPermission('memory_store_batch', token || '');
|
|
152
|
+
if (!permission.allowed) {
|
|
153
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'Permission denied', reason: permission.reason }) }] };
|
|
154
|
+
}
|
|
155
|
+
const result = await memoryStoreBatchTool({ memories });
|
|
156
|
+
executeAfterChain('memory_store_batch', { count: memories.length }, result).catch(() => { });
|
|
157
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
158
|
+
});
|
|
159
|
+
// Tool: memory_delete_batch
|
|
160
|
+
mcpServer.registerTool('memory_delete_batch', {
|
|
161
|
+
description: 'Delete multiple memories in one call',
|
|
162
|
+
inputSchema: {
|
|
163
|
+
memory_ids: z.array(z.string().uuid()).min(1).max(100).describe('Memory IDs to delete'),
|
|
164
|
+
token: z.string().optional().describe('Watchdog token for write operations')
|
|
165
|
+
}
|
|
166
|
+
}, async ({ memory_ids, token }) => {
|
|
167
|
+
const permission = checkPermission('memory_delete_batch', token || '');
|
|
168
|
+
if (!permission.allowed) {
|
|
169
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'Permission denied', reason: permission.reason }) }] };
|
|
170
|
+
}
|
|
171
|
+
const result = await memoryDeleteBatchTool({ memory_ids });
|
|
172
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
173
|
+
});
|
|
174
|
+
// Tool: memory_search
|
|
175
|
+
mcpServer.registerTool('memory_search', {
|
|
176
|
+
description: 'Search memories with explicit search mode control',
|
|
177
|
+
inputSchema: {
|
|
178
|
+
query: z.string().describe('Search query'),
|
|
179
|
+
project_tags: z.array(z.string()).optional().describe('Filter by project tags'),
|
|
180
|
+
limit: z.number().int().positive().optional().default(10).describe('Max results'),
|
|
181
|
+
search_mode: z.enum(['keyword', 'semantic', 'hybrid', 'auto']).optional().default('auto').describe('Search mode'),
|
|
182
|
+
user_id: z.string().optional().default('default').describe('User ID for storage isolation'),
|
|
183
|
+
agent_id: z.string().optional().default('default').describe('Agent ID for storage isolation'),
|
|
184
|
+
project_id: z.string().optional().default('default').describe('Project ID for storage isolation')
|
|
185
|
+
}
|
|
186
|
+
}, async ({ query, project_tags, limit, search_mode, user_id, agent_id, project_id }) => {
|
|
187
|
+
const result = await memorySearchTool({ query, project_tags, limit, search_mode, user_id, agent_id, project_id });
|
|
188
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
189
|
+
});
|
|
190
|
+
// Tool: configure_llm
|
|
191
|
+
mcpServer.registerTool('configure_llm', {
|
|
192
|
+
description: 'Configure LLM provider for summarization (OpenAI/Ollama/Anthropic)',
|
|
193
|
+
inputSchema: {
|
|
194
|
+
provider: z.enum(['openai', 'ollama', 'anthropic', 'none']).optional().describe('LLM provider'),
|
|
195
|
+
api_key: z.string().optional().describe('API key'),
|
|
196
|
+
base_url: z.string().optional().describe('Base URL for API'),
|
|
197
|
+
model: z.string().optional().describe('Model name'),
|
|
198
|
+
token: z.string().optional().describe('Watchdog token for write operations')
|
|
199
|
+
}
|
|
200
|
+
}, async ({ provider, api_key, base_url, model, token }) => {
|
|
201
|
+
const permission = checkPermission('configure_llm', token || '');
|
|
202
|
+
if (!permission.allowed) {
|
|
203
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'Permission denied', reason: permission.reason }) }] };
|
|
204
|
+
}
|
|
205
|
+
const result = await configureLLMTool({ provider, api_key, base_url, model });
|
|
206
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
207
|
+
});
|
|
208
|
+
// Tool: memory_stats
|
|
209
|
+
mcpServer.registerTool('memory_stats', {
|
|
210
|
+
description: 'Get memory statistics and cleanup expired entries',
|
|
211
|
+
inputSchema: {}
|
|
212
|
+
}, async () => {
|
|
213
|
+
const result = await memoryStatsTool();
|
|
214
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
215
|
+
});
|
|
216
|
+
// ============ Phase 1: AutoSkill-style Constraint Extraction ============
|
|
217
|
+
// Tool: memory_extract
|
|
218
|
+
mcpServer.registerTool('memory_extract', {
|
|
219
|
+
description: 'Extract durable constraints from conversation turns (AutoSkill-style). Analyzes user turns to identify persistent preferences, constraints, and workflows. Only processes user messages, ignores one-shot requests.',
|
|
220
|
+
inputSchema: {
|
|
221
|
+
conversation_turns: z.array(z.object({
|
|
222
|
+
role: z.enum(['user', 'assistant']),
|
|
223
|
+
content: z.string()
|
|
224
|
+
})).min(1).describe('Conversation turns to analyze'),
|
|
225
|
+
project_tags: z.array(z.string()).optional().describe('Project tags for extracted constraints'),
|
|
226
|
+
extract_mode: z.enum(['all', 'constraints_only', 'preferences_only']).optional()
|
|
227
|
+
.default('all').describe('Extraction mode'),
|
|
228
|
+
min_confidence: z.number().min(0).max(1).optional().default(0.5)
|
|
229
|
+
.describe('Minimum confidence threshold'),
|
|
230
|
+
use_llm: z.boolean().optional().default(true)
|
|
231
|
+
.describe('Use LLM extraction when available (fallback to keywords if unavailable)')
|
|
232
|
+
}
|
|
233
|
+
}, async ({ conversation_turns, project_tags, extract_mode, min_confidence, use_llm }) => {
|
|
234
|
+
// 记录对话轮次,供 After-Chain 使用
|
|
235
|
+
for (const turn of conversation_turns) {
|
|
236
|
+
recordConversationTurn(turn.role, turn.content);
|
|
237
|
+
}
|
|
238
|
+
const result = await memoryExtractTool({
|
|
239
|
+
conversation_turns,
|
|
240
|
+
project_tags,
|
|
241
|
+
extract_mode,
|
|
242
|
+
min_confidence,
|
|
243
|
+
use_llm,
|
|
244
|
+
});
|
|
245
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
246
|
+
});
|
|
247
|
+
// ============ Phase 2: MemGate-style Intelligent Recall ============
|
|
248
|
+
// Tool: intelligent_recall
|
|
249
|
+
mcpServer.registerTool('intelligent_recall', {
|
|
250
|
+
description: 'Recall memories with MemGate-style relevance scoring. Combines semantic similarity with learned relevance patterns, supports soft guidance injection and hard admissibility checking.',
|
|
251
|
+
inputSchema: {
|
|
252
|
+
query: z.string().describe('Current query or context'),
|
|
253
|
+
conversation_context: z.string().optional().describe('Extended conversation context'),
|
|
254
|
+
project_tags: z.array(z.string()).optional().describe('Project tags for filtering'),
|
|
255
|
+
limit: z.number().int().positive().optional().default(10).describe('Maximum results'),
|
|
256
|
+
relevance_threshold: z.number().min(0).max(1).optional().default(0.07)
|
|
257
|
+
.describe('MemGate-style relevance threshold (default 0.07)'),
|
|
258
|
+
return_mode: z.enum(['all', 'constraints_only', 'high_relevance_only']).optional()
|
|
259
|
+
.default('all').describe('Return mode'),
|
|
260
|
+
enable_soft_guidance: z.boolean().optional().default(true)
|
|
261
|
+
.describe('Enable soft guidance (memory injection context)'),
|
|
262
|
+
enable_hard_check: z.boolean().optional().default(false)
|
|
263
|
+
.describe('Enable hard admissibility check')
|
|
264
|
+
}
|
|
265
|
+
}, async ({ query, conversation_context, project_tags, limit, relevance_threshold, return_mode, enable_soft_guidance, enable_hard_check }) => {
|
|
266
|
+
const result = await intelligentRecallTool({
|
|
267
|
+
query,
|
|
268
|
+
conversation_context,
|
|
269
|
+
project_tags,
|
|
270
|
+
limit,
|
|
271
|
+
relevance_threshold,
|
|
272
|
+
return_mode,
|
|
273
|
+
enable_soft_guidance,
|
|
274
|
+
enable_hard_check
|
|
275
|
+
});
|
|
276
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
277
|
+
});
|
|
278
|
+
// ============ Phase 3: MPR-style Dual-Mode Execution ============
|
|
279
|
+
// Tool: dual_mode_execute
|
|
280
|
+
mcpServer.registerTool('dual_mode_execute', {
|
|
281
|
+
description: 'Dual-mode execution combining AutoSkill soft guidance with MPR hard admissibility. Validates proposed actions against stored constraints, injects relevant context, and returns decisions with suggestions.',
|
|
282
|
+
inputSchema: {
|
|
283
|
+
action: z.string().describe('Proposed action to validate'),
|
|
284
|
+
context: z.string().describe('Current execution context'),
|
|
285
|
+
project_tags: z.array(z.string()).optional().describe('Project tags for constraint lookup'),
|
|
286
|
+
mode: z.enum(['soft_only', 'hard_only', 'dual']).optional().default('dual')
|
|
287
|
+
.describe('Execution mode: soft (guidance), hard (check), or dual (both)'),
|
|
288
|
+
soft_guidance_style: z.enum(['concise', 'detailed', 'minimal']).optional().default('concise')
|
|
289
|
+
.describe('How much guidance to inject'),
|
|
290
|
+
hard_threshold: z.number().min(0).max(1).optional().default(0.5)
|
|
291
|
+
.describe('Threshold for hard admissibility')
|
|
292
|
+
}
|
|
293
|
+
}, async ({ action, context, project_tags, mode, soft_guidance_style, hard_threshold }) => {
|
|
294
|
+
const result = await dualModeExecuteTool({
|
|
295
|
+
action,
|
|
296
|
+
context,
|
|
297
|
+
project_tags,
|
|
298
|
+
mode,
|
|
299
|
+
soft_guidance_style,
|
|
300
|
+
hard_threshold
|
|
301
|
+
});
|
|
302
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
303
|
+
});
|
|
304
|
+
// ============ Infrastructure: Database Management ============
|
|
305
|
+
// Tool: db_flush
|
|
306
|
+
mcpServer.registerTool('db_flush', {
|
|
307
|
+
description: 'Manually flush the in-memory database to disk',
|
|
308
|
+
inputSchema: {
|
|
309
|
+
token: z.string().optional().describe('Watchdog token for write operations')
|
|
310
|
+
}
|
|
311
|
+
}, async ({ token }) => {
|
|
312
|
+
const permission = checkPermission('configure_llm', token || '');
|
|
313
|
+
if (!permission.allowed) {
|
|
314
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'Permission denied', reason: permission.reason }) }] };
|
|
315
|
+
}
|
|
316
|
+
const { flushDatabase, getDbPath } = await import('../utils/db.js');
|
|
317
|
+
const before = process.hrtime.bigint();
|
|
318
|
+
flushDatabase();
|
|
319
|
+
const after = process.hrtime.bigint();
|
|
320
|
+
return { content: [{ type: 'text', text: JSON.stringify({
|
|
321
|
+
success: true,
|
|
322
|
+
db_path: getDbPath(),
|
|
323
|
+
flushed_at: new Date().toISOString(),
|
|
324
|
+
duration_ms: Number(after - before) / 1_000_000
|
|
325
|
+
}) }] };
|
|
326
|
+
});
|
|
327
|
+
// ============ Watchdog Permission Management ============
|
|
328
|
+
// Tool: watchdog_manage
|
|
329
|
+
mcpServer.registerTool('watchdog_manage', {
|
|
330
|
+
description: 'Manage Watchdog tokens, generate new tokens, and check permissions',
|
|
331
|
+
inputSchema: {
|
|
332
|
+
action: z.enum(['generate_token', 'set_token', 'check_permission', 'list_tools', 'get_config']).describe('Action to perform'),
|
|
333
|
+
token_type: z.enum(['read', 'write', 'watchdog']).optional().describe('Token type for generate/set'),
|
|
334
|
+
token: z.string().optional().describe('Token value for set_token, or token to check for check_permission'),
|
|
335
|
+
tool_name: z.string().optional().describe('Tool name for check_permission')
|
|
336
|
+
}
|
|
337
|
+
}, async ({ action, token_type, token, tool_name }) => {
|
|
338
|
+
const manager = getWatchdogTokenManager();
|
|
339
|
+
switch (action) {
|
|
340
|
+
case 'generate_token': {
|
|
341
|
+
if (!token_type) {
|
|
342
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'token_type required for generate_token' }) }] };
|
|
343
|
+
}
|
|
344
|
+
const newToken = WatchdogTokenManager.generateToken();
|
|
345
|
+
manager.setToken(token_type, newToken);
|
|
346
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, token_type, token: newToken, warning: 'Store this token securely - it will not be shown again' }) }] };
|
|
347
|
+
}
|
|
348
|
+
case 'set_token': {
|
|
349
|
+
if (!token_type || !token) {
|
|
350
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'token_type and token required for set_token' }) }] };
|
|
351
|
+
}
|
|
352
|
+
manager.setToken(token_type, token);
|
|
353
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, token_type }) }] };
|
|
354
|
+
}
|
|
355
|
+
case 'check_permission': {
|
|
356
|
+
if (!tool_name || !token) {
|
|
357
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'tool_name and token required for check_permission' }) }] };
|
|
358
|
+
}
|
|
359
|
+
const result = checkPermission(tool_name, token);
|
|
360
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
361
|
+
}
|
|
362
|
+
case 'list_tools': {
|
|
363
|
+
return { content: [{ type: 'text', text: JSON.stringify({
|
|
364
|
+
read_tools: READ_ONLY_TOOLS,
|
|
365
|
+
write_tools: READ_WRITE_TOOLS,
|
|
366
|
+
total: TOOL_PERMISSIONS.length
|
|
367
|
+
}) }] };
|
|
368
|
+
}
|
|
369
|
+
case 'get_config': {
|
|
370
|
+
return { content: [{ type: 'text', text: JSON.stringify({
|
|
371
|
+
has_tokens: manager.hasTokens(),
|
|
372
|
+
token_configured: {
|
|
373
|
+
read: !!process.env.CG_READ_TOKEN,
|
|
374
|
+
write: !!process.env.CG_WRITE_TOKEN,
|
|
375
|
+
watchdog: !!process.env.CG_WATCHDOG_TOKEN
|
|
376
|
+
}
|
|
377
|
+
}) }] };
|
|
378
|
+
}
|
|
379
|
+
default:
|
|
380
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: `Unknown action: ${action}` }) }] };
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
// ============ Infrastructure: GDPR Compliance Tools ============
|
|
384
|
+
// Tool: gdpr_export
|
|
385
|
+
mcpServer.registerTool('gdpr_export', {
|
|
386
|
+
description: 'Export all user data for GDPR compliance (Article 20 - Right to Data Portability)',
|
|
387
|
+
inputSchema: {
|
|
388
|
+
user_id: z.string().describe('User ID to export data for'),
|
|
389
|
+
include_sessions: z.boolean().optional().default(true).describe('Include session data'),
|
|
390
|
+
include_projects: z.boolean().optional().default(true).describe('Include project data'),
|
|
391
|
+
include_knowledge_graph: z.boolean().optional().default(true).describe('Include knowledge graph data'),
|
|
392
|
+
token: z.string().optional().describe('Watchdog token for write operations')
|
|
393
|
+
}
|
|
394
|
+
}, async ({ user_id, include_sessions, include_projects, include_knowledge_graph, token }) => {
|
|
395
|
+
const permission = checkPermission('gdpr_export', token || '');
|
|
396
|
+
if (!permission.allowed) {
|
|
397
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'Permission denied', reason: permission.reason }) }] };
|
|
398
|
+
}
|
|
399
|
+
const { exportUserData } = await import('../api/gdpr.js');
|
|
400
|
+
const result = exportUserData(user_id, {
|
|
401
|
+
includeSessions: include_sessions,
|
|
402
|
+
includeProjects: include_projects,
|
|
403
|
+
includeKnowledgeGraph: include_knowledge_graph
|
|
404
|
+
});
|
|
405
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
406
|
+
});
|
|
407
|
+
// Tool: gdpr_delete
|
|
408
|
+
mcpServer.registerTool('gdpr_delete', {
|
|
409
|
+
description: 'Delete all user data for GDPR compliance (Article 17 - Right to Erasure)',
|
|
410
|
+
inputSchema: {
|
|
411
|
+
user_id: z.string().describe('User ID to delete data for'),
|
|
412
|
+
delete_sessions: z.boolean().optional().default(true).describe('Delete session data'),
|
|
413
|
+
delete_projects: z.boolean().optional().default(false).describe('Delete project data'),
|
|
414
|
+
delete_knowledge_graph: z.boolean().optional().default(true).describe('Delete knowledge graph data'),
|
|
415
|
+
retain_anchored: z.boolean().optional().default(true).describe('Retain anchored memories'),
|
|
416
|
+
token: z.string().optional().describe('Watchdog token for write operations')
|
|
417
|
+
}
|
|
418
|
+
}, async ({ user_id, delete_sessions, delete_projects, delete_knowledge_graph, retain_anchored, token }) => {
|
|
419
|
+
const permission = checkPermission('gdpr_delete', token || '');
|
|
420
|
+
if (!permission.allowed) {
|
|
421
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'Permission denied', reason: permission.reason }) }] };
|
|
422
|
+
}
|
|
423
|
+
const { deleteUserData } = await import('../api/gdpr.js');
|
|
424
|
+
const result = deleteUserData(user_id, {
|
|
425
|
+
deleteSessions: delete_sessions,
|
|
426
|
+
deleteProjects: delete_projects,
|
|
427
|
+
deleteKnowledgeGraph: delete_knowledge_graph,
|
|
428
|
+
retainAnchored: retain_anchored
|
|
429
|
+
});
|
|
430
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
431
|
+
});
|
|
432
|
+
// Tool: data_summary
|
|
433
|
+
mcpServer.registerTool('data_summary', {
|
|
434
|
+
description: 'Get summary of user data storage',
|
|
435
|
+
inputSchema: {
|
|
436
|
+
user_id: z.string().describe('User ID to get summary for')
|
|
437
|
+
}
|
|
438
|
+
}, async ({ user_id }) => {
|
|
439
|
+
const { getUserDataSummary } = await import('../api/gdpr.js');
|
|
440
|
+
const result = getUserDataSummary(user_id);
|
|
441
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
442
|
+
});
|
|
443
|
+
// ============ Session Management Tools ============
|
|
444
|
+
// Tool: session_store
|
|
445
|
+
mcpServer.registerTool('session_store', {
|
|
446
|
+
description: 'Store a session-level memory (key-value with scope control)',
|
|
447
|
+
inputSchema: {
|
|
448
|
+
key: z.string().min(1).describe('Session memory key'),
|
|
449
|
+
value: z.string().min(1).describe('Session memory value'),
|
|
450
|
+
scope: z.enum(['session', 'short', 'long', 'archival']).optional().default('session')
|
|
451
|
+
.describe('Scope: session (window-close release), short (hours), long (days), archival (permanent)'),
|
|
452
|
+
expires_in_hours: z.number().positive().optional().describe('TTL in hours'),
|
|
453
|
+
meta: z.record(z.string(), z.unknown()).optional().describe('Additional metadata'),
|
|
454
|
+
user_id: z.string().optional().default('default'),
|
|
455
|
+
agent_id: z.string().optional().default('default'),
|
|
456
|
+
project_id: z.string().optional().default('default'),
|
|
457
|
+
token: z.string().optional().describe('Watchdog token for write operations')
|
|
458
|
+
}
|
|
459
|
+
}, async ({ key, value, scope, expires_in_hours, meta, user_id, agent_id, project_id, token }) => {
|
|
460
|
+
const permission = checkPermission('memory_store', token || '');
|
|
461
|
+
if (!permission.allowed) {
|
|
462
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'Permission denied', reason: permission.reason }) }] };
|
|
463
|
+
}
|
|
464
|
+
const { memorySessionStoreTool } = await import('./tools/memory-session.js');
|
|
465
|
+
const result = await memorySessionStoreTool({ key, value, scope: scope || 'session', expires_in_hours, meta, user_id, agent_id, project_id });
|
|
466
|
+
executeAfterChain('session_store', { key, value, scope }, result).catch(() => { });
|
|
467
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
468
|
+
});
|
|
469
|
+
// Tool: session_get
|
|
470
|
+
mcpServer.registerTool('session_get', {
|
|
471
|
+
description: 'Get a session-level memory by key',
|
|
472
|
+
inputSchema: {
|
|
473
|
+
key: z.string().min(1).describe('Session memory key'),
|
|
474
|
+
user_id: z.string().optional().default('default'),
|
|
475
|
+
agent_id: z.string().optional().default('default'),
|
|
476
|
+
project_id: z.string().optional().default('default'),
|
|
477
|
+
scope: z.enum(['session', 'short', 'long', 'archival']).optional().default('session')
|
|
478
|
+
}
|
|
479
|
+
}, async ({ key, user_id, agent_id, project_id, scope }) => {
|
|
480
|
+
const { memorySessionGetTool } = await import('./tools/memory-session.js');
|
|
481
|
+
const result = await memorySessionGetTool({ key, user_id, agent_id, project_id, scope: scope || 'session' });
|
|
482
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
483
|
+
});
|
|
484
|
+
// Tool: session_list
|
|
485
|
+
mcpServer.registerTool('session_list', {
|
|
486
|
+
description: 'List all session-level memories',
|
|
487
|
+
inputSchema: {
|
|
488
|
+
user_id: z.string().optional().default('default'),
|
|
489
|
+
agent_id: z.string().optional().default('default'),
|
|
490
|
+
project_id: z.string().optional().default('default'),
|
|
491
|
+
scope: z.enum(['session', 'short', 'long', 'archival']).optional(),
|
|
492
|
+
limit: z.number().int().positive().optional().default(50)
|
|
493
|
+
}
|
|
494
|
+
}, async ({ user_id, agent_id, project_id, scope, limit }) => {
|
|
495
|
+
const { memorySessionListTool } = await import('./tools/memory-session.js');
|
|
496
|
+
const result = await memorySessionListTool({ user_id, agent_id, project_id, scope, limit });
|
|
497
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
498
|
+
});
|
|
499
|
+
// Tool: session_delete
|
|
500
|
+
mcpServer.registerTool('session_delete', {
|
|
501
|
+
description: 'Delete a session-level memory by key',
|
|
502
|
+
inputSchema: {
|
|
503
|
+
key: z.string().min(1).describe('Session memory key to delete'),
|
|
504
|
+
user_id: z.string().optional().default('default'),
|
|
505
|
+
agent_id: z.string().optional().default('default'),
|
|
506
|
+
project_id: z.string().optional().default('default'),
|
|
507
|
+
scope: z.enum(['session', 'short', 'long', 'archival']).optional().default('session'),
|
|
508
|
+
token: z.string().optional().describe('Watchdog token for write operations')
|
|
509
|
+
}
|
|
510
|
+
}, async ({ key, user_id, agent_id, project_id, scope, token }) => {
|
|
511
|
+
const permission = checkPermission('memory_delete_batch', token || '');
|
|
512
|
+
if (!permission.allowed) {
|
|
513
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'Permission denied', reason: permission.reason }) }] };
|
|
514
|
+
}
|
|
515
|
+
const { memorySessionDeleteTool } = await import('./tools/memory-session.js');
|
|
516
|
+
const result = await memorySessionDeleteTool({ key, user_id, agent_id, project_id, scope: scope || 'session' });
|
|
517
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
518
|
+
});
|
|
519
|
+
// ============ Infrastructure: After-Chain Configuration ============
|
|
520
|
+
// Tool: after_chain_configure
|
|
521
|
+
mcpServer.registerTool('after_chain_configure', {
|
|
522
|
+
description: 'Configure after-chain tool orchestration at runtime. Allows agents to register new chains, toggle chains on/off, set global enabled state, and list chains.',
|
|
523
|
+
inputSchema: {
|
|
524
|
+
action: z.enum(['list_chains', 'toggle_chain', 'set_global', 'register_chain', 'get_global_config']).describe('Action to perform'),
|
|
525
|
+
chain_name: z.string().optional().describe('Chain name for toggle_chain and register_chain actions'),
|
|
526
|
+
enabled: z.boolean().optional().describe('Enable/disable state for toggle_chain and set_global actions'),
|
|
527
|
+
chain_config: z.object({
|
|
528
|
+
name: z.string().describe('Chain name'),
|
|
529
|
+
description: z.string().optional().describe('Chain description'),
|
|
530
|
+
triggerTool: z.string().describe('Trigger tool name'),
|
|
531
|
+
followupTool: z.string().describe('Followup tool name'),
|
|
532
|
+
async: z.boolean().optional().default(true).describe('Async execution'),
|
|
533
|
+
condition: z.string().optional().describe('Condition function as string (advanced)'),
|
|
534
|
+
}).optional().describe('Chain config for register_chain action'),
|
|
535
|
+
token: z.string().optional().describe('Watchdog token for write operations')
|
|
536
|
+
}
|
|
537
|
+
}, async ({ action, chain_name, enabled, chain_config, token }) => {
|
|
538
|
+
const permission = checkPermission('configure_llm', token || '');
|
|
539
|
+
if (!permission.allowed) {
|
|
540
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'Permission denied', reason: permission.reason }) }] };
|
|
541
|
+
}
|
|
542
|
+
const registry = getAfterChainRegistry();
|
|
543
|
+
switch (action) {
|
|
544
|
+
case 'list_chains': {
|
|
545
|
+
const chains = registry.getAllChains();
|
|
546
|
+
return { content: [{ type: 'text', text: JSON.stringify({
|
|
547
|
+
chains: chains.map(c => ({
|
|
548
|
+
name: c.name,
|
|
549
|
+
description: c.description,
|
|
550
|
+
hooks: c.hooks.map(h => ({
|
|
551
|
+
triggerTool: h.triggerTool,
|
|
552
|
+
followupTool: h.followupTool,
|
|
553
|
+
async: h.async,
|
|
554
|
+
enabled: h.enabled,
|
|
555
|
+
})),
|
|
556
|
+
})),
|
|
557
|
+
total: chains.length,
|
|
558
|
+
}) }] };
|
|
559
|
+
}
|
|
560
|
+
case 'toggle_chain': {
|
|
561
|
+
if (!chain_name || enabled === undefined) {
|
|
562
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'chain_name and enabled required for toggle_chain' }) }] };
|
|
563
|
+
}
|
|
564
|
+
const success = registry.toggleChain(chain_name, enabled);
|
|
565
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success, chain_name, enabled }) }] };
|
|
566
|
+
}
|
|
567
|
+
case 'set_global': {
|
|
568
|
+
if (enabled === undefined) {
|
|
569
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'enabled required for set_global' }) }] };
|
|
570
|
+
}
|
|
571
|
+
registry.updateGlobalConfig({ enabled });
|
|
572
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, global_enabled: enabled }) }] };
|
|
573
|
+
}
|
|
574
|
+
case 'register_chain': {
|
|
575
|
+
if (!chain_config) {
|
|
576
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'chain_config required for register_chain' }) }] };
|
|
577
|
+
}
|
|
578
|
+
registry.registerChain({
|
|
579
|
+
name: chain_config.name,
|
|
580
|
+
description: chain_config.description,
|
|
581
|
+
hooks: [{
|
|
582
|
+
triggerTool: chain_config.triggerTool,
|
|
583
|
+
followupTool: chain_config.followupTool,
|
|
584
|
+
async: chain_config.async ?? true,
|
|
585
|
+
enabled: true,
|
|
586
|
+
}],
|
|
587
|
+
});
|
|
588
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, chain_name: chain_config.name }) }] };
|
|
589
|
+
}
|
|
590
|
+
case 'get_global_config': {
|
|
591
|
+
const config = registry.getGlobalConfig();
|
|
592
|
+
return { content: [{ type: 'text', text: JSON.stringify(config) }] };
|
|
593
|
+
}
|
|
594
|
+
default:
|
|
595
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: `Unknown action: ${action}` }) }] };
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
// Export for testing
|
|
599
|
+
export { mcpServer };
|
|
600
|
+
/**
|
|
601
|
+
* Main entry point - start the MCP server
|
|
602
|
+
*/
|
|
603
|
+
export async function runServer() {
|
|
604
|
+
await initialize();
|
|
605
|
+
const transport = new StdioServerTransport();
|
|
606
|
+
await mcpServer.connect(transport);
|
|
607
|
+
logger.info('Context Gatekeeper MCP server running on stdio');
|
|
608
|
+
}
|
|
609
|
+
runServer().catch(error => {
|
|
610
|
+
logger.error('Server error', { error });
|
|
611
|
+
process.exit(1);
|
|
612
|
+
});
|
|
613
|
+
//# sourceMappingURL=server.js.map
|