@smara/mcp-server 2.0.2 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,5 @@
1
1
  export declare const DEFAULT_SOURCE: string;
2
2
  export declare const DEFAULT_USER_ID: string;
3
3
  export declare const DEFAULT_NAMESPACE: string;
4
+ export declare const DEFAULT_TEAM_ID: string;
4
5
  export declare function smaraFetch(path: string, options?: RequestInit): Promise<unknown>;
@@ -3,6 +3,7 @@ const API_KEY = process.env.SMARA_API_KEY;
3
3
  export const DEFAULT_SOURCE = process.env.SMARA_SOURCE || "mcp";
4
4
  export const DEFAULT_USER_ID = process.env.SMARA_USER_ID || "";
5
5
  export const DEFAULT_NAMESPACE = process.env.SMARA_NAMESPACE || "default";
6
+ export const DEFAULT_TEAM_ID = process.env.SMARA_TEAM_ID || "";
6
7
  export async function smaraFetch(path, options = {}) {
7
8
  if (!API_KEY)
8
9
  throw new Error("SMARA_API_KEY environment variable is required. Get a free key at https://smara.io");
package/build/index.js CHANGED
@@ -2,11 +2,18 @@
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { z } from "zod";
5
- import { smaraFetch, DEFAULT_SOURCE, DEFAULT_USER_ID, DEFAULT_NAMESPACE } from "./api-client.js";
5
+ import { smaraFetch, DEFAULT_SOURCE, DEFAULT_USER_ID, DEFAULT_NAMESPACE, DEFAULT_TEAM_ID } from "./api-client.js";
6
6
  const userIdHint = DEFAULT_USER_ID
7
7
  ? `The user_id for this session is "${DEFAULT_USER_ID}". Always use this value.`
8
8
  : `Use a stable identifier for user_id — the project name, directory name, or username. Be consistent across sessions.`;
9
- const server = new McpServer({ name: "smara", version: "2.0.0" }, {
9
+ const teamHint = DEFAULT_TEAM_ID
10
+ ? `\nTEAM MODE: This session is connected to team "${DEFAULT_TEAM_ID}". When storing memories, classify each one:
11
+ - visibility "team" — project decisions, architecture choices, conventions, shared knowledge, bug fixes, API contracts. Anything a teammate would need to know.
12
+ - visibility "private" — personal preferences (editor settings, style preferences), individual notes, personal reminders. Things specific to this user, not the project.
13
+ When in doubt, default to "team" — it's better to over-share project knowledge than to silo it.
14
+ When searching, include_team is automatically enabled so you see both private and team memories.`
15
+ : '';
16
+ const server = new McpServer({ name: "smara", version: "2.1.0" }, {
10
17
  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.
11
18
 
12
19
  AUTOMATIC BEHAVIOR (do this without being asked):
@@ -16,6 +23,7 @@ AUTOMATIC BEHAVIOR (do this without being asked):
16
23
  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.
17
24
 
18
25
  ${userIdHint}
26
+ ${teamHint}
19
27
 
20
28
  RULES:
21
29
  - Do not store transient conversational filler. Only store facts useful in a future conversation.
@@ -41,24 +49,41 @@ server.registerTool("store_memory", {
41
49
  .string()
42
50
  .optional()
43
51
  .describe("Memory namespace for isolation (default: from env or 'default')"),
52
+ visibility: z
53
+ .enum(["private", "team"])
54
+ .optional()
55
+ .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."),
56
+ team_id: z
57
+ .string()
58
+ .optional()
59
+ .describe("Team ID to store this memory under. Defaults to SMARA_TEAM_ID env var if set."),
44
60
  },
45
- }, async ({ user_id, fact, importance, namespace }) => {
61
+ }, async ({ user_id, fact, importance, namespace, visibility, team_id }) => {
62
+ const effectiveTeamId = team_id || DEFAULT_TEAM_ID || undefined;
63
+ const effectiveVisibility = effectiveTeamId
64
+ ? (visibility || "team")
65
+ : undefined;
66
+ const body = {
67
+ user_id,
68
+ fact,
69
+ importance,
70
+ source: DEFAULT_SOURCE,
71
+ namespace: namespace || DEFAULT_NAMESPACE,
72
+ };
73
+ if (effectiveTeamId)
74
+ body.team_id = effectiveTeamId;
75
+ if (effectiveVisibility)
76
+ body.visibility = effectiveVisibility;
46
77
  const data = await smaraFetch("/v1/memories", {
47
78
  method: "POST",
48
- body: JSON.stringify({
49
- user_id,
50
- fact,
51
- importance,
52
- source: DEFAULT_SOURCE,
53
- namespace: namespace || DEFAULT_NAMESPACE,
54
- }),
79
+ body: JSON.stringify(body),
55
80
  });
56
81
  return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
57
82
  });
58
83
  // ── Search memories ─────────────────────────────────
59
84
  server.registerTool("search_memories", {
60
85
  title: "Search Memories",
61
- description: "Semantic search across stored memories for a user. Ranked by Temporal Memory Scoring — balances semantic relevance with memory freshness and importance.",
86
+ 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.",
62
87
  inputSchema: {
63
88
  user_id: z.string().describe("User to search memories for"),
64
89
  q: z.string().describe("Natural language search query"),
@@ -73,21 +98,34 @@ server.registerTool("search_memories", {
73
98
  .string()
74
99
  .optional()
75
100
  .describe("Memory namespace (default: from env or 'default')"),
101
+ team_id: z
102
+ .string()
103
+ .optional()
104
+ .describe("Team ID to include team memories from. Defaults to SMARA_TEAM_ID env var."),
105
+ include_team: z
106
+ .boolean()
107
+ .optional()
108
+ .describe("Include team memories in results. Defaults to true when a team is configured."),
76
109
  },
77
- }, async ({ user_id, q, limit, namespace }) => {
110
+ }, async ({ user_id, q, limit, namespace, team_id, include_team }) => {
111
+ const effectiveTeamId = team_id || DEFAULT_TEAM_ID || undefined;
78
112
  const params = new URLSearchParams({
79
113
  user_id,
80
114
  q,
81
115
  limit: String(limit),
82
116
  namespace: namespace || DEFAULT_NAMESPACE,
83
117
  });
118
+ if (effectiveTeamId) {
119
+ params.set("team_id", effectiveTeamId);
120
+ params.set("include_team", String(include_team !== false));
121
+ }
84
122
  const data = await smaraFetch(`/v1/memories/search?${params}`);
85
123
  return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
86
124
  });
87
125
  // ── Get user context ────────────────────────────────
88
126
  server.registerTool("get_user_context", {
89
127
  title: "Get User Context",
90
- 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.",
128
+ 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.",
91
129
  inputSchema: {
92
130
  user_id: z.string().describe("User to get context for"),
93
131
  q: z
@@ -105,14 +143,27 @@ server.registerTool("get_user_context", {
105
143
  .string()
106
144
  .optional()
107
145
  .describe("Memory namespace (default: from env or 'default')"),
146
+ team_id: z
147
+ .string()
148
+ .optional()
149
+ .describe("Team ID to include team context from. Defaults to SMARA_TEAM_ID env var."),
150
+ include_team: z
151
+ .boolean()
152
+ .optional()
153
+ .describe("Include team memories in context. Defaults to true when a team is configured."),
108
154
  },
109
- }, async ({ user_id, q, top_n, namespace }) => {
155
+ }, async ({ user_id, q, top_n, namespace, team_id, include_team }) => {
156
+ const effectiveTeamId = team_id || DEFAULT_TEAM_ID || undefined;
110
157
  const params = new URLSearchParams({
111
158
  top_n: String(top_n),
112
159
  namespace: namespace || DEFAULT_NAMESPACE,
113
160
  });
114
161
  if (q)
115
162
  params.set("q", q);
163
+ if (effectiveTeamId) {
164
+ params.set("team_id", effectiveTeamId);
165
+ params.set("include_team", String(include_team !== false));
166
+ }
116
167
  const data = await smaraFetch(`/v1/users/${encodeURIComponent(user_id)}/context?${params}`);
117
168
  return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
118
169
  });
@@ -140,7 +191,7 @@ server.registerTool("get_usage", {
140
191
  async function main() {
141
192
  const transport = new StdioServerTransport();
142
193
  await server.connect(transport);
143
- console.error("Smara MCP Server v2.0.0 running on stdio");
194
+ console.error("Smara MCP Server v2.1.0 running on stdio");
144
195
  }
145
196
  main().catch((error) => {
146
197
  console.error("Fatal error:", error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smara/mcp-server",
3
- "version": "2.0.2",
3
+ "version": "2.1.0",
4
4
  "mcpName": "io.github.parallelromb/smara",
5
5
  "description": "MCP server for Smara Memory API — persistent memory for AI agents",
6
6
  "type": "module",