Merge pull request #8 from modelcontextprotocol/claude_memory
Claude memory
This commit is contained in:
commit
5775836620
6 changed files with 576 additions and 1 deletions
20
package-lock.json
generated
20
package-lock.json
generated
|
|
@ -14,6 +14,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/server-everything": "*",
|
"@modelcontextprotocol/server-everything": "*",
|
||||||
"@modelcontextprotocol/server-gdrive": "*",
|
"@modelcontextprotocol/server-gdrive": "*",
|
||||||
|
"@modelcontextprotocol/server-memory": "*",
|
||||||
"@modelcontextprotocol/server-postgres": "*",
|
"@modelcontextprotocol/server-postgres": "*",
|
||||||
"@modelcontextprotocol/server-puppeteer": "*",
|
"@modelcontextprotocol/server-puppeteer": "*",
|
||||||
"@modelcontextprotocol/server-slack": "*"
|
"@modelcontextprotocol/server-slack": "*"
|
||||||
|
|
@ -76,6 +77,10 @@
|
||||||
"resolved": "src/google-maps",
|
"resolved": "src/google-maps",
|
||||||
"link": true
|
"link": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@modelcontextprotocol/server-memory": {
|
||||||
|
"resolved": "src/memory",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/@modelcontextprotocol/server-postgres": {
|
"node_modules/@modelcontextprotocol/server-postgres": {
|
||||||
"resolved": "src/postgres",
|
"resolved": "src/postgres",
|
||||||
"link": true
|
"link": true
|
||||||
|
|
@ -2953,6 +2958,21 @@
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"src/memory": {
|
||||||
|
"name": "@modelcontextprotocol/server-memory",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@modelcontextprotocol/sdk": "0.5.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"mcp-server-memory": "dist/index.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"shx": "^0.3.4",
|
||||||
|
"typescript": "^5.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"src/postgres": {
|
"src/postgres": {
|
||||||
"name": "@modelcontextprotocol/server-postgres",
|
"name": "@modelcontextprotocol/server-postgres",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
"@modelcontextprotocol/server-gdrive": "*",
|
"@modelcontextprotocol/server-gdrive": "*",
|
||||||
"@modelcontextprotocol/server-postgres": "*",
|
"@modelcontextprotocol/server-postgres": "*",
|
||||||
"@modelcontextprotocol/server-puppeteer": "*",
|
"@modelcontextprotocol/server-puppeteer": "*",
|
||||||
"@modelcontextprotocol/server-slack": "*"
|
"@modelcontextprotocol/server-slack": "*",
|
||||||
|
"@modelcontextprotocol/server-memory": "*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
101
src/memory/README.md
Normal file
101
src/memory/README.md
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
# Knowledge Graph Memory Server
|
||||||
|
A basic MCP server implementation that provides persistent memory using a knowledge-graph. The server manages entities, their observations, and the relationships between them using a JSON-based file system.
|
||||||
|
|
||||||
|
This lets Claude remember information about the user across chats and projects, and lets them bypass the issues of having super long chats
|
||||||
|
|
||||||
|
# Core Concepts
|
||||||
|
|
||||||
|
## Entities
|
||||||
|
Entities are the primary nodes in the knowledge graph. Each entity has:
|
||||||
|
- A unique name (identifier)
|
||||||
|
- An entity type (e.g., "person", "organization", "event")
|
||||||
|
- A list of observations
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "John_Smith",
|
||||||
|
"entityType": "person",
|
||||||
|
"observations": ["Lives in New York", "Works as a software engineer"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Relations
|
||||||
|
Relations define directed connections between entities. They are always stored in active voice and describe how entities interact or relate to each other.
|
||||||
|
Example:
|
||||||
|
```jsonCopy{
|
||||||
|
"from": "John_Smith",
|
||||||
|
"to": "TechCorp",
|
||||||
|
"relationType": "works_at"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## Observations
|
||||||
|
Observations are discrete pieces of information about an entity. They are:
|
||||||
|
|
||||||
|
- Stored as strings
|
||||||
|
- Attached to specific entities
|
||||||
|
- Can be added or removed independently
|
||||||
|
- Should be atomic (one fact per observation)
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```jsonCopy{
|
||||||
|
"entityName": "John_Smith",
|
||||||
|
"observations": [
|
||||||
|
"Speaks fluent Spanish",
|
||||||
|
"Graduated in 2019",
|
||||||
|
"Prefers morning meetings"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Tools
|
||||||
|
|
||||||
|
## Entity Management
|
||||||
|
|
||||||
|
- create_entities: Create new entities in the knowledge graph with names, types, and observations
|
||||||
|
- delete_entities: Remove entities and their associated relations from the graph
|
||||||
|
- add_observations: Add new observations to existing entities
|
||||||
|
- delete_observations: Remove specific observations from entities
|
||||||
|
|
||||||
|
|
||||||
|
## Relation Management
|
||||||
|
|
||||||
|
- create_relations: Establish relationships between entities in active voice
|
||||||
|
- delete_relations: Remove specific relationships between entities
|
||||||
|
|
||||||
|
|
||||||
|
## Query Tools
|
||||||
|
|
||||||
|
- read_graph: Retrieve the entire knowledge graph
|
||||||
|
- search_nodes: Search for nodes based on names, types, and observation content
|
||||||
|
- open_nodes: Access specific nodes by their names
|
||||||
|
|
||||||
|
# Prompts
|
||||||
|
|
||||||
|
The prompt for utilizing memory depends on the use case, but here is an example prompt for chat personalization. You could use this prompt in the "Custom Instructions" field of a Project
|
||||||
|
|
||||||
|
```
|
||||||
|
Follow these steps for each interaction:
|
||||||
|
|
||||||
|
1. User Identification:
|
||||||
|
- You should assume that you are interacting with default_user
|
||||||
|
- If you have not identified default_user, proactively try to do so.
|
||||||
|
|
||||||
|
2. Memory Retrieval:
|
||||||
|
- Always begin your chat by saying only "Remembering..." and retrieve all relevant information from your knowledge graph
|
||||||
|
- Always refer to your knowledge as your "memory"
|
||||||
|
|
||||||
|
3. Memory
|
||||||
|
- While conversing with the user, be attentive to any new information that falls into these categories:
|
||||||
|
a) Basic Identity (Age, gender, location, Job title, education level, etc.)
|
||||||
|
b) Behaviors (interests, habits, etc.)
|
||||||
|
c) Preferences (communication style, preferred language, etc.)
|
||||||
|
d) Goals/Psychology (Goals, targets, aspirations, etc.)
|
||||||
|
e) Relationships (personal and professional relationships up to 3 degrees of separation)
|
||||||
|
|
||||||
|
4. Memory Update:
|
||||||
|
- If any new information was gathered during the interaction, update your memory as follows:
|
||||||
|
a) Create nodes for recurring organizations, people, and significant events, connecting them to the current node.
|
||||||
|
b) Store most facts as observations within these nodes
|
||||||
|
- Try to perform all updates in one operation using the create and delete functions.
|
||||||
|
```
|
||||||
414
src/memory/index.ts
Normal file
414
src/memory/index.ts
Normal file
|
|
@ -0,0 +1,414 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
||||||
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||||
|
import {
|
||||||
|
CallToolRequestSchema,
|
||||||
|
ListToolsRequestSchema,
|
||||||
|
} from "@modelcontextprotocol/sdk/types.js";
|
||||||
|
import { promises as fs } from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
|
||||||
|
// Define the path to the JSONL file, you can change this to your desired local path
|
||||||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
const MEMORY_FILE_PATH = path.join(__dirname, 'memory.json');
|
||||||
|
|
||||||
|
// We are storing our memory using entities, relations, and observations in a graph structure
|
||||||
|
interface Entity {
|
||||||
|
name: string;
|
||||||
|
entityType: string;
|
||||||
|
observations: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Relation {
|
||||||
|
from: string;
|
||||||
|
to: string;
|
||||||
|
relationType: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KnowledgeGraph {
|
||||||
|
entities: Entity[];
|
||||||
|
relations: Relation[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// The KnowledgeGraphManager class contains all operations to interact with the knowledge graph
|
||||||
|
class KnowledgeGraphManager {
|
||||||
|
private async loadGraph(): Promise<KnowledgeGraph> {
|
||||||
|
try {
|
||||||
|
const data = await fs.readFile(MEMORY_FILE_PATH, "utf-8");
|
||||||
|
const lines = data.split("\n").filter(line => line.trim() !== "");
|
||||||
|
return lines.reduce((graph: KnowledgeGraph, line) => {
|
||||||
|
const item = JSON.parse(line);
|
||||||
|
if (item.type === "entity") graph.entities.push(item as Entity);
|
||||||
|
if (item.type === "relation") graph.relations.push(item as Relation);
|
||||||
|
return graph;
|
||||||
|
}, { entities: [], relations: [] });
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error && 'code' in error && (error as any).code === "ENOENT") {
|
||||||
|
return { entities: [], relations: [] };
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async saveGraph(graph: KnowledgeGraph): Promise<void> {
|
||||||
|
const lines = [
|
||||||
|
...graph.entities.map(e => JSON.stringify({ type: "entity", ...e })),
|
||||||
|
...graph.relations.map(r => JSON.stringify({ type: "relation", ...r })),
|
||||||
|
];
|
||||||
|
await fs.writeFile(MEMORY_FILE_PATH, lines.join("\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
async createEntities(entities: Entity[]): Promise<Entity[]> {
|
||||||
|
const graph = await this.loadGraph();
|
||||||
|
const newEntities = entities.filter(e => !graph.entities.some(existingEntity => existingEntity.name === e.name));
|
||||||
|
graph.entities.push(...newEntities);
|
||||||
|
await this.saveGraph(graph);
|
||||||
|
return newEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
async createRelations(relations: Relation[]): Promise<Relation[]> {
|
||||||
|
const graph = await this.loadGraph();
|
||||||
|
const newRelations = relations.filter(r => !graph.relations.some(existingRelation =>
|
||||||
|
existingRelation.from === r.from &&
|
||||||
|
existingRelation.to === r.to &&
|
||||||
|
existingRelation.relationType === r.relationType
|
||||||
|
));
|
||||||
|
graph.relations.push(...newRelations);
|
||||||
|
await this.saveGraph(graph);
|
||||||
|
return newRelations;
|
||||||
|
}
|
||||||
|
|
||||||
|
async addObservations(observations: { entityName: string; contents: string[] }[]): Promise<{ entityName: string; addedObservations: string[] }[]> {
|
||||||
|
const graph = await this.loadGraph();
|
||||||
|
const results = observations.map(o => {
|
||||||
|
const entity = graph.entities.find(e => e.name === o.entityName);
|
||||||
|
if (!entity) {
|
||||||
|
throw new Error(`Entity with name ${o.entityName} not found`);
|
||||||
|
}
|
||||||
|
const newObservations = o.contents.filter(content => !entity.observations.includes(content));
|
||||||
|
entity.observations.push(...newObservations);
|
||||||
|
return { entityName: o.entityName, addedObservations: newObservations };
|
||||||
|
});
|
||||||
|
await this.saveGraph(graph);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteEntities(entityNames: string[]): Promise<void> {
|
||||||
|
const graph = await this.loadGraph();
|
||||||
|
graph.entities = graph.entities.filter(e => !entityNames.includes(e.name));
|
||||||
|
graph.relations = graph.relations.filter(r => !entityNames.includes(r.from) && !entityNames.includes(r.to));
|
||||||
|
await this.saveGraph(graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteObservations(deletions: { entityName: string; observations: string[] }[]): Promise<void> {
|
||||||
|
const graph = await this.loadGraph();
|
||||||
|
deletions.forEach(d => {
|
||||||
|
const entity = graph.entities.find(e => e.name === d.entityName);
|
||||||
|
if (entity) {
|
||||||
|
entity.observations = entity.observations.filter(o => !d.observations.includes(o));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await this.saveGraph(graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteRelations(relations: Relation[]): Promise<void> {
|
||||||
|
const graph = await this.loadGraph();
|
||||||
|
graph.relations = graph.relations.filter(r => !relations.some(delRelation =>
|
||||||
|
r.from === delRelation.from &&
|
||||||
|
r.to === delRelation.to &&
|
||||||
|
r.relationType === delRelation.relationType
|
||||||
|
));
|
||||||
|
await this.saveGraph(graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
async readGraph(): Promise<KnowledgeGraph> {
|
||||||
|
return this.loadGraph();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Very basic search function
|
||||||
|
async searchNodes(query: string): Promise<KnowledgeGraph> {
|
||||||
|
const graph = await this.loadGraph();
|
||||||
|
|
||||||
|
// Filter entities
|
||||||
|
const filteredEntities = graph.entities.filter(e =>
|
||||||
|
e.name.toLowerCase().includes(query.toLowerCase()) ||
|
||||||
|
e.entityType.toLowerCase().includes(query.toLowerCase()) ||
|
||||||
|
e.observations.some(o => o.toLowerCase().includes(query.toLowerCase()))
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create a Set of filtered entity names for quick lookup
|
||||||
|
const filteredEntityNames = new Set(filteredEntities.map(e => e.name));
|
||||||
|
|
||||||
|
// Filter relations to only include those between filtered entities
|
||||||
|
const filteredRelations = graph.relations.filter(r =>
|
||||||
|
filteredEntityNames.has(r.from) && filteredEntityNames.has(r.to)
|
||||||
|
);
|
||||||
|
|
||||||
|
const filteredGraph: KnowledgeGraph = {
|
||||||
|
entities: filteredEntities,
|
||||||
|
relations: filteredRelations,
|
||||||
|
};
|
||||||
|
|
||||||
|
return filteredGraph;
|
||||||
|
}
|
||||||
|
|
||||||
|
async openNodes(names: string[]): Promise<KnowledgeGraph> {
|
||||||
|
const graph = await this.loadGraph();
|
||||||
|
|
||||||
|
// Filter entities
|
||||||
|
const filteredEntities = graph.entities.filter(e => names.includes(e.name));
|
||||||
|
|
||||||
|
// Create a Set of filtered entity names for quick lookup
|
||||||
|
const filteredEntityNames = new Set(filteredEntities.map(e => e.name));
|
||||||
|
|
||||||
|
// Filter relations to only include those between filtered entities
|
||||||
|
const filteredRelations = graph.relations.filter(r =>
|
||||||
|
filteredEntityNames.has(r.from) && filteredEntityNames.has(r.to)
|
||||||
|
);
|
||||||
|
|
||||||
|
const filteredGraph: KnowledgeGraph = {
|
||||||
|
entities: filteredEntities,
|
||||||
|
relations: filteredRelations,
|
||||||
|
};
|
||||||
|
|
||||||
|
return filteredGraph;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const knowledgeGraphManager = new KnowledgeGraphManager();
|
||||||
|
|
||||||
|
|
||||||
|
// The server instance and tools exposed to Claude
|
||||||
|
const server = new Server({
|
||||||
|
name: "memory-server",
|
||||||
|
version: "1.0.0",
|
||||||
|
}, {
|
||||||
|
capabilities: {
|
||||||
|
tools: {},
|
||||||
|
},
|
||||||
|
},);
|
||||||
|
|
||||||
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||||
|
return {
|
||||||
|
tools: [
|
||||||
|
{
|
||||||
|
name: "create_entities",
|
||||||
|
description: "Create multiple new entities in the knowledge graph",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
entities: {
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
name: { type: "string", description: "The name of the entity" },
|
||||||
|
entityType: { type: "string", description: "The type of the entity" },
|
||||||
|
observations: {
|
||||||
|
type: "array",
|
||||||
|
items: { type: "string" },
|
||||||
|
description: "An array of observation contents associated with the entity"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["name", "entityType", "observations"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["entities"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "create_relations",
|
||||||
|
description: "Create multiple new relations between entities in the knowledge graph. Relations should be in active voice",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
relations: {
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
from: { type: "string", description: "The name of the entity where the relation starts" },
|
||||||
|
to: { type: "string", description: "The name of the entity where the relation ends" },
|
||||||
|
relationType: { type: "string", description: "The type of the relation" },
|
||||||
|
},
|
||||||
|
required: ["from", "to", "relationType"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["relations"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "add_observations",
|
||||||
|
description: "Add new observations to existing entities in the knowledge graph",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
observations: {
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
entityName: { type: "string", description: "The name of the entity to add the observations to" },
|
||||||
|
contents: {
|
||||||
|
type: "array",
|
||||||
|
items: { type: "string" },
|
||||||
|
description: "An array of observation contents to add"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["entityName", "contents"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["observations"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "delete_entities",
|
||||||
|
description: "Delete multiple entities and their associated relations from the knowledge graph",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
entityNames: {
|
||||||
|
type: "array",
|
||||||
|
items: { type: "string" },
|
||||||
|
description: "An array of entity names to delete"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["entityNames"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "delete_observations",
|
||||||
|
description: "Delete specific observations from entities in the knowledge graph",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
deletions: {
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
entityName: { type: "string", description: "The name of the entity containing the observations" },
|
||||||
|
observations: {
|
||||||
|
type: "array",
|
||||||
|
items: { type: "string" },
|
||||||
|
description: "An array of observations to delete"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["entityName", "observations"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["deletions"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "delete_relations",
|
||||||
|
description: "Delete multiple relations from the knowledge graph",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
relations: {
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
from: { type: "string", description: "The name of the entity where the relation starts" },
|
||||||
|
to: { type: "string", description: "The name of the entity where the relation ends" },
|
||||||
|
relationType: { type: "string", description: "The type of the relation" },
|
||||||
|
},
|
||||||
|
required: ["from", "to", "relationType"],
|
||||||
|
},
|
||||||
|
description: "An array of relations to delete"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["relations"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "read_graph",
|
||||||
|
description: "Read the entire knowledge graph",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "search_nodes",
|
||||||
|
description: "Search for nodes in the knowledge graph based on a query",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
query: { type: "string", description: "The search query to match against entity names, types, and observation content" },
|
||||||
|
},
|
||||||
|
required: ["query"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "open_nodes",
|
||||||
|
description: "Open specific nodes in the knowledge graph by their names",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
names: {
|
||||||
|
type: "array",
|
||||||
|
items: { type: "string" },
|
||||||
|
description: "An array of entity names to retrieve",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["names"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||||
|
const { name, arguments: args } = request.params;
|
||||||
|
|
||||||
|
if (!args) {
|
||||||
|
throw new Error(`No arguments provided for tool: ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (name) {
|
||||||
|
case "create_entities":
|
||||||
|
return { toolResult: await knowledgeGraphManager.createEntities(args.entities as Entity[]) };
|
||||||
|
case "create_relations":
|
||||||
|
return { toolResult: await knowledgeGraphManager.createRelations(args.relations as Relation[]) };
|
||||||
|
case "add_observations":
|
||||||
|
return { toolResult: await knowledgeGraphManager.addObservations(args.observations as { entityName: string; contents: string[] }[]) };
|
||||||
|
case "delete_entities":
|
||||||
|
await knowledgeGraphManager.deleteEntities(args.entityNames as string[]);
|
||||||
|
return { toolResult: "Entities deleted successfully" };
|
||||||
|
case "delete_observations":
|
||||||
|
await knowledgeGraphManager.deleteObservations(args.deletions as { entityName: string; observations: string[] }[]);
|
||||||
|
return { toolResult: "Observations deleted successfully" };
|
||||||
|
case "delete_relations":
|
||||||
|
await knowledgeGraphManager.deleteRelations(args.relations as Relation[]);
|
||||||
|
return { toolResult: "Relations deleted successfully" };
|
||||||
|
case "read_graph":
|
||||||
|
return { toolResult: await knowledgeGraphManager.readGraph() };
|
||||||
|
case "search_nodes":
|
||||||
|
return { toolResult: await knowledgeGraphManager.searchNodes(args.query as string) };
|
||||||
|
case "open_nodes":
|
||||||
|
return { toolResult: await knowledgeGraphManager.openNodes(args.names as string[]) };
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown tool: ${name}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const transport = new StdioServerTransport();
|
||||||
|
await server.connect(transport);
|
||||||
|
console.error("Knowledge Graph MCP Server running on stdio");
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error("Fatal error in main():", error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
28
src/memory/package.json
Normal file
28
src/memory/package.json
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"name": "@modelcontextprotocol/server-memory",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "MCP server for enabling memory for Claude through a knowledge graph",
|
||||||
|
"license": "MIT",
|
||||||
|
"author": "Anthropic, PBC (https://anthropic.com)",
|
||||||
|
"homepage": "https://modelcontextprotocol.io",
|
||||||
|
"bugs": "https://github.com/modelcontextprotocol/servers/issues",
|
||||||
|
"type": "module",
|
||||||
|
"bin": {
|
||||||
|
"mcp-server-memory": "dist/index.js"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc && shx chmod +x dist/*.js",
|
||||||
|
"prepare": "npm run build",
|
||||||
|
"watch": "tsc --watch"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@modelcontextprotocol/sdk": "0.5.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"shx": "^0.3.4",
|
||||||
|
"typescript": "^5.6.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/memory/tsconfig.json
Normal file
11
src/memory/tsconfig.json
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "."
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./**/*.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in a new issue