Skip to content

feat: #502 resource templates with basic template matcher#606

Merged
kpavlov merged 8 commits intomainfrom
kpavlov/502-resource-templates
Mar 19, 2026
Merged

feat: #502 resource templates with basic template matcher#606
kpavlov merged 8 commits intomainfrom
kpavlov/502-resource-templates

Conversation

@kpavlov
Copy link
Contributor

@kpavlov kpavlov commented Mar 16, 2026

Summary

Important

Full support of RFC-6570 is out of scope and can be implemented by users or as an independent feature.
Reasoning: Safe and secure RFC-6570 implementation is a separate problem and should not block the support of basic MCP features.

Adds resource template matching for the MCP server, enabling handlers to be registered against RFC 6570 Level 1 URI templates (e.g. files/{path}, users/{id}/profile) and resolved by specificity when multiple templates match the same URI.

  • ResourceTemplateMatcher / ResourceTemplateMatcherFactory — extension point for URI
    template matching; ServerOptions.resourceTemplateMatcherFactory is public so callers can inject a custom implementation.
    • PathSegmentTemplateMatcher — default implementation: splits on /, parses the template once at construction, and scores each match (literal segment = 2 pts, variable capture = 1 pt) so the most-specific template always wins. Enforces safety limits (URI length cap, segment depth cap) and delegates dot-segment normalization to the platform URI parser (JVM: java.net.URI.normalize, JS: URL API, native/WASM: no-op — documented limitation).
    • Specificity selectionhandleReadResource uses maxWithOrNull (O(n)) to select the highest-scoring match; ties broken by fewest variable captures, then registration order.
    • fix(core): rethrow CancellationExceptionProtocol.kt had a catch (cause: Throwable) that silently suppressed coroutine cancellation. The catch block now re-throws CancellationException before the generic handler runs.
    • fix(server): checkNotNull in capability validation — replaces check(x != null) with the idiomatic checkNotNull(x) across all capability guard sites in Server.kt.

Security

PathSegmentTemplateMatcher applies one percent-decode pass via Ktor's decodeURLPart. Decoded variable values are attacker-controlled and documented as such — handlers must validate before using values in file paths, database queries, or downstream URLs. A dedicated security regression test suite (PathSegmentTemplateMatcherSecurityTest) covers double-decode, null bytes, encoded slashes, depth exhaustion, dot-segment traversal, and query/fragment pass-through.

Motivation and Context

Closes #502, #591

How Has This Been Tested?

Conformance test (resources-templates-read #591), unit/integration/security test

Breaking Changes

Any code that called McpException(-32600, "Connection closed") previously received exception.message == "MCP error -32600: Connection closed". After this change it returns "Connection closed". This is a behavioral API break — the Exception.message contract changed without a deprecation path.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

#603, #604, #503

@kpavlov kpavlov added enhancement New feature or request api API Update 🎭 labels Mar 16, 2026
@kpavlov kpavlov marked this pull request as ready for review March 16, 2026 21:00
@kpavlov kpavlov mentioned this pull request Mar 16, 2026
9 tasks
@kpavlov kpavlov requested a review from e5l March 16, 2026 21:10
@codecov-commenter
Copy link

codecov-commenter commented Mar 16, 2026

e5l
e5l previously approved these changes Mar 17, 2026
Copy link
Contributor

@e5l e5l left a comment

Choose a reason for hiding this comment

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

lgtm, please check comments before merging

@kpavlov kpavlov requested a review from e5l March 17, 2026 20:45
@kpavlov kpavlov force-pushed the kpavlov/502-resource-templates branch from 8edad43 to aa0ee0f Compare March 18, 2026 08:09
kpavlov added 8 commits March 19, 2026 09:33
Introduce `ResourceTemplate` and `RegisteredResourceTemplate` implementation to register and manage parameterized resource templates. Added support for listing, reading, and removing resource templates. Updated error handling for unmatched URIs with a new `RESOURCE_NOT_FOUND` RPC error. Includes corresponding tests and API updates.
…lidation

Replaced `check(options.capabilities.* != null)` with `checkNotNull` for improved clarity and consistency in validating server capabilities.
…ssion

Add specific handling for `CancellationException` in `Protocol.kt` to ensure it is rethrown instead of being suppressed by the generic `Throwable` catch block.
…URI matching

- Added `ResourceTemplateMatcher` interface and its implementation `SimpleUriResourceTemplateMatcher` to improve URI matching specificity and safety.
- Replaced usage of `UriTemplate` and `UriTemplateMatcher` with `ResourceTemplateMatcher` in `RegisteredResourceTemplate`.
- Updated `ServerOptions` to include a configurable `ResourceTemplateMatcherFactory`, defaulting to `SimpleUriResourceTemplateMatcher.factory`.
- Enhanced resource registration logic to utilize matchers for improved URI matching robustness.
- Improved template selection logic by prioritizing specificity, variable minimization, and registration order.
…tors

- Enhanced `McpException` default message logic to ensure consistency and eliminate redundant prefixes.
- Simplified test assertions in integration tests using `shouldBe` for better readability.
- Added synthetic constructors in `ServerOptions` and `McpException` for better Kotlin compatibility.
- Updated `Protocol` to rethrow `CancellationException` explicitly, ensuring proper cancellation behavior.
@kpavlov kpavlov force-pushed the kpavlov/502-resource-templates branch from aa0ee0f to 9ce68b7 Compare March 19, 2026 07:33
Copy link
Contributor

@e5l e5l left a comment

Choose a reason for hiding this comment

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

lgtm

@kpavlov kpavlov merged commit ee6561c into main Mar 19, 2026
32 of 34 checks passed
@kpavlov kpavlov deleted the kpavlov/502-resource-templates branch March 19, 2026 10:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api API Update 🎭 enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Implement Support for Resource Templates

3 participants