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';