Node-RED MCP fixes: N2 input validation, N6 auto api_help
This commit is contained in:
@@ -75,7 +75,15 @@ async def update_flows(flows_json: str, deployment_type: str = "full") -> str:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Confirmation message.
|
Confirmation message.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If deployment_type is not one of: full, nodes, flows, reload.
|
||||||
"""
|
"""
|
||||||
|
_VALID_DEPLOYMENT_TYPES = ("full", "nodes", "flows", "reload")
|
||||||
|
if deployment_type not in _VALID_DEPLOYMENT_TYPES:
|
||||||
|
raise ValueError(
|
||||||
|
f"Invalid deployment_type '{deployment_type}'. Must be one of: {', '.join(_VALID_DEPLOYMENT_TYPES)}"
|
||||||
|
)
|
||||||
client = get_client()
|
client = get_client()
|
||||||
flows = json.loads(flows_json)
|
flows = json.loads(flows_json)
|
||||||
await client.update_flows(flows, deployment_type=deployment_type)
|
await client.update_flows(flows, deployment_type=deployment_type)
|
||||||
@@ -144,9 +152,15 @@ async def create_flow(flow_json: str) -> FlowCreateResult:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
FlowCreateResult with the new flow ID.
|
FlowCreateResult with the new flow ID.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If flow_json is not valid JSON.
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
|
flow = json.loads(flow_json)
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
raise ValueError(f"Invalid JSON in flow_json: {e}") from e
|
||||||
client = get_client()
|
client = get_client()
|
||||||
flow = json.loads(flow_json)
|
|
||||||
result = await client.create_flow(flow)
|
result = await client.create_flow(flow)
|
||||||
return FlowCreateResult.from_api(result)
|
return FlowCreateResult.from_api(result)
|
||||||
|
|
||||||
@@ -187,7 +201,12 @@ async def set_flows_state(state: str) -> FlowState:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
FlowState with new state.
|
FlowState with new state.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If state is not "start" or "stop".
|
||||||
"""
|
"""
|
||||||
|
if state not in ("start", "stop"):
|
||||||
|
raise ValueError(f"Invalid state '{state}'. Must be 'start' or 'stop'.")
|
||||||
client = get_client()
|
client = get_client()
|
||||||
raw_state = await client.set_flows_state(state)
|
raw_state = await client.set_flows_state(state)
|
||||||
return FlowState.from_api(raw_state)
|
return FlowState.from_api(raw_state)
|
||||||
|
|||||||
@@ -2,6 +2,32 @@
|
|||||||
|
|
||||||
from nodered_mcp.server import mcp
|
from nodered_mcp.server import mcp
|
||||||
|
|
||||||
|
# Centralized endpoint registry: maps path to (method, description, implemented)
|
||||||
|
_ENDPOINT_REGISTRY = [
|
||||||
|
("GET", "/flows", "Get all flows", True),
|
||||||
|
("GET", "/flows/formatted", "Get flows with formatted summary", True),
|
||||||
|
("GET", "/flows/visualize", "Visualize flow structure", True),
|
||||||
|
("POST", "/flows", "Update all flows", True),
|
||||||
|
("GET", "/flow/:id", "Get a specific flow", True),
|
||||||
|
("PUT", "/flow/:id", "Update a specific flow", True),
|
||||||
|
("PATCH", "/flow/:id", "Patch a flow incrementally", True),
|
||||||
|
("DELETE","/flow/:id", "Delete a specific flow", True),
|
||||||
|
("POST", "/flow", "Create a new flow", True),
|
||||||
|
("GET", "/flows/state", "Get the state of flows", True),
|
||||||
|
("POST", "/flows/state", "Set the state of flows", True),
|
||||||
|
("GET", "/tabs", "List all flow tabs", True),
|
||||||
|
("GET", "/nodes", "Get list of installed nodes", True),
|
||||||
|
("GET", "/nodes/:module", "Get node module info", True),
|
||||||
|
("GET", "/nodes/search", "Search for nodes", True),
|
||||||
|
("GET", "/nodes/find", "Find nodes by type", True),
|
||||||
|
("POST", "/nodes/:module/toggle", "Toggle node module", True),
|
||||||
|
("POST", "/nodes", "Install a new node module", False),
|
||||||
|
("GET", "/settings", "Get runtime settings", True),
|
||||||
|
("GET", "/diagnostics", "Get diagnostics information", True),
|
||||||
|
("POST", "/inject/:id", "Trigger an inject node", True),
|
||||||
|
("GET", "/lint/:id", "Lint flow layout", True),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
async def api_help() -> str:
|
async def api_help() -> str:
|
||||||
@@ -9,23 +35,8 @@ async def api_help() -> str:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Markdown table of API endpoints and their MCP implementation status.
|
Markdown table of API endpoints and their MCP implementation status.
|
||||||
|
Endpoints are defined in the centralized _ENDPOINT_REGISTRY.
|
||||||
"""
|
"""
|
||||||
endpoints = [
|
|
||||||
("GET", "/flows", "Get all flows", True),
|
|
||||||
("POST", "/flows", "Update all flows", True),
|
|
||||||
("GET", "/flow/:id", "Get a specific flow", True),
|
|
||||||
("PUT", "/flow/:id", "Update a specific flow", True),
|
|
||||||
("DELETE", "/flow/:id", "Delete a specific flow", True),
|
|
||||||
("POST", "/flow", "Create a new flow", True),
|
|
||||||
("GET", "/flows/state", "Get the state of flows", True),
|
|
||||||
("POST", "/flows/state", "Set the state of flows", True),
|
|
||||||
("GET", "/nodes", "Get list of installed nodes", True),
|
|
||||||
("POST", "/nodes", "Install a new node module", False),
|
|
||||||
("GET", "/settings", "Get runtime settings", True),
|
|
||||||
("GET", "/diagnostics", "Get diagnostics information", True),
|
|
||||||
("POST", "/inject/:id", "Trigger an inject node", True),
|
|
||||||
]
|
|
||||||
|
|
||||||
output = [
|
output = [
|
||||||
"# Node-RED API Help",
|
"# Node-RED API Help",
|
||||||
"",
|
"",
|
||||||
@@ -33,8 +44,8 @@ async def api_help() -> str:
|
|||||||
"|--------|------|-------------|---------------------|",
|
"|--------|------|-------------|---------------------|",
|
||||||
]
|
]
|
||||||
|
|
||||||
for method, path, description, implemented in endpoints:
|
for method, path, description, implemented in _ENDPOINT_REGISTRY:
|
||||||
status = "✅" if implemented else "❌"
|
status = "\u2705" if implemented else "\u274c"
|
||||||
output.append(f"| {method} | {path} | {description} | {status} |")
|
output.append(f"| {method} | {path} | {description} | {status} |")
|
||||||
|
|
||||||
return "\n".join(output)
|
return "\n".join(output)
|
||||||
|
|||||||
Reference in New Issue
Block a user