Skip to content

[MCP] #1095 follow-ups: programmatic static-properties schema wiring + MCP/convergence test coverage #1920

Description

@kylebernhardy

Follow-up to #1095, which was delivered by #1167 and closed. The production functionality (GraphQL docstrings → MCP + OpenAPI descriptions, the operations catalog, @hidden, outputSchema, per-attribute descriptions, OpenAPI parity) is live. This issue tracks the remainder from the #1095 acceptance list that #1167 did not fully cover — see the audit comment on #1095 for the full checkbox-by-checkbox verdict.

1. Programmatic-Resource static properties → MCP input schema

A bare static properties = {…} literal on a Resource class is not read by MCP or OpenAPI schema derivation — both read .attributes (components/mcp/tools/application.ts:1359, resources/openApi.ts:112). static properties only enriches schemas once compiled through defineResource/withSchema (resources/defineResource.ts:607-610). Consequences:

  • A pure programmatic Resource declaring only static properties (no attributes, no contract) yields a skeletal MCP inputSchema — the "skeletal schema for programmatic Resources" gap [MCP] Quality descriptions and richer tool-payload metadata for LLM tool selection #1095 set out to close, still open for the bare-class path.
  • There is no lazy Resource.properties getter; the attributes→properties projection is eager at Table construction (resources/Table.ts:278, resources/databases.ts:1157). Back-compat co-population works and is tested, but item "Resource.properties getter projects from Resource.attributes lazily" (acceptance) is unmet as written.
  • No static properties inheritance / spread-override fixture (kriszyp's CustomProduct example). Static-field inheritance works natively in JS, but nothing verifies it, and it's moot until static properties feeds MCP derivation.

Decide: is the intended authoring path defineResource/withSchema only (in which case document that and drop the bare-literal acceptance items), or should a bare static properties literal also drive MCP/OpenAPI schemas? kriszyp locked in static properties as the canonical public API in the #1095 discussion, which points at the latter.

2. MCP-side + convergence test coverage

The OpenAPI side and the GraphQL parser are tested; the MCP assertions and the cross-surface convergence tests were never written:

  • Missingtools/list against a docstring-carrying fixture asserting the tool description includes the docstring and inputSchema.properties[*].description carry attribute descriptions. (unitTests/components/mcp/tools/application.test.js asserts only names/verbs; its .description assertions are for custom mcpTools.) No fixture under integrationTests/fixtures contains """ docstrings.
  • Missing — convergence test: a Resource with descriptions surfaces them in both MCP tools/list and OpenAPI /openapi.json.
  • Missing — a @table Resource with docstrings (no override) produces identical MCP + OpenAPI output to one with explicit static description + static properties (both paths converge).
  • Ineffective — the idempotent guard (unitTests/components/mcp/tools/operations.test.js:386-391) only checks !('idempotentHint' in OPERATION_DESCRIPTIONS) (a string map); it never inspects an emitted add_user/create_* tool's annotations. Behavior is correct today (IDEMPOTENT_OPERATIONS ships empty), but nothing would catch a future mis-population — the exact safety this check was meant to provide. Rewrite it to assert the real emitted annotation is absent.
  • Partial — operations-profile test asserts description coverage but not that a specific curated string lands on the right tool; back-compat is tested per-surface but not as a unified golden assertion.

Out of scope

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

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions