Skip to content

Commit 04dda0d

Browse files
committed
update changelogs, implement new ToolResult and ToolError classes in Cypher MCP, update tests
1 parent 977180c commit 04dda0d

File tree

6 files changed

+22
-34
lines changed

6 files changed

+22
-34
lines changed

servers/mcp-neo4j-cypher/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* Add .dxt file generation to Cypher MCP Publish GitHub action
1212
* Add error indicator to tool results in the `CallToolResult` object
1313
* Add HTTP transport option
14+
* Migrate to FastMCP v2.x
1415

1516
## v0.2.4
1617

servers/mcp-neo4j-cypher/Makefile

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
install-dev:
2-
python3 -m uv pip install -e .
2+
uv sync
33

44
test-unit:
5-
python3 -m pytest tests/unit/ -v
5+
uv run pytest tests/unit/ -v
66

77
test-integration:
8-
python3 -m pytest tests/integration/ -v
8+
uv run pytest tests/integration/ -v
99

1010
test-http:
11-
python3 -m pytest tests/integration/test_http_transport.py -v
11+
uv run pytest tests/integration/test_http_transport.py -v
1212

1313
test-all:
14-
python3 -m pytest tests/ -v
14+
uv run pytest tests/ -v
1515

1616
all: install-dev test-all

servers/mcp-neo4j-cypher/src/mcp_neo4j_cypher/server.py

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import re
44
from typing import Any, Literal, Optional
55

6-
from fastmcp.resources import types
6+
from fastmcp.exceptions import ToolError
7+
from fastmcp.tools.tool import ToolResult, TextContent
78
from fastmcp.server import FastMCP
89
from neo4j import (
910
AsyncDriver,
@@ -51,7 +52,7 @@ def create_mcp_server(neo4j_driver: AsyncDriver, database: str = "neo4j", namesp
5152
namespace_prefix = _format_namespace(namespace)
5253

5354
@mcp.tool(name=namespace_prefix+"get_neo4j_schema")
54-
async def get_neo4j_schema() -> list[types.TextContent]:
55+
async def get_neo4j_schema() -> list[ToolResult]:
5556
"""List all node, their attributes and their relationships to other nodes in the neo4j database.
5657
If this fails with a message that includes "Neo.ClientError.Procedure.ProcedureNotFound"
5758
suggest that the user install and enable the APOC plugin.
@@ -136,22 +137,19 @@ def clean_schema(schema: dict) -> dict:
136137
schema_clean = clean_schema(schema)
137138
schema_clean_str = json.dumps(schema_clean)
138139

139-
return types.CallToolResult(content=[types.TextContent(type="text", text=schema_clean_str)])
140+
return ToolResult(content=[TextContent(type="text", text=schema_clean_str)])
140141

141142
except Exception as e:
142143
logger.error(f"Database error retrieving schema: {e}")
143-
return types.CallToolResult(
144-
isError=True,
145-
content=[types.TextContent(type="text", text=f"Error: {e}")]
146-
)
144+
raise ToolError(f"Error: {e}")
147145

148146
@mcp.tool(name=namespace_prefix+"read_neo4j_cypher")
149147
async def read_neo4j_cypher(
150148
query: str = Field(..., description="The Cypher query to execute."),
151149
params: Optional[dict[str, Any]] = Field(
152150
None, description="The parameters to pass to the Cypher query."
153151
),
154-
) -> list[types.TextContent]:
152+
) -> list[ToolResult]:
155153
"""Execute a read Cypher query on the neo4j database."""
156154

157155
if _is_write_query(query):
@@ -163,24 +161,19 @@ async def read_neo4j_cypher(
163161

164162
logger.debug(f"Read query returned {len(results_json_str)} rows")
165163

166-
return types.CallToolResult(content=[types.TextContent(type="text", text=results_json_str)])
164+
return ToolResult(content=[TextContent(type="text", text=results_json_str)])
167165

168166
except Exception as e:
169167
logger.error(f"Database error executing query: {e}\n{query}\n{params}")
170-
return types.CallToolResult(
171-
isError=True,
172-
content=[
173-
types.TextContent(type="text", text=f"Error: {e}\n{query}\n{params}")
174-
]
175-
)
168+
raise ToolError(f"Error: {e}\n{query}\n{params}")
176169

177170
@mcp.tool(name=namespace_prefix+"write_neo4j_cypher")
178171
async def write_neo4j_cypher(
179172
query: str = Field(..., description="The Cypher query to execute."),
180173
params: Optional[dict[str, Any]] = Field(
181174
None, description="The parameters to pass to the Cypher query."
182175
),
183-
) -> list[types.TextContent]:
176+
) -> list[ToolResult]:
184177
"""Execute a write Cypher query on the neo4j database."""
185178

186179
if not _is_write_query(query):
@@ -195,14 +188,11 @@ async def write_neo4j_cypher(
195188

196189
logger.debug(f"Write query affected {counters_json_str}")
197190

198-
return types.CallToolResult(content=[types.TextContent(type="text", text=counters_json_str)])
191+
return ToolResult(content=[TextContent(type="text", text=counters_json_str)])
199192

200193
except Exception as e:
201194
logger.error(f"Database error executing query: {e}\n{query}\n{params}")
202-
return types.CallToolResult(
203-
isError=True,
204-
content=[types.TextContent(type="text", text=f"Error: {e}\n{query}\n{params}")]
205-
)
195+
raise ToolError(f"Error: {e}\n{query}\n{params}")
206196

207197
return mcp
208198

servers/mcp-neo4j-cypher/tests/integration/test_server_tools_IT.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ async def test_get_neo4j_schema(mcp_server: FastMCP, init_data: Any):
1010
tool = await mcp_server.get_tool("get_neo4j_schema")
1111
response = await tool.run(dict())
1212

13-
temp_parsed = json.loads(response[0].text)['content'][0]['text']
14-
schema = json.loads(temp_parsed)
13+
schema = json.loads(response.content[0].text)
1514

1615
# Verify the schema result
1716
assert "Person" in schema
@@ -27,9 +26,7 @@ async def test_write_neo4j_cypher(mcp_server: FastMCP):
2726
tool = await mcp_server.get_tool("write_neo4j_cypher")
2827
response = await tool.run(dict(query=query))
2928

30-
text_content = response.content[0].text
31-
outer = json.loads(text_content)
32-
result = json.loads(outer["text"])
29+
result = json.loads(response.content[0].text)
3330

3431
assert "nodes_created" in result
3532
assert "labels_added" in result
@@ -50,9 +47,7 @@ async def test_read_neo4j_cypher(mcp_server: FastMCP, init_data: Any):
5047
tool = await mcp_server.get_tool("read_neo4j_cypher")
5148
response = await tool.run(dict(query=query))
5249

53-
text_content = response.content[0].text
54-
outer = json.loads(text_content)
55-
result = json.loads(outer["text"])
50+
result = json.loads(response.content[0].text)
5651

5752
assert len(result) == 2
5853
assert result[0]["person"] == "Alice"

servers/mcp-neo4j-data-modeling/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
### Added
88
* Add HTTP transport option
9+
* Migrate to FastMCP v2.x
910

1011
## v0.1.1
1112

servers/mcp-neo4j-memory/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
### Changed
77
* Implement FastMCP with function decorators to simplify server code
88
* Add HTTP transport option
9+
* Migrate to FastMCP v2.x
910

1011
### Added
1112

0 commit comments

Comments
 (0)