Skip to content

Conversation

opencow
Copy link
Contributor

@opencow opencow commented Aug 27, 2025

Description

Fixes #352
Adds an option to configure hosting the streamble-http server with TLS

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

MCP Spec Compliance

  • This PR implements a feature defined in the MCP specification
  • Link to relevant spec section: Link text
  • Implementation follows the specification exactly

Additional Information

Summary by CodeRabbit

  • New Features

    • Optional HTTPS (TLS) support for the HTTP transport: provide certificate and key to run securely; falls back to HTTP and returns clearer errors when TLS files are missing/invalid.
  • Tests

    • Added test to verify TLS configuration is recorded; updated JSON helper to set Content-Type.
  • Documentation

    • Updated docs to show how to enable TLS for the HTTP transport.

tls
Copy link
Contributor

coderabbitai bot commented Aug 27, 2025

Walkthrough

Adds optional TLS support to StreamableHTTPServer via a new WithTLSCert option, two new tls file fields, runtime validation of cert/key paths, conditional ListenAndServeTLS use in Start, a unit test asserting TLS fields, and docs showing the new option. (≤50 words)

Changes

Cohort / File(s) Summary
Server: TLS option & runtime
server/streamable_http.go
Added public option WithTLSCert(certFile, keyFile string); added tlsCertFile and tlsKeyFile fields to StreamableHTTPServer; validate both cert and key are provided and exist (using os.Stat); Start calls ListenAndServeTLS when valid TLS paths are set, otherwise falls back to ListenAndServe; minor whitespace edits in handlers.
Server: tests
server/streamable_http_test.go
Added TestStreamableHTTPServer_TLS asserting WithTLSCert stores cert/key paths on the server instance; postJSON helper now sets Content-Type: application/json.
Docs
www/docs/pages/servers/basics.mdx
Documentation updated to show WithTLSCert(certPath, keyPath) as a ServerOption for the HTTP transport and included in example server creation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
Add TLS support to HTTP server startup so ListenAndServeTLS can be used instead of ListenAndServe (#352)

Possibly related PRs

Suggested reviewers

  • pottekkat

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d9a637a and b9749d4.

📒 Files selected for processing (1)
  • www/docs/pages/servers/basics.mdx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • www/docs/pages/servers/basics.mdx
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbit in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbit 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:
    • @coderabbit gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbit read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

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

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbit help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbit ignore or @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbit summary or @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbit or @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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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: 2

🧹 Nitpick comments (3)
server/streamable_http.go (2)

676-697: canUseTLS comment overpromises; either validate keypair or soften wording

The code only checks file existence; it doesn’t validate certificate/key contents. Either update the comment or load/parse the keypair.

Minimal doc fix:

-// canUseTLS checks if TLS is properly configured and files are valid
+// canUseTLS reports whether TLS was configured and both files exist on disk.
+// Note: It does not validate certificate/key contents.

Optionally, actually validate:

 func (s *StreamableHTTPServer) canUseTLS() bool {
@@
- // Check certificate file
- if _, err := os.Stat(s.tlsCertFile); err != nil {
+ // Check certificate file
+ if _, err := os.Stat(s.tlsCertFile); err != nil {
   s.logger.Errorf("TLS certificate file error: %v", err)
   return false
 }
@@
- // Check key file
- if _, err := os.Stat(s.tlsKeyFile); err != nil {
+ // Check key file
+ if _, err := os.Stat(s.tlsKeyFile); err != nil {
   s.logger.Errorf("TLS key file error: %v", err)
   return false
 }
 
- return true
+ // Ensure the pair is loadable
+ if _, err := tls.LoadX509KeyPair(s.tlsCertFile, s.tlsKeyFile); err != nil {
+   s.logger.Errorf("TLS keypair load error: %v", err)
+   return false
+ }
+ return true
 }

Add import:

import (
  // ...
  "crypto/tls"
)

97-105: Clarify option semantics and scope in docstring

Make it explicit this affects Start only and that invalid paths will cause Start to error (with the above change).

-// WithTLSCert sets the TLS certificate and key files for HTTPS support.
-// Both certFile and keyFile must be provided to enable TLS.
+// WithTLSCert sets the TLS certificate and key files for HTTPS support.
+// Only used by Start(); it has no effect when using this server as an http.Handler behind another server.
+// If either parameter is set, TLS is considered requested. Start will return an error if the files are not usable.
server/streamable_http_test.go (1)

962-987: Rename test to reflect existence-only check (not validity)

The files are empty; canUseTLS doesn’t validate contents. Rename for clarity.

- t.Run("canUseTLS returns true with valid temp cert and key files", func(t *testing.T) {
+ t.Run("canUseTLS returns true when cert and key files exist (content not validated)", func(t *testing.T) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4e353ac and b00fc65.

📒 Files selected for processing (2)
  • server/streamable_http.go (10 hunks)
  • server/streamable_http_test.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
server/streamable_http.go (1)
mcp/types.go (1)
  • JSONRPCNotification (333-336)
server/streamable_http_test.go (2)
server/server.go (1)
  • NewMCPServer (299-325)
server/streamable_http.go (2)
  • NewStreamableHTTPServer (150-165)
  • WithTLSCert (99-104)
🔇 Additional comments (7)
server/streamable_http.go (4)

145-146: LGTM: private TLS fields added

Keeps surface minimal; combined with options pattern this is fine.


257-259: LGTM: clearer sampling-response detection condition

The boolean is precise and readable.


411-414: LGTM: active session tracking with cleanup

Store/Delete via defer avoids leaks for sampling responses.


785-797: LGTM: sampling request lifecycle and backpressure

Buffered chans, per-request response channel, Store/Delete, and context handling look correct for avoiding deadlocks.

Also applies to: 852-886

server/streamable_http_test.go (3)

898-915: LGTM: option wiring test

Asserts fields are set via WithTLSCert.


917-960: LGTM: negative cases for canUseTLS

Covers unconfigured and missing-file scenarios well.


989-1025: LGTM: asymmetric existence cases covered

Good negative coverage.

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 (6)
www/docs/pages/servers/basics.mdx (2)

181-187: Add TLS option example: good; fix option name and clarify PEM paths

  • The example looks right, but the option is spelled WithStateLess in code (capital L). Docs show WithStateless. Align the snippet.
  • Consider showing PEM extensions to reduce confusion.

Apply:

 httpServer := server.NewStreamableHTTPServer(s,
     server.WithEndpointPath("/mcp"),
-    server.WithStateless(true),
-    server.WithTLSCert("/path/to/cert", "/path/to/key")
+    server.WithStateLess(true),
+    server.WithTLSCert("/path/to/cert.pem", "/path/to/key.pem")
 )

228-231: Stray closing brace in example block

There appears to be one extra “}” at the end of the Environment-Based Configuration example. Trim it to avoid copy/paste errors.

Apply:

-}
-}
+}
server/streamable_http.go (4)

204-216: Fail-fast TLS startup logic: good; add minor hardening and polish

  • Keep fail-fast behavior (great).
  • Improve error style (lowercase, Go convention).
  • Guard against directories being passed.
  • Optionally enforce TLS 1.2+ via http.Server.TLSConfig.

Apply:

 if s.tlsCertFile != "" || s.tlsKeyFile != "" {
-    if s.tlsCertFile == "" || s.tlsKeyFile == "" {
-        return fmt.Errorf("both TLS cert and key must be provided")
-    }
-    if _, err := os.Stat(s.tlsCertFile); err != nil {
-        return fmt.Errorf("Failed to find TLS certificate file: %w", err)
-    }
-    if _, err := os.Stat(s.tlsKeyFile); err != nil {
-        return fmt.Errorf("Failed to find TLS key file: %w", err)
-    }
+    if s.tlsCertFile == "" || s.tlsKeyFile == "" {
+        return fmt.Errorf("both tls cert and key must be provided")
+    }
+    if fi, err := os.Stat(s.tlsCertFile); err != nil {
+        return fmt.Errorf("failed to find tls certificate file: %w", err)
+    } else if !fi.Mode().IsRegular() {
+        return fmt.Errorf("tls certificate path is not a regular file: %q", s.tlsCertFile)
+    }
+    if fi, err := os.Stat(s.tlsKeyFile); err != nil {
+        return fmt.Errorf("failed to find tls key file: %w", err)
+    } else if !fi.Mode().IsRegular() {
+        return fmt.Errorf("tls key path is not a regular file: %q", s.tlsKeyFile)
+    }
+    // Enforce modern TLS by default; honor existing TLSConfig if set
+    if srv.TLSConfig == nil {
+        srv.TLSConfig = &tls.Config{MinVersion: tls.VersionTLS12}
+    } else if srv.TLSConfig.MinVersion == 0 {
+        srv.TLSConfig.MinVersion = tls.VersionTLS12
+    }
     return srv.ListenAndServeTLS(s.tlsCertFile, s.tlsKeyFile)
 }

Add import:

import "crypto/tls"

772-775: Sampling flow: consider configurability and timeout ergonomics

  • Channel sizes (notification 100, sampling 10) are hard-coded. Consider a StreamableHTTPOption to tune these for high-load deployments.
  • RequestSampling returns “server overloaded” when the queue is full; offering a context-aware wait with a short timeout could be nicer DX.

Also applies to: 779-784, 839-874


185-201: Minor: log when starting with TLS

Optional: emit an Info-level log when TLS is enabled (address + endpoint), which helps ops verify mode.

Example:

 s.mu.Unlock()

 if s.tlsCertFile != "" || s.tlsKeyFile != "" {
+    s.logger.Infof("Starting HTTPS server on %s%s", srv.Addr, s.endpointPath)
     ...
 }

81-88: Custom http.Server note is clear, but TLSConfig interplay is implicit

If callers pass a custom http.Server, clarifying that Start honors srv.TLSConfig (and won’t override it) would help. No code change required.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 8bc3e0d and 4d88782.

📒 Files selected for processing (3)
  • server/streamable_http.go (9 hunks)
  • server/streamable_http_test.go (1 hunks)
  • www/docs/pages/servers/basics.mdx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • server/streamable_http_test.go
🧰 Additional context used
🧬 Code graph analysis (1)
server/streamable_http.go (1)
mcp/types.go (1)
  • JSONRPCNotification (333-336)
🔇 Additional comments (5)
server/streamable_http.go (5)

11-11: Import os: OK

Needed for cert/key existence checks. No issues.


97-104: Public TLS option API: clear and minimally scoped

Naming and doc comment are clear; storing paths on the server is appropriate.


145-147: New TLS fields: appropriate encapsulation

Unexported fields on the server struct are correct.


266-268: Sampling-response detection readability: OK

Refactor improves clarity without changing behavior.


420-423: Active session registration for sampling: OK

Registering and deferring delete looks correct and prevents leaks.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
www/docs/pages/servers/basics.mdx (1)

181-186: Fix Go snippet: add trailing comma after WithTLSCert in multiline call

Missing trailing comma will make this example not compile when gofmt’d.

 httpServer := server.NewStreamableHTTPServer(s,
     server.WithEndpointPath("/mcp"),
     server.WithStateless(true),
-    server.WithTLSCert("/path/to/cert.pem", "/path/to/key.pem")
+    server.WithTLSCert("/path/to/cert.pem", "/path/to/key.pem"),
 )
🧹 Nitpick comments (1)
www/docs/pages/servers/basics.mdx (1)

181-186: Optional doc note: clarify TLS expectations

Consider a one-liner below the snippet: “WithTLSCert enables HTTPS; expects PEM-encoded cert/key files readable by the process. Start returns an error if either file is missing/invalid.”

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4d88782 and d9a637a.

📒 Files selected for processing (2)
  • server/streamable_http.go (9 hunks)
  • www/docs/pages/servers/basics.mdx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • server/streamable_http.go
🔇 Additional comments (1)
www/docs/pages/servers/basics.mdx (1)

181-186: No action needed: WithTLSCert signature and behavior match the documentation
Verified that in server/streamable_http.go (around line 99) the exported function

func WithTLSCert(certFile, keyFile string) StreamableHTTPOption

exactly matches the docs’ use of

server.WithTLSCert("/path/to/cert.pem", "/path/to/key.pem")

– the parameter order (cert then key) and return type (StreamableHTTPOption) are correct. The TLS fields on StreamableHTTPServer are properly applied and ListenAndServeTLS is invoked when both files are set.

@ezynda3 ezynda3 merged commit 40ce109 into mark3labs:main Sep 2, 2025
4 checks passed
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.

feature: TLS suppprt
2 participants