Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@ezynda3
Copy link
Contributor

@ezynda3 ezynda3 commented Oct 24, 2025

Description

Implements session-specific resource templates to achieve parity with existing SessionWithTools and SessionWithResources interfaces. This allows individual sessions to have their own resource templates that override global templates with the same URI pattern.

Fixes #622

Type of Change

  • New feature (non-breaking change that adds functionality)
  • MCP spec compatibility implementation

Implementation Details

Core Components

  • SessionWithResourceTemplates Interface: New interface extending ClientSession with methods to get/set session-specific resource templates
  • Session Management Methods: AddSessionResourceTemplate(s) and DeleteSessionResourceTemplates methods following the pattern of existing session management APIs
  • Transport Support: Full implementation in both SSE and StreamableHTTP transports using thread-safe storage patterns

Key Features

  1. Session Template Precedence: Session templates override global templates with matching URI patterns
  2. Resource Listing Integration: handleListResourceTemplates merges session and global templates
  3. Resource Reading Integration: handleReadResource checks session templates before global templates
  4. Notification Support: Sends notifications/resources/list_changed when session templates are modified
  5. Thread Safety: Uses sync.Map (SSE) and centralized sync.RWMutex store (HTTP) for concurrent access

Files Changed

  • server/session.go: Interface definition and session management methods
  • server/errors.go: New error constant for unsupported sessions
  • server/sse.go: SSE transport implementation using sync.Map
  • server/streamable_http.go: StreamableHTTP transport using centralized store pattern
  • server/server.go: Resource handler integration for listing and reading
  • server/streamable_http_sampling_test.go: Updated test calls

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: Resource Templates
  • Implementation follows the specification exactly

Testing

All automated verification passed:

  • βœ… Build successful: go build ./...
  • βœ… Linting passed: golangci-lint run (0 issues)
  • βœ… Tests passed: go test ./server
  • βœ… Race detection compatible

Test Coverage

  • Thread-safety verified through sync.Map and sync.RWMutex patterns
  • Existing tests continue to pass without modification
  • Pattern consistency verified against SessionWithTools and SessionWithResources

Additional Information

This implementation resolves the issue where users could not add resource templates at the session level because URI validation rejected RFC 6570 template syntax. Session-specific resource templates now work identically to session-specific tools and resources, providing a consistent API experience.

Summary by CodeRabbit

  • New Features

    • Sessions can store per-session resource templates that override global templates; session templates are included in listings and reads
    • Add/delete session resource templates with lifecycle-aware notifications
  • Bug Fixes / Behavior

    • Notifications only sent for initialized sessions and when capability enabled
    • Validation for template URIs and explicit error returned when a session lacks template support
  • Tests

    • Comprehensive tests for session templates, overrides, notifications, and error cases

…templates

Implements session-specific resource templates to achieve parity with
SessionWithTools and SessionWithResources. This allows sessions to have
their own resource templates that override global templates with the
same URI pattern.

Key changes:
- Add SessionWithResourceTemplates interface to ClientSession hierarchy
- Implement interface in both SSE and StreamableHTTP transports
- Add AddSessionResourceTemplate(s) and DeleteSessionResourceTemplates methods
- Update handleListResourceTemplates to merge session and global templates
- Update handleReadResource to check session templates before global ones
- Session templates trigger notifications/resources/list_changed when modified

Closes #622
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 24, 2025

Walkthrough

Adds session-scoped resource template support: new SessionWithResourceTemplates interface and error constant, per-session template storage/access in SSE and StreamableHTTP sessions, server APIs to add/delete session templates, and handler changes to prefer session templates over global ones.

Changes

Cohort / File(s) Summary
Error Definition
server/errors.go
Adds exported error constant ErrSessionDoesNotSupportResourceTemplates.
Core handler updates
server/server.go
handleListResourceTemplates merges session templates with global templates (session overrides); handleReadResource consults session templates before global ones and extracts URI params from matching template.
Session API & logic
server/session.go
Adds SessionWithResourceTemplates interface and MCPServer methods: AddSessionResourceTemplate, AddSessionResourceTemplates, DeleteSessionResourceTemplates with URI validation, merging, and list_changed notification semantics.
SSE session implementation
server/sse.go
Adds resourceTemplates sync.Map to sseSession, implements GetSessionResourceTemplates and SetSessionResourceTemplates, and asserts _ SessionWithResourceTemplates = (*sseSession)(nil).
StreamableHTTP session & store
server/streamable_http.go
Introduces sessionResourceTemplatesStore type and wiring; adds sessionResourceTemplates store field to StreamableHTTPServer and resourceTemplates to streamableHttpSession; updates constructors and lifecycle handlers (POST/GET/DELETE) to pass/store templates; adds session accessors.
Tests
server/streamable_http_sampling_test.go, server/session_resource_templates_test.go
Updates newStreamableHttpSession call sites to pass templates store; adds comprehensive tests for session-scoped resource templates, notifications, overrides, additions, deletions, and error cases.
Module manifest
go.mod
Module file present in diff.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Potential hotspots to review:

  • Concurrency and copying semantics of session template stores (sync.Map usage and map cloning).
  • Notification/send-list-changed logic paths (initialized vs uninitialized sessions) in AddSessionResourceTemplates and DeleteSessionResourceTemplates.
  • Template matching precedence and URI variable extraction in handleReadResource.
  • Streamable HTTP session lifecycle plumbing to ensure templates are cleaned up on delete.

Possibly related PRs

Suggested labels

type: enhancement

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
βœ… Passed checks (4 passed)
Check name Status Explanation
Title Check βœ… Passed The pull request title "feat: add SessionWithResourceTemplates for session-specific resource templates" directly and concisely describes the main change: introducing a new SessionWithResourceTemplates interface to support session-scoped resource templates. The title is clear, specific, and avoids vague terminology. It accurately reflects the primary objective of achieving parity with existing SessionWithTools and SessionWithResources interfaces.
Linked Issues Check βœ… Passed The code changes comprehensively address all primary objectives from linked issue #622. The implementation introduces the SessionWithResourceTemplates interface extending ClientSession [#622], exposes management methods AddSessionResourceTemplate(s) and DeleteSessionResourceTemplates accepting handlers tied to session IDs [#622], implements session templates that override global templates for matching URI patterns [#622], and adds support across both SSE and StreamableHTTP transports using thread-safe storage patterns. The new error constant ErrSessionDoesNotSupportResourceTemplates handles validation for unsupported sessions [#622], and resource listing/reading handlers properly merge and prioritize session templates over global ones [#622].
Out of Scope Changes Check βœ… Passed All code changes are directly aligned with implementing session-specific resource templates as defined in issue #622. Modifications to server/errors.go, server/session.go, server/sse.go, and server/streamable_http.go provide the core interface and transport implementations; changes to server/server.go integrate session templates into resource listing and reading handlers; test updates in server/streamable_http_sampling_test.go maintain consistency with modified signatures; and the new server/session_resource_templates_test.go provides comprehensive test coverage. No unrelated refactoring, formatting changes, or feature scope creep is evident.
Description Check βœ… Passed The pull request description comprehensively follows the repository template with all required sections properly filled out. It includes a clear description of the feature, properly categorized type of change selections, a completed checklist, detailed MCP spec compliance information with a link to the relevant specification section, and thorough additional information covering implementation details, files changed, and testing verification. The description provides sufficient context for reviewers to understand both the what and why of the changes.
✨ Finishing touches
  • πŸ“ Generate docstrings
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/session-resource-templates

πŸ“œ 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 952ecbd and 1350e4c.

πŸ“’ Files selected for processing (3)
  • server/server.go (2 hunks)
  • server/session.go (2 hunks)
  • server/session_resource_templates_test.go (1 hunks)
🧰 Additional context used
πŸ““ Path-based instructions (2)
**/*.go

πŸ“„ CodeRabbit inference engine (AGENTS.md)

**/*.go: Order imports: standard library first, then third-party, then local packages (goimports enforces this)
Follow Go naming conventions: exported identifiers in PascalCase; unexported in camelCase; acronyms uppercase (HTTP, JSON, MCP)
Error handling: return sentinel errors, wrap with fmt.Errorf("context: %w", err), and check with errors.Is/As
Prefer explicit types and strongly-typed structs; avoid using any except where protocol flexibility is required (e.g., Arguments any)
All exported types and functions must have GoDoc comments starting with the identifier name; avoid inline comments unless necessary
Functions that are handlers or long-running must accept context.Context as the first parameter
Ensure thread safety for shared state using sync.Mutex and document thread-safety requirements in comments
For JSON: use json struct tags with omitempty for optional fields; use json.RawMessage for flexible/deferred parsing

Files:

  • server/server.go
  • server/session_resource_templates_test.go
  • server/session.go
**/*_test.go

πŸ“„ CodeRabbit inference engine (AGENTS.md)

**/*_test.go: Testing: use testify/assert and testify/require
Write table-driven tests using a tests := []struct{ name, ... } pattern
Go test files must end with _test.go

Files:

  • server/session_resource_templates_test.go
🧬 Code graph analysis (3)
server/server.go (2)
mcp/types.go (3)
  • ResourceTemplate (709-728)
  • URITemplate (77-79)
  • Params (180-180)
server/session.go (2)
  • ClientSessionFromContext (105-110)
  • SessionWithResourceTemplates (55-63)
server/session_resource_templates_test.go (6)
mcp/types.go (8)
  • JSONRPCNotification (335-338)
  • ReadResourceRequest (612-616)
  • ResourceContents (737-739)
  • Params (180-180)
  • ListResourceTemplatesResult (605-608)
  • ResourceTemplate (709-728)
  • URITemplate (77-79)
  • ReadResourceResult (628-631)
server/server.go (3)
  • ServerResourceTemplate (73-76)
  • NewMCPServer (337-365)
  • WithResourceCapabilities (205-213)
server/session.go (2)
  • SessionWithResourceTemplates (55-63)
  • ClientSessionFromContext (105-110)
mcp/resources.go (1)
  • NewResourceTemplate (60-71)
server/hooks.go (1)
  • Hooks (94-121)
server/errors.go (1)
  • ErrSessionDoesNotSupportResourceTemplates (21-21)
server/session.go (4)
server/server.go (3)
  • ServerResourceTemplate (73-76)
  • MCPServer (142-169)
  • ResourceTemplateHandlerFunc (37-37)
mcp/types.go (2)
  • ResourceTemplate (709-728)
  • URITemplate (77-79)
server/errors.go (2)
  • ErrSessionNotFound (16-16)
  • ErrSessionDoesNotSupportResourceTemplates (21-21)
server/hooks.go (1)
  • Hooks (94-121)
πŸ”‡ Additional comments (10)
server/server.go (2)

883-909: LGTM! Session template merging correctly prioritizes session templates.

The map-based merge strategy correctly allows session-specific templates to override global templates by URI template key. Converting to a slice for sorting and pagination follows the established pattern.


997-1039: Nil checks successfully added per previous review feedback.

The defensive nil checks at lines 1002-1004 (session templates) and 1024-1026 (global templates) prevent panics when URITemplate is nil. Session templates correctly take precedence over global templates in the matching logic.

server/session_resource_templates_test.go (4)

18-54: LGTM! Test helper correctly implements thread-safe session template storage.

The test helper properly uses sync.RWMutex for thread-safe access and maps.Clone to return defensive copies. The compile-time interface check at line 54 ensures conformance to SessionWithResourceTemplates.


56-111: Good integration test coverage.

This test verifies the basic flow: session registration, template storage, context retrieval, and handler invocation. The test correctly validates that session templates are accessible and functional.


113-204: Excellent test of session template override behavior.

This test thoroughly validates that session templates override global templates with the same URI pattern. Both the listing (name verification) and reading (handler result) are tested to ensure the override is complete.


206-563: Comprehensive test coverage of session resource templates.

The test suite thoroughly covers:

  • Adding single and multiple templates
  • Deletion with notification behavior
  • Uninitialized session handling (no notifications sent)
  • Error cases (unsupported sessions)
  • Capability flag behavior (listChanged disabled)
  • Session template precedence over global templates

The tests correctly use timeouts for async notification checks and validate both success and error paths.

server/session.go (4)

54-63: LGTM! Interface follows established patterns.

The SessionWithResourceTemplates interface correctly mirrors the design of SessionWithTools and SessionWithResources. The GoDoc comments properly start with the identifier name and document thread-safety requirements.

As per coding guidelines


628-634: LGTM! Convenience wrapper follows established pattern.

This wrapper method mirrors AddSessionTool (line 349-351) and delegates to the bulk method, maintaining consistency across the API.


636-702: Validation successfully added per previous review feedback.

The template validation at lines 668-677 prevents nil dereference panics by checking:

  • URITemplate is not nil (line 668-670)
  • URITemplate.Raw() is not empty (line 671-674)
  • Template.Name is not empty (line 675-677)

Validation occurs before state mutation, and clear error messages are returned. The implementation correctly follows the thread-safe Get/Set pattern and notification behavior established by AddSessionResources.


704-760: LGTM! Deletion logic includes no-op optimization.

The implementation correctly tracks whether any templates were actually deleted (line 719-720) and only updates state and sends notifications if changes occurred (line 737). This matches the optimization in DeleteSessionResources (line 592-594) and prevents unnecessary notifications.


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
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: 3

🧹 Nitpick comments (10)
server/errors.go (1)

16-22: Align error message with existing β€œper-session” phrasing

Keep wording consistent with ErrSessionDoesNotSupportTools/Resources.

-ErrSessionDoesNotSupportResourceTemplates = errors.New("session does not support resource templates")
+ErrSessionDoesNotSupportResourceTemplates = errors.New("session does not support per-session resource templates")
server/streamable_http_sampling_test.go (2)

27-36: Add interface assertion for SessionWithResourceTemplates

Guard the new constructor param with a compile-time-style assertion, mirroring the sampling check.

   // Verify it implements SessionWithSampling
   _, ok := any(session).(SessionWithSampling)
   if !ok {
     t.Error("streamableHttpSession should implement SessionWithSampling")
   }
+
+  // Verify it implements SessionWithResourceTemplates
+  if _, ok := any(session).(SessionWithResourceTemplates); !ok {
+    t.Error("streamableHttpSession should implement SessionWithResourceTemplates")
+  }

140-148: Also assert SessionWithResourceTemplates in the interface test

Mirror the sampling assertion to cover the new capability.

   // Verify it implements SessionWithSampling
   _, ok := any(session).(SessionWithSampling)
   if !ok {
     t.Error("streamableHttpSession should implement SessionWithSampling")
   }
+
+  // Verify it implements SessionWithResourceTemplates
+  if _, ok := any(session).(SessionWithResourceTemplates); !ok {
+    t.Error("streamableHttpSession should implement SessionWithResourceTemplates")
+  }
server/sse.go (1)

31-35: Clarify key semantics for resourceTemplates

Note that the map key is the template’s URITemplate.Raw() string for consistency with server/session.go.

server/server.go (1)

883-910: Merge precedence is correct; align sort style with resources

Session templates override globals; good. Optionally use slices.SortedFunc like handleListResources for consistency.

- // Convert map to slice for sorting and pagination
- templates := make([]mcp.ResourceTemplate, 0, len(templateMap))
- for _, template := range templateMap {
-   templates = append(templates, template)
- }
- sort.Slice(templates, func(i, j int) bool {
-   return templates[i].Name < templates[j].Name
- })
+ // Convert map to slice and sort by name (consistent with resources)
+ templates := slices.SortedFunc(maps.Values(templateMap), func(a, b mcp.ResourceTemplate) int {
+   return cmp.Compare(a.Name, b.Name)
+ })
server/session.go (1)

695-751: Clarify expected identifier for deletion

Document that uriTemplates must be the URITemplate.Raw() string; optional helper to delete by mcp.ResourceTemplate could reduce footguns.

Happy to add a DeleteSessionResourceTemplateByTemplate(sessionID string, t mcp.ResourceTemplate) wrapper if helpful.

server/streamable_http.go (4)

624-631: Cleanup includes per-session templates

Templates store is cleared with other session-scoped data. Consider fixing minor typos in comments (β€œrelateddata”, β€œrequstID”) later.


840-872: Thread-safe store mirrors existing patterns; optional simplification

Implementation is correct and race-safe. Optionally, simplify cloning for readability:

-	cloned := make(map[string]ServerResourceTemplate, len(s.templates[sessionID]))
-	maps.Copy(cloned, s.templates[sessionID])
-	return cloned
+	src := s.templates[sessionID]
+	cloned := maps.Clone(src)
+	if cloned == nil {
+		cloned = make(map[string]ServerResourceTemplate)
+	}
+	return cloned

1004-1011: Interface conformance achieved with safe Get/Set

Get/Set delegate to the store, preserving copy-on-get semantics. Assertions cover SessionWithResourceTemplates. If helpful, add a brief comment noting Set replaces the entire map (callers should use server-level Add/Delete helpers for incremental updates).

Also applies to: 1013-1017


521-527: Send notification by value, not pointer

Avoid taking the address of the select-scoped variable; just send the value:

-				case writeChan <- &nt:
+				case writeChan <- nt:

This reduces escapes and keeps semantics consistent with POST path.

If you prefer to keep pointers for large payloads, confirm there’s measurable benefit and no unintended escapes in benchmarks.

πŸ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 8b7d60c and 9de3423.

πŸ“’ Files selected for processing (6)
  • server/errors.go (1 hunks)
  • server/server.go (2 hunks)
  • server/session.go (2 hunks)
  • server/sse.go (3 hunks)
  • server/streamable_http.go (9 hunks)
  • server/streamable_http_sampling_test.go (3 hunks)
🧰 Additional context used
πŸ““ Path-based instructions (2)
**/*.go

πŸ“„ CodeRabbit inference engine (AGENTS.md)

**/*.go: Order imports: standard library first, then third-party, then local packages (goimports enforces this)
Follow Go naming conventions: exported identifiers in PascalCase; unexported in camelCase; acronyms uppercase (HTTP, JSON, MCP)
Error handling: return sentinel errors, wrap with fmt.Errorf("context: %w", err), and check with errors.Is/As
Prefer explicit types and strongly-typed structs; avoid using any except where protocol flexibility is required (e.g., Arguments any)
All exported types and functions must have GoDoc comments starting with the identifier name; avoid inline comments unless necessary
Functions that are handlers or long-running must accept context.Context as the first parameter
Ensure thread safety for shared state using sync.Mutex and document thread-safety requirements in comments
For JSON: use json struct tags with omitempty for optional fields; use json.RawMessage for flexible/deferred parsing

Files:

  • server/session.go
  • server/sse.go
  • server/streamable_http_sampling_test.go
  • server/errors.go
  • server/server.go
  • server/streamable_http.go
**/*_test.go

πŸ“„ CodeRabbit inference engine (AGENTS.md)

**/*_test.go: Testing: use testify/assert and testify/require
Write table-driven tests using a tests := []struct{ name, ... } pattern
Go test files must end with _test.go

Files:

  • server/streamable_http_sampling_test.go
🧬 Code graph analysis (4)
server/session.go (4)
server/server.go (3)
  • ServerResourceTemplate (73-76)
  • MCPServer (142-169)
  • ResourceTemplateHandlerFunc (37-37)
mcp/types.go (2)
  • ResourceTemplate (709-728)
  • URITemplate (77-79)
server/errors.go (2)
  • ErrSessionNotFound (16-16)
  • ErrSessionDoesNotSupportResourceTemplates (21-21)
server/hooks.go (1)
  • Hooks (94-121)
server/sse.go (2)
server/server.go (1)
  • ServerResourceTemplate (73-76)
server/session.go (2)
  • ClientSession (12-21)
  • SessionWithResourceTemplates (55-63)
server/server.go (2)
mcp/types.go (3)
  • ResourceTemplate (709-728)
  • Params (180-180)
  • URITemplate (77-79)
server/session.go (2)
  • ClientSessionFromContext (105-110)
  • SessionWithResourceTemplates (55-63)
server/streamable_http.go (2)
server/server.go (2)
  • MCPServer (142-169)
  • ServerResourceTemplate (73-76)
server/session.go (3)
  • SessionWithTools (33-41)
  • SessionWithResources (44-52)
  • SessionWithResourceTemplates (55-63)
πŸ”‡ Additional comments (9)
server/streamable_http_sampling_test.go (1)

180-183: Constructor call with nil stores looks fine

Passing nil for the new store in this queue-full test maintains behavior. No change needed.

server/sse.go (2)

101-121: Thread-safe copy/setter pattern LGTM

Range to copy and Clear+Store keep per-session templates safe for concurrent access.


169-176: Interface conformance marker LGTM

sseSession now explicitly implements SessionWithResourceTemplates.

server/session.go (2)

54-63: Interface shape LGTM

Thread-safe getters/setters match existing patterns for tools/resources.


628-635: Convenience wrapper LGTM

Delegates to AddSessionResourceTemplates as expected.

server/streamable_http.go (4)

143-149: Store wiring for session-scoped templates looks correct

Field added and initialized consistently with existing stores; thread-safety approach matches tools/resources. No blockers.

Also applies to: 168-176


350-351: Constructor injection covers both ephemeral (POST) and persistent (GET) sessions

Passing the shared templates store into newStreamableHttpSession ensures session-scoped template ops work across transports and lifecycles. Good use of LoadOrStore to avoid TOCTOU on GET.

Also applies to: 485-487


934-936: Session gains templates store; constructor wiring is consistent

Field and constructor param added without altering existing behavior. No issues.

Also applies to: 947-953


143-149: <!-- [scratchpad_start]
[task review_verification 1/1]
Verification complete - full handler logic confirmed.

[observations]

  • handleListResourceTemplates (lines 878-920):

    • Global templates loaded first into templateMap
    • Session templates checked and merged with override semantics
    • Result: session templates override global ones via map assignment
    • Verified at line 903: templateMap[uriTemplate] = serverTemplate.Template
  • handleReadResource (lines 936-1050):

    • Direct handlers: session checked first (945-953), global fallback (956-961)
    • Template matching: session templates checked first (998-1013), with break on match
    • Global template fallback: lines 1015-1028 - "If not found in session templates, check global templates"
    • Both flows have precedence: session > global
    • Merge behavior: session takes priority, global is fallback

[analysis]

  • Session-level precedence confirmed in both list and read handlers
  • Merge logic verified: session overrides global templates
  • Fallback pattern consistent across handlers
  • Code matches PR goals exactly
  • No issues found

[done]
Verification confirms review comment request is satisfied by current code implementation.
</scratchpad_end] -->

Session template precedence and merging verifiedβ€”no issues found

The code correctly implements session-level precedence:

  • handleListResourceTemplates: Global templates loaded, then session templates merged with override semantics (line 903: templateMap[uriTemplate] = serverTemplate.Template)
  • handleReadResource: Session templates checked first (lines 998–1013), global templates checked only if no match found (lines 1015–1028)

Both handlers follow consistent patterns with explicit comments documenting the merge and precedence logic. The implementation satisfies PR goals.

- Add sessionTestClientWithResourceTemplates mock
- Test AddSessionResourceTemplate and AddSessionResourceTemplates
- Test DeleteSessionResourceTemplates
- Test session template override behavior
- Test notification behavior (enabled/disabled)
- Test uninitialized session handling
- Test error cases for unsupported sessions
- Verify thread-safety through existing patterns

Coverage increased from 70.17% to 72.8% (+2.63%)
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 (7)
server/session_resource_templates_test.go (7)

33-39: Protect initialized flag to avoid data races (tests under -race).

Use atomic.Bool (or guard with the existing mutex). Keeps tests race-free when server goroutines read it.

 type sessionTestClientWithResourceTemplates struct {
-	sessionID                string
-	notificationChannel      chan mcp.JSONRPCNotification
-	initialized              bool
+	sessionID           string
+	notificationChannel chan mcp.JSONRPCNotification
+	initialized         atomic.Bool
 	sessionResourceTemplates map[string]ServerResourceTemplate
 	mu                       sync.RWMutex
 }
 
 func (f *sessionTestClientWithResourceTemplates) Initialize() {
-	f.initialized = true
+	f.initialized.Store(true)
 }
 
 func (f *sessionTestClientWithResourceTemplates) Initialized() bool {
-	return f.initialized
+	return f.initialized.Load()
 }

Remember to import sync/atomic in the stdlib section.


41-52: Simplify GetSessionResourceTemplates with maps.Clone.

Removes nil checks and manual allocation.

 func (f *sessionTestClientWithResourceTemplates) GetSessionResourceTemplates() map[string]ServerResourceTemplate {
   f.mu.RLock()
   defer f.mu.RUnlock()
-
-  if f.sessionResourceTemplates == nil {
-    return nil
-  }
-
-  templatesCopy := make(map[string]ServerResourceTemplate, len(f.sessionResourceTemplates))
-  maps.Copy(templatesCopy, f.sessionResourceTemplates)
-  return templatesCopy
+  return maps.Clone(f.sessionResourceTemplates)
 }

54-66: Likewise, Clone on SetSessionResourceTemplates.

Less code, same semantics.

 func (f *sessionTestClientWithResourceTemplates) SetSessionResourceTemplates(templates map[string]ServerResourceTemplate) {
   f.mu.Lock()
   defer f.mu.Unlock()
-
-  if templates == nil {
-    f.sessionResourceTemplates = nil
-    return
-  }
-
-  templatesCopy := make(map[string]ServerResourceTemplate, len(templates))
-  maps.Copy(templatesCopy, templates)
-  f.sessionResourceTemplates = templatesCopy
+  f.sessionResourceTemplates = maps.Clone(templates)
 }

239-245: Reduce flakiness in notification waits.

Replace repeated select+time.After with a small helper or assert/require.Eventually and slightly longer overall timeout.

Add a helper once:

func expectNotification(t *testing.T, ch <-chan mcp.JSONRPCNotification, want string, d time.Duration) mcp.JSONRPCNotification {
  t.Helper()
  select {
  case n := <-ch:
    require.Equal(t, want, n.Method)
    return n
  case <-time.After(d):
    t.Fatalf("timeout waiting for %s", want)
    return mcp.JSONRPCNotification{}
  }
}

Then call:

_ = expectNotification(t, sessionChan, "notifications/resources/list_changed", 500*time.Millisecond)

Alternatively, use require.Eventually with a non-busy poll.

Also applies to: 276-282, 317-325, 339-350, 389-399, 416-421, 512-517, 563-567, 575-579


475-483: Guard result before indexing and assert type.

Avoid panics and improve failure signals.

 response := server.HandleMessage(sessionCtx, requestBytes)
 resp, ok := response.(mcp.JSONRPCResponse)
 require.True(t, ok)
- readResourceResult, ok := resp.Result.(mcp.ReadResourceResult)
- assert.True(t, ok)
-
- if text := readResourceResult.Contents[0].(mcp.TextResourceContents).Text; text != "session result" {
-   t.Errorf("Expected result 'session result', got %q", text)
- }
+ readResourceResult, ok := resp.Result.(mcp.ReadResourceResult)
+ require.True(t, ok)
+ require.Len(t, readResourceResult.Contents, 1)
+ tc, ok := readResourceResult.Contents[0].(mcp.TextResourceContents)
+ require.True(t, ok)
+ assert.Equal(t, "session result", tc.Text)

127-218: Add read-path assertions for global usage and fallback after delete.

  • After listing, also read test://another/{id} to confirm global handler is used.
  • After deleting a session template, read the same URI to confirm fallback to global.

I can draft targeted tests mirroring the existing HandleMessage patterns if you want them added.

Also applies to: 487-522


70-582: Consider table-driven tests and t.Parallel for similar cases.

Several tests follow the same add/delete/notify pattern. Table-driven subtests with t.Parallel would cut duplication and speed runs.

πŸ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 9de3423 and 952ecbd.

πŸ“’ Files selected for processing (1)
  • server/session_resource_templates_test.go (1 hunks)
🧰 Additional context used
πŸ““ Path-based instructions (2)
**/*.go

πŸ“„ CodeRabbit inference engine (AGENTS.md)

**/*.go: Order imports: standard library first, then third-party, then local packages (goimports enforces this)
Follow Go naming conventions: exported identifiers in PascalCase; unexported in camelCase; acronyms uppercase (HTTP, JSON, MCP)
Error handling: return sentinel errors, wrap with fmt.Errorf("context: %w", err), and check with errors.Is/As
Prefer explicit types and strongly-typed structs; avoid using any except where protocol flexibility is required (e.g., Arguments any)
All exported types and functions must have GoDoc comments starting with the identifier name; avoid inline comments unless necessary
Functions that are handlers or long-running must accept context.Context as the first parameter
Ensure thread safety for shared state using sync.Mutex and document thread-safety requirements in comments
For JSON: use json struct tags with omitempty for optional fields; use json.RawMessage for flexible/deferred parsing

Files:

  • server/session_resource_templates_test.go
**/*_test.go

πŸ“„ CodeRabbit inference engine (AGENTS.md)

**/*_test.go: Testing: use testify/assert and testify/require
Write table-driven tests using a tests := []struct{ name, ... } pattern
Go test files must end with _test.go

Files:

  • server/session_resource_templates_test.go
🧬 Code graph analysis (1)
server/session_resource_templates_test.go (6)
mcp/types.go (8)
  • JSONRPCNotification (335-338)
  • ReadResourceRequest (612-616)
  • ResourceContents (737-739)
  • Params (180-180)
  • ListResourceTemplatesResult (605-608)
  • ResourceTemplate (709-728)
  • URITemplate (77-79)
  • ReadResourceResult (628-631)
server/server.go (2)
  • ServerResourceTemplate (73-76)
  • WithResourceCapabilities (205-213)
server/session.go (2)
  • SessionWithResourceTemplates (55-63)
  • ClientSessionFromContext (105-110)
mcp/resources.go (1)
  • NewResourceTemplate (60-71)
server/hooks.go (1)
  • Hooks (94-121)
server/errors.go (1)
  • ErrSessionDoesNotSupportResourceTemplates (21-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: coverage
  • GitHub Check: test
πŸ”‡ Additional comments (1)
server/session_resource_templates_test.go (1)

3-15: Go toolchain version confirmed.

The go.mod declares go 1.23.0, which satisfies the minimum requirement (go 1.21+) for using the maps stdlib package. No changes needed.

- Use atomic.Bool for initialized field in test mock to prevent data races
- Add nil checks for URITemplate in handleReadResource for both session and global templates
- Add validation in AddSessionResourceTemplates to prevent nil URITemplate, empty URI, or empty Name
- Simplify Get/SetSessionResourceTemplates using maps.Clone
- Fix test initialization states to match expected behavior

All tests pass with race detector.
@github-actions
Copy link

Merging this branch will decrease overall coverage

Impacted Packages Coverage Ξ” πŸ€–
github.com/mark3labs/mcp-go/server 72.66% (-0.54%) πŸ‘Ž

Coverage by file

Changed files (no unit tests)

Changed File Coverage Ξ” Total Covered Missed πŸ€–
github.com/mark3labs/mcp-go/server/errors.go 100.00% (ΓΈ) 1 1 0
github.com/mark3labs/mcp-go/server/server.go 95.57% (-0.21%) 429 (+26) 410 (+24) 19 (+2) πŸ‘Ž
github.com/mark3labs/mcp-go/server/session.go 81.89% (-3.59%) 243 (+57) 199 (+40) 44 (+17) πŸ‘Ž
github.com/mark3labs/mcp-go/server/sse.go 65.31% (-2.24%) 271 (+9) 177 94 (+9) πŸ‘Ž
github.com/mark3labs/mcp-go/server/streamable_http.go 66.89% (-1.47%) 450 (+17) 301 (+5) 149 (+12) πŸ‘Ž

Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code.

Changed unit test files

  • github.com/mark3labs/mcp-go/server/session_resource_templates_test.go
  • github.com/mark3labs/mcp-go/server/streamable_http_sampling_test.go

@ezynda3 ezynda3 merged commit 5088c93 into main Oct 25, 2025
5 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: Add support for Session-specific Resource Templates (SessionWithResourceTemplates)

1 participant