diff options
| -rw-r--r-- | packages/mcp/package.json | 33 | ||||
| -rw-r--r-- | packages/mcp/src/index.ts | 193 | ||||
| -rw-r--r-- | packages/mcp/tsconfig.json | 21 |
3 files changed, 247 insertions, 0 deletions
diff --git a/packages/mcp/package.json b/packages/mcp/package.json new file mode 100644 index 0000000..f45d98d --- /dev/null +++ b/packages/mcp/package.json @@ -0,0 +1,33 @@ +{ + "name": "@imemio/mcp", + "version": "0.0.1", + "description": "MCP server for imemio AI agent memory service", + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "bin": { + "imemio-mcp": "./dist/index.js" + }, + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + } + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "@imemio/sdk": "workspace:*", + "@modelcontextprotocol/sdk": "^1.0.0", + "zod": "^3.24.0" + }, + "devDependencies": { + "@types/node": "^22.13.3", + "typescript": "^5.7.3" + } +} diff --git a/packages/mcp/src/index.ts b/packages/mcp/src/index.ts new file mode 100644 index 0000000..18c61ce --- /dev/null +++ b/packages/mcp/src/index.ts @@ -0,0 +1,193 @@ +#!/usr/bin/env node + +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { z } from "zod"; +import { InMemoryStore } from "@imemio/sdk"; + +const store = new InMemoryStore(); +const tagSchema = z.object({ + id: z.string(), + name: z.string(), +}); +const metadataSchema = z.record(z.unknown()); +const server = new McpServer({ + name: "imemio", + version: "0.0.1", +}); + +server.tool( + "create_memory", + "Create a new memory", + { + content: z.string().describe("The content of the memory"), + projectId: z.string().describe("The project ID this memory belongs to"), + folderId: z.string().optional().describe("Optional folder ID"), + tags: z.array(tagSchema).optional().describe("Optional tags"), + metadata: metadataSchema.optional().describe("Optional metadata"), + }, + async (parameters) => { + const memory = await store.create({ + content: parameters.content, + projectId: parameters.projectId, + folderId: parameters.folderId, + tags: parameters.tags, + metadata: parameters.metadata, + }); + + return { + content: [ + { + type: "text" as const, + text: JSON.stringify(memory, null, 2), + }, + ], + }; + }, +); + +server.tool( + "get_memory", + "Get a memory by ID", + { + id: z.string().describe("The memory ID"), + }, + async (parameters) => { + const result = await store.read(parameters.id); + + if (!result.success) { + return { + content: [ + { + type: "text" as const, + text: `Memory not found: ${parameters.id}`, + }, + ], + isError: true, + }; + } + + return { + content: [ + { + type: "text" as const, + text: JSON.stringify(result.value, null, 2), + }, + ], + }; + }, +); + +server.tool( + "update_memory", + "Update an existing memory", + { + id: z.string().describe("The memory ID to update"), + content: z.string().optional().describe("New content"), + folderId: z.string().nullable().optional().describe("New folder ID"), + tags: z.array(tagSchema).optional().describe("New tags"), + metadata: metadataSchema.optional().describe("New metadata"), + }, + async (parameters) => { + const result = await store.update(parameters.id, { + content: parameters.content, + folderId: parameters.folderId, + tags: parameters.tags, + metadata: parameters.metadata, + }); + + if (!result.success) { + return { + content: [ + { + type: "text" as const, + text: `Memory not found: ${parameters.id}`, + }, + ], + isError: true, + }; + } + + return { + content: [ + { + type: "text" as const, + text: JSON.stringify(result.value, null, 2), + }, + ], + }; + }, +); + +server.tool( + "delete_memory", + "Delete a memory", + { + id: z.string().describe("The memory ID to delete"), + }, + async (parameters) => { + const result = await store.delete(parameters.id); + + if (!result.success) { + return { + content: [ + { + type: "text" as const, + text: `Memory not found: ${parameters.id}`, + }, + ], + isError: true, + }; + } + + return { + content: [ + { + type: "text" as const, + text: `Memory deleted: ${parameters.id}`, + }, + ], + }; + }, +); + +server.tool( + "list_memories", + "List memories with optional filters", + { + projectId: z.string().optional().describe("Filter by project ID"), + folderId: z.string().optional().describe("Filter by folder ID"), + tags: z.array(z.string()).optional().describe("Filter by tag IDs"), + }, + async (parameters) => { + const filter = + parameters.projectId || parameters.folderId || parameters.tags + ? { + projectId: parameters.projectId, + folderId: parameters.folderId, + tags: parameters.tags, + } + : undefined; + const memories = await store.list(filter); + + return { + content: [ + { + type: "text" as const, + text: JSON.stringify(memories, null, 2), + }, + ], + }; + }, +); + +async function main(): Promise<void> { + const transport = new StdioServerTransport(); + + await server.connect(transport); +} + +main().catch((error) => { + console.error("Server error:", error); + process.exit(1); +}); diff --git a/packages/mcp/tsconfig.json b/packages/mcp/tsconfig.json new file mode 100644 index 0000000..a55afed --- /dev/null +++ b/packages/mcp/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "lib": ["ES2022"], + "strict": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": "./dist", + "rootDir": "./src", + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "noUncheckedIndexedAccess": true, + "noEmitOnError": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} |