Skip to main content
Glama
clpi

CLP MCP - DevOps Infrastructure Server

Official
by clpi
server.ts13.1 kB
import { type Server } from "@modelcontextprotocol/sdk/server/index.js" import { type Transport } from "@modelcontextprotocol/sdk/shared/transport.js" import { } from "@smithery/sdk" import { createStatefulServer, type CreateServerFn} from "@smithery/sdk/server/stateful.js" import clpMcpConfig from "./config" import console from "node:console" import { z } from "zod" import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js" import { KnowledgeGraph, Entity, Relationship } from "./knowledge-graph.js" export interface MemoryEntry { key: string; value: any; metadata?: { created: Date; updated: Date; tags?: string[]; category?: string; entityId?: string; // Link to knowledge graph entity }; } export class ClpMcpServer { private _memory: Map<string, MemoryEntry> = new Map(); private _contexts: Map<string, any> = new Map(); private _reasoning: Array<{ timestamp: Date; context: string; decision: string }> = []; private _knowledgeGraph: KnowledgeGraph = new KnowledgeGraph(); public store(key: string, value: any, tags?: string[], category?: string): { content: Array<{ type: string; text: string }>; isError?: boolean; } { const now = new Date(); const entry: MemoryEntry = { key, value, metadata: { created: this._memory.has(key) ? this._memory.get(key)!.metadata!.created : now, updated: now, tags, category, }, }; this._memory.set(key, entry); return { content: [ { type: "text" as const, text: `Stored: ${key} = ${JSON.stringify(value)}`, } ] }; } public recall(key?: string): { content: Array<{ type: string; text: string }>; isError?: boolean; } { if (key) { const entry = this._memory.get(key); if (!entry) { return { content: [ { type: "text" as const, text: `Key not found: ${key}`, } ], isError: true, }; } return { content: [ { type: "text" as const, text: JSON.stringify(entry, null, 2), } ] }; } // Return all memory const allMemory = Array.from(this._memory.entries()).map(([k, v]) => ({ key: k, value: v.value, metadata: v.metadata, })); return { content: [ { type: "text" as const, text: JSON.stringify(allMemory, null, 2), } ] }; } public delete(key: string): { content: Array<{ type: string; text: string }>; isError?: boolean; } { const deleted = this._memory.delete(key); return { content: [ { type: "text" as const, text: deleted ? `Deleted: ${key}` : `Key not found: ${key}`, } ], isError: !deleted, }; } public search(query: string, category?: string): { content: Array<{ type: string; text: string }>; isError?: boolean; } { const results = Array.from(this._memory.entries()) .filter(([key, entry]) => { const matchesQuery = key.includes(query) || JSON.stringify(entry.value).includes(query) || (entry.metadata?.tags?.some(tag => tag.includes(query)) ?? false); const matchesCategory = !category || entry.metadata?.category === category; return matchesQuery && matchesCategory; }) .map(([k, v]) => ({ key: k, value: v.value, metadata: v.metadata })); return { content: [ { type: "text" as const, text: JSON.stringify(results, null, 2), } ] }; } public addReasoning(context: string, decision: string): void { this._reasoning.push({ timestamp: new Date(), context, decision, }); } public getReasoningHistory(limit: number = 10): { content: Array<{ type: string; text: string }>; } { const recent = this._reasoning.slice(-limit); return { content: [ { type: "text" as const, text: JSON.stringify(recent, null, 2), } ] }; } public storeContext(contextId: string, context: any): void { this._contexts.set(contextId, { ...context, timestamp: new Date(), }); } public getContext(contextId: string): any { return this._contexts.get(contextId); } // Knowledge Graph Methods public addEntity( type: string, properties: Record<string, any>, tags?: string[] ): { content: Array<{ type: string; text: string }>; isError?: boolean; } { const entity = this._knowledgeGraph.addEntity(type, properties, undefined, tags); return { content: [ { type: "text" as const, text: `Entity created: ${entity.id}\nType: ${entity.type}\nProperties: ${JSON.stringify(entity.properties, null, 2)}`, } ] }; } public getEntity(entityId: string): { content: Array<{ type: string; text: string }>; isError?: boolean; } { const entity = this._knowledgeGraph.getEntity(entityId); if (!entity) { return { content: [ { type: "text" as const, text: `Entity not found: ${entityId}`, } ], isError: true, }; } return { content: [ { type: "text" as const, text: JSON.stringify(entity, null, 2), } ] }; } public addRelationship( sourceId: string, targetId: string, relationshipType: string, properties?: Record<string, any>, weight?: number ): { content: Array<{ type: string; text: string }>; isError?: boolean; } { const relationship = this._knowledgeGraph.addRelationship( sourceId, targetId, relationshipType, properties, weight ); if (!relationship) { return { content: [ { type: "text" as const, text: `Failed to create relationship: source or target entity not found`, } ], isError: true, }; } return { content: [ { type: "text" as const, text: `Relationship created: ${relationship.id}\nType: ${relationship.type}\nFrom: ${relationship.sourceId}\nTo: ${relationship.targetId}`, } ] }; } public queryEntities( query?: string, type?: string, tags?: string[] ): { content: Array<{ type: string; text: string }>; } { let entities: Entity[]; if (query) { entities = this._knowledgeGraph.searchEntities(query, type, tags); } else if (type) { entities = this._knowledgeGraph.getEntitiesByType(type); } else { // Return all entities (limited for performance) const stats = this._knowledgeGraph.getStats(); return { content: [ { type: "text" as const, text: `Total entities: ${stats.entityCount}\nType distribution: ${JSON.stringify(stats.typeDistribution, null, 2)}\n\nProvide a query or type to search for specific entities.`, } ] }; } return { content: [ { type: "text" as const, text: `Found ${entities.length} entities:\n\n${JSON.stringify(entities, null, 2)}`, } ] }; } public queryRelationships(entityId: string, relationshipType?: string): { content: Array<{ type: string; text: string }>; isError?: boolean; } { const entity = this._knowledgeGraph.getEntity(entityId); if (!entity) { return { content: [ { type: "text" as const, text: `Entity not found: ${entityId}`, } ], isError: true, }; } const related = this._knowledgeGraph.getRelatedEntities(entityId, relationshipType); const relationships = this._knowledgeGraph.getEntityRelationships(entityId); return { content: [ { type: "text" as const, text: `Entity: ${entity.type} (${entity.id})\n\nRelationships: ${relationships.length}\n\nRelated Entities:\n${JSON.stringify(related.map(r => ({ entity: { id: r.entity.id, type: r.entity.type, properties: r.entity.properties }, relationship: { type: r.relationship.type, properties: r.relationship.properties } })), null, 2)}`, } ] }; } public traverseGraph( sourceId: string, targetId: string, maxDepth?: number ): { content: Array<{ type: string; text: string }>; isError?: boolean; } { const result = this._knowledgeGraph.findPaths(sourceId, targetId, maxDepth || 5); if (result.entities.length === 0) { return { content: [ { type: "text" as const, text: `No path found between ${sourceId} and ${targetId}`, } ], isError: false, }; } return { content: [ { type: "text" as const, text: `Found ${result.paths?.length || 0} paths between entities:\n\nEntities involved: ${result.entities.length}\nRelationships: ${result.relationships.length}\n\nPaths:\n${JSON.stringify(result.paths?.map((path, i) => ({ path: i + 1, length: path.entities.length, entities: path.entities.map(e => `${e.type}:${e.id}`), relationships: path.relationships.map(r => r.type) })), null, 2)}`, } ] }; } public getGraphStats(): { content: Array<{ type: string; text: string }>; } { const stats = this._knowledgeGraph.getStats(); return { content: [ { type: "text" as const, text: `Knowledge Graph Statistics:\n\nTotal Entities: ${stats.entityCount}\nTotal Relationships: ${stats.relationshipCount}\n\nEntity Types:\n${JSON.stringify(stats.typeDistribution, null, 2)}`, } ] }; } public exportGraph(): { content: Array<{ type: string; text: string }>; } { const graph = this._knowledgeGraph.exportGraph(); return { content: [ { type: "text" as const, text: JSON.stringify(graph, null, 2), } ] }; } public linkMemoryToEntity(key: string, entityId: string): { content: Array<{ type: string; text: string }>; isError?: boolean; } { const memoryEntry = this._memory.get(key); const entity = this._knowledgeGraph.getEntity(entityId); if (!memoryEntry) { return { content: [ { type: "text" as const, text: `Memory key not found: ${key}`, } ], isError: true, }; } if (!entity) { return { content: [ { type: "text" as const, text: `Entity not found: ${entityId}`, } ], isError: true, }; } // Update memory entry to link to entity if (memoryEntry.metadata) { memoryEntry.metadata.entityId = entityId; } else { memoryEntry.metadata = { created: new Date(), updated: new Date(), entityId, }; } return { content: [ { type: "text" as const, text: `Linked memory key "${key}" to entity ${entityId} (${entity.type})`, } ] }; } public getMemoryByEntity(entityId: string): { content: Array<{ type: string; text: string }>; isError?: boolean; } { const entity = this._knowledgeGraph.getEntity(entityId); if (!entity) { return { content: [ { type: "text" as const, text: `Entity not found: ${entityId}`, } ], isError: true, }; } const linkedMemory = Array.from(this._memory.entries()) .filter(([_, entry]) => entry.metadata?.entityId === entityId) .map(([key, entry]) => ({ key, value: entry.value, metadata: entry.metadata })); return { content: [ { type: "text" as const, text: `Memory entries linked to entity ${entityId} (${entity.type}):\n\n${JSON.stringify(linkedMemory, null, 2)}`, } ] }; } } export default function createStatelessServer({ config, }: { config: z.infer<typeof clpMcpConfig> }) { const server = new McpServer({ name: "clp-mcp", title: "CLP MCP", websiteUrl: "https://clp.im", version: "0.0.1", }) const mem = new ClpMcpServer() server.tool("init", "Initialize a workspace", () => { return { isError: false, structuredContent: { }, content: [ { data: "Workspace initialized", name: "init", type: "text", text: "Workspace initialized", _meta: {} } ] } }) return server.server }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/clpi/clp-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server