diff --git a/src/Infrastructure/BotSharp.Abstraction/MCP/Services/IMcpClientHeaderProvider.cs b/src/Infrastructure/BotSharp.Abstraction/MCP/Services/IMcpClientHeaderProvider.cs
new file mode 100644
index 000000000..fd591a660
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/MCP/Services/IMcpClientHeaderProvider.cs
@@ -0,0 +1,30 @@
+namespace BotSharp.Abstraction.MCP.Services;
+
+///
+/// An optional host hook over the HTTP headers used to open one MCP server connection.
+///
+///
+/// Nothing registers this by default. With no implementation registered the headers configured
+/// under MCP:McpServerConfigs are used verbatim, which is the only behaviour there was
+/// before the hook existed — a host that does not implement it sees no change at all.
+///
+/// It exists so a host can call a server as whoever is driving the conversation instead of with
+/// one fixed credential. That decision belongs to the host: it is the only side that knows what
+/// a caller's credential is and which servers may be shown it.
+///
+///
+public interface IMcpClientHeaderProvider
+{
+ ///
+ /// Answers the headers to send to .
+ ///
+ ///
+ /// The headers from configuration. This dictionary is shared for the lifetime of the process,
+ /// so an implementation that changes a header MUST copy it rather than write into it.
+ ///
+ ///
+ /// The headers to send. Returning unchanged is the no-op answer,
+ /// and is the answer expected for any server the implementation does not recognise.
+ ///
+ Dictionary? GetHeaders(string serverId, Dictionary? configured);
+}
diff --git a/src/Infrastructure/BotSharp.Core/MCP/Managers/McpClientManager.cs b/src/Infrastructure/BotSharp.Core/MCP/Managers/McpClientManager.cs
index a07792919..8e21d74ef 100644
--- a/src/Infrastructure/BotSharp.Core/MCP/Managers/McpClientManager.cs
+++ b/src/Infrastructure/BotSharp.Core/MCP/Managers/McpClientManager.cs
@@ -34,7 +34,7 @@ public McpClientManager(
{
Name = config.Name,
Endpoint = new Uri(config.HttpConfig.EndPoint),
- AdditionalHeaders = config.HttpConfig.AdditionalHeaders,
+ AdditionalHeaders = ResolveHeaders(config.Id, config.HttpConfig.AdditionalHeaders),
ConnectionTimeout = config.HttpConfig.ConnectionTimeout
});
}
@@ -44,7 +44,7 @@ public McpClientManager(
{
Name = config.Name,
Endpoint = new Uri(config.SseConfig.EndPoint),
- AdditionalHeaders = config.SseConfig.AdditionalHeaders,
+ AdditionalHeaders = ResolveHeaders(config.Id, config.SseConfig.AdditionalHeaders),
ConnectionTimeout = config.SseConfig.ConnectionTimeout
});
}
@@ -74,6 +74,21 @@ public McpClientManager(
}
}
+ ///
+ /// The headers to open a connection with: the ones from configuration, unless the host has
+ /// registered an that wants to adjust them.
+ ///
+ ///
+ /// No provider is registered by default, and a provider is free to answer with what it was
+ /// given, so a host without one — or with one that does not recognise this server — gets the
+ /// configured headers back untouched.
+ ///
+ private Dictionary? ResolveHeaders(string serverId, Dictionary? configured)
+ {
+ var provider = _services.GetService();
+ return provider == null ? configured : provider.GetHeaders(serverId, configured);
+ }
+
public void Dispose()
{