Skip to content

# MCP SDK ResourceTemplate URI Validation Issue: RFC 6570 Template Matching Behavior #1079

@4bd4ll4h

Description

@4bd4ll4h

Problem Description

When using MCP SDK's ResourceTemplate with URI templates following RFC 6570, the template matching fails when optional query parameters are not provided in the exact format and order specified in the template. This causes "Resource not found" errors even when the base URI pattern matches.

Issue Details

Current Behavior

  • Template: "dom://{pageId}{?selector,includeAttributes,includeText,includeChildren}"
  • Test URI: "dom://5a072bc8-a8c7-43c3-84ac-154651ac5d44"
  • Result: null (no match)

The template only matches when ALL query parameters are provided in the exact order:

  • ✅ Matches: "dom://{pageId}?selector=body&includeAttributes=true&includeText=true&includeChildren=true"
  • ❌ Fails: "dom://{pageId}" (no query parameters)
  • ❌ Fails: "dom://{pageId}?selector=body" (partial parameters)
  • ❌ Fails: "dom://{pageId}?includeAttributes=true" (wrong parameter order)

Expected Behavior

According to RFC 6570, query parameter templates with the {?param1,param2} syntax should:

  • Match when no query parameters are present (empty query string)
  • Match when some parameters are present
  • Match when parameters are in any order
  • Provide default/empty values for missing parameters

Root Cause Analysis

The issue is in the URI template matching logic in UriTemplate.match() method. The current implementation creates a strict regex pattern that requires:

  1. All specified query parameters must be present in the exact order defined
  2. No partial matches are allowed
  3. Parameter order is fixed and cannot vary

Code Location

  • File: node_modules/@modelcontextprotocol/sdk/dist/esm/shared/uriTemplate.js
  • Method: UriTemplate.match() (lines 202-237)
  • Regex Generation: partToRegExp() method (lines 163-201)

Impact

This behavior breaks common MCP resource patterns where:

  • Resources have optional query parameters
  • Users want to access basic resources without specifying all options
  • Progressive enhancement patterns (simple → advanced usage)

Proposed Solution

The URI template matching should be updated to:

  1. Make query parameters truly optional - match when some or none are present
  2. Allow parameter order flexibility - accept parameters in any order
  3. Provide default values for missing parameters in the match result

Expected Matching Behavior

  • "dom://{pageId}{?selector,includeAttributes}" should match:
    • "dom://page123"
    • "dom://page123?selector=body"
    • "dom://page123?includeAttributes=true"
    • "dom://page123?includeAttributes=true&selector=body"

Reproduction Steps

  1. Create a ResourceTemplate with optional query parameters:

    const template = new ResourceTemplate("resource://{id}{?param1,param2}", {
      complete: {
        id: async () => ["test1", "test2"],
        param1: async () => ["value1", "value2"],
        param2: async () => ["valueA", "valueB"]
      }
    });
  2. Try to match URIs with different query parameter combinations:

    // These should all match but currently fail:
    template.match("resource://test1"); // null
    template.match("resource://test1?param1=value1"); // null
    template.match("resource://test1?param2=valueA"); // null
    
    // Only this matches currently:
    template.match("resource://test1?param1=value1&param2=valueA"); // { id: "test1", param1: "value1", param2: "valueA" }
  3. Observe that only the exact parameter set in exact order matches

Test Code

Here's a test script that demonstrates the issue:

import { UriTemplate } from '@modelcontextprotocol/sdk/dist/esm/shared/uriTemplate.js';

const template = new UriTemplate("dom://{pageId}{?selector,includeAttributes,includeText,includeChildren}");

const testUris = [
  "dom://5a072bc8-a8c7-43c3-84ac-154651ac5d44",
  "dom://5a072bc8-a8c7-43c3-84ac-154651ac5d44?selector=body",
  "dom://5a072bc8-a8c7-43c3-84ac-154651ac5d44?includeAttributes=true",
  "dom://5a072bc8-a8c7-43c3-84ac-154651ac5d44?selector=body&includeAttributes=true&includeText=true&includeChildren=true"
];

testUris.forEach(uri => {
  const match = template.match(uri);
  console.log(`URI: ${uri} -> ${match ? 'MATCH' : 'NO MATCH'}`);
});

Environment

  • MCP SDK Version: 1.20.2
  • Node.js Version: Tested on Node 18+
  • Platform: Windows/Linux/Mac

Related RFC

  • RFC 6570: URI Template specification

This issue affects the usability of MCP resource templates and should be addressed to align with RFC 6570 expectations for optional query parameter handling.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions