Skip to content

Commit f5455b0

Browse files
authored
Merge pull request #34 from meilisearch/fix/issue-16-get-documents-json-only
Fix get-documents to return JSON instead of Python objects
2 parents 9016948 + 270c2c5 commit f5455b0

File tree

3 files changed

+111
-6
lines changed

3 files changed

+111
-6
lines changed

src/meilisearch_mcp/documents.py

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,43 @@ async def get_documents(
1818
"""Get documents from an index"""
1919
try:
2020
index = self.client.index(index_uid)
21-
return index.get_documents(
22-
{"offset": offset, "limit": limit, "fields": fields}
23-
)
21+
# Build parameters dict, excluding None values to avoid API errors
22+
params = {}
23+
if offset is not None:
24+
params["offset"] = offset
25+
if limit is not None:
26+
params["limit"] = limit
27+
if fields is not None:
28+
params["fields"] = fields
29+
30+
result = index.get_documents(params if params else {})
31+
32+
# Convert meilisearch model objects to JSON-serializable format
33+
if hasattr(result, '__dict__'):
34+
result_dict = result.__dict__.copy()
35+
# Convert individual document objects in results if they exist
36+
if 'results' in result_dict and isinstance(result_dict['results'], list):
37+
serialized_results = []
38+
for doc in result_dict['results']:
39+
if hasattr(doc, '__dict__'):
40+
# Extract the actual document data
41+
doc_dict = doc.__dict__.copy()
42+
# Look for private attributes that might contain the actual data
43+
for key, value in doc_dict.items():
44+
if key.startswith('_') and isinstance(value, dict):
45+
# Use the dict content instead of the wrapper
46+
serialized_results.append(value)
47+
break
48+
else:
49+
# If no private dict found, use the object dict directly
50+
serialized_results.append(doc_dict)
51+
else:
52+
serialized_results.append(doc)
53+
result_dict['results'] = serialized_results
54+
return result_dict
55+
else:
56+
return result
57+
2458
except Exception as e:
2559
raise Exception(f"Failed to get documents: {str(e)}")
2660

src/meilisearch_mcp/server.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ def json_serializer(obj: Any) -> str:
1818
"""Custom JSON serializer for objects not serializable by default json code"""
1919
if isinstance(obj, datetime):
2020
return obj.isoformat()
21+
# Handle Meilisearch model objects by using their __dict__ if available
22+
if hasattr(obj, '__dict__'):
23+
return obj.__dict__
2124
return str(obj)
2225

2326

@@ -318,13 +321,18 @@ async def handle_call_tool(
318321
]
319322

320323
elif name == "get-documents":
324+
# Use default values to fix None parameter issues (related to issue #17)
325+
offset = arguments.get("offset", 0)
326+
limit = arguments.get("limit", 20)
321327
documents = await self.meili_client.documents.get_documents(
322328
arguments["indexUid"],
323-
arguments.get("offset"),
324-
arguments.get("limit"),
329+
offset,
330+
limit,
325331
)
332+
# Convert DocumentsResults object to proper JSON format (fixes issue #16)
333+
formatted_json = json.dumps(documents, indent=2, default=json_serializer)
326334
return [
327-
types.TextContent(type="text", text=f"Documents: {documents}")
335+
types.TextContent(type="text", text=f"Documents:\n{formatted_json}")
328336
]
329337

330338
elif name == "add-documents":

tests/test_mcp_client.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,69 @@ async def test_get_connection_settings_format(self, server):
303303
assert "********" in text or "Not set" in text
304304
else:
305305
assert "Not set" in text
306+
307+
308+
class TestIssue16GetDocumentsJsonSerialization:
309+
"""Test for issue #16 - get-documents should return JSON, not Python object representations"""
310+
311+
@pytest.fixture
312+
async def server(self):
313+
"""Create server instance for issue #16 tests"""
314+
url = os.getenv("MEILI_HTTP_ADDR", "http://localhost:7700")
315+
api_key = os.getenv("MEILI_MASTER_KEY")
316+
server = create_server(url, api_key)
317+
yield server
318+
await server.cleanup()
319+
320+
async def test_get_documents_returns_json_not_python_object(self, server):
321+
"""Test that get-documents returns JSON-formatted text, not Python object string representation (issue #16)"""
322+
import time
323+
test_index = f"test_issue16_{int(time.time() * 1000)}"
324+
325+
# Create index and add a test document
326+
await simulate_mcp_call(server, "create-index", {"uid": test_index})
327+
328+
test_document = {"id": 1, "title": "Test Document", "content": "Test content"}
329+
await simulate_mcp_call(server, "add-documents", {
330+
"indexUid": test_index,
331+
"documents": [test_document]
332+
})
333+
334+
# Wait for indexing
335+
import asyncio
336+
await asyncio.sleep(0.5)
337+
338+
# Get documents with explicit parameters
339+
result = await simulate_mcp_call(server, "get-documents", {
340+
"indexUid": test_index,
341+
"offset": 0,
342+
"limit": 10
343+
})
344+
345+
assert len(result) == 1
346+
assert result[0].type == "text"
347+
348+
response_text = result[0].text
349+
350+
# Issue #16 assertion: Should NOT contain Python object representation
351+
assert "<meilisearch.models.document.DocumentsResults object at" not in response_text
352+
assert "DocumentsResults" not in response_text
353+
354+
# Should contain proper JSON structure
355+
assert "Documents:" in response_text
356+
assert "Test Document" in response_text # Actual document content should be accessible
357+
assert "Test content" in response_text
358+
359+
# Should be valid JSON after the "Documents:" prefix
360+
json_part = response_text.replace("Documents:", "").strip()
361+
import json
362+
try:
363+
parsed_data = json.loads(json_part)
364+
assert isinstance(parsed_data, dict)
365+
assert "results" in parsed_data
366+
assert len(parsed_data["results"]) > 0
367+
except json.JSONDecodeError:
368+
pytest.fail(f"get-documents returned non-JSON data: {response_text}")
306369

307370
async def test_update_connection_settings_persistence(self, server):
308371
"""Test that connection updates persist for MCP client sessions"""

0 commit comments

Comments
 (0)