Skip to content

Conversation

pottekkat
Copy link
Collaborator

@pottekkat pottekkat commented Jul 16, 2025

Description

Fixes the nil pointer dereference error when sendHTTP fails but the method is initialize and the resp is nil.

Ideally, we might need to rethink this to handle carefully.

There's also a race condition in the test which surfaced when I made this change. That is also fixed.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • MCP spec compatibility implementation
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code refactoring (no functional changes)
  • Performance improvement
  • Tests only (no functional changes)
  • Other (please describe):

Checklist

  • My code follows the code style of this project
  • I have performed a self-review of my own code
  • I have added tests that prove my fix is effective or that my feature works
  • I have updated the documentation accordingly

Summary by CodeRabbit

Summary by CodeRabbit

  • Bug Fixes
    • Fixed a rare issue that could cause the application to crash during certain request initializations.
    • Improved reliability of internal processes by enhancing test synchronization methods.

Copy link
Contributor

coderabbitai bot commented Jul 16, 2025

Walkthrough

The update modifies the SendRequest method in the StreamableHTTP type to prevent a potential nil pointer dereference by adding a nil check before deferring the closure of resp.Body. Additionally, test cases in server/sse_test.go were improved by replacing boolean flags with channels to synchronize hook invocation more reliably.

Changes

File(s) Change Summary
client/transport/streamable_http.go Added a nil check before deferring resp.Body.Close() in SendRequest to prevent panic.
server/sse_test.go Replaced boolean flags with unbuffered channels and select statements to synchronize hook calls in tests.

Possibly related PRs

Suggested reviewers

  • ezynda3
  • dugenkui03

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ef2e795 and 800e529.

📒 Files selected for processing (1)
  • server/sse_test.go (3 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: ezynda3
PR: mark3labs/mcp-go#461
File: server/sampling.go:22-26
Timestamp: 2025-06-30T07:13:17.052Z
Learning: In the mark3labs/mcp-go project, the MCPServer.capabilities field is a struct value (serverCapabilities), not a pointer, so it cannot be nil and doesn't require nil checking. Only pointer fields within the capabilities struct should be checked for nil.
Learnt from: leavez
PR: mark3labs/mcp-go#114
File: client/transport/sse.go:137-179
Timestamp: 2025-04-06T10:07:06.685Z
Learning: The SSE client implementation in the MCP-Go project uses a 30-second timeout for reading SSE events to match the behavior of the original implementation before the transport layer refactoring.
Learnt from: robert-jackson-glean
PR: mark3labs/mcp-go#214
File: server/sse.go:0-0
Timestamp: 2025-04-28T00:14:49.263Z
Learning: The SSE server in mcp-go implements path sanitization within the `WithDynamicBasePath` function that ensures the dynamic base path starts with "/" and has no trailing "/" to prevent double slashes in URL construction.
server/sse_test.go (2)
Learnt from: octo
PR: mark3labs/mcp-go#149
File: mcptest/mcptest.go:0-0
Timestamp: 2025-04-21T21:26:32.945Z
Learning: In the mcptest package, prefer returning errors from helper functions rather than calling t.Fatalf() directly, giving callers flexibility in how to handle errors.
Learnt from: floatingIce91
PR: mark3labs/mcp-go#401
File: server/server.go:1082-1092
Timestamp: 2025-06-23T11:10:42.948Z
Learning: In Go MCP server, ServerTool.Tool field is only used for tool listing and indexing, not for tool execution or middleware. During handleToolCall, only the Handler field is used, so dynamic tools don't need the Tool field populated.
🔇 Additional comments (4)
server/sse_test.go (4)

1449-1456: Excellent synchronization improvement using channels.

The replacement of boolean flags with unbuffered channels provides much more reliable synchronization. The select statement with default case properly prevents double-closing of the channel, which is a good defensive programming practice.


1513-1518: Proper timeout handling for channel synchronization.

The select statement with timeout provides reliable detection of hook invocation while preventing indefinite blocking. The 1-second timeout is appropriate for this test scenario.


1523-1530: Consistent channel-based synchronization pattern.

This follows the same improved synchronization approach as the first test case, maintaining consistency across the test suite. The channel-based approach is much more reliable than the previous boolean flag method.


1602-1607: Completes the synchronization improvement consistently.

The timeout handling matches the pattern from the first test case, maintaining consistency across the test suite. This replaces the unreliable sleep-based approach with deterministic channel synchronization.

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
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 (1)
client/transport/streamable_http.go (1)

255-260: Good defensive fix for nil pointer dereference.

The nil check before deferring resp.Body.Close() correctly prevents the panic when sendHTTP fails and returns a nil response. This is a solid defensive programming practice.

The comment accurately describes the issue and acknowledges that this is a temporary solution. The fallthrough logic around lines 247-254 does appear to need restructuring for better clarity and maintainability.

Consider refactoring the fallthrough logic to make the code flow clearer:

 resp, err := c.sendHTTP(ctx, http.MethodPost, bytes.NewReader(requestBody), "application/json, text/event-stream")
 if err != nil {
-	if errors.Is(err, ErrSessionTerminated) && request.Method == string(mcp.MethodInitialize) {
-		// If the request is initialize, should not return a SessionTerminated error
-		// It should be a genuine endpoint-routing issue.
-		// ( Fall through to return StatusCode checking. )
-	} else {
-		return nil, fmt.Errorf("failed to send request: %w", err)
-	}
+	// For initialize requests, ErrSessionTerminated should be treated as endpoint-routing issue
+	if !(errors.Is(err, ErrSessionTerminated) && request.Method == string(mcp.MethodInitialize)) {
+		return nil, fmt.Errorf("failed to send request: %w", err)
+	}
+	// resp might be nil here, so we need to check before using it
 }
-// When sendHTTP fails and resp is nil but method is mcp.MethodInitialize
-// defer resp.Body.Close() fails with nil pointer dereference.
-// TODO: Restructure this fallthrough logic properly.
 if resp != nil {
 	defer resp.Body.Close()
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between baa7153 and 95201f2.

📒 Files selected for processing (1)
  • client/transport/streamable_http.go (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: ezynda3
PR: mark3labs/mcp-go#461
File: server/sampling.go:22-26
Timestamp: 2025-06-30T07:13:17.052Z
Learning: In the mark3labs/mcp-go project, the MCPServer.capabilities field is a struct value (serverCapabilities), not a pointer, so it cannot be nil and doesn't require nil checking. Only pointer fields within the capabilities struct should be checked for nil.
client/transport/streamable_http.go (1)
Learnt from: ezynda3
PR: mark3labs/mcp-go#461
File: server/sampling.go:22-26
Timestamp: 2025-06-30T07:13:17.052Z
Learning: In the mark3labs/mcp-go project, the MCPServer.capabilities field is a struct value (serverCapabilities), not a pointer, so it cannot be nil and doesn't require nil checking. Only pointer fields within the capabilities struct should be checked for nil.

@pottekkat pottekkat marked this pull request as draft July 16, 2025 18:02
@pottekkat pottekkat marked this pull request as ready for review July 16, 2025 18:14
@pottekkat pottekkat marked this pull request as draft July 16, 2025 18:49
@pottekkat pottekkat marked this pull request as ready for review July 17, 2025 05:49
@pottekkat pottekkat merged commit 7c38b56 into mark3labs:main Jul 21, 2025
4 checks passed
@pottekkat pottekkat deleted the fix/nil-pointer-dereference branch July 21, 2025 05:58
@andig
Copy link
Contributor

andig commented Jul 27, 2025

Please allow me to comment that this does not look like a safe and solid fix. It would be clearer to handle the return in the if err statement above and then rely on resp being non-nil. This solution looks a bit awkward. Please ignore me if this comment is undesired.

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.

3 participants