99import json
1010
1111
12- def _patch_mcp_server (monkeypatch , config , palace_path , kg ):
12+ def _patch_mcp_server (monkeypatch , config , kg ):
1313 """Patch the mcp_server module globals to use test fixtures."""
1414 from mempalace import mcp_server
1515
16- assert getattr (config , "palace_path" , None ) == palace_path , (
17- f"config.palace_path ({ getattr (config , 'palace_path' , None )!r} ) does not match palace_path fixture ({ palace_path !r} )"
18- )
1916 monkeypatch .setattr (mcp_server , "_config" , config )
2017 monkeypatch .setattr (mcp_server , "_kg" , kg )
2118
2219
2320def _get_collection (palace_path , create = False ):
24- """Helper to get collection from test palace."""
21+ """Helper to get collection from test palace.
22+
23+ Returns (client, collection) so callers can clean up the client
24+ when they are done.
25+ """
2526 import chromadb
2627
2728 client = chromadb .PersistentClient (path = palace_path )
2829 if create :
29- return client .get_or_create_collection ("mempalace_drawers" )
30- return client .get_collection ("mempalace_drawers" )
30+ return client , client .get_or_create_collection ("mempalace_drawers" )
31+ return client , client .get_collection ("mempalace_drawers" )
3132
3233
3334# ── Protocol Layer ──────────────────────────────────────────────────────
@@ -77,11 +78,11 @@ def test_unknown_method(self):
7778 assert resp ["error" ]["code" ] == - 32601
7879
7980 def test_tools_call_dispatches (self , monkeypatch , config , palace_path , seeded_kg ):
80- _patch_mcp_server (monkeypatch , config , palace_path , seeded_kg )
81+ _patch_mcp_server (monkeypatch , config , seeded_kg )
8182 from mempalace .mcp_server import handle_request
8283
8384 # Create a collection so status works
84- _get_collection (palace_path , create = True )
85+ _client , _col = _get_collection (palace_path , create = True ); del _client
8586
8687 resp = handle_request (
8788 {
@@ -100,16 +101,16 @@ def test_tools_call_dispatches(self, monkeypatch, config, palace_path, seeded_kg
100101
101102class TestReadTools :
102103 def test_status_empty_palace (self , monkeypatch , config , palace_path , kg ):
103- _patch_mcp_server (monkeypatch , config , palace_path , kg )
104- _get_collection (palace_path , create = True )
104+ _patch_mcp_server (monkeypatch , config , kg )
105+ _client , _col = _get_collection (palace_path , create = True ); del _client
105106 from mempalace .mcp_server import tool_status
106107
107108 result = tool_status ()
108109 assert result ["total_drawers" ] == 0
109110 assert result ["wings" ] == {}
110111
111112 def test_status_with_data (self , monkeypatch , config , palace_path , seeded_collection , kg ):
112- _patch_mcp_server (monkeypatch , config , palace_path , kg )
113+ _patch_mcp_server (monkeypatch , config , kg )
113114 from mempalace .mcp_server import tool_status
114115
115116 result = tool_status ()
@@ -118,15 +119,15 @@ def test_status_with_data(self, monkeypatch, config, palace_path, seeded_collect
118119 assert "notes" in result ["wings" ]
119120
120121 def test_list_wings (self , monkeypatch , config , palace_path , seeded_collection , kg ):
121- _patch_mcp_server (monkeypatch , config , palace_path , kg )
122+ _patch_mcp_server (monkeypatch , config , kg )
122123 from mempalace .mcp_server import tool_list_wings
123124
124125 result = tool_list_wings ()
125126 assert result ["wings" ]["project" ] == 3
126127 assert result ["wings" ]["notes" ] == 1
127128
128129 def test_list_rooms_all (self , monkeypatch , config , palace_path , seeded_collection , kg ):
129- _patch_mcp_server (monkeypatch , config , palace_path , kg )
130+ _patch_mcp_server (monkeypatch , config , kg )
130131 from mempalace .mcp_server import tool_list_rooms
131132
132133 result = tool_list_rooms ()
@@ -135,26 +136,24 @@ def test_list_rooms_all(self, monkeypatch, config, palace_path, seeded_collectio
135136 assert "planning" in result ["rooms" ]
136137
137138 def test_list_rooms_filtered (self , monkeypatch , config , palace_path , seeded_collection , kg ):
138- _patch_mcp_server (monkeypatch , config , palace_path , kg )
139+ _patch_mcp_server (monkeypatch , config , kg )
139140 from mempalace .mcp_server import tool_list_rooms
140141
141142 result = tool_list_rooms (wing = "project" )
142143 assert "backend" in result ["rooms" ]
143144 assert "planning" not in result ["rooms" ]
144145
145146 def test_get_taxonomy (self , monkeypatch , config , palace_path , seeded_collection , kg ):
146- _patch_mcp_server (monkeypatch , config , palace_path , kg )
147+ _patch_mcp_server (monkeypatch , config , kg )
147148 from mempalace .mcp_server import tool_get_taxonomy
148149
149150 result = tool_get_taxonomy ()
150151 assert result ["taxonomy" ]["project" ]["backend" ] == 2
151152 assert result ["taxonomy" ]["project" ]["frontend" ] == 1
152153 assert result ["taxonomy" ]["notes" ]["planning" ] == 1
153154
154- def test_no_palace_returns_error (self , monkeypatch , config , kg , tmp_path ):
155- missing = str (tmp_path / "missing" )
156- config ._file_config ["palace_path" ] = missing
157- _patch_mcp_server (monkeypatch , config , missing , kg )
155+ def test_no_palace_returns_error (self , monkeypatch , config , kg ):
156+ _patch_mcp_server (monkeypatch , config , kg )
158157 from mempalace .mcp_server import tool_status
159158
160159 result = tool_status ()
@@ -166,7 +165,7 @@ def test_no_palace_returns_error(self, monkeypatch, config, kg, tmp_path):
166165
167166class TestSearchTool :
168167 def test_search_basic (self , monkeypatch , config , palace_path , seeded_collection , kg ):
169- _patch_mcp_server (monkeypatch , config , palace_path , kg )
168+ _patch_mcp_server (monkeypatch , config , kg )
170169 from mempalace .mcp_server import tool_search
171170
172171 result = tool_search (query = "JWT authentication tokens" )
@@ -177,14 +176,14 @@ def test_search_basic(self, monkeypatch, config, palace_path, seeded_collection,
177176 assert "JWT" in top ["text" ] or "authentication" in top ["text" ].lower ()
178177
179178 def test_search_with_wing_filter (self , monkeypatch , config , palace_path , seeded_collection , kg ):
180- _patch_mcp_server (monkeypatch , config , palace_path , kg )
179+ _patch_mcp_server (monkeypatch , config , kg )
181180 from mempalace .mcp_server import tool_search
182181
183182 result = tool_search (query = "planning" , wing = "notes" )
184183 assert all (r ["wing" ] == "notes" for r in result ["results" ])
185184
186185 def test_search_with_room_filter (self , monkeypatch , config , palace_path , seeded_collection , kg ):
187- _patch_mcp_server (monkeypatch , config , palace_path , kg )
186+ _patch_mcp_server (monkeypatch , config , kg )
188187 from mempalace .mcp_server import tool_search
189188
190189 result = tool_search (query = "database" , room = "backend" )
@@ -196,8 +195,8 @@ def test_search_with_room_filter(self, monkeypatch, config, palace_path, seeded_
196195
197196class TestWriteTools :
198197 def test_add_drawer (self , monkeypatch , config , palace_path , kg ):
199- _patch_mcp_server (monkeypatch , config , palace_path , kg )
200- _get_collection (palace_path , create = True )
198+ _patch_mcp_server (monkeypatch , config , kg )
199+ _client , _col = _get_collection (palace_path , create = True ); del _client
201200 from mempalace .mcp_server import tool_add_drawer
202201
203202 result = tool_add_drawer (
@@ -211,35 +210,35 @@ def test_add_drawer(self, monkeypatch, config, palace_path, kg):
211210 assert result ["drawer_id" ].startswith ("drawer_test_wing_test_room_" )
212211
213212 def test_add_drawer_duplicate_detection (self , monkeypatch , config , palace_path , kg ):
214- _patch_mcp_server (monkeypatch , config , palace_path , kg )
215- _get_collection (palace_path , create = True )
213+ _patch_mcp_server (monkeypatch , config , kg )
214+ _client , _col = _get_collection (palace_path , create = True ); del _client
216215 from mempalace .mcp_server import tool_add_drawer
217216
218217 content = "This is a unique test memory about Rust ownership and borrowing."
219218 result1 = tool_add_drawer (wing = "w" , room = "r" , content = content )
220219 assert result1 ["success" ] is True
221220
222221 result2 = tool_add_drawer (wing = "w" , room = "r" , content = content )
223- assert result2 ["success" ] is False
224- assert result2 ["reason" ] == "duplicate "
222+ assert result2 ["success" ] is True
223+ assert result2 ["reason" ] == "already_exists "
225224
226225 def test_delete_drawer (self , monkeypatch , config , palace_path , seeded_collection , kg ):
227- _patch_mcp_server (monkeypatch , config , palace_path , kg )
226+ _patch_mcp_server (monkeypatch , config , kg )
228227 from mempalace .mcp_server import tool_delete_drawer
229228
230229 result = tool_delete_drawer ("drawer_proj_backend_aaa" )
231230 assert result ["success" ] is True
232231 assert seeded_collection .count () == 3
233232
234233 def test_delete_drawer_not_found (self , monkeypatch , config , palace_path , seeded_collection , kg ):
235- _patch_mcp_server (monkeypatch , config , palace_path , kg )
234+ _patch_mcp_server (monkeypatch , config , kg )
236235 from mempalace .mcp_server import tool_delete_drawer
237236
238237 result = tool_delete_drawer ("nonexistent_drawer" )
239238 assert result ["success" ] is False
240239
241240 def test_check_duplicate (self , monkeypatch , config , palace_path , seeded_collection , kg ):
242- _patch_mcp_server (monkeypatch , config , palace_path , kg )
241+ _patch_mcp_server (monkeypatch , config , kg )
243242 from mempalace .mcp_server import tool_check_duplicate
244243
245244 # Exact match text from seeded_collection should be flagged
@@ -263,7 +262,7 @@ def test_check_duplicate(self, monkeypatch, config, palace_path, seeded_collecti
263262
264263class TestKGTools :
265264 def test_kg_add (self , monkeypatch , config , palace_path , kg ):
266- _patch_mcp_server (monkeypatch , config , palace_path , kg )
265+ _patch_mcp_server (monkeypatch , config , kg )
267266 from mempalace .mcp_server import tool_kg_add
268267
269268 result = tool_kg_add (
@@ -275,14 +274,14 @@ def test_kg_add(self, monkeypatch, config, palace_path, kg):
275274 assert result ["success" ] is True
276275
277276 def test_kg_query (self , monkeypatch , config , palace_path , seeded_kg ):
278- _patch_mcp_server (monkeypatch , config , palace_path , seeded_kg )
277+ _patch_mcp_server (monkeypatch , config , seeded_kg )
279278 from mempalace .mcp_server import tool_kg_query
280279
281280 result = tool_kg_query (entity = "Max" )
282281 assert result ["count" ] > 0
283282
284283 def test_kg_invalidate (self , monkeypatch , config , palace_path , seeded_kg ):
285- _patch_mcp_server (monkeypatch , config , palace_path , seeded_kg )
284+ _patch_mcp_server (monkeypatch , config , seeded_kg )
286285 from mempalace .mcp_server import tool_kg_invalidate
287286
288287 result = tool_kg_invalidate (
@@ -294,14 +293,14 @@ def test_kg_invalidate(self, monkeypatch, config, palace_path, seeded_kg):
294293 assert result ["success" ] is True
295294
296295 def test_kg_timeline (self , monkeypatch , config , palace_path , seeded_kg ):
297- _patch_mcp_server (monkeypatch , config , palace_path , seeded_kg )
296+ _patch_mcp_server (monkeypatch , config , seeded_kg )
298297 from mempalace .mcp_server import tool_kg_timeline
299298
300299 result = tool_kg_timeline (entity = "Alice" )
301300 assert result ["count" ] > 0
302301
303302 def test_kg_stats (self , monkeypatch , config , palace_path , seeded_kg ):
304- _patch_mcp_server (monkeypatch , config , palace_path , seeded_kg )
303+ _patch_mcp_server (monkeypatch , config , seeded_kg )
305304 from mempalace .mcp_server import tool_kg_stats
306305
307306 result = tool_kg_stats ()
@@ -313,8 +312,8 @@ def test_kg_stats(self, monkeypatch, config, palace_path, seeded_kg):
313312
314313class TestDiaryTools :
315314 def test_diary_write_and_read (self , monkeypatch , config , palace_path , kg ):
316- _patch_mcp_server (monkeypatch , config , palace_path , kg )
317- _get_collection (palace_path , create = True )
315+ _patch_mcp_server (monkeypatch , config , kg )
316+ _client , _col = _get_collection (palace_path , create = True ); del _client
318317 from mempalace .mcp_server import tool_diary_write , tool_diary_read
319318
320319 w = tool_diary_write (
@@ -331,8 +330,8 @@ def test_diary_write_and_read(self, monkeypatch, config, palace_path, kg):
331330 assert "authentication" in r ["entries" ][0 ]["content" ]
332331
333332 def test_diary_read_empty (self , monkeypatch , config , palace_path , kg ):
334- _patch_mcp_server (monkeypatch , config , palace_path , kg )
335- _get_collection (palace_path , create = True )
333+ _patch_mcp_server (monkeypatch , config , kg )
334+ _client , _col = _get_collection (palace_path , create = True ); del _client
336335 from mempalace .mcp_server import tool_diary_read
337336
338337 r = tool_diary_read (agent_name = "Nobody" )
0 commit comments