@smara/mcp-server
Advanced tools
@@ -0,1 +1,4 @@ | ||
| export declare const DEFAULT_SOURCE: string; | ||
| export declare const DEFAULT_USER_ID: string; | ||
| export declare const DEFAULT_NAMESPACE: string; | ||
| export declare function smaraFetch(path: string, options?: RequestInit): Promise<unknown>; |
| const BASE_URL = process.env.SMARA_API_URL || "https://api.smara.io"; | ||
| const API_KEY = process.env.SMARA_API_KEY; | ||
| export const DEFAULT_SOURCE = process.env.SMARA_SOURCE || "mcp"; | ||
| export const DEFAULT_USER_ID = process.env.SMARA_USER_ID || ""; | ||
| export const DEFAULT_NAMESPACE = process.env.SMARA_NAMESPACE || "default"; | ||
| export async function smaraFetch(path, options = {}) { | ||
@@ -4,0 +7,0 @@ if (!API_KEY) |
+55
-13
@@ -5,6 +5,22 @@ #!/usr/bin/env node | ||
| import { z } from "zod"; | ||
| import { smaraFetch } from "./api-client.js"; | ||
| const server = new McpServer({ | ||
| name: "smara", | ||
| version: "1.0.0", | ||
| import { smaraFetch, DEFAULT_SOURCE, DEFAULT_USER_ID, DEFAULT_NAMESPACE } from "./api-client.js"; | ||
| const userIdHint = DEFAULT_USER_ID | ||
| ? `The user_id for this session is "${DEFAULT_USER_ID}". Always use this value.` | ||
| : `Use a stable identifier for user_id — the project name, directory name, or username. Be consistent across sessions.`; | ||
| const server = new McpServer({ name: "smara", version: "2.0.0" }, { | ||
| instructions: `You have access to Smara, a persistent cross-platform memory system. Memories stored here persist across conversations and are shared across all AI tools the user has connected. | ||
| AUTOMATIC BEHAVIOR (do this without being asked): | ||
| 1. AT CONVERSATION START: Call get_user_context with the user's ID to load relevant memories. If the conversation has a clear topic, pass it as the query parameter to focus results. | ||
| 2. WHEN YOU LEARN NEW FACTS: If the user shares a preference, correction, important decision, project detail, or personal fact, call store_memory to save it. Use importance 0.7-1.0 for preferences and corrections, 0.5 for general facts, 0.1-0.3 for trivia. | ||
| 3. WHEN THE USER SAYS "remember this" or "don't forget": Always call store_memory with importance 0.9. | ||
| 4. WHEN THE USER SAYS "forget this" or "delete that memory": Call search_memories to find the relevant memory, then call delete_memory with its ID. | ||
| ${userIdHint} | ||
| RULES: | ||
| - Do not store transient conversational filler. Only store facts useful in a future conversation. | ||
| - Do not announce memory operations unless the user asks. Load and store silently. | ||
| - If get_user_context returns memories, incorporate them naturally into your understanding. | ||
| - Smara handles deduplication automatically — don't worry about storing something twice.`, | ||
| }); | ||
@@ -25,7 +41,17 @@ // ── Store a memory ────────────────────────────────── | ||
| .describe("Importance score (0-1). Higher = slower decay."), | ||
| namespace: z | ||
| .string() | ||
| .optional() | ||
| .describe("Memory namespace for isolation (default: from env or 'default')"), | ||
| }, | ||
| }, async ({ user_id, fact, importance }) => { | ||
| }, async ({ user_id, fact, importance, namespace }) => { | ||
| const data = await smaraFetch("/v1/memories", { | ||
| method: "POST", | ||
| body: JSON.stringify({ user_id, fact, importance }), | ||
| body: JSON.stringify({ | ||
| user_id, | ||
| fact, | ||
| importance, | ||
| source: DEFAULT_SOURCE, | ||
| namespace: namespace || DEFAULT_NAMESPACE, | ||
| }), | ||
| }); | ||
@@ -37,3 +63,3 @@ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] }; | ||
| title: "Search Memories", | ||
| description: "Semantic search across stored memories for a user. Returns results ranked by a blend of vector similarity (70%) and Ebbinghaus decay score (30%). Recent, frequently-accessed memories rank higher.", | ||
| description: "Semantic search across stored memories for a user. Ranked by Temporal Memory Scoring — balances semantic relevance with memory freshness and importance.", | ||
| inputSchema: { | ||
@@ -49,5 +75,14 @@ user_id: z.string().describe("User to search memories for"), | ||
| .describe("Max results to return"), | ||
| namespace: z | ||
| .string() | ||
| .optional() | ||
| .describe("Memory namespace (default: from env or 'default')"), | ||
| }, | ||
| }, async ({ user_id, q, limit }) => { | ||
| const params = new URLSearchParams({ user_id, q, limit: String(limit) }); | ||
| }, async ({ user_id, q, limit, namespace }) => { | ||
| const params = new URLSearchParams({ | ||
| user_id, | ||
| q, | ||
| limit: String(limit), | ||
| namespace: namespace || DEFAULT_NAMESPACE, | ||
| }); | ||
| const data = await smaraFetch(`/v1/memories/search?${params}`); | ||
@@ -59,3 +94,3 @@ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] }; | ||
| title: "Get User Context", | ||
| description: "Retrieve a pre-formatted context string for a user, ready to inject into an LLM system prompt. Returns the most relevant memories ranked by decay-aware scoring.", | ||
| description: "Retrieve a pre-formatted context string for a user, ready to inject into an LLM system prompt. Ranked by Temporal Memory Scoring. Can be called without a query to get the most important recent memories.", | ||
| inputSchema: { | ||
@@ -74,5 +109,12 @@ user_id: z.string().describe("User to get context for"), | ||
| .describe("Number of top memories to include"), | ||
| namespace: z | ||
| .string() | ||
| .optional() | ||
| .describe("Memory namespace (default: from env or 'default')"), | ||
| }, | ||
| }, async ({ user_id, q, top_n }) => { | ||
| const params = new URLSearchParams({ top_n: String(top_n) }); | ||
| }, async ({ user_id, q, top_n, namespace }) => { | ||
| const params = new URLSearchParams({ | ||
| top_n: String(top_n), | ||
| namespace: namespace || DEFAULT_NAMESPACE, | ||
| }); | ||
| if (q) | ||
@@ -107,3 +149,3 @@ params.set("q", q); | ||
| await server.connect(transport); | ||
| console.error("Smara MCP Server running on stdio"); | ||
| console.error("Smara MCP Server v2.0.0 running on stdio"); | ||
| } | ||
@@ -110,0 +152,0 @@ main().catch((error) => { |
+1
-1
| { | ||
| "name": "@smara/mcp-server", | ||
| "version": "1.0.0", | ||
| "version": "2.0.0", | ||
| "description": "MCP server for Smara Memory API — persistent memory for AI agents", | ||
@@ -5,0 +5,0 @@ "type": "module", |
+3
-7
| # @smara/mcp-server | ||
| MCP server for the [Smara Memory API](https://smara.io) — give any AI app persistent, decay-aware memory. | ||
| MCP server for the [Smara Memory API](https://smara.io) — give any AI app persistent memory with Temporal Memory Scoring™. | ||
@@ -30,3 +30,3 @@ ## Quick Start | ||
| | `store_memory` | Store a fact about a user with importance scoring | | ||
| | `search_memories` | Semantic search with Ebbinghaus decay-aware ranking | | ||
| | `search_memories` | Semantic search with Temporal Memory Scoring™ | | ||
| | `get_user_context` | Pre-formatted context string for LLM system prompts | | ||
@@ -38,8 +38,4 @@ | `delete_memory` | Delete a specific memory | | ||
| Smara combines vector similarity search (Voyage AI embeddings) with Ebbinghaus forgetting curves. Memories decay over time — recent, frequently-accessed memories rank higher, just like human recall. | ||
| Smara uses **Temporal Memory Scoring™** — a proprietary ranking system that makes AI memory work like human recall. Memories naturally fade over time, modulated by importance and access patterns. Recent, critical memories surface first. Stale, trivial ones fade. Contradictions are auto-detected and resolved. | ||
| ``` | ||
| score = similarity × 0.7 + decay_score × 0.3 | ||
| ``` | ||
| ## Works With | ||
@@ -46,0 +42,0 @@ |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances
10918
34.51%173
35.16%58
-6.45%6
100%