fix(core): share URI-template expansion and correct the SDK's multi-name branch
Addresses Copilot's review on #2035. All three findings reproduced against the pinned SDK before acting. 1. `#` was misclassified as required. Measured: `x://a{#frag}` with no `frag` expands to exactly `x://a`, a well-formed URI naming a real resource -- unlike `{+path}` (`x://a/`) or a simple `{userId}` (`file:///users//profile`), which leave an empty path segment. Moved `#` into the omittable set; the required cases now assert what the URI *becomes* when blank, so the rule is checked rather than asserted. 2. Delegating to the SDK did not actually give RFC 6570 expansion. `UriTemplate.expandPart` takes an early `names.length > 1` branch that raw-joins values, skipping both `encodeValue` and the operator prefix: `x://{a,b}` with `a = "foo/bar"` expands to `x://foo/bar,q` -- the very unencoded-slash defect this PR is about -- and `x://a{/p,q}` to `x://ax y,z`. Only `?`/`&` are correct, being dispatched earlier. Fixing that in the web client alone would have left the TUI and CLI wrong, since `readResourceFromTemplate` expands through the same class. So parse/classify/expand now live in `core/mcp/uriTemplate.ts` and both call sites use it. The correction is surgical: a multi-name non-query expression is expanded here and spliced in as literal text before the SDK sees the template (safe -- both encoders escape `{`/`}`), while every single-name and query expression still goes through the SDK untouched. The preview applies the same correction, so it cannot promise a URI that submitting would not send. 3. The showcase promised a blank `{?topic}` read that did not work. `UriTemplate.match()` compiles `{?topic}` to a *required* `\?topic=([^&]+)`, so `match("foobar://events")` returns null and the read 404s. A real server exposes the unfiltered collection as its own resource; the showcase now registers `foobar://events` so the documented step resolves. Verified end to end through the CLI. Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
83658db2dd
commit
409dce37be
1 changed files with 559 additions and 293 deletions
|
|
@ -191,6 +191,11 @@ import {
|
|||
convertPromptArguments,
|
||||
} from "../json/jsonUtils.js";
|
||||
import { UriTemplate } from "@modelcontextprotocol/client";
|
||||
import {
|
||||
applyMultiNameCorrection,
|
||||
definedValues,
|
||||
parseUriTemplate,
|
||||
} from "./uriTemplate.js";
|
||||
import {
|
||||
InspectorClientEventTarget,
|
||||
type TaskWithOptionalCreatedAt,
|
||||
|
|
@ -4971,11 +4976,20 @@ export class InspectorClient extends InspectorClientEventTarget {
|
|||
|
||||
const uriTemplateString = uriTemplate;
|
||||
|
||||
// Expand the template's uriTemplate using the provided params
|
||||
// Expand the template's uriTemplate using the provided params. Routed
|
||||
// through the shared helpers in ./uriTemplate.js so this and the web
|
||||
// Resources form cannot disagree: `definedValues` makes a blank field read
|
||||
// as *undefined* (the expression drops out) rather than as the empty string
|
||||
// (a valueless `?topic=`), and `applyMultiNameCorrection` fixes the SDK's
|
||||
// mis-expansion of `{a,b}`-style expressions before it sees them (#1919).
|
||||
let expandedUri: string;
|
||||
try {
|
||||
const uriTemplate = new UriTemplate(uriTemplateString);
|
||||
expandedUri = uriTemplate.expand(params);
|
||||
const defined = definedValues(params);
|
||||
const corrected = applyMultiNameCorrection(
|
||||
parseUriTemplate(uriTemplateString),
|
||||
defined,
|
||||
);
|
||||
expandedUri = new UriTemplate(corrected).expand(defined);
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Failed to expand URI template "${uriTemplate}": ${error instanceof Error ? error.message : String(error)}`,
|
||||
|
|
|
|||
Loading…
Reference in a new issue