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
Copy Markdown
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 Public API changes 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
Copy Markdown

codecov-commenter commented Mar 16, 2026

e5l
e5l previously approved these changes Mar 17, 2026
Copy link
Copy Markdown
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
Copy Markdown
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 Public API changes enhancement New feature or request

Projects

No open projects
Status: Done

Development

Successfully merging this pull request may close these issues.

Implement Support for Resource Templates

3 participants