@persistadev/mcp-server 3.2.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.
package/README.md ADDED
@@ -0,0 +1,126 @@
1
+ # @persistadev/mcp-server
2
+
3
+ > Give your AI persistent memory across sessions
4
+
5
+ Persista is an MCP (Model Context Protocol) server that provides AI assistants with persistent memory, context management, and intelligent learning capabilities.
6
+
7
+ ## Features
8
+
9
+ 🧠 **Memory** - Save and retrieve user preferences, facts, and behaviors across sessions
10
+ 📝 **Context** - Smart context packing with relevance scoring and threading
11
+ 🔄 **Sync** - Multi-instance coordination with intent broadcasting
12
+ 📚 **Knowledge** - Version-aware best practices and deprecation warnings
13
+ 🧬 **Codebase DNA** - Automatic detection of patterns, conventions, and architecture
14
+ ⚠️ **Error Learning** - Captures build errors and anti-patterns to avoid repeating mistakes
15
+
16
+ ## Quick Start
17
+
18
+ ### 1. Get an API Key
19
+
20
+ Sign up at [persista.dev](https://persista.dev) and create an API key from the dashboard.
21
+
22
+ ### 2. Add to Cursor
23
+
24
+ Add this to your `~/.cursor/mcp.json`:
25
+
26
+ ```json
27
+ {
28
+ "mcpServers": {
29
+ "persista": {
30
+ "command": "npx",
31
+ "args": ["-y", "@persistadev/mcp-server"],
32
+ "env": {
33
+ "PERSISTA_API_KEY": "pst_your_api_key_here"
34
+ }
35
+ }
36
+ }
37
+ }
38
+ ```
39
+
40
+ ### 3. Restart Cursor
41
+
42
+ That's it! Your AI now has persistent memory.
43
+
44
+ ## What It Does
45
+
46
+ Once installed, the AI can:
47
+
48
+ - **Remember** your preferences, coding style, and project decisions
49
+ - **Detect** your codebase patterns and conventions automatically
50
+ - **Learn** from errors to avoid making the same mistakes
51
+ - **Track** git changes between sessions
52
+ - **Coordinate** with other AI instances working on the same project
53
+
54
+ ## Environment Variables
55
+
56
+ | Variable | Required | Description |
57
+ |----------|----------|-------------|
58
+ | `PERSISTA_API_KEY` | Yes | Your API key from persista.dev |
59
+ | `PERSISTA_API_URL` | No | Custom API URL (defaults to api.persista.dev) |
60
+ | `PERSISTA_USER_ID` | No | Custom user ID (defaults to system username) |
61
+ | `PERSISTA_PROJECT_DIR` | No | Override project directory detection |
62
+
63
+ ## Available Tools
64
+
65
+ The MCP server provides these tools to the AI:
66
+
67
+ ### Memory
68
+ - `memory_save` - Save memories with confidence decay and code attachment
69
+ - `memory_get` - Retrieve all memories with effective confidence scores
70
+ - `memory_search` - Semantic search through memories
71
+ - `memory_for_file` - Get memories attached to specific files
72
+
73
+ ### Context
74
+ - `context_pack` - Smart context packing within token budget
75
+ - `context_relevant` - Get most relevant context for conversation
76
+ - `context_thread_create` - Create conversation threads
77
+ - `context_summary_save` - Save conversation summaries
78
+
79
+ ### Sync
80
+ - `sync_discover` - Find other AI instances on this project
81
+ - `sync_intent` - Broadcast editing intent to prevent conflicts
82
+ - `sync_check_conflicts` - Check for conflicting edits
83
+
84
+ ### Knowledge
85
+ - `knowledge_check` - Version-aware best practices
86
+ - `knowledge_deprecations` - Get deprecation warnings
87
+ - `knowledge_scan_code` - Scan code for deprecated patterns
88
+ - `knowledge_learn_pattern` - Learn custom patterns
89
+
90
+ ### DNA (Codebase Analysis)
91
+ - `dna_analyze` - Deep codebase analysis
92
+ - `dna_conventions` - Get coding conventions
93
+ - `dna_patterns` - Get detected patterns
94
+ - `dna_architecture` - Get architecture info
95
+ - `dna_add_decision` - Record tech decisions
96
+ - `dna_mark_critical` - Mark critical paths
97
+
98
+ ### Error Learning
99
+ - `error_capture` - Capture errors for learning
100
+ - `error_patterns` - Get known error patterns
101
+
102
+ ### Session
103
+ - `session_refresh` - Reload session context
104
+ - `session_summary` - Get full session summary
105
+
106
+ ## Resources
107
+
108
+ The MCP server also provides these auto-injected resources:
109
+
110
+ - `persista://session/context` - Full session context (memory, git, DNA)
111
+ - `persista://user/memory` - All user memories
112
+ - `persista://codebase/dna` - Basic codebase analysis
113
+ - `persista://codebase/dna-deep` - Deep codebase DNA
114
+ - `persista://git/changes` - Git changes since last session
115
+ - `persista://knowledge/relevant` - Relevant best practices
116
+ - `persista://errors/learned` - Learned error patterns
117
+
118
+ ## Links
119
+
120
+ - **Website**: [persista.dev](https://persista.dev)
121
+ - **Dashboard**: [persista.dev/dashboard](https://persista.dev/dashboard)
122
+ - **Docs**: [persista.dev/docs](https://persista.dev/docs)
123
+
124
+ ## License
125
+
126
+ MIT
@@ -0,0 +1,307 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Persista MCP Server - Direct Supabase Version
5
+ * Connects directly to Supabase instead of Edge Functions
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
9
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
10
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
11
+ const supabase_js_1 = require("@supabase/supabase-js");
12
+ // Config from environment
13
+ const SUPABASE_URL = process.env.SUPABASE_URL;
14
+ const SUPABASE_KEY = process.env.SUPABASE_KEY; // anon key
15
+ const API_KEY = process.env.PERSISTA_API_KEY;
16
+ const USER_ID = process.env.PERSISTA_USER_ID || 'default';
17
+ if (!SUPABASE_URL || !SUPABASE_KEY) {
18
+ console.error('Error: SUPABASE_URL and SUPABASE_KEY environment variables are required');
19
+ process.exit(1);
20
+ }
21
+ if (!API_KEY) {
22
+ console.error('Error: PERSISTA_API_KEY environment variable is required');
23
+ process.exit(1);
24
+ }
25
+ const supabase = (0, supabase_js_1.createClient)(SUPABASE_URL, SUPABASE_KEY);
26
+ // Get app_id from API key
27
+ async function getAppId() {
28
+ const encoder = new TextEncoder();
29
+ const data = encoder.encode(API_KEY);
30
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
31
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
32
+ const apiKeyHash = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
33
+ const { data: app } = await supabase
34
+ .from('apps')
35
+ .select('id')
36
+ .eq('api_key_hash', apiKeyHash)
37
+ .single();
38
+ return app?.id || null;
39
+ }
40
+ // Get or create user
41
+ async function getOrCreateUser(externalId) {
42
+ // Try to find existing user
43
+ const { data: existing } = await supabase
44
+ .from('users')
45
+ .select('id')
46
+ .eq('external_id', externalId)
47
+ .single();
48
+ if (existing)
49
+ return existing.id;
50
+ // Create new user
51
+ const { data: newUser } = await supabase
52
+ .from('users')
53
+ .insert({ external_id: externalId })
54
+ .select('id')
55
+ .single();
56
+ return newUser?.id || null;
57
+ }
58
+ // Create MCP server
59
+ const server = new index_js_1.Server({ name: 'persista', version: '0.1.0' }, { capabilities: { tools: {} } });
60
+ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
61
+ return {
62
+ tools: [
63
+ {
64
+ name: 'memory_save',
65
+ description: 'Save something about the user to persistent memory. Use this when you learn preferences, facts, decisions, or behaviors.',
66
+ inputSchema: {
67
+ type: 'object',
68
+ properties: {
69
+ category: {
70
+ type: 'string',
71
+ enum: ['preference', 'fact', 'project', 'behavior', 'custom'],
72
+ description: 'Category: preference, fact, project, behavior, or custom'
73
+ },
74
+ key: {
75
+ type: 'string',
76
+ description: 'Unique identifier like "coding_style" or "timezone"'
77
+ },
78
+ value: {
79
+ description: 'The data to store (any JSON)'
80
+ }
81
+ },
82
+ required: ['category', 'key', 'value']
83
+ }
84
+ },
85
+ {
86
+ name: 'memory_get',
87
+ description: 'Get all memories about the user. Use at the start of conversations for context.',
88
+ inputSchema: { type: 'object', properties: {} }
89
+ },
90
+ {
91
+ name: 'memory_forget',
92
+ description: 'Delete a specific memory by key.',
93
+ inputSchema: {
94
+ type: 'object',
95
+ properties: {
96
+ key: { type: 'string', description: 'The key to delete' }
97
+ },
98
+ required: ['key']
99
+ }
100
+ },
101
+ {
102
+ name: 'project_save',
103
+ description: 'Save or update information about a project the user is working on.',
104
+ inputSchema: {
105
+ type: 'object',
106
+ properties: {
107
+ name: { type: 'string', description: 'Project name' },
108
+ description: { type: 'string', description: 'What the project is about' },
109
+ tech_stack: {
110
+ type: 'array',
111
+ items: { type: 'string' },
112
+ description: 'Technologies used'
113
+ },
114
+ current_tasks: {
115
+ type: 'array',
116
+ items: { type: 'string' },
117
+ description: 'Current tasks or todos'
118
+ }
119
+ },
120
+ required: ['name']
121
+ }
122
+ },
123
+ {
124
+ name: 'project_get',
125
+ description: 'Get the current active project.',
126
+ inputSchema: { type: 'object', properties: {} }
127
+ },
128
+ {
129
+ name: 'history_save',
130
+ description: 'Save a summary of the current conversation for future reference.',
131
+ inputSchema: {
132
+ type: 'object',
133
+ properties: {
134
+ summary: { type: 'string', description: 'Summary of what was discussed' },
135
+ key_points: {
136
+ type: 'array',
137
+ items: { type: 'string' },
138
+ description: 'Key points from the conversation'
139
+ },
140
+ decisions: {
141
+ type: 'array',
142
+ items: { type: 'string' },
143
+ description: 'Decisions that were made'
144
+ }
145
+ },
146
+ required: ['summary']
147
+ }
148
+ }
149
+ ]
150
+ };
151
+ });
152
+ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
153
+ const { name, arguments: args } = request.params;
154
+ try {
155
+ const appId = await getAppId();
156
+ if (!appId) {
157
+ return { content: [{ type: 'text', text: 'Error: Invalid API key' }], isError: true };
158
+ }
159
+ const userId = await getOrCreateUser(USER_ID);
160
+ if (!userId) {
161
+ return { content: [{ type: 'text', text: 'Error: Could not get/create user' }], isError: true };
162
+ }
163
+ switch (name) {
164
+ case 'memory_save': {
165
+ const { category, key, value } = args;
166
+ // Upsert context
167
+ const { data, error } = await supabase
168
+ .from('user_context')
169
+ .upsert({
170
+ user_id: userId,
171
+ app_id: appId,
172
+ category,
173
+ key,
174
+ value,
175
+ source: 'explicit',
176
+ confidence: 1.0
177
+ }, {
178
+ onConflict: 'user_id,app_id,category,key'
179
+ })
180
+ .select()
181
+ .single();
182
+ if (error)
183
+ throw error;
184
+ return { content: [{ type: 'text', text: `✅ Saved: ${category}/${key}` }] };
185
+ }
186
+ case 'memory_get': {
187
+ const { data, error } = await supabase
188
+ .from('user_context')
189
+ .select('category, key, value')
190
+ .eq('user_id', userId)
191
+ .eq('app_id', appId);
192
+ if (error)
193
+ throw error;
194
+ // Group by category
195
+ const grouped = {};
196
+ for (const item of data || []) {
197
+ if (!grouped[item.category])
198
+ grouped[item.category] = {};
199
+ grouped[item.category][item.key] = item.value;
200
+ }
201
+ return { content: [{ type: 'text', text: JSON.stringify(grouped, null, 2) }] };
202
+ }
203
+ case 'memory_forget': {
204
+ const { key } = args;
205
+ const { error } = await supabase
206
+ .from('user_context')
207
+ .delete()
208
+ .eq('user_id', userId)
209
+ .eq('app_id', appId)
210
+ .eq('key', key);
211
+ if (error)
212
+ throw error;
213
+ return { content: [{ type: 'text', text: `✅ Deleted: ${key}` }] };
214
+ }
215
+ case 'project_save': {
216
+ const { name: projName, description, tech_stack, current_tasks } = args;
217
+ // Check if project exists
218
+ const { data: existing } = await supabase
219
+ .from('projects')
220
+ .select('id')
221
+ .eq('user_id', userId)
222
+ .eq('app_id', appId)
223
+ .eq('name', projName)
224
+ .single();
225
+ if (existing) {
226
+ // Update
227
+ const { error } = await supabase
228
+ .from('projects')
229
+ .update({
230
+ description,
231
+ tech_stack,
232
+ current_tasks,
233
+ last_active_at: new Date().toISOString()
234
+ })
235
+ .eq('id', existing.id);
236
+ if (error)
237
+ throw error;
238
+ return { content: [{ type: 'text', text: `✅ Updated project: ${projName}` }] };
239
+ }
240
+ else {
241
+ // Create
242
+ const { error } = await supabase
243
+ .from('projects')
244
+ .insert({
245
+ user_id: userId,
246
+ app_id: appId,
247
+ name: projName,
248
+ description,
249
+ tech_stack: tech_stack || [],
250
+ current_tasks: current_tasks || [],
251
+ status: 'active'
252
+ });
253
+ if (error)
254
+ throw error;
255
+ return { content: [{ type: 'text', text: `✅ Created project: ${projName}` }] };
256
+ }
257
+ }
258
+ case 'project_get': {
259
+ const { data, error } = await supabase
260
+ .from('projects')
261
+ .select('*')
262
+ .eq('user_id', userId)
263
+ .eq('app_id', appId)
264
+ .eq('status', 'active')
265
+ .order('last_active_at', { ascending: false })
266
+ .limit(1)
267
+ .single();
268
+ if (error && error.code !== 'PGRST116')
269
+ throw error;
270
+ if (!data) {
271
+ return { content: [{ type: 'text', text: 'No active project found.' }] };
272
+ }
273
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
274
+ }
275
+ case 'history_save': {
276
+ const { summary, key_points, decisions } = args;
277
+ const { error } = await supabase
278
+ .from('conversation_summaries')
279
+ .insert({
280
+ user_id: userId,
281
+ app_id: appId,
282
+ summary,
283
+ key_points: key_points || [],
284
+ decisions: decisions || []
285
+ });
286
+ if (error)
287
+ throw error;
288
+ return { content: [{ type: 'text', text: '✅ Conversation summary saved' }] };
289
+ }
290
+ default:
291
+ return { content: [{ type: 'text', text: `Unknown tool: ${name}` }], isError: true };
292
+ }
293
+ }
294
+ catch (error) {
295
+ const message = error instanceof Error ? error.message : 'Unknown error';
296
+ return { content: [{ type: 'text', text: `Error: ${message}` }], isError: true };
297
+ }
298
+ });
299
+ async function main() {
300
+ const transport = new stdio_js_1.StdioServerTransport();
301
+ await server.connect(transport);
302
+ console.error('Persista MCP server (direct) running');
303
+ }
304
+ main().catch((error) => {
305
+ console.error('Fatal error:', error);
306
+ process.exit(1);
307
+ });
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Persista MCP Server v3.0 - Complete AI Memory Infrastructure
4
+ *
5
+ * FEATURES:
6
+ * ═══════════════════════════════════════════════════════════════
7
+ *
8
+ * 🧠 MEMORY (v3)
9
+ * - Confidence decay over time
10
+ * - Semantic search
11
+ * - Auto-extraction from text
12
+ * - Code-attached memories
13
+ * - Memory history/versioning
14
+ * - Smart merge for conflicts
15
+ *
16
+ * 📝 CONTEXT (v3)
17
+ * - Relevance scoring
18
+ * - Smart context packing
19
+ * - Cross-session threading
20
+ * - Auto-compression
21
+ * - Milestone marking
22
+ *
23
+ * 🔄 SYNC (v3)
24
+ * - Intent broadcasting
25
+ * - Conflict detection
26
+ * - Auto-discovery
27
+ * - Cursor position sharing
28
+ *
29
+ * 📚 KNOWLEDGE (v3)
30
+ * - Version-aware queries
31
+ * - Deprecation scanning
32
+ * - User pattern learning
33
+ * - Migration guides
34
+ *
35
+ * 🚀 AUTO-HOOKS
36
+ * - Git tracking between sessions
37
+ * - Codebase analysis
38
+ * - Proactive context injection
39
+ * ═══════════════════════════════════════════════════════════════
40
+ */
41
+ export {};
42
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG"}