Skip to content

[MCP] parsePath attribute-suffix routing doesn't resolve for programmatic static-properties Resources #1922

Description

@kylebernhardy

Follow-up from #1920 / PR #1921 (cross-model review finding, adjudicated out-of-scope there).

Resource.parsePath resolves URL attribute-suffix routes (e.g. GET /Widget/id.label) by reading this.attributes directly:

(this as any).attributes?.find((a) => a.name === suffix)

A programmatic Resource that declares only static properties (no attributes Array) has attributes === undefined, so attribute-suffix routing silently doesn't resolve for it. This is a pre-existing gap (not introduced by #1921, which only touched schema derivation), surfaced now that #1921 makes static properties a first-class schema source.

Why not fixed in #1921

parsePath is a per-request hot path. The schema-derivation surfaces (#1921) use resolveAttributes(...), which projects properties → attributes on each call when attributes is empty — fine on the cold registration/introspection paths, but projecting on every request in parsePath is not acceptable.

Suggested approach

Cache the projected attribute Array on the class the first time it's needed (e.g. a lazily-computed #resolvedAttributes memo, invalidated on schema reload), then have parsePath (and any other per-request .attributes reader) use the memo. resolveAttributes from resources/jsonSchemaTypes.ts is the projection to reuse.

Acceptance

  • GET /X/id.field resolves for a programmatic Resource declaring static properties.
  • No per-request projection cost (memoized).
  • A test covering attribute-suffix routing on a programmatic static properties Resource.

Issue generated by kAIle (Claude Opus 4.8).

Metadata

Metadata

Assignees

Labels

area:mcpModel Context Protocol (MCP) server: protocol, profiles, stdio CLI

Type

No type

Fields

Priority

None yet

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions