diff --git a/backend/open_webui/routers/configs.py b/backend/open_webui/routers/configs.py index 5fd744c793..56e91e1fd1 100644 --- a/backend/open_webui/routers/configs.py +++ b/backend/open_webui/routers/configs.py @@ -262,7 +262,12 @@ async def verify_tool_servers_config( else: try: client = MCPClient() - headers = None + headers = {} + + # Add custom headers if provided + custom_headers = getattr(form_data, "headers", None) or {} + if isinstance(custom_headers, dict): + headers.update(custom_headers) token = None if form_data.auth_type == "bearer": @@ -279,10 +284,11 @@ async def verify_tool_servers_config( except Exception as e: pass + # Authorization header from auth takes precedence over custom headers if token: - headers = {"Authorization": f"Bearer {token}"} + headers["Authorization"] = f"Bearer {token}" - await client.connect(form_data.url, headers=headers) + await client.connect(form_data.url, headers=headers if headers else None) specs = await client.list_tool_specs() return { "status": True, diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index e5b84a3d79..3f56439b1f 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -1325,6 +1325,12 @@ async def process_chat_payload(request, form_data, user, metadata, model): auth_type = mcp_server_connection.get("auth_type", "") headers = {} + # Add custom headers if provided + custom_headers = mcp_server_connection.get("headers", {}) + if isinstance(custom_headers, dict): + headers.update(custom_headers) + + # Authorization header from auth takes precedence over custom headers if auth_type == "bearer": headers["Authorization"] = ( f"Bearer {mcp_server_connection.get('key', '')}" diff --git a/src/lib/components/AddToolServerModal.svelte b/src/lib/components/AddToolServerModal.svelte index 21ce63f014..1a08489b14 100644 --- a/src/lib/components/AddToolServerModal.svelte +++ b/src/lib/components/AddToolServerModal.svelte @@ -44,6 +44,7 @@ let auth_type = 'bearer'; let key = ''; + let headers: { key: string; value: string }[] = []; let accessControl = {}; @@ -123,12 +124,21 @@ console.debug('Connection successful', res); } } else { + // Convert headers array to object + const headersObj = {}; + headers.forEach((h) => { + if (h.key && h.value) { + headersObj[h.key] = h.value; + } + }); + const res = await verifyToolServerConnection(localStorage.token, { url, path, type, auth_type, key, + headers: Object.keys(headersObj).length > 0 ? headersObj : undefined, config: { enable: enable, access_control: accessControl @@ -179,6 +189,14 @@ if (data.auth_type) auth_type = data.auth_type; if (data.key) key = data.key; + // Import custom headers + if (data.headers && typeof data.headers === 'object') { + headers = Object.entries(data.headers).map(([key, value]) => ({ + key, + value: String(value) + })); + } + if (data.info) { id = data.info.id ?? ''; name = data.info.name ?? ''; @@ -200,6 +218,14 @@ const exportHandler = async () => { // export current connection as json file + // Convert headers array to object + const headersObj = {}; + headers.forEach((h) => { + if (h.key && h.value) { + headersObj[h.key] = h.value; + } + }); + const json = JSON.stringify([ { type, @@ -211,6 +237,7 @@ auth_type, key, + ...(Object.keys(headersObj).length > 0 ? { headers: headersObj } : {}), info: { id: id, @@ -256,6 +283,14 @@ } } + // Convert headers array to object + const headersObj = {}; + headers.forEach((h) => { + if (h.key && h.value) { + headersObj[h.key] = h.value; + } + }); + const connection = { type, url, @@ -266,6 +301,7 @@ auth_type, key, + ...(Object.keys(headersObj).length > 0 ? { headers: headersObj } : {}), config: { enable: enable, access_control: accessControl @@ -293,6 +329,7 @@ key = ''; auth_type = 'bearer'; + headers = []; id = ''; name = ''; @@ -315,6 +352,16 @@ auth_type = connection?.auth_type ?? 'bearer'; key = connection?.key ?? ''; + // Initialize custom headers from connection + if (connection?.headers && typeof connection.headers === 'object') { + headers = Object.entries(connection.headers).map(([key, value]) => ({ + key, + value: String(value) + })); + } else { + headers = []; + } + id = connection.info?.id ?? ''; name = connection.info?.name ?? ''; description = connection.info?.description ?? ''; @@ -656,6 +703,73 @@ + {#if type === 'mcp'} +
+
+
+
+
+ {$i18n.t('Custom Headers')} +
+
+ + + +
+ + {#if headers.length > 0} +
+ {#each headers as header, index} +
+ + + +
+ {/each} +
+ {:else} +
+ {$i18n.t('No custom headers configured')} +
+ {/if} +
+
+ {/if} + {#if !direct}