mcp-sqlite-memory-bank 1.5.1__py3-none-any.whl → 1.6.0__py3-none-any.whl
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.
- mcp_sqlite_memory_bank/__init__.py +2 -2
- mcp_sqlite_memory_bank/__main__.py +20 -11
- mcp_sqlite_memory_bank/database.py +234 -68
- mcp_sqlite_memory_bank/prompts.py +76 -52
- mcp_sqlite_memory_bank/resources.py +250 -150
- mcp_sqlite_memory_bank/semantic.py +50 -17
- mcp_sqlite_memory_bank/server.py +203 -31
- mcp_sqlite_memory_bank/tools/__init__.py +26 -29
- mcp_sqlite_memory_bank/tools/analytics.py +225 -139
- mcp_sqlite_memory_bank/tools/basic.py +417 -7
- mcp_sqlite_memory_bank/tools/discovery.py +636 -384
- mcp_sqlite_memory_bank/tools/search.py +159 -72
- mcp_sqlite_memory_bank/types.py +6 -1
- mcp_sqlite_memory_bank/utils.py +165 -107
- {mcp_sqlite_memory_bank-1.5.1.dist-info → mcp_sqlite_memory_bank-1.6.0.dist-info}/METADATA +54 -6
- mcp_sqlite_memory_bank-1.6.0.dist-info/RECORD +21 -0
- mcp_sqlite_memory_bank-1.5.1.dist-info/RECORD +0 -21
- {mcp_sqlite_memory_bank-1.5.1.dist-info → mcp_sqlite_memory_bank-1.6.0.dist-info}/WHEEL +0 -0
- {mcp_sqlite_memory_bank-1.5.1.dist-info → mcp_sqlite_memory_bank-1.6.0.dist-info}/entry_points.txt +0 -0
- {mcp_sqlite_memory_bank-1.5.1.dist-info → mcp_sqlite_memory_bank-1.6.0.dist-info}/licenses/LICENSE +0 -0
- {mcp_sqlite_memory_bank-1.5.1.dist-info → mcp_sqlite_memory_bank-1.6.0.dist-info}/top_level.txt +0 -0
@@ -19,26 +19,26 @@ import json
|
|
19
19
|
|
20
20
|
class MemoryBankPrompts:
|
21
21
|
"""Manages MCP Prompts for the SQLite Memory Bank."""
|
22
|
-
|
22
|
+
|
23
23
|
def __init__(self, mcp_app: FastMCP, db_path: str):
|
24
24
|
self.mcp = mcp_app
|
25
25
|
self.db_path = db_path
|
26
26
|
self._register_prompts()
|
27
|
-
|
27
|
+
|
28
28
|
def _register_prompts(self):
|
29
29
|
"""Register MCP prompts with the FastMCP app."""
|
30
|
-
|
30
|
+
|
31
31
|
@self.mcp.prompt("analyze-memory-content")
|
32
32
|
async def analyze_memory_content(table_name: Optional[str] = None) -> str:
|
33
33
|
"""Analyze memory bank content and provide insights."""
|
34
34
|
db = get_database(self.db_path)
|
35
|
-
|
35
|
+
|
36
36
|
if table_name:
|
37
37
|
# Analyze specific table
|
38
38
|
result = cast(Dict[str, Any], db.read_rows(table_name, {}))
|
39
39
|
if not result.get("success"):
|
40
40
|
return f"Error: Could not access table '{table_name}'. Please check if it exists."
|
41
|
-
|
41
|
+
|
42
42
|
rows = result.get("rows", [])
|
43
43
|
prompt = f"""Please analyze the content in the '{table_name}' table from the memory bank.
|
44
44
|
|
@@ -58,21 +58,23 @@ Focus on actionable insights that could help improve how this information is sto
|
|
58
58
|
tables_result = cast(Dict[str, Any], db.list_tables())
|
59
59
|
if not tables_result.get("success"):
|
60
60
|
return "Error: Could not access memory bank tables."
|
61
|
-
|
61
|
+
|
62
62
|
tables = tables_result.get("tables", [])
|
63
63
|
overview = {"tables": len(tables), "total_content": []}
|
64
|
-
|
64
|
+
|
65
65
|
for table in tables[:5]: # Limit to first 5 tables
|
66
66
|
rows_result = cast(Dict[str, Any], db.read_rows(table, {}))
|
67
67
|
if rows_result.get("success"):
|
68
68
|
rows = rows_result.get("rows", [])
|
69
69
|
total_content = cast(List[Any], overview["total_content"])
|
70
|
-
total_content.append(
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
70
|
+
total_content.append(
|
71
|
+
{
|
72
|
+
"table": table,
|
73
|
+
"rows": len(rows),
|
74
|
+
"sample": rows[:2] if rows else [],
|
75
|
+
}
|
76
|
+
)
|
77
|
+
|
76
78
|
prompt = f"""Please analyze the overall content in this memory bank.
|
77
79
|
|
78
80
|
Memory Bank Overview:
|
@@ -85,31 +87,41 @@ Please provide:
|
|
85
87
|
4. Suggestions for leveraging this content more effectively
|
86
88
|
|
87
89
|
Focus on high-level strategic insights about the memory bank's utility and organization."""
|
88
|
-
|
90
|
+
|
89
91
|
return prompt
|
90
|
-
|
92
|
+
|
91
93
|
@self.mcp.prompt("search-and-summarize")
|
92
|
-
async def search_and_summarize(
|
94
|
+
async def search_and_summarize(
|
95
|
+
query: str, max_results: Optional[int] = 10
|
96
|
+
) -> str:
|
93
97
|
"""Search memory content and create a summary prompt."""
|
94
98
|
db = get_database(self.db_path)
|
95
|
-
|
99
|
+
|
96
100
|
# Perform search
|
97
|
-
result = cast(
|
101
|
+
result = cast(
|
102
|
+
Dict[str, Any], db.search_content(query, None, max_results or 10)
|
103
|
+
)
|
98
104
|
if not result.get("success"):
|
99
105
|
return f"Error: Could not search for '{query}'. {result.get('error', 'Unknown error')}"
|
100
|
-
|
106
|
+
|
101
107
|
search_results = result.get("results", [])
|
102
108
|
if not search_results:
|
103
109
|
return f"No results found for query: '{query}'. Please try different search terms or check if relevant content exists in the memory bank."
|
104
|
-
|
110
|
+
|
105
111
|
# Format results for prompt
|
106
112
|
formatted_results = []
|
107
|
-
for i, result in enumerate(search_results[:max_results or 10], 1):
|
108
|
-
formatted_results.append(
|
109
|
-
|
110
|
-
|
113
|
+
for i, result in enumerate(search_results[: max_results or 10], 1):
|
114
|
+
formatted_results.append(
|
115
|
+
f"{i}. Table: {result.get('table', 'unknown')}"
|
116
|
+
)
|
117
|
+
formatted_results.append(
|
118
|
+
f" Content: {result.get('content', 'No content')[:200]}..."
|
119
|
+
)
|
120
|
+
formatted_results.append(
|
121
|
+
f" Relevance: {result.get('relevance', 'N/A')}"
|
122
|
+
)
|
111
123
|
formatted_results.append("")
|
112
|
-
|
124
|
+
|
113
125
|
prompt = f"""Based on the search query "{query}", here are the most relevant results from the memory bank:
|
114
126
|
|
115
127
|
Search Results:
|
@@ -122,19 +134,21 @@ Please provide:
|
|
122
134
|
4. Actionable insights based on this content
|
123
135
|
|
124
136
|
Use this information to provide a thorough, well-organized response that synthesizes the search results."""
|
125
|
-
|
137
|
+
|
126
138
|
return prompt
|
127
|
-
|
139
|
+
|
128
140
|
@self.mcp.prompt("technical-decision-analysis")
|
129
|
-
async def technical_decision_analysis(
|
141
|
+
async def technical_decision_analysis(
|
142
|
+
decision_topic: Optional[str] = None,
|
143
|
+
) -> str:
|
130
144
|
"""Analyze technical decisions from the memory bank."""
|
131
145
|
db = get_database(self.db_path)
|
132
|
-
|
146
|
+
|
133
147
|
# Try to find technical_decisions table
|
134
148
|
tables_result = cast(Dict[str, Any], db.list_tables())
|
135
149
|
if not tables_result.get("success"):
|
136
150
|
return "Error: Could not access memory bank."
|
137
|
-
|
151
|
+
|
138
152
|
tables = tables_result.get("tables", [])
|
139
153
|
if "technical_decisions" not in tables:
|
140
154
|
return """No technical decisions table found in the memory bank.
|
@@ -145,34 +159,44 @@ To use this prompt effectively, please:
|
|
145
159
|
3. Try this prompt again
|
146
160
|
|
147
161
|
The table should include fields like: decision_name, chosen_approach, rationale, alternatives, timestamp."""
|
148
|
-
|
162
|
+
|
149
163
|
# Get technical decisions
|
150
164
|
where_clause = {}
|
151
165
|
if decision_topic:
|
152
166
|
# This is a simplified search - in practice you'd want semantic search
|
153
167
|
where_clause = {"decision_name": decision_topic}
|
154
|
-
|
168
|
+
|
155
169
|
result = db.read_rows("technical_decisions", where_clause)
|
156
170
|
if not result.get("success"):
|
157
171
|
return "Error: Could not read technical decisions."
|
158
|
-
|
172
|
+
|
159
173
|
decisions = result.get("rows", [])
|
160
174
|
if not decisions:
|
161
175
|
topic_msg = f" related to '{decision_topic}'" if decision_topic else ""
|
162
176
|
return f"No technical decisions found{topic_msg}. Consider adding some decisions to the memory bank first."
|
163
|
-
|
177
|
+
|
164
178
|
# Format decisions for analysis
|
165
179
|
formatted_decisions = []
|
166
180
|
decisions_list = cast(List[Dict[str, Any]], decisions)
|
167
181
|
for i, decision in enumerate(decisions_list, 1):
|
168
|
-
formatted_decisions.append(
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
182
|
+
formatted_decisions.append(
|
183
|
+
f"{i}. Decision: {decision.get('decision_name', 'Unknown')}"
|
184
|
+
)
|
185
|
+
formatted_decisions.append(
|
186
|
+
f" Approach: {decision.get('chosen_approach', 'Not specified')}"
|
187
|
+
)
|
188
|
+
formatted_decisions.append(
|
189
|
+
f" Rationale: {decision.get('rationale', 'Not provided')}"
|
190
|
+
)
|
191
|
+
if decision.get("alternatives"):
|
192
|
+
formatted_decisions.append(
|
193
|
+
f" Alternatives: {decision.get('alternatives')}"
|
194
|
+
)
|
195
|
+
formatted_decisions.append(
|
196
|
+
f" Date: {decision.get('timestamp', 'Unknown')}"
|
197
|
+
)
|
174
198
|
formatted_decisions.append("")
|
175
|
-
|
199
|
+
|
176
200
|
prompt = f"""Please analyze these technical decisions from the memory bank:
|
177
201
|
|
178
202
|
Technical Decisions{f" (filtered by: {decision_topic})" if decision_topic else ""}:
|
@@ -186,19 +210,19 @@ Please provide:
|
|
186
210
|
5. Suggestions for improving decision documentation
|
187
211
|
|
188
212
|
Focus on actionable insights that can improve technical decision-making processes."""
|
189
|
-
|
213
|
+
|
190
214
|
return prompt
|
191
|
-
|
215
|
+
|
192
216
|
@self.mcp.prompt("memory-bank-context")
|
193
217
|
async def memory_bank_context(context_type: str = "full") -> str:
|
194
218
|
"""Provide memory bank context for AI conversations."""
|
195
219
|
db = get_database(self.db_path)
|
196
|
-
|
220
|
+
|
197
221
|
# Get overview
|
198
222
|
tables_result = db.list_tables()
|
199
223
|
if not tables_result.get("success"):
|
200
224
|
return "Error: Could not access memory bank for context."
|
201
|
-
|
225
|
+
|
202
226
|
tables = tables_result.get("tables", [])
|
203
227
|
context_info = {
|
204
228
|
"available_tables": tables,
|
@@ -206,16 +230,16 @@ Focus on actionable insights that can improve technical decision-making processe
|
|
206
230
|
"Full-text search across all content",
|
207
231
|
"Semantic search (if embeddings are available)",
|
208
232
|
"Structured data queries",
|
209
|
-
"Content analytics and insights"
|
233
|
+
"Content analytics and insights",
|
210
234
|
],
|
211
235
|
"usage_suggestions": [
|
212
236
|
"Use search_content() for finding specific information",
|
213
237
|
"Use semantic_search() for conceptual queries",
|
214
238
|
"Use read_rows() for structured data access",
|
215
|
-
"Use explore_tables() to discover available content"
|
216
|
-
]
|
239
|
+
"Use explore_tables() to discover available content",
|
240
|
+
],
|
217
241
|
}
|
218
|
-
|
242
|
+
|
219
243
|
if context_type == "brief":
|
220
244
|
tables_list = cast(List[str], tables)
|
221
245
|
prompt = f"""Memory Bank Context (Brief):
|
@@ -234,11 +258,11 @@ This memory bank contains structured information that can be searched and analyz
|
|
234
258
|
rows = cast(List[Any], result.get("rows", []))
|
235
259
|
sample_content[table] = {
|
236
260
|
"row_count": len(rows),
|
237
|
-
"sample_row": rows[0] if rows else None
|
261
|
+
"sample_row": rows[0] if rows else None,
|
238
262
|
}
|
239
263
|
except Exception:
|
240
264
|
continue
|
241
|
-
|
265
|
+
|
242
266
|
prompt = f"""Memory Bank Context (Full):
|
243
267
|
|
244
268
|
{json.dumps(context_info, indent=2)}
|
@@ -247,7 +271,7 @@ Sample Content:
|
|
247
271
|
{json.dumps(sample_content, indent=2)}
|
248
272
|
|
249
273
|
This memory bank contains structured information that can be searched, analyzed, and leveraged for various tasks. The content is organized in tables with different types of information. Use the available search and query tools to access specific content as needed for your current task."""
|
250
|
-
|
274
|
+
|
251
275
|
return prompt
|
252
276
|
|
253
277
|
|