fix: Standardize flow name handling with snake_case conversion in MCP API (#7242)

* support spaces

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Sebastián Estévez 2025-03-24 11:11:40 -04:00 • committed by GitHub
commit ee1b5494fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 9 additions and 8 deletions

View file

@ -21,7 +21,7 @@ from starlette.background import BackgroundTasks
from langflow.api.v1.chat import build_flow_and_stream from langflow.api.v1.chat import build_flow_and_stream
from langflow.api.v1.schemas import InputValueRequest from langflow.api.v1.schemas import InputValueRequest
from langflow.base.mcp.util import get_flow from langflow.base.mcp.util import get_flow_snake_case
from langflow.helpers.flow import json_schema_from_flow from langflow.helpers.flow import json_schema_from_flow
from langflow.services.auth.utils import get_current_active_user from langflow.services.auth.utils import get_current_active_user
from langflow.services.database.models import Flow, User from langflow.services.database.models import Flow, User
@ -186,11 +186,12 @@ async def handle_list_tools():
if flow.user_id is None: if flow.user_id is None:
continue continue
flow_name = "_".join(flow.name.lower().split())
tool = types.Tool( tool = types.Tool(
name=flow.name, name=flow_name,
description=f"{flow.id}: {flow.description}" description=f"{flow.id}: {flow.description}"
if flow.description if flow.description
else f"Tool generated from flow: {flow.name}", else f"Tool generated from flow: {flow_name}",
inputSchema=json_schema_from_flow(flow), inputSchema=json_schema_from_flow(flow),
) )
tools.append(tool) tools.append(tool)
@ -215,7 +216,7 @@ async def handle_call_tool(name: str, arguments: dict) -> list[types.TextContent
async def execute_tool(session): async def execute_tool(session):
# get flow id from name # get flow id from name
flow = await get_flow(name, current_user.id, session) flow = await get_flow_snake_case(name, current_user.id, session)
if not flow: if not flow:
msg = f"Flow with name '{name}' not found" msg = f"Flow with name '{name}' not found"
raise ValueError(msg) raise ValueError(msg)

View file

@ -60,13 +60,14 @@ def create_tool_func(tool_name: str, arg_schema: type[BaseModel], session) -> Ca
return tool_func return tool_func
async def get_flow(flow_name: str, user_id: str, session) -> Flow | None: async def get_flow_snake_case(flow_name: str, user_id: str, session) -> Flow | None:
uuid_user_id = UUID(user_id) if isinstance(user_id, str) else user_id uuid_user_id = UUID(user_id) if isinstance(user_id, str) else user_id
stmt = select(Flow).where(Flow.user_id == uuid_user_id).where(Flow.is_component == False) # noqa: E712 stmt = select(Flow).where(Flow.user_id == uuid_user_id).where(Flow.is_component == False) # noqa: E712
flows = (await session.exec(stmt)).all() flows = (await session.exec(stmt)).all()
for flow in flows: for flow in flows:
if flow.to_data().name == flow_name: this_flow_name = "_".join(flow.name.lower().split())
if this_flow_name == flow_name:
return flow return flow
return None return None

View file

@ -8,7 +8,7 @@ import pytest
import respx import respx
from httpx import Response from httpx import Response
from langflow.components.data import APIRequestComponent from langflow.components.data import APIRequestComponent
from langflow.schema import Data, DataFrame, Message from langflow.schema import Data, DataFrame
from tests.base import ComponentTestBaseWithoutClient from tests.base import ComponentTestBaseWithoutClient
@ -146,7 +146,6 @@ class TestAPIRequestComponent(ComponentTestBaseWithoutClient):
assert isinstance(result, Data) assert isinstance(result, Data)
assert result.data["source"] == url assert result.data["source"] == url
@respx.mock @respx.mock
async def test_make_request_timeout(self, component): async def test_make_request_timeout(self, component):
# Test request timeout # Test request timeout