@smara/mcp-server
Advanced tools
| export declare const DEFAULT_SOURCE: string; | ||
| export declare const DEFAULT_USER_ID: string; | ||
| export declare const DEFAULT_NAMESPACE: string; | ||
| export declare const DEFAULT_TEAM_ID: string; | ||
| export declare function smaraFetch(path: string, options?: RequestInit): Promise<unknown>; |
@@ -6,2 +6,3 @@ const BASE_URL = process.env.SMARA_API_URL || "https://api.smara.io"; | ||
| export const DEFAULT_NAMESPACE = process.env.SMARA_NAMESPACE || "default"; | ||
| export const DEFAULT_TEAM_ID = process.env.SMARA_TEAM_ID || ""; | ||
| export async function smaraFetch(path, options = {}) { | ||
@@ -8,0 +9,0 @@ if (!API_KEY) |
+66
-15
@@ -5,7 +5,14 @@ #!/usr/bin/env node | ||
| import { z } from "zod"; | ||
| import { smaraFetch, DEFAULT_SOURCE, DEFAULT_USER_ID, DEFAULT_NAMESPACE } from "./api-client.js"; | ||
| import { smaraFetch, DEFAULT_SOURCE, DEFAULT_USER_ID, DEFAULT_NAMESPACE, DEFAULT_TEAM_ID } 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" }, { | ||
| const teamHint = DEFAULT_TEAM_ID | ||
| ? `\nTEAM MODE: This session is connected to team "${DEFAULT_TEAM_ID}". When storing memories, classify each one: | ||
| - visibility "team" — project decisions, architecture choices, conventions, shared knowledge, bug fixes, API contracts. Anything a teammate would need to know. | ||
| - visibility "private" — personal preferences (editor settings, style preferences), individual notes, personal reminders. Things specific to this user, not the project. | ||
| When in doubt, default to "team" — it's better to over-share project knowledge than to silo it. | ||
| When searching, include_team is automatically enabled so you see both private and team memories.` | ||
| : ''; | ||
| const server = new McpServer({ name: "smara", version: "2.1.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. | ||
@@ -20,2 +27,3 @@ | ||
| ${userIdHint} | ||
| ${teamHint} | ||
@@ -46,13 +54,30 @@ RULES: | ||
| .describe("Memory namespace for isolation (default: from env or 'default')"), | ||
| visibility: z | ||
| .enum(["private", "team"]) | ||
| .optional() | ||
| .describe("Who can see this memory. Use 'team' for project decisions, architecture, conventions, shared knowledge — anything a teammate needs. Use 'private' for personal preferences, editor settings, individual style choices. Only applies when SMARA_TEAM_ID is set."), | ||
| team_id: z | ||
| .string() | ||
| .optional() | ||
| .describe("Team ID to store this memory under. Defaults to SMARA_TEAM_ID env var if set."), | ||
| }, | ||
| }, async ({ user_id, fact, importance, namespace }) => { | ||
| }, async ({ user_id, fact, importance, namespace, visibility, team_id }) => { | ||
| const effectiveTeamId = team_id || DEFAULT_TEAM_ID || undefined; | ||
| const effectiveVisibility = effectiveTeamId | ||
| ? (visibility || "team") | ||
| : undefined; | ||
| const body = { | ||
| user_id, | ||
| fact, | ||
| importance, | ||
| source: DEFAULT_SOURCE, | ||
| namespace: namespace || DEFAULT_NAMESPACE, | ||
| }; | ||
| if (effectiveTeamId) | ||
| body.team_id = effectiveTeamId; | ||
| if (effectiveVisibility) | ||
| body.visibility = effectiveVisibility; | ||
| const data = await smaraFetch("/v1/memories", { | ||
| method: "POST", | ||
| body: JSON.stringify({ | ||
| user_id, | ||
| fact, | ||
| importance, | ||
| source: DEFAULT_SOURCE, | ||
| namespace: namespace || DEFAULT_NAMESPACE, | ||
| }), | ||
| body: JSON.stringify(body), | ||
| }); | ||
@@ -64,3 +89,3 @@ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] }; | ||
| title: "Search Memories", | ||
| description: "Semantic search across stored memories for a user. Ranked by Temporal Memory Scoring — balances semantic relevance with memory freshness and importance.", | ||
| description: "Semantic search across stored memories for a user. Ranked by Temporal Memory Scoring — balances semantic relevance with memory freshness and importance. When a team is configured, returns both private and team memories by default.", | ||
| inputSchema: { | ||
@@ -80,4 +105,13 @@ user_id: z.string().describe("User to search memories for"), | ||
| .describe("Memory namespace (default: from env or 'default')"), | ||
| team_id: z | ||
| .string() | ||
| .optional() | ||
| .describe("Team ID to include team memories from. Defaults to SMARA_TEAM_ID env var."), | ||
| include_team: z | ||
| .boolean() | ||
| .optional() | ||
| .describe("Include team memories in results. Defaults to true when a team is configured."), | ||
| }, | ||
| }, async ({ user_id, q, limit, namespace }) => { | ||
| }, async ({ user_id, q, limit, namespace, team_id, include_team }) => { | ||
| const effectiveTeamId = team_id || DEFAULT_TEAM_ID || undefined; | ||
| const params = new URLSearchParams({ | ||
@@ -89,2 +123,6 @@ user_id, | ||
| }); | ||
| if (effectiveTeamId) { | ||
| params.set("team_id", effectiveTeamId); | ||
| params.set("include_team", String(include_team !== false)); | ||
| } | ||
| const data = await smaraFetch(`/v1/memories/search?${params}`); | ||
@@ -96,3 +134,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. Ranked by Temporal Memory Scoring. Can be called without a query to get the most important recent memories.", | ||
| 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. When a team is configured, includes team memories automatically.", | ||
| inputSchema: { | ||
@@ -115,4 +153,13 @@ user_id: z.string().describe("User to get context for"), | ||
| .describe("Memory namespace (default: from env or 'default')"), | ||
| team_id: z | ||
| .string() | ||
| .optional() | ||
| .describe("Team ID to include team context from. Defaults to SMARA_TEAM_ID env var."), | ||
| include_team: z | ||
| .boolean() | ||
| .optional() | ||
| .describe("Include team memories in context. Defaults to true when a team is configured."), | ||
| }, | ||
| }, async ({ user_id, q, top_n, namespace }) => { | ||
| }, async ({ user_id, q, top_n, namespace, team_id, include_team }) => { | ||
| const effectiveTeamId = team_id || DEFAULT_TEAM_ID || undefined; | ||
| const params = new URLSearchParams({ | ||
@@ -124,2 +171,6 @@ top_n: String(top_n), | ||
| params.set("q", q); | ||
| if (effectiveTeamId) { | ||
| params.set("team_id", effectiveTeamId); | ||
| params.set("include_team", String(include_team !== false)); | ||
| } | ||
| const data = await smaraFetch(`/v1/users/${encodeURIComponent(user_id)}/context?${params}`); | ||
@@ -152,3 +203,3 @@ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] }; | ||
| await server.connect(transport); | ||
| console.error("Smara MCP Server v2.0.0 running on stdio"); | ||
| console.error("Smara MCP Server v2.1.0 running on stdio"); | ||
| } | ||
@@ -155,0 +206,0 @@ main().catch((error) => { |
+1
-1
| { | ||
| "name": "@smara/mcp-server", | ||
| "version": "2.0.2", | ||
| "version": "2.1.0", | ||
| "mcpName": "io.github.parallelromb/smara", | ||
@@ -5,0 +5,0 @@ "description": "MCP server for Smara Memory API — persistent memory for AI agents", |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
13971
27.37%226
30.64%7
16.67%