Skip to content

Conversation

@dask-58
Copy link
Contributor

@dask-58 dask-58 commented Dec 10, 2025

Description

Implemented support for lastModified field in Annotations according to MCP specification version 2025-11-25.

Key Changes:

  • LastModified Support:
    • Updated Annotations struct in mcp/types.go to include LastModified (ISO 8601 string) and changed Priority to *float64 for proper optional handling.
    • Updated WithAnnotations and WithTemplateAnnotations builder signatures in mcp/resources.go to accept lastModified.
    • Added WithLastModified builder method for convenience.
    • Added ValidateISO8601Timestamp helper function.
    • Updated examples/everything/main.go to demonstrate usage.
    • Updated documentation in www/docs/pages/servers/resources.mdx to reflect these changes.

Fixes #654

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: Resources Annotations
  • Implementation follows the specification exactly

Additional Information

The change to WithAnnotations and WithTemplateAnnotations signature is a breaking change for existing Go code. The Priority field change in Annotations struct is also a breaking change for direct struct initialization if using non-pointer values, but aligns better with JSON marshaling for optional fields.

Summary by CodeRabbit

  • New Features

    • Resources now record a LastModified timestamp with ISO 8601 (RFC3339) validation.
    • Added an option to set LastModified independently of other annotations.
  • Improvements

    • Annotations support a nullable priority so priority can be omitted or explicitly unset.
    • Annotation-related APIs and parsing updated to accept last-modified metadata and handle nullable priority; tests adjusted accordingly.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 10, 2025

Walkthrough

Add LastModified to Annotations, make Priority nullable (*float64), extend builder signatures to accept lastModified and add WithLastModified, add RFC3339 timestamp validation, and update parsing and tests to use pointer-based priority and handle LastModified.

Changes

Cohort / File(s) Summary
Type definitions
mcp/types.go
Added LastModified string to Annotations; changed Priority from float64 to *float64.
Resource builders & helpers
mcp/resources.go
Expanded WithAnnotations and WithTemplateAnnotations to accept lastModified string; added WithLastModified(timestamp string) ResourceOption; added ValidateISO8601Timestamp(timestamp string) error; updated imports (added time, uritemplate/v3).
Annotation parsing & utilities
mcp/utils.go
ParseAnnotations now parses/stores Priority as *float64 (nil-safe) and reads LastModified into Annotations; added nil-checks and pointer assignment.
Builder tests
mcp/resources_test.go
Updated tests for new WithAnnotations/WithTemplateAnnotations signatures, pointer-based Priority, WithLastModified behavior, and override interactions.
Parsing/unit tests
mcp/utils_test.go
Tests adjusted to expect pointer-wrapped Priority values, nil priority cases, and lastModified parsing/handling; import formatting tweaked.
Docs / example content
www/docs/pages/servers/tools.mdx
Added LastModified: "2025-01-12T15:00:58Z" to an annotated resource example.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Pay attention to nil vs non-nil Priority usage across builders, parsing, JSON marshaling/unmarshaling (omitempty).
  • Verify ValidateISO8601Timestamp accepts empty string and correctly enforces RFC3339 format where used.
  • Audit all call sites and tests for updated WithAnnotations / WithTemplateAnnotations signatures and pointer dereferencing.
  • Confirm override semantics between WithLastModified and WithAnnotations/WithTemplateAnnotations.

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 17.39% 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 title 'Add lastModified field to Annotations for MCP spec 2025-11-25' is specific, concise, and directly describes the main change in the PR.
Description check ✅ Passed The PR description follows the template structure with all required sections completed, including clear description, type of change, checklist items, MCP spec compliance details, and additional context about breaking changes.
Linked Issues check ✅ Passed The implementation addresses all coding requirements from issue #654: LastModified field added to Annotations, Priority converted to *float64, builder methods updated with lastModified parameter, WithLastModified helper added, and ValidateISO8601Timestamp validation function implemented.
Out of Scope Changes check ✅ Passed All code changes are directly related to implementing lastModified support in Annotations per MCP spec 2025-11-25, with no extraneous modifications beyond the PR scope.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • 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

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

Caution

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

⚠️ Outside diff range comments (1)
mcp/utils.go (1)

539-562: Missing LastModified parsing in ParseAnnotations.

The ParseAnnotations function handles priority and audience but does not extract the lastModified field from the input map. Per the PR objectives and the Annotations struct definition, LastModified should also be parsed here for consistency when deserializing annotation data.

 func ParseAnnotations(data map[string]any) *Annotations {
 	if data == nil {
 		return nil
 	}
 	annotations := &Annotations{}
 	if value, ok := data["priority"]; ok {
 		if value != nil {
 			if priority, err := cast.ToFloat64E(value); err == nil {
 				annotations.Priority = &priority
 			}
 		}
 	}

 	if value, ok := data["audience"]; ok {
 		for _, a := range cast.ToStringSlice(value) {
 			a := Role(a)
 			if a == RoleUser || a == RoleAssistant {
 				annotations.Audience = append(annotations.Audience, a)
 			}
 		}
 	}
+
+	if value, ok := data["lastModified"]; ok {
+		if str, ok := value.(string); ok {
+			annotations.LastModified = str
+		}
+	}
 	return annotations
 }
🧹 Nitpick comments (3)
mcp/types.go (1)

968-983: Incomplete comment for Priority field.

The comment on lines 978-980 appears truncated. It states "0 means 'least important,' and indicates that" but the sentence is incomplete. The new comment on line 979 partially overlaps with the original context.

Consider completing or restructuring the comment:

 	// Describes how important this data is for operating the server.
 	//
 	// A value of 1 means "most important," and indicates that the data is
-	// effectively required, while 0 means "least important," and indicates that
-	// Priority from 0.0 to 1.0 (1 = most important, 0 = least important)
+	// effectively required, while 0 means "least important," and indicates that
+	// the data is entirely optional.
+	// Priority ranges from 0.0 to 1.0 (1 = most important, 0 = least important).
 	Priority *float64 `json:"priority,omitempty"`
mcp/resources.go (1)

58-67: New WithLastModified option lacks timestamp validation.

Similar to WithAnnotations, this builder accepts any string without validating it's a valid ISO 8601 timestamp. While ValidateISO8601Timestamp exists, it's not used here. This could lead to invalid timestamps being stored silently.

Either validate internally or document that callers must validate:

 // WithLastModified adds a last modified timestamp to the Resource.
 // The timestamp should be in ISO 8601 format (e.g., "2025-01-12T15:00:58Z").
+// Callers should use ValidateISO8601Timestamp to validate the timestamp before use.
 func WithLastModified(timestamp string) ResourceOption {
 	return func(r *Resource) {
 		if r.Annotations == nil {
 			r.Annotations = &Annotations{}
 		}
 		r.Annotations.LastModified = timestamp
 	}
 }
mcp/resources_test.go (1)

387-395: Test for WithLastModified verifies basic functionality.

The test correctly validates that Annotations is created when nil and that LastModified is properly assigned.

Consider adding test cases for:

  1. WithAnnotations with a non-empty lastModified value
  2. Combined usage of WithAnnotations and WithLastModified
  3. WithTemplateAnnotations with a non-empty lastModified value
func TestWithAnnotationsIncludingLastModified(t *testing.T) {
    resource := Resource{}
    timestamp := "2025-01-12T15:00:58Z"
    opt := WithAnnotations([]Role{RoleUser}, 1.0, timestamp)
    opt(&resource)

    require.NotNil(t, resource.Annotations)
    assert.Equal(t, timestamp, resource.Annotations.LastModified)
    assert.Equal(t, 1.0, *resource.Annotations.Priority)
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1f07bf3 and c12057c.

📒 Files selected for processing (5)
  • mcp/resources.go (3 hunks)
  • mcp/resources_test.go (9 hunks)
  • mcp/types.go (1 hunks)
  • mcp/utils.go (1 hunks)
  • mcp/utils_test.go (6 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:

  • mcp/types.go
  • mcp/utils_test.go
  • mcp/resources.go
  • mcp/utils.go
  • mcp/resources_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:

  • mcp/utils_test.go
  • mcp/resources_test.go
🧠 Learnings (5)
📚 Learning: 2025-04-21T21:26:32.945Z
Learnt from: octo
Repo: mark3labs/mcp-go PR: 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.

Applied to files:

  • mcp/utils_test.go
📚 Learning: 2025-10-13T09:35:20.180Z
Learnt from: CR
Repo: mark3labs/mcp-go PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-13T09:35:20.180Z
Learning: Applies to **/*_test.go : Testing: use testify/assert and testify/require

Applied to files:

  • mcp/utils_test.go
  • mcp/resources_test.go
📚 Learning: 2025-10-13T09:35:20.180Z
Learnt from: CR
Repo: mark3labs/mcp-go PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-13T09:35:20.180Z
Learning: Applies to **/*_test.go : Write table-driven tests using a tests := []struct{ name, ... } pattern

Applied to files:

  • mcp/utils_test.go
  • mcp/resources_test.go
📚 Learning: 2025-06-20T20:39:51.870Z
Learnt from: lariel-fernandes
Repo: mark3labs/mcp-go PR: 428
File: www/docs/pages/servers/prompts.mdx:218-234
Timestamp: 2025-06-20T20:39:51.870Z
Learning: In the mcp-go library, the GetPromptParams.Arguments field is of type map[string]string, not map[string]interface{}, so direct string access without type assertions is safe and correct.

Applied to files:

  • mcp/utils_test.go
📚 Learning: 2025-06-30T07:13:17.052Z
Learnt from: ezynda3
Repo: mark3labs/mcp-go PR: 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.

Applied to files:

  • mcp/utils.go
🧬 Code graph analysis (2)
mcp/resources.go (2)
mcp/prompts.go (1)
  • Role (83-83)
mcp/types.go (3)
  • Resource (715-734)
  • Annotations (968-983)
  • ResourceTemplate (743-764)
mcp/resources_test.go (3)
mcp/resources.go (4)
  • WithAnnotations (47-56)
  • WithTemplateAnnotations (107-116)
  • ValidateISO8601Timestamp (119-126)
  • WithLastModified (60-67)
mcp/types.go (4)
  • Resource (715-734)
  • Annotated (988-990)
  • Annotations (968-983)
  • ResourceTemplate (743-764)
mcp/tools.go (1)
  • Description (928-932)
⏰ 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). (1)
  • GitHub Check: test
🔇 Additional comments (8)
mcp/utils_test.go (2)

4-8: LGTM!

Import formatting is clean with standard library first, followed by third-party packages, per coding guidelines.


10-95: Test coverage is good but missing lastModified test cases.

The table-driven tests properly validate the pointer-based Priority handling using the ptr() helper (defined in resources_test.go). However, once ParseAnnotations is updated to parse lastModified, corresponding test cases should be added here.

Consider adding test cases for lastModified parsing after the implementation is updated:

{
    name: "lastModified only",
    data: map[string]any{
        "lastModified": "2025-01-12T15:00:58Z",
    },
    expected: &Annotations{
        LastModified: "2025-01-12T15:00:58Z",
    },
},
{
    name: "all fields",
    data: map[string]any{
        "priority":     1.0,
        "audience":     []any{"user"},
        "lastModified": "2025-01-12T15:00:58Z",
    },
    expected: &Annotations{
        Priority:     ptr(1.0),
        Audience:     []Role{"user"},
        LastModified: "2025-01-12T15:00:58Z",
    },
},
mcp/resources.go (3)

47-56: Breaking change: WithAnnotations signature updated.

The function now accepts a lastModified parameter, which is a breaking change for existing callers. The implementation correctly stores Priority as a pointer. However, the lastModified timestamp is not validated before assignment.

Consider whether to validate lastModified within the builder to fail fast on invalid timestamps:

 func WithAnnotations(audience []Role, priority float64, lastModified string) ResourceOption {
 	return func(r *Resource) {
+		// Note: Consider calling ValidateISO8601Timestamp(lastModified) here
+		// to catch invalid timestamps early, or document that validation
+		// is the caller's responsibility.
 		if r.Annotations == nil {
 			r.Annotations = &Annotations{}
 		}
 		r.Annotations.Audience = audience
 		r.Annotations.Priority = &priority
 		r.Annotations.LastModified = lastModified
 	}
 }

107-116: WithTemplateAnnotations mirrors WithAnnotations correctly.

The implementation is consistent with WithAnnotations, correctly storing Priority as a pointer and setting LastModified. Same consideration about timestamp validation applies here.


118-126: ValidateISO8601Timestamp correctly uses RFC3339, which matches MCP spec requirements.

The MCP specification requires ISO 8601 timestamps for the lastModified field in the format "2025-01-12T15:00:58Z" (RFC3339 with timezone), which the function correctly validates. The implementation appropriately allows empty strings for optional fields.

mcp/resources_test.go (3)

317-317: LGTM!

The ptr() helper is a clean utility for creating float64 pointers in tests. This is a common Go testing pattern.


342-385: Thorough validation tests for ValidateISO8601Timestamp.

Good coverage of valid timestamps (Z and offset formats), empty string handling, and invalid formats. The table-driven approach follows coding guidelines.


45-78: Test cases updated for new WithAnnotations signature.

The tests correctly pass empty string "" for lastModified and use ptr() for expected Priority values. The assertions properly compare pointer values.

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 (3)
mcp/resources.go (1)

119-127: ValidateISO8601Timestamp matches the requested RFC3339‑based contract

Allowing empty strings and using time.Parse(time.RFC3339, timestamp) is exactly what the issue describes, and the helper returns the raw parse error for callers to wrap with context as needed. Consider very mildly tightening the docstring to mention RFC3339 explicitly to avoid implying full ISO‑8601 coverage, but the implementation itself is solid.

mcp/resources_test.go (2)

46-317: Tests for pointer‑based Priority and annotation options are consistent, with a couple of minor polish opportunities

Across TestNewResource, TestNewResourceTemplate, TestWithAnnotations, TestWithTemplateAnnotations, and the “creation from nil” tests, the updates to:

  • pass the new lastModified parameter (currently as ""), and
  • assert Priority via ptr(...) or *...Annotations.Priority

accurately reflect the new *float64 field and the updated option signatures. The small ptr helper keeps expectations readable, and the tests verify that options correctly allocate Annotations when starting from zero values.

Two non‑blocking suggestions:

  • The Annotations.Priority doc comment in mcp/types.go says the range is 0.0–1.0, but several tests still use values like 2.0, 2.5, or 3.0. Consider normalizing these to the documented range (or adding validation in a future change) so examples don’t contradict the spec.
  • TestResourceJSONMarshaling now uses the new WithAnnotations signature but still doesn’t assert on LastModified. If there isn’t JSON round‑trip coverage for lastModified elsewhere, it might be worth adding a variant here that sets a non‑empty timestamp and checks it survives marshal/unmarshal.

Based on learnings, these tests follow the testify/table‑driven style the project prefers.


387-455: LastModified option tests clearly define precedence semantics

TestWithLastModified, TestWithAnnotationsIncludingLastModified, and TestWithAnnotationsAndLastModifiedCombined do a good job of specifying:

  • that WithLastModified allocates Annotations as needed and sets LastModified, and
  • that whichever of WithAnnotations or WithLastModified runs last “wins” for the timestamp while preserving Priority.

One tiny cleanup you might consider: in the first subtest of TestWithAnnotationsAndLastModifiedCombined, the NewResource(...) call’s result is discarded and all assertions are done on a manually‑constructed resource. Either assert directly on the NewResource return value or drop that call to avoid dead code in the test.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c12057c and 84a28c6.

📒 Files selected for processing (4)
  • mcp/resources.go (3 hunks)
  • mcp/resources_test.go (9 hunks)
  • mcp/types.go (1 hunks)
  • mcp/utils.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • mcp/utils.go
  • mcp/types.go
🧰 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:

  • mcp/resources.go
  • mcp/resources_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:

  • mcp/resources_test.go
🧠 Learnings (2)
📚 Learning: 2025-10-13T09:35:20.180Z
Learnt from: CR
Repo: mark3labs/mcp-go PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-13T09:35:20.180Z
Learning: Applies to **/*_test.go : Write table-driven tests using a tests := []struct{ name, ... } pattern

Applied to files:

  • mcp/resources_test.go
📚 Learning: 2025-10-13T09:35:20.180Z
Learnt from: CR
Repo: mark3labs/mcp-go PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-13T09:35:20.180Z
Learning: Applies to **/*_test.go : Testing: use testify/assert and testify/require

Applied to files:

  • mcp/resources_test.go
🧬 Code graph analysis (2)
mcp/resources.go (1)
mcp/prompts.go (1)
  • Role (83-83)
mcp/resources_test.go (2)
mcp/resources.go (6)
  • WithAnnotations (47-56)
  • WithTemplateAnnotations (108-117)
  • NewResourceTemplate (77-88)
  • ValidateISO8601Timestamp (120-127)
  • WithLastModified (61-68)
  • NewResource (16-27)
mcp/types.go (4)
  • Resource (715-734)
  • Annotated (989-991)
  • Annotations (968-984)
  • ResourceTemplate (743-764)
⏰ 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). (1)
  • GitHub Check: test
🔇 Additional comments (5)
mcp/resources.go (4)

3-7: Import block and new time dependency look correct

time is only used by ValidateISO8601Timestamp, and the import grouping (stdlib first, then third‑party) matches the Go style the repo targets. No issues here.


45-56: WithAnnotations correctly wires Priority pointer and LastModified

The option now ensures Annotations is non‑nil, sets Audience, and stores Priority as a *float64 via &priority, plus the new LastModified field. This matches the updated Annotations shape and MCP spec expectations, while keeping the existing “call the option to opt‑in” behavior.

As per coding guidelines, the exported function comment starts with WithAnnotations and remains accurate enough after the signature change.


58-67: WithLastModified behaves as a focused, non‑disruptive annotation option

The helper allocates Annotations when needed and only mutates LastModified, preserving any existing Audience/Priority. That composes cleanly with WithAnnotations, allowing whichever option runs last to own the timestamp, as exercised in tests. Leaving ISO‑8601 validation to callers (guided by the comment) is a reasonable design given the ResourceOption signature.


106-117: WithTemplateAnnotations mirrors resource behavior correctly

Template annotations now receive Audience, Priority as *float64, and LastModified in the same way as WithAnnotations for resources. This keeps resource and template configuration symmetric and ensures templates also gain lastModified support automatically.

mcp/resources_test.go (1)

342-385: ValidateISO8601Timestamp tests cover the key success and failure modes

The table‑driven cases exercise:

  • valid Z‑suffix timestamps,
  • valid numeric‑offset timestamps,
  • the special “empty string is allowed” path, and
  • clearly invalid formats/values.

That aligns with the helper’s time.RFC3339‑based behavior and the issue requirements.

@dask-58
Copy link
Contributor Author

dask-58 commented Dec 10, 2025

@coderabbitai generate docstrings

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 10, 2025

✅ Actions performed

Initiated docstring generation; will generate only if new commits exist.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 10, 2025

Note

Docstrings generation - SUCCESS
Generated docstrings for this pull request at #664

coderabbitai bot added a commit that referenced this pull request Dec 10, 2025
Docstrings generation was requested by @dask-58.

* #663 (comment)

The following files were modified:

* `mcp/resources.go`
* `mcp/utils.go`
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 (5)
mcp/resources_test.go (5)

46-78: Resource annotations tests correctly updated for pointer priority and new builder API

Using WithAnnotations(..., 0.5, "") / WithAnnotations(..., 1.0, "") and switching expectations to Priority: ptr(0.5) / ptr(1.0) keeps the tests aligned with Priority *float64 and the new lastModified parameter. Since lastModified is passed as an empty string here, omitting it from the expected struct is correct because the zero value matches. You might optionally add an assertion that Annotations.LastModified is empty in one of these cases to document the default behavior, but that's not strictly necessary.


125-148: Template annotations tests correctly reflect pointer priority; optional LastModified assertion

The WithTemplateAnnotations calls now pass the extra lastModified parameter as an empty string and the expectations dereference *template.Annotations.Priority, which matches the new type. Similar to the resource tests, you could add a quick assert.Empty(t, template.Annotations.LastModified) in one of these cases if you want to explicitly lock in the default behavior when lastModified is not used, but the current coverage is sufficient.


175-207: TestWithAnnotations updated correctly to use new signature and pointer priority

Updating the options to WithAnnotations(tt.audience, tt.priority, "") and asserting against *resource.Annotations.Priority is consistent with Priority *float64 and ensures annotations are created when needed. If you want slightly broader coverage of the new field, you could add a case with a non-empty lastModified and assert both Priority and LastModified here, but it's already well covered by later tests.


227-255: TestWithTemplateAnnotations correctly aligned with new API

The template annotations tests now exercise the updated WithTemplateAnnotations(audience, priority, lastModified) signature and verify the dereferenced pointer *template.Annotations.Priority. Similar to the resource-side tests, you might optionally assert that LastModified is empty here to document that behavior for templates as well, but functionally this is solid.


262-278: JSON round‑trip test now verifies LastModified behavior

Adding WithAnnotations(..., 1.0, "2025-01-01T12:00:00Z") and the subsequent assertions:

  • require.NotNil(t, unmarshaled.Annotations)
  • checking resource.Annotations.LastModified equals the literal string
  • and then resource.Annotations.LastModified == unmarshaled.Annotations.LastModified

properly validates that lastModified is set by the builder and preserved across JSON marshal/unmarshal. If you want to simplify, you could collapse the last two lines into a single assert.Equal(t, "2025-01-01T12:00:00Z", unmarshaled.Annotations.LastModified), but the current approach is clear and correct.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 50e563f and 28bd996.

📒 Files selected for processing (1)
  • mcp/resources_test.go (11 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:

  • mcp/resources_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:

  • mcp/resources_test.go
🧠 Learnings (2)
📚 Learning: 2025-10-13T09:35:20.180Z
Learnt from: CR
Repo: mark3labs/mcp-go PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-13T09:35:20.180Z
Learning: Applies to **/*_test.go : Write table-driven tests using a tests := []struct{ name, ... } pattern

Applied to files:

  • mcp/resources_test.go
📚 Learning: 2025-10-13T09:35:20.180Z
Learnt from: CR
Repo: mark3labs/mcp-go PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-13T09:35:20.180Z
Learning: Applies to **/*_test.go : Testing: use testify/assert and testify/require

Applied to files:

  • mcp/resources_test.go
🧬 Code graph analysis (1)
mcp/resources_test.go (2)
mcp/resources.go (3)
  • WithAnnotations (47-56)
  • ValidateISO8601Timestamp (120-127)
  • WithLastModified (61-68)
mcp/types.go (4)
  • Resource (715-734)
  • Annotated (989-991)
  • Annotations (968-984)
  • ResourceTemplate (743-764)
⏰ 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). (1)
  • GitHub Check: test
🔇 Additional comments (8)
mcp/resources_test.go (8)

298-307: Creation-from-nil test correctly covers pointer priority for resources

TestAnnotationsCreationFromNil now uses WithAnnotations(..., 1.0, "") and asserts *resource.Annotations.Priority == 1.0, which directly guards the updated behavior that the option allocates Annotations when nil and sets the pointer-valued Priority. This is a good regression test for the new struct shape.


309-318: Template creation-from-nil test correctly covers pointer priority

TestTemplateAnnotationsCreationFromNil mirrors the resource test for ResourceTemplate, ensuring annotations are allocated and Priority is set to 0.5 via pointer. This is consistent with the ResourceTemplate structure and the updated option semantics.


320-321: Helper ptr is a clean way to construct float64 pointers in tests

The ptr helper keeps expectations for pointer-valued priorities concise and readable across tests. This is idiomatic for tests and avoids cluttering assertions with inline pointer-taking.


345-388: TestValidateISO8601Timestamp gives solid coverage of RFC3339/ISO8601 validation

The table-driven test covers:

  • Valid Zulu timestamp
  • Valid offset timestamp
  • Empty string treated as valid
  • Bad format and non-date strings treated as errors

This matches ValidateISO8601Timestamp’s contract (RFC3339 parse with empty allowed). If you ever expand acceptable formats (e.g., fractional seconds), you can extend this table easily, but as-is it’s a good, concise suite. (Based on learnings, this also follows the preferred table-driven style.)


390-398: TestWithLastModified correctly verifies standalone LastModified option

The test ensures WithLastModified initializes Annotations when nil and sets LastModified while leaving other fields untouched, which is exactly the behavior implied by the option implementation. This is a useful focused test on the new helper.


400-409: TestWithAnnotationsIncludingLastModified validates combined priority and timestamp setting

This test confirms that WithAnnotations sets both Priority and LastModified in one call, which aligns with the new signature. It nicely complements TestWithLastModified to cover both ways of populating the timestamp.


411-441: Order-sensitive tests correctly capture overwrite semantics between options

The two subtests in TestWithAnnotationsAndLastModifiedCombined verify:

  • When WithAnnotations(..., ts1) is followed by WithLastModified(ts2) in NewResource, the later option overwrites LastModified but preserves Priority.
  • When applying options manually to a Resource, WithLastModified(ts1) followed by WithAnnotations(..., ts2) results in LastModified == ts2 and Priority == 1.0.

This is a clear and valuable check of option ordering semantics, which is easy to regress when modifying builder behavior.


443-452: Template annotations test properly exercises LastModified + priority on templates

TestWithTemplateAnnotationsIncludingLastModified ensures that WithTemplateAnnotations sets both LastModified and pointer-valued Priority for ResourceTemplate, mirroring the resource-side behavior. This helps guarantee parity between resources and templates with respect to the new field.

@ezynda3 ezynda3 merged commit 919c4bf into mark3labs:main Dec 11, 2025
4 checks passed
@dask-58 dask-58 deleted the feat/annotations-mcp-2025-11-25 branch December 11, 2025 16:54
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.

Add lastModified field to Annotations for MCP spec 2025-11-25

2 participants