fix: accept both string and dict for body/params in n8n_api_call
All checks were successful
Build and Push n8n MCP Docker Image / build (push) Successful in 19s

Handle the case where MCP clients may pass JSON as either a string or
dict object. Adds _normalize_json_param helper to handle both formats
gracefully, preventing Pydantic validation errors.
This commit is contained in:
Ben
2025-12-26 19:38:51 +00:00
parent 946f8bd97e
commit 3071083970

View File

@@ -338,12 +338,34 @@ async def trigger_webhook(
# ============================================================================= # =============================================================================
def _normalize_json_param(value: str | dict[str, Any] | None) -> dict[str, Any]:
"""Normalize a parameter that can be either a JSON string or a dict.
This handles the case where MCP clients may pass either:
- A JSON string: '{"key": "value"}'
- A dict object: {"key": "value"}
"""
if value is None:
return {}
if isinstance(value, dict):
return value
if isinstance(value, str):
if not value or value == "{}":
return {}
try:
parsed = json.loads(value)
return parsed if isinstance(parsed, dict) else {}
except json.JSONDecodeError:
return {}
return {}
@mcp.tool() @mcp.tool()
async def n8n_api_call( async def n8n_api_call(
endpoint: str, endpoint: str,
method: str = "GET", method: str = "GET",
params: str = "{}", params: str | dict[str, Any] | None = None,
body: str = "{}", body: str | dict[str, Any] | None = None,
) -> str: ) -> str:
"""Execute a raw API call to n8n. """Execute a raw API call to n8n.
@@ -353,8 +375,8 @@ async def n8n_api_call(
Args: Args:
endpoint: API endpoint path (e.g., '/workflows', '/credentials') endpoint: API endpoint path (e.g., '/workflows', '/credentials')
method: HTTP method (GET, POST, PUT, PATCH, DELETE) method: HTTP method (GET, POST, PUT, PATCH, DELETE)
params: JSON string of query parameters (optional) params: Query parameters as JSON string or dict (optional)
body: JSON string of request body for POST/PUT/PATCH (optional) body: Request body as JSON string or dict for POST/PUT/PATCH (optional)
Examples: Examples:
- Create workflow: n8n_api_call('/workflows', 'POST', body='{"name": "My Workflow", "nodes": [...], "connections": {...}}') - Create workflow: n8n_api_call('/workflows', 'POST', body='{"name": "My Workflow", "nodes": [...], "connections": {...}}')
@@ -362,11 +384,8 @@ async def n8n_api_call(
- List credentials: n8n_api_call('/credentials') - List credentials: n8n_api_call('/credentials')
- Create tag: n8n_api_call('/tags', 'POST', body='{"name": "production"}') - Create tag: n8n_api_call('/tags', 'POST', body='{"name": "production"}')
""" """
try: params_dict = _normalize_json_param(params)
params_dict = json.loads(params) if params else {} body_dict = _normalize_json_param(body)
body_dict = json.loads(body) if body else {}
except json.JSONDecodeError as e:
return json.dumps({"error": True, "message": f"Invalid JSON: {e}"})
result = await client.request( result = await client.request(
method=method, method=method,