feat: Adds MCP_SSE to be filled from frontend (#7594)
* add mcp sse to copy field
* add MCP_SSE from frontend
* [autofix.ci] apply automated fixes
* refactor: reorder imports in mcp_component.py for consistency
* ✅ (mcp-server.spec.ts): refactor code to use consistent selector for sse_url textarea element in tests
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
Co-authored-by: cristhianzl <cristhian.lousa@gmail.com>
This commit is contained in:
parent
67f744cdf2
commit
0ba8f6559c
4 changed files with 31 additions and 30 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue