# What Custom Headers Are Automatically Added to MCP Requests in Dify Plugins

> Discover the custom headers Dify MCP SSE plugins automatically add to requests. Learn about Content-Type, Accept, and Mcp-Session-Id headers for JSON-RPC 2.0 compliance and session affinity.

- Repository: [Junjie.M/dify-plugin-tools-mcp_sse](https://github.com/junjiem/dify-plugin-tools-mcp_sse)
- Tags: how-to-guide
- Published: 2026-03-05

---

**The Dify MCP SSE plugin automatically injects `Content-Type: application/json`, `Accept: application/json, text/event-stream`, and `Mcp-Session-Id` headers into MCP requests to ensure JSON-RPC 2.0 compliance, content negotiation, and session affinity.**

When integrating with the `junjiem/dify-plugin-tools-mcp_sse` repository, understanding what custom headers are automatically added to MCP requests is critical for debugging authentication flows and managing stateful connections. The plugin supports two transport mechanisms—Server-Sent Events (SSE) and streamable HTTP—each automatically injecting specific headers to maintain protocol compliance and session state.

## Automatically Injected MCP Headers

The transport clients in [`utils/mcp_client.py`](https://github.com/junjiem/dify-plugin-tools-mcp_sse/blob/main/utils/mcp_client.py) automatically append specific headers based on the transport type and connection state.

### Content-Type: application/json

Both the SSE-based client (`McpSseClient.send_message`) and the streamable-HTTP client (`McpStreamableHttpClient.send_message`) automatically inject **`Content-Type: application/json`** when sending POST requests to the MCP server.

This header informs the MCP server that the request body follows JSON-RPC 2.0 encoding, which is required for all MCP method calls according to the protocol specification.

### Accept: application/json, text/event-stream

The **`Accept: application/json, text/event-stream`** header is automatically added by `McpStreamableHttpClient.send_message` during HTTP transport initialization.

This content-negotiation header tells the MCP server that the client can process either standard JSON responses or Server-Sent Events (SSE) streams. The client handles both formats dynamically based on the server's response type, enabling flexible transport mechanisms.

### Mcp-Session-Id: Session Affinity

The **`Mcp-Session-Id`** header provides session affinity for stateful MCP connections and is managed dynamically by `McpStreamableHttpClient`:

1. After the first server response containing the `mcp-session-id` header, the client extracts and stores the UUID
2. The client capitalizes the header name as `Mcp-Session-Id` when storing it (`headers["Mcp-Session-Id"] = self.session_id`)
3. Every subsequent request automatically includes this header without manual intervention

This mechanism ensures the server can associate all calls with the same logical session for state preservation, rate-limiting, or maintaining authentication context across multiple requests.

## User-Defined Custom Headers

Beyond automatically injected protocol headers, the plugin supports user-defined headers through server configuration in [`provider/mcp_tool.yaml`](https://github.com/junjiem/dify-plugin-tools-mcp_sse/blob/main/provider/mcp_tool.yaml).

When configuring an MCP server, developers can specify a `headers` dictionary in the configuration. These headers are retrieved via `config.get("headers", None)` and passed directly to the underlying `httpx.Client` initialization.

This mechanism allows injection of deployment-specific headers such as API keys, tenant identifiers, or custom authentication tokens that are not part of the MCP protocol but are required by specific server implementations.

## Implementation Details in the Source Code

The header injection logic resides primarily in [`utils/mcp_client.py`](https://github.com/junjiem/dify-plugin-tools-mcp_sse/blob/main/utils/mcp_client.py), which contains both client implementations:

- **`McpSseClient.send_message`**: Handles SSE transport and injects `Content-Type: application/json` for POST requests
- **`McpStreamableHttpClient.send_message`**: Handles streamable HTTP transport and manages `Content-Type`, `Accept`, and dynamic `Mcp-Session-Id` headers

The session ID persistence mechanism checks for the `mcp-session-id` response header after each request and updates the client's `session_id` attribute, which is then referenced in subsequent request headers.

## Practical Code Examples

### Streamable HTTP Client with Automatic Headers

```python

# Streamable‑HTTP client – automatic headers when sending a request

client = McpStreamableHttpClient(
    name="my_mcp",
    url="https://example.com/mcp",
    headers={"Authorization": "Bearer <token>"},  # user‑provided, forwarded automatically

)

# First request – only the JSON headers are sent

client.send_message({
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {...}
})

# => Headers sent:

#   Content-Type: application/json

#   Accept: application/json, text/event-stream

#   Authorization: Bearer <token>

# Server answers with a session header

#   mcp-session-id: 9b3e1fca‑d4a7‑4f2b‑a0f4‑c1e2d5e7f9a0

# Subsequent requests automatically include the session header

client.send_message({...})

# => Headers sent now also include:

#   Mcp-Session-Id: 9b3e1fca‑d4a7‑4f2b‑a0f4‑c1e2d5e7f9a0

```

### SSE Client with User-Defined Headers

```python

# SSE client – only the JSON header is needed for POSTs

sse_client = McpSseClient(
    name="my_mcp",
    url="https://example.com/mcp/sse",
    headers={"X-Custom": "value"}  # user‑provided, forwarded automatically

)

sse_client.send_message({
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/list",
    "params": {}
})

# => Headers sent:

#   Content-Type: application/json

#   X-Custom: value

```

## Summary

- **`Content-Type: application/json`** is automatically added by both `McpSseClient` and `McpStreamableHttpClient` to ensure JSON-RPC 2.0 compliance.
- **`Accept: application/json, text/event-stream`** is injected by the streamable HTTP client to negotiate response formats.
- **`Mcp-Session-Id`** is dynamically managed by `McpStreamableHttpClient` after the server returns a session ID, ensuring stateful session affinity.
- **User-defined headers** from the YAML configuration in [`provider/mcp_tool.yaml`](https://github.com/junjiem/dify-plugin-tools-mcp_sse/blob/main/provider/mcp_tool.yaml) are propagated through `httpx.Client` for deployment-specific requirements like authentication tokens.

## Frequently Asked Questions

### What is the purpose of the Mcp-Session-Id header?

The `Mcp-Session-Id` header provides session affinity for stateful MCP connections. After the initial handshake, the server returns a unique session identifier that the client stores and resends with every subsequent request. This allows the server to associate all calls with the same logical session for state preservation, rate-limiting, or maintaining authentication context across multiple API calls.

### Can I add custom authentication headers to MCP requests?

Yes, you can add custom authentication headers through the server configuration in [`provider/mcp_tool.yaml`](https://github.com/junjiem/dify-plugin-tools-mcp_sse/blob/main/provider/mcp_tool.yaml). When defining an MCP server, include a `headers` dictionary containing your required headers such as `Authorization: Bearer <token>` or API keys. These headers are retrieved via `config.get("headers", None)` and automatically passed to the underlying `httpx.Client`, ensuring they are included in every request alongside the automatically injected protocol headers.

### Does the SSE client support the same headers as the HTTP client?

No, the SSE client (`McpSseClient`) and the streamable HTTP client (`McpStreamableHttpClient`) handle headers differently. Both automatically inject `Content-Type: application/json`, but only the HTTP client adds `Accept: application/json, text/event-stream` and manages the `Mcp-Session-Id` header for session affinity. The SSE transport maintains connection state through the SSE protocol itself rather than HTTP session headers, making the session ID header unnecessary for that transport mechanism.

### Where are these headers configured in the Dify plugin?

The automatic headers are hardcoded in [`utils/mcp_client.py`](https://github.com/junjiem/dify-plugin-tools-mcp_sse/blob/main/utils/mcp_client.py) within the `send_message` methods of both client classes. User-defined custom headers are configured in [`provider/mcp_tool.yaml`](https://github.com/junjiem/dify-plugin-tools-mcp_sse/blob/main/provider/mcp_tool.yaml) under the server configuration's `headers` field. These custom headers are then propagated through the `httpx.Client` initialization, allowing you to inject deployment-specific requirements like tenant identifiers or custom authentication tokens alongside the automatically managed protocol headers.