diff --git a/tools/server/public/index.html.gz b/tools/server/public/index.html.gz index ffeed79ff7..bc9124dd1c 100644 Binary files a/tools/server/public/index.html.gz and b/tools/server/public/index.html.gz differ diff --git a/tools/server/server-cors-proxy.h b/tools/server/server-cors-proxy.h index c412d4c252..ffdd073b9d 100644 --- a/tools/server/server-cors-proxy.h +++ b/tools/server/server-cors-proxy.h @@ -32,13 +32,22 @@ static server_http_res_ptr proxy_request(const server_http_req & req, std::strin SRV_INF("proxying %s request to %s://%s:%i%s\n", method.c_str(), parsed_url.scheme.c_str(), parsed_url.host.c_str(), parsed_url.port, parsed_url.path.c_str()); + std::map headers; + for (auto [key, value] : req.headers) { + auto new_key = key; + if (string_starts_with(new_key, "X-Proxy-Header-")) { + string_replace_all(new_key, "X-Proxy-Header-", ""); + } + headers[new_key] = value; + } + auto proxy = std::make_unique( method, parsed_url.scheme, parsed_url.host, parsed_url.port, parsed_url.path, - req.headers, + headers, req.body, req.should_stop, 600, // timeout_read (default to 10 minutes) diff --git a/tools/server/server-http.h b/tools/server/server-http.h index 3621064cdf..f8a174c440 100644 --- a/tools/server/server-http.h +++ b/tools/server/server-http.h @@ -35,7 +35,7 @@ using server_http_res_ptr = std::unique_ptr; struct server_http_req { std::map params; // path_params + query_params - std::map headers; // reserved for future use + std::map headers; // used by MCP proxy std::string path; std::string query_string; // query parameters string (e.g. "action=save") std::string body; diff --git a/tools/server/webui/src/lib/services/mcp.service.ts b/tools/server/webui/src/lib/services/mcp.service.ts index b38d18676d..cf401bc30e 100644 --- a/tools/server/webui/src/lib/services/mcp.service.ts +++ b/tools/server/webui/src/lib/services/mcp.service.ts @@ -39,7 +39,13 @@ import type { MCPResourceContent, MCPReadResourceResult } from '$lib/types'; -import { buildProxiedUrl, throwIfAborted, isAbortError, createBase64DataUrl } from '$lib/utils'; +import { + buildProxiedUrl, + buildProxiedHeaders, + throwIfAborted, + isAbortError, + createBase64DataUrl +} from '$lib/utils'; interface ToolResultContentItem { type: string; @@ -118,7 +124,7 @@ export class MCPService { const requestInit: RequestInit = {}; if (config.headers) { - requestInit.headers = config.headers; + requestInit.headers = buildProxiedHeaders(config.headers); } if (config.credentials) { diff --git a/tools/server/webui/src/lib/utils/cors-proxy.ts b/tools/server/webui/src/lib/utils/cors-proxy.ts index 39c368ba0b..2eb10b16d4 100644 --- a/tools/server/webui/src/lib/utils/cors-proxy.ts +++ b/tools/server/webui/src/lib/utils/cors-proxy.ts @@ -19,6 +19,21 @@ export function buildProxiedUrl(targetUrl: string): URL { return proxyUrl; } +/** + * Wrap original headers for proxying through the CORS proxy. This avoids issues with duplicated llama.cpp-specific and target headers when using the CORS proxy. + * @param headers - The original headers to be proxied to target + * @returns List of "wrapped" headers to be sent to the CORS proxy + */ +export function buildProxiedHeaders(headers: Record): Record { + const proxiedHeaders: Record = {}; + + for (const [key, value] of Object.entries(headers)) { + proxiedHeaders[`X-Proxy-Header-${key}`] = value; + } + + return proxiedHeaders; +} + /** * Get a proxied URL string for use in fetch requests. * @param targetUrl - The original URL to proxy diff --git a/tools/server/webui/src/lib/utils/index.ts b/tools/server/webui/src/lib/utils/index.ts index 2caaf9ac3b..e3bf1b9f5f 100644 --- a/tools/server/webui/src/lib/utils/index.ts +++ b/tools/server/webui/src/lib/utils/index.ts @@ -38,7 +38,7 @@ export { highlightCode, detectIncompleteCodeBlock, type IncompleteCodeBlock } fr export { setConfigValue, getConfigValue, configToParameterRecord } from './config-helpers'; // CORS Proxy -export { buildProxiedUrl, getProxiedUrlString } from './cors-proxy'; +export { buildProxiedUrl, getProxiedUrlString, buildProxiedHeaders } from './cors-proxy'; // Conversation utilities export { createMessageCountMap, getMessageCount } from './conversation-utils';