Skip to content

feat: headers override for MCP operations#253

Merged
iamfiscus merged 1 commit intonerding-io:mainfrom
dtr-rgolubowicz:feature/override-headers
Dec 10, 2025
Merged

feat: headers override for MCP operations#253
iamfiscus merged 1 commit intonerding-io:mainfrom
dtr-rgolubowicz:feature/override-headers

Conversation

@dtr-rgolubowicz
Copy link
Copy Markdown
Contributor

@dtr-rgolubowicz dtr-rgolubowicz commented Nov 26, 2025

Description

Adds Headers Override functionality for MCP Client node, allowing dynamic header injection for HTTP and SSE connections. Override headers take precedence over credential headers, enabling per-workflow customization of API requests.

Related Issue

N/A

Type of Change

  • New feature (non-breaking change that adds functionality)
  • Bug fix (non-breaking change that fixes an issue)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Other (please describe):

How Has This Been Tested?

  • Added 12 unit tests for parseHeaders and mergeHeaders utility functions (all passing)
  • Tested locally in Docker n8n instance (v1.121.2)
  • Verified header parsing with various formats (newline-separated NAME=VALUE)
  • Validated header merging with precedence (override > credential)
  • Confirmed UI field visibility (HTTP/SSE only)

Checklist

  • My code follows the code style of this project
  • I have updated the documentation accordingly
  • I have added tests to cover my changes
  • All new and existing tests passed

Release Notes

New Feature: Headers Override

  • Add ability to override HTTP headers for MCP operations
  • Supports all operations: executeTool, readResource, listTools, etc.
  • Override headers take precedence over credential headers
  • Available for HTTP Streamable and SSE connection types
  • Format: newline-separated NAME=VALUE pairs

Screenshots (if applicable)

image

Summary by CodeRabbit

  • New Features
    • Added "Headers Override" parameter to MCP Client node for SSE and HTTP connections. Users can specify custom request headers in NAME=VALUE format; override headers take precedence over default headers.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Nov 26, 2025

Walkthrough

The pull request introduces a new "Headers Override" parameter to the McpClient node for SSE and HTTP connections, enabling users to add or override request headers. Header handling is refactored by extracting parseHeaders and mergeHeaders utility functions, with override headers taking precedence over credential headers.

Changes

Cohort / File(s) Summary
Utility functions
nodes/McpClient/utils.ts
New module exporting parseHeaders (converts newline-separated NAME=VALUE string to Record) and mergeHeaders (merges credential and override headers with override precedence)
Unit tests
nodes/McpClient/__tests__/utils.test.ts
Comprehensive test coverage for both utility functions, including edge cases (empty lines, equals signs in values, whitespace trimming, empty inputs)
Node parameter & header handling
nodes/McpClient/McpClient.node.ts
Added "Headers Override" parameter (SSE/HTTP only), refactored header parsing to use new utilities, integrated header merging into HTTP and SSE transport setup

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Node as McpClient Node
    participant Utils as Header Utils
    participant Transport as Transport Setup

    User->>Node: Provide credentials + headers override
    
    rect rgb(200, 220, 240)
    Note over Node,Utils: Header Processing
    Node->>Utils: parseHeaders(credentialHeaders)
    Utils-->>Node: parsedCredentials
    Node->>Utils: parseHeaders(headersOverride)
    Utils-->>Node: parsedOverride
    end
    
    rect rgb(220, 240, 200)
    Note over Node,Utils: Header Merging
    Node->>Utils: mergeHeaders(parsedCredentials, parsedOverride)
    Utils-->>Node: mergedHeaders<br/>(override takes precedence)
    end
    
    Node->>Transport: Setup with mergedHeaders
    Transport-->>User: Request ready with combined headers
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • The utility functions (parseHeaders, mergeHeaders) are straightforward with clear logic
  • Test coverage is thorough but follows standard patterns
  • Integration into the main node file is a clean refactor extracting previously inline logic
  • No complex control flow or edge cases beyond what the tests cover

Possibly related PRs

Poem

🐰 Headers dance in pairs so neat,
Override and credential meet,
Parse and merge with grace complete,
Tests ensure the logic's sweet,
Now requests are tall and fleet! 🎉

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main feature introduced: headers override capability for MCP operations. It directly reflects the primary change in the changeset.
Description check ✅ Passed The pull request description follows the repository template with all major sections completed: Description, Type of Change, How Has This Been Tested, Checklist, and Release Notes. All required information is present and well-documented.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
nodes/McpClient/utils.ts (1)

4-22: Consider simplifying the value check.

The condition value !== undefined at line 15 is redundant because substring() always returns a string, never undefined. If you want to allow empty header values (e.g., "Key="), you can simplify to just check name. If you want to exclude empty values, check name && value instead.

Apply this diff if you want to allow empty values:

 				const name = line.substring(0, equalsIndex).trim();
 				const value = line.substring(equalsIndex + 1).trim();
 				// Add to headers object if key is not empty and value is defined
-				if (name && value !== undefined) {
+				if (name) {
 					headers[name] = value;
 				}

Or this diff if you want to exclude empty values:

 				const name = line.substring(0, equalsIndex).trim();
 				const value = line.substring(equalsIndex + 1).trim();
-				// Add to headers object if key is not empty and value is defined
-				if (name && value !== undefined) {
+				// Add to headers object if key and value are not empty
+				if (name && value) {
 					headers[name] = value;
 				}
nodes/McpClient/__tests__/utils.test.ts (1)

4-55: Consider adding a test for empty header values.

The test suite is comprehensive, but it doesn't explicitly test the case where a header has an empty value (e.g., "Authorization=\nKey=value"). While the current implementation would handle this, explicit test coverage would make the intended behavior clearer.

Consider adding a test like:

it('should handle headers with empty values', () => {
  const input = 'Authorization=\nContent-Type=application/json\nX-Empty=';
  const result = parseHeaders(input);
  expect(result).toEqual({
    Authorization: '',
    'Content-Type': 'application/json',
    'X-Empty': '',
  });
});
nodes/McpClient/McpClient.node.ts (1)

364-379: Consider reusing parseHeaders for environment variable parsing.

The manual parsing logic here (lines 364-379) is very similar to the parseHeaders utility function. While outside the scope of this PR, consider refactoring this to use parseHeaders in the future to reduce code duplication and improve maintainability.

Example future refactor:

// Parse newline-separated environment variables from credentials
if (cmdCredentials.environments) {
  const parsedEnv = parseHeaders(cmdCredentials.environments as string);
  Object.assign(env, parsedEnv);
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 71c3d5b and d2da643.

📒 Files selected for processing (3)
  • nodes/McpClient/McpClient.node.ts (4 hunks)
  • nodes/McpClient/__tests__/utils.test.ts (1 hunks)
  • nodes/McpClient/utils.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
nodes/McpClient/McpClient.node.ts (1)
nodes/McpClient/utils.ts (2)
  • parseHeaders (4-22)
  • mergeHeaders (28-33)
nodes/McpClient/__tests__/utils.test.ts (1)
nodes/McpClient/utils.ts (2)
  • parseHeaders (4-22)
  • mergeHeaders (28-33)
🔇 Additional comments (6)
nodes/McpClient/utils.ts (1)

28-32: LGTM!

The merge implementation is clean and correctly implements the documented precedence behavior where dynamic headers override credential headers.

nodes/McpClient/__tests__/utils.test.ts (1)

57-136: LGTM!

The test coverage for mergeHeaders is thorough and validates all key scenarios including precedence behavior, empty inputs, and multiple header merging.

nodes/McpClient/McpClient.node.ts (4)

15-15: LGTM!

The import statement correctly references the new utility functions.


104-116: LGTM!

The parameter definition is well-structured with appropriate display options limiting visibility to SSE and HTTP connection types, and the description clearly explains the expected format and merge precedence behavior.


265-278: LGTM!

The header handling for HTTP transport correctly implements the feature with proper parsing of both credential and override headers, backward-compatible parameter retrieval, and correct merge precedence.


313-326: LGTM!

The SSE transport implementation mirrors the HTTP path correctly, with headers properly applied to both eventSourceInit and requestInit as needed for SSE connections.

@dtr-rgolubowicz
Copy link
Copy Markdown
Contributor Author

is there any chance to merge it?

@iamfiscus iamfiscus merged commit 06a948a into nerding-io:main Dec 10, 2025
4 checks passed
@dtr-rgolubowicz
Copy link
Copy Markdown
Contributor Author

hey @iamfiscus , thanks for merging that. Although, publish to NPM registry failed -> token has expired. Could you sort it out? :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants