From 1d211ee9f77ff2a03fe9632d271fbf0f4476889b Mon Sep 17 00:00:00 2001 From: LiuVaayne <10231735+vaayne@users.noreply.github.com> Date: Mon, 14 Apr 2025 17:17:13 +0800 Subject: [PATCH] feat: mcp custom headers (#4800) * Add support for custom HTTP headers in MCP servers Allow users to configure custom HTTP headers for SSE and streamable HTTP MCP server connections. This enables authentication and other API requirements. * Add custom headers i18n strings --- src/main/services/MCPService.ts | 19 ++++-- src/renderer/src/i18n/locales/en-us.json | 2 + src/renderer/src/i18n/locales/ja-jp.json | 2 + src/renderer/src/i18n/locales/ru-ru.json | 2 + src/renderer/src/i18n/locales/zh-cn.json | 2 + src/renderer/src/i18n/locales/zh-tw.json | 2 + .../settings/MCPSettings/McpSettings.tsx | 66 +++++++++++++++---- src/renderer/src/types/index.ts | 1 + 8 files changed, 76 insertions(+), 20 deletions(-) diff --git a/src/main/services/MCPService.ts b/src/main/services/MCPService.ts index 9165eb85..e43ce556 100644 --- a/src/main/services/MCPService.ts +++ b/src/main/services/MCPService.ts @@ -7,7 +7,7 @@ import { createInMemoryMCPServer } from '@main/mcpServers/factory' import { makeSureDirExists } from '@main/utils' import { getBinaryName, getBinaryPath } from '@main/utils/process' import { Client } from '@modelcontextprotocol/sdk/client/index.js' -import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js' +import { SSEClientTransport, SSEClientTransportOptions } from '@modelcontextprotocol/sdk/client/sse.js' import { getDefaultEnvironment, StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js' import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory' import { nanoid } from '@reduxjs/toolkit' @@ -137,12 +137,19 @@ class McpService { transport = clientTransport } else if (server.baseUrl) { if (server.type === 'streamableHttp') { - transport = new StreamableHTTPClientTransport( - new URL(server.baseUrl!), - {} as StreamableHTTPClientTransportOptions - ) + const options: StreamableHTTPClientTransportOptions = { + requestInit: { + headers: server.headers || {} + } + } + transport = new StreamableHTTPClientTransport(new URL(server.baseUrl!), options) } else if (server.type === 'sse') { - transport = new SSEClientTransport(new URL(server.baseUrl!)) + const options: SSEClientTransportOptions = { + requestInit: { + headers: server.headers || {} + } + } + transport = new SSEClientTransport(new URL(server.baseUrl!), options) } else { throw new Error('Invalid server type') } diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index 0088d842..d0edf69f 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -1072,6 +1072,8 @@ "editServer": "Edit Server", "env": "Environment Variables", "envTooltip": "Format: KEY=value, one per line", + "headers": "Headers", + "headersTooltip": "Custom headers for HTTP requests", "findMore": "Find More MCP", "searchNpx": "Search MCP", "install": "Install", diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json index cda00b69..26706708 100644 --- a/src/renderer/src/i18n/locales/ja-jp.json +++ b/src/renderer/src/i18n/locales/ja-jp.json @@ -1071,6 +1071,8 @@ "editServer": "サーバーを編集", "env": "環境変数", "envTooltip": "形式: KEY=value, 1行に1つ", + "headers": "ヘッダー", + "headersTooltip": "HTTP リクエストのカスタムヘッダー", "findMore": "MCP を見つける", "searchNpx": "MCP を検索", "install": "インストール", diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json index bfb734ab..e9338100 100644 --- a/src/renderer/src/i18n/locales/ru-ru.json +++ b/src/renderer/src/i18n/locales/ru-ru.json @@ -1071,6 +1071,8 @@ "editServer": "Редактировать сервер", "env": "Переменные окружения", "envTooltip": "Формат: KEY=value, по одной на строку", + "headers": "Заголовки", + "headersTooltip": "Пользовательские заголовки для HTTP-запросов", "findMore": "Найти больше MCP", "searchNpx": "Найти MCP", "install": "Установить", diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index c6d5eb2d..4002bbd1 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -1072,6 +1072,8 @@ "editServer": "编辑服务器", "env": "环境变量", "envTooltip": "格式:KEY=value,每行一个", + "headers": "请求头", + "headersTooltip": "HTTP 请求的自定义请求头", "findMore": "更多 MCP", "searchNpx": "搜索 MCP", "install": "安装", diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index 21e07e07..6b9e3bcd 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -1071,6 +1071,8 @@ "editServer": "編輯伺服器", "env": "環境變數", "envTooltip": "格式:KEY=value,每行一個", + "headers": "請求標頭", + "headersTooltip": "HTTP 請求的自定義標頭", "findMore": "更多 MCP", "searchNpx": "搜索 MCP", "install": "安裝", diff --git a/src/renderer/src/pages/settings/MCPSettings/McpSettings.tsx b/src/renderer/src/pages/settings/MCPSettings/McpSettings.tsx index 45a06953..2673df85 100644 --- a/src/renderer/src/pages/settings/MCPSettings/McpSettings.tsx +++ b/src/renderer/src/pages/settings/MCPSettings/McpSettings.tsx @@ -27,6 +27,7 @@ interface MCPFormValues { args?: string env?: string isActive: boolean + headers?: string } interface Registry { @@ -101,6 +102,11 @@ const McpSettings: React.FC = ({ server }) => { ? Object.entries(server.env) .map(([key, value]) => `${key}=${value}`) .join('\n') + : '', + headers: server.headers + ? Object.entries(server.headers) + .map(([key, value]) => `${key}=${value}`) + .join('\n') : '' }) }, [server, form]) @@ -218,6 +224,20 @@ const McpSettings: React.FC = ({ server }) => { mcpServer.env = env } + if (values.headers) { + const headers: Record = {} + values.headers.split('\n').forEach((line) => { + if (line.trim()) { + const [key, ...chunks] = line.split(':') + const value = chunks.join(':') + if (key && value) { + headers[key.trim()] = value.trim() + } + } + }) + mcpServer.headers = headers + } + try { await window.api.mcp.restartServer(mcpServer) updateMCPServer({ ...mcpServer, isActive: true }) @@ -400,22 +420,40 @@ const McpSettings: React.FC = ({ server }) => { )} {serverType === 'sse' && ( - - - + <> + + + + +