diff --git a/src/backend/base/langflow/components/tools/mcp_component.py b/src/backend/base/langflow/components/tools/mcp_component.py index 4a366f07d..ec5d8219e 100644 --- a/src/backend/base/langflow/components/tools/mcp_component.py +++ b/src/backend/base/langflow/components/tools/mcp_component.py @@ -15,7 +15,7 @@ from langflow.base.mcp.util import ( from langflow.custom import Component from langflow.inputs import DropdownInput from langflow.inputs.inputs import InputTypes -from langflow.io import MessageTextInput, Output, TabInput +from langflow.io import MessageTextInput, MultilineInput, Output, TabInput from langflow.io.schema import schema_to_langflow_inputs from langflow.logging import logger from langflow.schema import Message @@ -52,7 +52,7 @@ class MCPToolsComponent(Component): show=True, refresh_button=True, ), - MessageTextInput( + MultilineInput( name="sse_url", display_name="MCP SSE URL", info="URL for MCP SSE connection", @@ -147,9 +147,7 @@ class MCPToolsComponent(Component): elif field_value == "SSE": build_config["command"]["show"] = False build_config["sse_url"]["show"] = True - _, port, _ = await self.find_langflow_instance() - if port: - build_config["sse_url"]["value"] = f"http://localhost:{port}/api/v1/mcp/sse" + build_config["sse_url"]["value"] = "MCP_SSE" return build_config if field_name in ("command", "sse_url", "mode"): try: diff --git a/src/frontend/src/components/core/parameterRenderComponent/components/copyFieldAreaComponent/index.tsx b/src/frontend/src/components/core/parameterRenderComponent/components/copyFieldAreaComponent/index.tsx index a0fc03192..4c5a933f9 100644 --- a/src/frontend/src/components/core/parameterRenderComponent/components/copyFieldAreaComponent/index.tsx +++ b/src/frontend/src/components/core/parameterRenderComponent/components/copyFieldAreaComponent/index.tsx @@ -8,7 +8,9 @@ import { Input } from "../../../../ui/input"; import { InputProps, TextAreaComponentType } from "../../types"; const BACKEND_URL = "BACKEND_URL"; +const MCP_SSE_VALUE = "MCP_SSE"; const URL_WEBHOOK = `${window.location.protocol}//${window.location.host}/api/v1/webhook/`; +const URL_MCP_SSE = `${window.location.protocol}//${window.location.host}/api/v1/mcp/sse`; const inputClasses = { base: ({ isFocused }: { isFocused: boolean }) => @@ -60,15 +62,16 @@ export default function CopyFieldAreaComponent({ const [isFocused, setIsFocused] = useState(false); const [isCopied, setIsCopied] = useState(false); - const isValueToReplace = value === BACKEND_URL; + const isValueToReplace = value === BACKEND_URL || value === MCP_SSE_VALUE; const setSuccessData = useAlertStore((state) => state.setSuccessData); const currentFlow = useFlowStore((state) => state.currentFlow); const endpointName = currentFlow?.endpoint_name ?? ""; const valueToRender = useMemo(() => { - if (isValueToReplace) { - const urlWebhook = `${URL_WEBHOOK}${endpointName}`; - return isValueToReplace ? urlWebhook : value; + if (value === BACKEND_URL) { + return `${URL_WEBHOOK}${endpointName}`; + } else if (value === MCP_SSE_VALUE) { + return `${URL_MCP_SSE}`; } return value; }, [value, endpointName]); diff --git a/src/frontend/src/components/core/parameterRenderComponent/components/textAreaComponent/index.tsx b/src/frontend/src/components/core/parameterRenderComponent/components/textAreaComponent/index.tsx index 14efc4bf4..17c57c5bd 100644 --- a/src/frontend/src/components/core/parameterRenderComponent/components/textAreaComponent/index.tsx +++ b/src/frontend/src/components/core/parameterRenderComponent/components/textAreaComponent/index.tsx @@ -20,6 +20,8 @@ const inputClasses = { }; const WEBHOOK_VALUE = "CURL_WEBHOOK"; +const MCP_SSE_VALUE = "MCP_SSE"; +const URL_MCP_SSE = `${window.location.protocol}//${window.location.host}/api/v1/mcp/sse`; const externalLinkIconClasses = { gradient: ({ @@ -75,6 +77,11 @@ export default function TextAreaComponent({ [nodeInformationMetadata?.nodeType], ); + const isMCPSSE = useMemo( + () => nodeInformationMetadata?.nodeType === "mcp_sse", + [nodeInformationMetadata?.nodeType], + ); + useEffect(() => { if (isWebhook && value === WEBHOOK_VALUE) { const curlWebhookCode = getCurlWebhookCode({ @@ -84,8 +91,11 @@ export default function TextAreaComponent({ format: "singleline", }); handleOnNewValue({ value: curlWebhookCode }); + } else if (value === MCP_SSE_VALUE) { + const mcpSSEUrl = `${URL_MCP_SSE}`; + handleOnNewValue({ value: mcpSSEUrl }); } - }, [isWebhook]); + }, [isWebhook, value, nodeInformationMetadata, handleOnNewValue]); const getInputClassName = () => { return cn( diff --git a/src/frontend/tests/extended/features/mcp-server.spec.ts b/src/frontend/tests/extended/features/mcp-server.spec.ts index a6ae7a342..666335284 100644 --- a/src/frontend/tests/extended/features/mcp-server.spec.ts +++ b/src/frontend/tests/extended/features/mcp-server.spec.ts @@ -68,17 +68,12 @@ test( await page.getByTestId("tab_1_sse").click(); - await page.waitForSelector( - '[data-testid="anchor-popover-anchor-input-sse_url"]', - { - state: "visible", - timeout: 30000, - }, - ); + await page.waitForSelector('[data-testid="textarea_str_sse_url"]', { + state: "visible", + timeout: 30000, + }); - let sseURLCount = await page - .getByTestId("anchor-popover-anchor-input-sse_url") - .count(); + let sseURLCount = await page.getByTestId("textarea_str_sse_url").count(); expect(sseURLCount).toBeGreaterThan(0); @@ -122,17 +117,12 @@ test( await page.getByTestId("tab_1_sse").click(); - await page.waitForSelector( - '[data-testid="anchor-popover-anchor-input-sse_url"]', - { - state: "visible", - timeout: 30000, - }, - ); + await page.waitForSelector('[data-testid="textarea_str_sse_url"]', { + state: "visible", + timeout: 30000, + }); - sseURLCount = await page - .getByTestId("anchor-popover-anchor-input-sse_url") - .count(); + sseURLCount = await page.getByTestId("textarea_str_sse_url").count(); expect(sseURLCount).toBeGreaterThan(0);