From 8aefe5cb742116d5a8f436efa21ab83e44bd3c22 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 9165eb854..e43ce5565 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 0088d8420..d0edf69fe 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 cda00b694..26706708d 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 bfb734abd..e9338100f 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 c6d5eb2d9..4002bbd18 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 21e07e072..6b9e3bcdb 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 45a06953d..2673df85b 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' && ( - - - + <> + + + + +