Skip to content

Commit a98adf0

Browse files
authored
Merge pull request #62 from ph3t/ph3t/fix-mcp-errors
Ensure correct order and handling of function arguments and literals
2 parents 9b8309f + d6e65ef commit a98adf0

File tree

2 files changed

+57
-1
lines changed

2 files changed

+57
-1
lines changed

nerve/tools/mcp/compiler.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,11 @@ async def create_function_body(client: Client, mcp_tool: Tool) -> tuple[str, dic
9797
type_defs.update(args_def)
9898

9999
if "default" in arg_props:
100-
arg["default"] = arg_props["default"]
100+
arg["default"] = repr(arg_props["default"])
101101

102102
typed_args.append(arg)
103+
104+
typed_args.sort(key=lambda arg: 'default' in arg)
103105

104106
# load the template from the same directory as this script
105107
template_path = os.path.join(os.path.dirname(__file__), "body.j2")
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,60 @@ async def calculate(operation: Annotated[str, "The operation to perform"], value
8989
func_body,
9090
)
9191

92+
async def test_create_function_body_with_unsorted_string_and_int_arguments_with_default(self) -> None:
93+
# Mock the client
94+
client = MagicMock(spec=Client)
95+
96+
# Create a mock tool with string and int arguments
97+
mock_tool = Tool(
98+
name="calculate",
99+
description="A function that performs a calculation",
100+
inputSchema={
101+
"type": "object",
102+
"properties": {
103+
"value": {"type": "integer", "description": "The value to calculate with", "default": 10},
104+
"operation": {"type": "string", "description": "The operation to perform"},
105+
},
106+
"required": ["operation"],
107+
},
108+
)
109+
110+
func_body, type_defs = await create_function_body(client, mock_tool)
111+
112+
self.assertIn(
113+
'''
114+
async def calculate(operation: Annotated[str, "The operation to perform"], value: Annotated[int, "The value to calculate with"] = 10) -> Any:
115+
"""A function that performs a calculation"""
116+
'''.strip(),
117+
func_body,
118+
)
119+
120+
async def test_create_function_body_with_string_default_colliding_with_builtin(self) -> None:
121+
client = MagicMock(spec=Client)
122+
123+
mock_tool = Tool(
124+
name="test_state_tool",
125+
description="A tool to test default string handling.",
126+
inputSchema={
127+
"type": "object",
128+
"properties": {
129+
"state": {
130+
"type": "string",
131+
"description": "The state of the entity.",
132+
"default": "open", # This default value could be misinterpreted as the 'open' function.
133+
},
134+
},
135+
},
136+
)
137+
138+
func_body, type_defs = await create_function_body(client, mock_tool)
139+
140+
# Default value to be correctly quoted as a string literal: 'open'
141+
self.assertIn(
142+
"""async def test_state_tool(state: Annotated[str, "The state of the entity."] = 'open') -> Any:""",
143+
func_body,
144+
)
145+
92146
async def test_create_function_body_with_complex_nested_arguments(self) -> None:
93147
# Mock the client
94148
client = MagicMock(spec=Client)

0 commit comments

Comments
 (0)