mcp-context-engineering
Version:
The intelligent context optimization system for AI coding assistants. Built with Cole's PRP methodology, Context Portal knowledge graphs, and production-ready MongoDB architecture.
804 lines (689 loc) β’ 23.8 kB
text/typescript
import { z } from 'zod';
import { ObjectId } from 'mongodb';
import {
Decision,
ProgressEntry,
SystemPattern,
ContextLink,
COLLECTIONS
} from '../../mongodb/models/contextPattern.js';
import { getConnectionManager } from '../../mongodb/operations/connection.js';
import { securityManager } from '../../security/securityManager.js';
import { performanceOptimizer } from '../../performance/performanceOptimizer.js';
/**
* Knowledge Graph Manager - Context Portal Integration
*
* Implements Context Portal's sophisticated knowledge graph patterns:
* - Explicit relationship modeling with directional links
* - Hierarchical progress tracking with parent-child relationships
* - Structured decision capture with rationale and consequences
* - System pattern management with usage examples and trade-offs
* - Cross-workspace knowledge sharing with access control
* - Real-time graph traversal and relationship discovery
*/
// Graph query schema
export const GraphQuerySchema = z.object({
workspace_id: z.string(),
query_type: z.enum(['traverse', 'find_related', 'pattern_search', 'decision_path', 'impact_analysis']),
// Source entity
source: z.object({
item_type: z.string(),
item_id: z.string()
}).optional(),
// Query parameters
parameters: z.object({
relationship_types: z.array(z.string()).optional(),
max_depth: z.number().min(1).max(10).default(3),
include_metadata: z.boolean().default(true),
filter_by_status: z.array(z.string()).optional(),
min_relevance_score: z.number().min(0).max(1).optional()
}).optional(),
// Traversal direction
direction: z.enum(['forward', 'backward', 'bidirectional']).default('bidirectional'),
// Result limits
limit: z.number().min(1).max(1000).default(100)
});
export type GraphQuery = z.infer<typeof GraphQuerySchema>;
// Graph result schema
export const GraphResultSchema = z.object({
nodes: z.array(z.object({
id: z.string(),
type: z.string(),
data: z.any(),
metadata: z.object({
created_at: z.date(),
updated_at: z.date(),
access_count: z.number().default(0),
relevance_score: z.number().min(0).max(1).optional()
})
})),
edges: z.array(z.object({
source_id: z.string(),
target_id: z.string(),
relationship_type: z.string(),
description: z.string().optional(),
weight: z.number().min(0).max(1).default(1),
metadata: z.object({
created_at: z.date(),
last_traversed: z.date().optional(),
traversal_count: z.number().default(0)
})
})),
query_metadata: z.object({
total_nodes: z.number(),
total_edges: z.number(),
traversal_depth: z.number(),
processing_time_ms: z.number(),
cache_used: z.boolean()
})
});
export type GraphResult = z.infer<typeof GraphResultSchema>;
// Workspace context schema
export const WorkspaceContextSchema = z.object({
workspace_id: z.string(),
project_id: z.string(),
// Product context (static, high-level information)
product_context: z.object({
project_overview: z.string(),
architecture_decisions: z.array(z.string()),
tech_stack: z.array(z.string()),
business_requirements: z.array(z.string()),
constraints: z.array(z.string())
}),
// Active context (dynamic, session-specific)
active_context: z.object({
current_features: z.array(z.string()),
active_issues: z.array(z.string()),
recent_changes: z.array(z.object({
change_id: z.string(),
description: z.string(),
timestamp: z.date(),
impact_level: z.enum(['low', 'medium', 'high'])
})),
session_goals: z.array(z.string())
}),
// Access control
access_control: z.object({
workspace_type: z.enum(['private', 'team', 'organization', 'public']),
access_level: z.enum(['read', 'write', 'admin']),
allowed_users: z.array(z.string()).optional(),
sharing_settings: z.object({
allow_cross_workspace: z.boolean().default(false),
public_patterns: z.boolean().default(false)
})
}),
metadata: z.object({
created_at: z.date(),
updated_at: z.date(),
last_accessed: z.date(),
version: z.number().default(1)
})
});
export type WorkspaceContext = z.infer<typeof WorkspaceContextSchema>;
/**
* Knowledge Graph Manager - Context Portal Integration
*/
export class KnowledgeGraphManager {
private mongoManager: any;
constructor() {
this.mongoManager = getConnectionManager();
}
/**
* Initialize workspace with Context Portal patterns
*/
async initializeWorkspace(
workspaceId: string,
projectId: string,
initialContext: Partial<WorkspaceContext>
): Promise<WorkspaceContext> {
const startTime = Date.now();
// Security check
const securityResult = await securityManager.processInput(
JSON.stringify(initialContext),
{ source: 'api', agent_type: 'system' }
);
if (securityResult.blocked) {
throw new Error(`Workspace initialization blocked: ${securityResult.security_flags.join(', ')}`);
}
const workspace: WorkspaceContext = {
workspace_id: workspaceId,
project_id: projectId,
product_context: {
project_overview: '',
architecture_decisions: [],
tech_stack: [],
business_requirements: [],
constraints: [],
...initialContext.product_context
},
active_context: {
current_features: [],
active_issues: [],
recent_changes: [],
session_goals: [],
...initialContext.active_context
},
access_control: {
workspace_type: 'private',
access_level: 'admin',
sharing_settings: {
allow_cross_workspace: false,
public_patterns: false
},
...initialContext.access_control
},
metadata: {
created_at: new Date(),
updated_at: new Date(),
last_accessed: new Date(),
version: 1
}
};
// Store in MongoDB
const db = this.mongoManager.getDatabase();
await db.collection(COLLECTIONS.WORKSPACES).insertOne(workspace);
console.log(`ποΈ Workspace ${workspaceId} initialized in ${Date.now() - startTime}ms`);
return workspace;
}
/**
* Create decision with Context Portal patterns
*/
async createDecision(
workspaceId: string,
decision: Omit<Decision, 'id' | 'workspace_id' | 'date'>
): Promise<Decision> {
const newDecision: Decision = {
id: new ObjectId().toString(),
workspace_id: workspaceId,
date: new Date(),
...decision
};
// Security processing
const securityResult = await securityManager.processInput(
`${decision.title} ${decision.description} ${decision.rationale}`,
{ source: 'user', agent_type: 'generic' }
);
if (securityResult.blocked) {
throw new Error(`Decision creation blocked: ${securityResult.security_flags.join(', ')}`);
}
// Store decision
const db = this.mongoManager.getDatabase();
await db.collection(COLLECTIONS.DECISIONS).insertOne(newDecision);
// Auto-link to related progress entries (Context Portal pattern)
await this.autoLinkDecisionToProgress(newDecision);
console.log(`π Decision created: ${newDecision.title}`);
return newDecision;
}
/**
* Create progress entry with hierarchical relationships
*/
async createProgressEntry(
workspaceId: string,
progress: Omit<ProgressEntry, 'id' | 'workspace_id' | 'date'>
): Promise<ProgressEntry> {
const newProgress: ProgressEntry = {
id: new ObjectId().toString(),
workspace_id: workspaceId,
date: new Date(),
...progress
};
// Store progress entry
const db = this.mongoManager.getDatabase();
await db.collection(COLLECTIONS.PROGRESS_ENTRIES).insertOne(newProgress);
// Create hierarchical links if parent exists
if (newProgress.parent_id) {
await this.createContextLink(workspaceId, {
source_item_type: 'progress_entry',
source_item_id: newProgress.parent_id,
target_item_type: 'progress_entry',
target_item_id: newProgress.id,
relationship_type: 'enables',
description: 'Parent-child progress relationship'
});
}
console.log(`β
Progress entry created: ${newProgress.task}`);
return newProgress;
}
/**
* Create system pattern with usage examples and trade-offs
*/
async createSystemPattern(
workspaceId: string,
pattern: Omit<SystemPattern, 'id' | 'workspace_id'>
): Promise<SystemPattern> {
const newPattern: SystemPattern = {
id: new ObjectId().toString(),
workspace_id: workspaceId,
...pattern
};
// Store system pattern
const db = this.mongoManager.getDatabase();
await db.collection(COLLECTIONS.SYSTEM_PATTERNS).insertOne(newPattern);
console.log(`π§ System pattern created: ${newPattern.pattern_name}`);
return newPattern;
}
/**
* Create explicit context link (Context Portal core pattern)
*/
async createContextLink(
workspaceId: string,
link: Omit<ContextLink, 'workspace_id' | 'timestamp'>
): Promise<ContextLink> {
const newLink: ContextLink = {
workspace_id: workspaceId,
timestamp: new Date(),
...link
};
// Validate entities exist
await this.validateLinkEntities(newLink);
// Store context link
const db = this.mongoManager.getDatabase();
await db.collection(COLLECTIONS.CONTEXT_LINKS).insertOne(newLink);
console.log(`π Context link created: ${link.source_item_type}:${link.source_item_id} β ${link.target_item_type}:${link.target_item_id} (${link.relationship_type})`);
return newLink;
}
/**
* Query knowledge graph with Context Portal patterns
*/
async queryGraph(query: GraphQuery): Promise<GraphResult> {
const startTime = Date.now();
// Use performance optimizer for complex queries
const result = await performanceOptimizer.processTask(
{
type: 'search',
input_data: query,
context: { workspace_id: query.workspace_id }
},
async (task) => {
return await this.executeGraphQuery(task.input_data as GraphQuery);
}
);
const processingTime = Date.now() - startTime;
console.log(`πΈοΈ Graph query completed in ${processingTime}ms`);
return result.result;
}
/**
* Execute graph query with optimized traversal
*/
private async executeGraphQuery(query: GraphQuery): Promise<GraphResult> {
const db = this.mongoManager.getDatabase();
const nodes: GraphResult['nodes'] = [];
const edges: GraphResult['edges'] = [];
const visitedNodes = new Set<string>();
const maxDepth = query.parameters?.max_depth || 3;
let currentDepth = 0;
let nodesToProcess = query.source ? [`${query.source.item_type}:${query.source.item_id}`] : [];
// If no source, start with pattern search
if (!query.source && query.query_type === 'pattern_search') {
const patterns = await this.findPatterns(query);
nodesToProcess = patterns.map(p => `system_pattern:${p.id}`);
}
// Breadth-first traversal
while (nodesToProcess.length > 0 && currentDepth < maxDepth) {
const nextNodes: string[] = [];
for (const nodeId of nodesToProcess) {
if (visitedNodes.has(nodeId)) continue;
visitedNodes.add(nodeId);
// Load node data
const nodeData = await this.loadNodeData(nodeId, query.workspace_id);
if (nodeData) {
nodes.push(nodeData);
// Find connected nodes
const connections = await this.findConnections(
nodeId,
query.workspace_id,
query.direction,
query.parameters?.relationship_types
);
for (const connection of connections) {
edges.push(connection);
// Add target nodes for next iteration
const targetId = `${connection.target_id}`;
if (!visitedNodes.has(targetId)) {
nextNodes.push(targetId);
}
}
}
}
nodesToProcess = nextNodes;
currentDepth++;
}
return {
nodes,
edges,
query_metadata: {
total_nodes: nodes.length,
total_edges: edges.length,
traversal_depth: currentDepth,
processing_time_ms: 0, // Will be set by caller
cache_used: false // Simplified
}
};
}
/**
* Load node data by ID and type
*/
private async loadNodeData(
nodeId: string,
workspaceId: string
): Promise<GraphResult['nodes'][0] | null> {
const [itemType, itemId] = nodeId.split(':');
const db = this.mongoManager.getDatabase();
let collection: string;
switch (itemType) {
case 'decision':
collection = COLLECTIONS.DECISIONS;
break;
case 'progress_entry':
collection = COLLECTIONS.PROGRESS_ENTRIES;
break;
case 'system_pattern':
collection = COLLECTIONS.SYSTEM_PATTERNS;
break;
default:
return null;
}
const data = await db.collection(collection).findOne({
id: itemId,
workspace_id: workspaceId
});
if (!data) return null;
return {
id: nodeId,
type: itemType,
data: data,
metadata: {
created_at: data.date || data.created_at || new Date(),
updated_at: data.updated_at || new Date(),
access_count: 0
}
};
}
/**
* Find connections for a node
*/
private async findConnections(
nodeId: string,
workspaceId: string,
direction: GraphQuery['direction'],
relationshipTypes?: string[]
): Promise<GraphResult['edges']> {
const [itemType, itemId] = nodeId.split(':');
const db = this.mongoManager.getDatabase();
const query: any = { workspace_id: workspaceId };
// Build query based on direction
if (direction === 'forward' || direction === 'bidirectional') {
query.$or = [
{ source_item_type: itemType, source_item_id: itemId }
];
}
if (direction === 'backward' || direction === 'bidirectional') {
if (query.$or) {
query.$or.push({ target_item_type: itemType, target_item_id: itemId });
} else {
query.$or = [{ target_item_type: itemType, target_item_id: itemId }];
}
}
// Filter by relationship types
if (relationshipTypes && relationshipTypes.length > 0) {
query.relationship_type = { $in: relationshipTypes };
}
const links = await db.collection(COLLECTIONS.CONTEXT_LINKS).find(query).toArray();
return links.map(link => ({
source_id: `${link.source_item_type}:${link.source_item_id}`,
target_id: `${link.target_item_type}:${link.target_item_id}`,
relationship_type: link.relationship_type,
description: link.description,
weight: 1.0, // Simplified
metadata: {
created_at: link.timestamp,
traversal_count: 0
}
}));
}
/**
* Find patterns matching query
*/
private async findPatterns(query: GraphQuery): Promise<SystemPattern[]> {
const db = this.mongoManager.getDatabase();
const patterns = await db.collection(COLLECTIONS.SYSTEM_PATTERNS)
.find({ workspace_id: query.workspace_id })
.limit(query.limit)
.toArray();
return patterns;
}
/**
* Auto-link decisions to related progress entries (Context Portal pattern)
*/
private async autoLinkDecisionToProgress(decision: Decision): Promise<void> {
const db = this.mongoManager.getDatabase();
// Find progress entries with similar keywords
const keywords = this.extractKeywords(`${decision.title} ${decision.description}`);
const relatedProgress = await db.collection(COLLECTIONS.PROGRESS_ENTRIES)
.find({
workspace_id: decision.workspace_id,
$or: keywords.map(keyword => ({
$or: [
{ task: { $regex: keyword, $options: 'i' } },
{ progress_notes: { $regex: keyword, $options: 'i' } }
]
}))
})
.limit(5)
.toArray();
// Create context links
for (const progress of relatedProgress) {
await this.createContextLink(decision.workspace_id, {
source_item_type: 'decision',
source_item_id: decision.id,
target_item_type: 'progress_entry',
target_item_id: progress.id,
relationship_type: 'relates_to_progress',
description: 'Auto-linked based on content similarity'
});
}
}
/**
* Validate that link entities exist
*/
private async validateLinkEntities(link: ContextLink): Promise<void> {
const db = this.mongoManager.getDatabase();
// Validate source entity
const sourceExists = await this.entityExists(
link.workspace_id,
link.source_item_type,
link.source_item_id
);
if (!sourceExists) {
throw new Error(`Source entity not found: ${link.source_item_type}:${link.source_item_id}`);
}
// Validate target entity
const targetExists = await this.entityExists(
link.workspace_id,
link.target_item_type,
link.target_item_id
);
if (!targetExists) {
throw new Error(`Target entity not found: ${link.target_item_type}:${link.target_item_id}`);
}
}
/**
* Check if entity exists
*/
private async entityExists(
workspaceId: string,
itemType: string,
itemId: string
): Promise<boolean> {
const db = this.mongoManager.getDatabase();
let collection: string;
switch (itemType) {
case 'decision':
collection = COLLECTIONS.DECISIONS;
break;
case 'progress_entry':
collection = COLLECTIONS.PROGRESS_ENTRIES;
break;
case 'system_pattern':
collection = COLLECTIONS.SYSTEM_PATTERNS;
break;
case 'context_pattern':
collection = COLLECTIONS.CONTEXT_PATTERNS;
break;
default:
return false;
}
const count = await db.collection(collection).countDocuments({
id: itemId,
workspace_id: workspaceId
});
return count > 0;
}
/**
* Extract keywords for auto-linking
*/
private extractKeywords(text: string): string[] {
const words = text.toLowerCase()
.replace(/[^\w\s]/g, ' ')
.split(/\s+/)
.filter(word => word.length > 3);
// Remove common stop words
const stopWords = new Set([
'this', 'that', 'with', 'have', 'will', 'from', 'they', 'been',
'have', 'were', 'said', 'each', 'which', 'their', 'time'
]);
const keywords = words.filter(word => !stopWords.has(word));
// Return top 10 most relevant keywords
return Array.from(new Set(keywords)).slice(0, 10);
}
/**
* Get workspace analytics and health metrics
*/
async getWorkspaceAnalytics(workspaceId: string): Promise<{
entity_counts: Record<string, number>;
relationship_stats: Record<string, number>;
activity_metrics: {
daily_changes: number;
decision_velocity: number;
pattern_reuse: number;
};
health_score: number;
}> {
const db = this.mongoManager.getDatabase();
// Count entities
const [decisions, progress, patterns, links] = await Promise.all([
db.collection(COLLECTIONS.DECISIONS).countDocuments({ workspace_id: workspaceId }),
db.collection(COLLECTIONS.PROGRESS_ENTRIES).countDocuments({ workspace_id: workspaceId }),
db.collection(COLLECTIONS.SYSTEM_PATTERNS).countDocuments({ workspace_id: workspaceId }),
db.collection(COLLECTIONS.CONTEXT_LINKS).countDocuments({ workspace_id: workspaceId })
]);
// Get relationship statistics
const relationshipStats = await db.collection(COLLECTIONS.CONTEXT_LINKS)
.aggregate([
{ $match: { workspace_id: workspaceId } },
{ $group: { _id: '$relationship_type', count: { $sum: 1 } } }
]).toArray();
const relationshipCounts = relationshipStats.reduce((acc, stat) => {
acc[stat._id] = stat.count;
return acc;
}, {} as Record<string, number>);
// Calculate health score (simplified)
const totalEntities = decisions + progress + patterns;
const connectivityRatio = totalEntities > 0 ? links / totalEntities : 0;
const healthScore = Math.min(connectivityRatio * 0.7 + (totalEntities > 10 ? 0.3 : 0.1), 1.0);
return {
entity_counts: {
decisions,
progress_entries: progress,
system_patterns: patterns,
context_links: links
},
relationship_stats: relationshipCounts,
activity_metrics: {
daily_changes: 0, // Would be calculated from history
decision_velocity: 0, // Decisions per week
pattern_reuse: 0 // Pattern usage frequency
},
health_score: healthScore
};
}
/**
* Export workspace knowledge graph
*/
async exportWorkspaceGraph(
workspaceId: string,
format: 'json' | 'cypher' | 'graphml' = 'json'
): Promise<any> {
const query: GraphQuery = {
workspace_id: workspaceId,
query_type: 'traverse',
parameters: {
max_depth: 10
},
limit: 10000
};
const graphResult = await this.queryGraph(query);
switch (format) {
case 'json':
return {
nodes: graphResult.nodes,
edges: graphResult.edges,
metadata: graphResult.query_metadata,
exported_at: new Date()
};
case 'cypher':
return this.convertToCypher(graphResult);
case 'graphml':
return this.convertToGraphML(graphResult);
default:
throw new Error(`Unsupported export format: ${format}`);
}
}
/**
* Convert graph result to Cypher format
*/
private convertToCypher(graph: GraphResult): string {
let cypher = '// Workspace Knowledge Graph Export\n';
// Create nodes
for (const node of graph.nodes) {
cypher += `CREATE (${node.id.replace(':', '_')}:${node.type} {`;
cypher += `id: '${node.data.id}', `;
cypher += `title: '${node.data.title || node.data.task || node.data.pattern_name}', `;
cypher += `created_at: '${node.metadata.created_at}'`;
cypher += '})\n';
}
// Create relationships
for (const edge of graph.edges) {
const sourceId = edge.source_id.replace(':', '_');
const targetId = edge.target_id.replace(':', '_');
cypher += `CREATE (${sourceId})-[:${edge.relationship_type.toUpperCase()}]->(${targetId})\n`;
}
return cypher;
}
/**
* Convert graph result to GraphML format
*/
private convertToGraphML(graph: GraphResult): string {
let graphml = '<?xml version="1.0" encoding="UTF-8"?>\n';
graphml += '<graphml xmlns="http://graphml.graphdrawing.org/xmlns">\n';
graphml += ' <graph id="workspace_graph" edgedefault="directed">\n';
// Add nodes
for (const node of graph.nodes) {
graphml += ` <node id="${node.id}">\n`;
graphml += ` <data key="type">${node.type}</data>\n`;
graphml += ` <data key="title">${node.data.title || node.data.task || node.data.pattern_name}</data>\n`;
graphml += ' </node>\n';
}
// Add edges
for (const edge of graph.edges) {
graphml += ` <edge source="${edge.source_id}" target="${edge.target_id}">\n`;
graphml += ` <data key="relationship">${edge.relationship_type}</data>\n`;
graphml += ' </edge>\n';
}
graphml += ' </graph>\n';
graphml += '</graphml>';
return graphml;
}
}
// Export singleton instance
export const knowledgeGraphManager = new KnowledgeGraphManager();