diff --git a/src/backend/base/langflow/api/v1/mcp_projects.py b/src/backend/base/langflow/api/v1/mcp_projects.py index 88bfd55b7..388123a88 100644 --- a/src/backend/base/langflow/api/v1/mcp_projects.py +++ b/src/backend/base/langflow/api/v1/mcp_projects.py @@ -327,7 +327,7 @@ async def install_mcp_config( request: Request, current_user: CurrentActiveMCPUser, ): - """Install MCP server configuration for Cursor or Claude.""" + """Install MCP server configuration for Cursor, Windsurf, or Claude.""" # Check if the request is coming from a local IP address client_ip = get_client_ip(request) if not is_local_ip(client_ip): @@ -408,6 +408,8 @@ async def install_mcp_config( # Determine the config file path based on the client and OS if body.client.lower() == "cursor": config_path = Path.home() / ".cursor" / "mcp.json" + elif body.client.lower() == "windsurf": + config_path = Path.home() / ".codeium" / "windsurf" / "mcp_config.json" elif body.client.lower() == "claude": if os_type == "Darwin": # macOS config_path = Path.home() / "Library" / "Application Support" / "Claude" / "claude_desktop_config.json" @@ -502,7 +504,7 @@ async def check_installed_mcp_servers( project_id: UUID, current_user: CurrentActiveMCPUser, ): - """Check if MCP server configuration is installed for this project in Cursor or Claude.""" + """Check if MCP server configuration is installed for this project in Cursor, Windsurf, or Claude.""" try: # Verify project exists and user has access async with session_scope() as session: @@ -544,6 +546,27 @@ async def check_installed_mcp_servers( except json.JSONDecodeError: logger.warning("Failed to parse Cursor config JSON at: %s", cursor_config_path) + # Check Windsurf configuration + windsurf_config_path = Path.home() / ".codeium" / "windsurf" / "mcp_config.json" + logger.debug( + "Checking Windsurf config at: %s (exists: %s)", windsurf_config_path, windsurf_config_path.exists() + ) + if windsurf_config_path.exists(): + try: + with windsurf_config_path.open("r") as f: + windsurf_config = json.load(f) + if "mcpServers" in windsurf_config and project_server_name in windsurf_config["mcpServers"]: + logger.debug("Found Windsurf config for project server: %s", project_server_name) + results.append("windsurf") + else: + logger.debug( + "Windsurf config exists but no entry for server: %s (available servers: %s)", + project_server_name, + list(windsurf_config.get("mcpServers", {}).keys()), + ) + except json.JSONDecodeError: + logger.warning("Failed to parse Windsurf config JSON at: %s", windsurf_config_path) + # Check Claude configuration claude_config_path = None os_type = platform.system() diff --git a/src/frontend/src/icons/Windsurf/Windsurf.jsx b/src/frontend/src/icons/Windsurf/Windsurf.jsx new file mode 100644 index 000000000..1ef5e4784 --- /dev/null +++ b/src/frontend/src/icons/Windsurf/Windsurf.jsx @@ -0,0 +1,18 @@ +import { stringToBool } from "@/utils/utils"; + +const SvgWindsurf = (props) => ( + + + +); +export default SvgWindsurf; diff --git a/src/frontend/src/icons/Windsurf/index.tsx b/src/frontend/src/icons/Windsurf/index.tsx new file mode 100644 index 000000000..9ac43757f --- /dev/null +++ b/src/frontend/src/icons/Windsurf/index.tsx @@ -0,0 +1,11 @@ +import { useDarkStore } from "@/stores/darkStore"; +import React, { forwardRef } from "react"; +import SvgWindsurf from "./Windsurf"; + +export const WindsurfIcon = forwardRef< + SVGSVGElement, + React.PropsWithChildren<{}> +>((props, ref) => { + const isdark = useDarkStore((state) => state.dark).toString(); + return ; +}); diff --git a/src/frontend/src/icons/Windsurf/windsurf.svg b/src/frontend/src/icons/Windsurf/windsurf.svg new file mode 100644 index 000000000..85536d8f5 --- /dev/null +++ b/src/frontend/src/icons/Windsurf/windsurf.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/frontend/src/icons/eagerIconImports.ts b/src/frontend/src/icons/eagerIconImports.ts index 10736e663..3b8e61758 100644 --- a/src/frontend/src/icons/eagerIconImports.ts +++ b/src/frontend/src/icons/eagerIconImports.ts @@ -112,6 +112,7 @@ import { WolframIcon } from "@/icons/Wolfram"; import { XAIIcon } from "@/icons/xAI"; import { YouTubeSvgIcon as YouTubeIcon } from "@/icons/Youtube"; import { ZepMemoryIcon } from "@/icons/ZepMemory"; +import { WindsurfIcon } from "./Windsurf"; // Export the eagerly loaded icons map export const eagerIconsMapping = { @@ -225,6 +226,7 @@ export const eagerIconsMapping = { WatsonxAI: WatsonxAiIcon, Weaviate: WeaviateIcon, Wikipedia: WikipediaIcon, + Windsurf: WindsurfIcon, Wolfram: WolframIcon, xAI: XAIIcon, YouTube: YouTubeIcon, diff --git a/src/frontend/src/icons/lazyIconImports.ts b/src/frontend/src/icons/lazyIconImports.ts index b76fcdbd0..e096079f9 100644 --- a/src/frontend/src/icons/lazyIconImports.ts +++ b/src/frontend/src/icons/lazyIconImports.ts @@ -296,6 +296,8 @@ export const lazyIconsMapping = { import("@/icons/Wikipedia/Wikipedia").then((mod) => ({ default: mod.default, })), + Windsurf: () => + import("@/icons/Windsurf").then((mod) => ({ default: mod.WindsurfIcon })), Wolfram: () => import("@/icons/Wolfram/Wolfram").then((mod) => ({ default: mod.default })), xAI: () => import("@/icons/xAI").then((mod) => ({ default: mod.XAIIcon })), diff --git a/src/frontend/src/pages/MainPage/pages/homePage/components/McpServerTab.tsx b/src/frontend/src/pages/MainPage/pages/homePage/components/McpServerTab.tsx index 11d127bff..50e9cf237 100644 --- a/src/frontend/src/pages/MainPage/pages/homePage/components/McpServerTab.tsx +++ b/src/frontend/src/pages/MainPage/pages/homePage/components/McpServerTab.tsx @@ -102,6 +102,11 @@ const autoInstallers = [ title: "Claude", icon: "Claude", }, + { + name: "windsurf", + title: "Windsurf", + icon: "Windsurf", + }, ]; const operatingSystemTabs = [