How to Configure Custom Headers for MCP Server Authentication in Dify Plugins
The MCP client classes in the junjiem/dify-plugin-agent-mcp_sse repository accept a headers dictionary that is automatically attached to every HTTP request sent to an MCP server, enabling authentication via standard HTTP headers.
The junjiem/dify-plugin-agent-mcp_sse plugin provides Dify agents with the ability to connect to MCP (Model Context Protocol) servers using either SSE or Streamable HTTP transports. When these servers require authentication, you must configure custom headers to pass credentials such as Bearer tokens or API keys. This guide explains exactly how the header injection mechanism works and how to configure it properly.
Understanding the MCP Client Architecture
The plugin implements two concrete client classes—McpSseClient and McpStreamableHttpClient—that handle the underlying HTTP communication. Both classes utilize the httpx library for HTTP requests and support custom header injection during initialization.
Where Headers Are Read
The factory method McpClients.init_client (located in utils/mcp_client.py, lines 49‑62) extracts the optional headers field from each server's configuration dictionary. This factory inspects the transport type (sse or streamable_http) and instantiates the appropriate client class, forwarding the headers parameter directly to the constructor.
How Headers Are Applied
Both client implementations pass the received headers dictionary to the underlying httpx.Client instance upon initialization:
- SSE Client: In
utils/mcp_client.py(lines 94‑95), theMcpSseClientcreates anhttpx.Client(headers=self._headers), ensuring all SSE connections include the custom headers. - Streamable HTTP Client: In
utils/mcp_client.py(lines 41‑43), theMcpStreamableHttpClientsimilarly initializeshttpx.Client(headers=self._headers)for all RPC method calls.
Because the headers are bound to the httpx.Client instance, every subsequent operation—including initialize, list_tools, and call_tool—automatically includes the configured authentication headers.
Configuring Custom Headers in Your Dify Plugin
You can supply custom headers through the Dify plugin configuration interface using either YAML syntax (for declarative setup) or Python dictionaries (for programmatic instantiation).
YAML Configuration Example
When configuring the plugin through Dify's interface or a configuration file, structure your mcpServers entry with a headers sub-dictionary:
mcpServers:
my_secure_server:
url: "https://mcp.example.com/api"
transport: "sse" # or "streamable_http"
headers:
Authorization: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
X-API-Key: "sk_live_1234567890abcdef"
X-Custom-Header: "custom-value"
timeout: 60
sse_read_timeout: 120 # Only required for SSE transport
The headers object supports any valid HTTP header name. Standard authentication patterns include Authorization for Bearer tokens or X-API-Key for service-specific credentials.
Python Dictionary Configuration
If you are instantiating the McpClients class directly within Python code, pass the headers as part of the server configuration dictionary:
from utils.mcp_client import McpClients
servers_config = {
"my_secure_server": {
"url": "https://mcp.example.com/api",
"transport": "streamable_http",
"headers": {
"Authorization": "Bearer <your-access-token>",
"X-Request-ID": "unique-trace-id-12345"
},
"timeout": 30,
}
}
# Initialize clients with custom headers
clients = McpClients(servers_config, resources_as_tools=True)
Upon instantiation, the McpClients factory iterates through the configuration, detects the headers key, and passes it to the respective McpSseClient or McpStreamableHttpClient constructor.
Supported Authentication Header Patterns
The implementation supports any headers compatible with Python's httpx library. Common authentication patterns include:
- Bearer Token Authentication: Use the
Authorizationheader with aBearerprefix for OAuth 2.0 or JWT-based authentication. - API Key Authentication: Use custom headers such as
X-API-Keyorapi-keydepending on the MCP server's requirements. - Custom Corporate Headers: Include headers like
X-Request-ID,X-Correlation-ID, orX-Client-Versionfor tracing and audit purposes.
Since the headers are passed directly to the underlying HTTP client without transformation, you can implement any authentication scheme that relies on HTTP headers.
Summary
- The
junjiem/dify-plugin-agent-mcp_sseplugin supports custom headers through theheadersconfiguration key inmcpServersdefinitions. - The
McpClients.init_clientfactory inutils/mcp_client.py(lines 49‑62) extracts headers and passes them toMcpSseClientorMcpStreamableHttpClient. - Both client implementations bind the headers to an
httpx.Clientinstance (lines 41‑43 for HTTP, lines 94‑95 for SSE), ensuring automatic inclusion in all RPC calls. - Configuration supports standard authentication patterns including
Authorization(Bearer tokens) and custom headers likeX-API-Key.
Frequently Asked Questions
What file contains the header configuration logic for MCP clients?
The header configuration logic resides in utils/mcp_client.py. Specifically, the McpClients.init_client factory method (lines 49‑62) reads the headers field from the server configuration, and the client constructors (lines 41‑43 for McpStreamableHttpClient and lines 94‑95 for McpSseClient) apply these headers to the underlying httpx.Client.
Can I use both SSE and Streamable HTTP transports with custom headers?
Yes. Both transport implementations support custom headers identically. When you specify transport: "sse" or transport: "streamable_http" in your configuration, the init_client factory instantiates the appropriate class (McpSseClient or McpStreamableHttpClient) and passes the headers dictionary to both. The headers are then bound to the HTTP client in both cases.
How do I rotate or update authentication headers without restarting the Dify plugin?
The current implementation in utils/mcp_client.py initializes headers during client instantiation and binds them to the httpx.Client. To update headers dynamically, you would need to reinitialize the McpClients instance with updated configuration dictionaries containing the new header values. There is no built-in method to hot-swap headers on an active client connection; creating a new client instance with the updated headers configuration is the recommended approach.
Are there any restrictions on header names or values?
No specific restrictions are imposed by the plugin code beyond what Python's httpx library and HTTP standards enforce. You can use standard headers like Authorization or X-API-Key, as well as custom X- prefixed headers. The values are passed directly to httpx.Client(headers=...) without sanitization or transformation, so ensure your values are valid HTTP header strings (e.g., no newlines or non-ASCII characters unless properly encoded).
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →