Skip to content

Commit 4025ebe

Browse files
committed
feat: add mcp_base_url to config endpoint for MCP server URL override
Add LANGFLOW_MCP_BASE_URL setting that the frontend uses as a fallback when building MCP server URLs in the UI configuration JSON. This allows deployments behind reverse proxies to specify the correct external URL. Priority chain: mcp_base_url > api.defaults.baseURL > window.location.origin
1 parent acf2ae0 commit 4025ebe

6 files changed

Lines changed: 22 additions & 1 deletion

File tree

src/backend/base/langflow/api/v1/schemas/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ class BaseConfigResponse(BaseModel):
379379
event_delivery: Literal["polling", "streaming", "direct"]
380380
voice_mode_available: bool
381381
frontend_timeout: int
382+
mcp_base_url: str
382383

383384

384385
class PublicConfigResponse(BaseConfigResponse):
@@ -407,6 +408,7 @@ def from_settings(cls, settings: Settings) -> "PublicConfigResponse":
407408
event_delivery=settings.event_delivery,
408409
voice_mode_available=settings.voice_mode_available,
409410
frontend_timeout=settings.frontend_timeout,
411+
mcp_base_url=settings.mcp_base_url,
410412
allow_custom_components=settings.allow_custom_components,
411413
)
412414

@@ -460,6 +462,7 @@ def from_settings(cls, settings: Settings, auth_settings) -> "ConfigResponse":
460462
public_flow_expiration=settings.public_flow_expiration,
461463
event_delivery=settings.event_delivery,
462464
voice_mode_available=settings.voice_mode_available,
465+
mcp_base_url=settings.mcp_base_url,
463466
webhook_auth_enable=auth_settings.WEBHOOK_AUTH_ENABLE,
464467
default_folder_name=DEFAULT_FOLDER_NAME,
465468
hide_getting_started_progress=os.getenv("HIDE_GETTING_STARTED_PROGRESS", "").lower() == "true",

src/frontend/src/controllers/API/queries/config/use-get-config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ interface BaseConfig {
2020
event_delivery: EventDeliveryType;
2121
voice_mode_available: boolean;
2222
allow_custom_components: boolean;
23+
mcp_base_url: string;
2324
}
2425

2526
// Public config = base config (unauthenticated users get only base fields)
@@ -82,6 +83,7 @@ export const useGetConfig: useQueryFunctionType<
8283
const setAllowCustomComponents = useUtilityStore(
8384
(state) => state.setAllowCustomComponents,
8485
);
86+
const setMcpBaseUrl = useUtilityStore((state) => state.setMcpBaseUrl);
8587

8688
const { query } = UseRequestProcessor();
8789

@@ -104,6 +106,7 @@ export const useGetConfig: useQueryFunctionType<
104106
setEventDelivery(data.event_delivery ?? EventDeliveryType.POLLING);
105107
const allowCustomComponents = data.allow_custom_components ?? true;
106108
setAllowCustomComponents(allowCustomComponents);
109+
setMcpBaseUrl(data.mcp_base_url ?? "");
107110
recomputeComponentsToUpdateIfNeeded();
108111

109112
// Set authenticated-only fields if present (full config)

src/frontend/src/customization/utils/custom-mcp-url.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { api } from "@/controllers/API/api";
22
import type { MCPTransport } from "@/controllers/API/queries/mcp/use-patch-install-mcp";
3+
import { useUtilityStore } from "@/stores/utilityStore";
34

45
type ComposerConnectionOptions = {
56
useComposer?: boolean;
@@ -26,7 +27,12 @@ export const customGetMCPUrl = (
2627
}
2728
}
2829

29-
const apiHost = api.defaults.baseURL || window.location.origin;
30+
const configBaseUrl = useUtilityStore.getState().mcpBaseUrl;
31+
const apiHost = (
32+
configBaseUrl ||
33+
api.defaults.baseURL ||
34+
window.location.origin
35+
).replace(/\/+$/, "");
3036
const baseUrl = `${apiHost}/api/v1/mcp/project/${projectId}`;
3137
return transport === "streamablehttp"
3238
? `${baseUrl}/streamable`

src/frontend/src/stores/utilityStore.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,6 @@ export const useUtilityStore = create<UtilityStoreType>((set, get) => ({
6464
allowCustomComponents: true,
6565
setAllowCustomComponents: (allowCustomComponents: boolean) =>
6666
set({ allowCustomComponents }),
67+
mcpBaseUrl: "",
68+
setMcpBaseUrl: (mcpBaseUrl: string) => set({ mcpBaseUrl }),
6769
}));

src/frontend/src/types/zustand/utility/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,6 @@ export type UtilityStoreType = {
3838
setHideGettingStartedProgress: (hideGettingStartedProgress: boolean) => void;
3939
allowCustomComponents: boolean;
4040
setAllowCustomComponents: (allowCustomComponents: boolean) => void;
41+
mcpBaseUrl: string;
42+
setMcpBaseUrl: (mcpBaseUrl: string) => void;
4143
};

src/lfx/src/lfx/services/settings/base.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ class Settings(BaseSettings):
9292
If not provided, a hash of the database URL will be used. Useful when multiple Langflow
9393
instances share the same database and need coordinated migration locking."""
9494

95+
mcp_base_url: str = ""
96+
"""External base URL used to build MCP server URLs in the UI configuration JSON
97+
(e.g. 'https://langflow.example.com'). When empty, the frontend falls back to
98+
the browser's window.location.origin."""
99+
95100
mcp_server_timeout: int = 20
96101
"""The number of seconds to wait before giving up on a lock to released or establishing a connection to the
97102
database."""

0 commit comments

Comments
 (0)