modelcontextprotocol / modelcontextprotocol/typescript-sdk

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

Open
#1,079 8 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug fix proposed help wanted P2 ready for work
Dominant language
TypeScript
Stars
13.4k
Forks
2.2k
Avg merge
3d 15h
Merged PRs (30d)
4

Description

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with UriTemplate.match() and partToRegExp() in node_modules/@modelcontextprotocol/sdk/dist/esm/shared/uriTemplate.js, then run the reproduction script from the issue against the listed URI combinations. Done means optional query parameters match when absent, partial, or reordered, with the expected match values returned.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
api
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.