Skip to content

[Capability][Server] Add element sources and isolate loading failures - #687

Draft
chr-hertel wants to merge 1 commit into
modelcontextprotocol:issue-495-capability-element-sourcesfrom
chr-hertel:element-sources
Draft

chr-hertel wants to merge 1 commit into
modelcontextprotocol:issue-495-capability-element-sourcesfrom
chr-hertel:element-sources

Conversation

@chr-hertel

@chr-hertel chr-hertel commented Nov 8, 2026 •

Copy link
Copy Markdown
Member

Stacked on #686, items 1, 3 and 4 of #495.

A source returns its elements as an immutable ElementCollection, and Builder::addSource() adds it to the load. Discovery becomes one of those sources, without the $owned state of DiscoveryLoader, which is deprecated.

A failing loader or source is now logged and skipped, the rest stays servable and the load stays pending, so the next read retries only what failed. While the load is incomplete the server advertises all kinds, otherwise a client would miss them for the whole session. [BC Break] build() no longer throws for such a failure.

Where this differs from #495:

  • no kinds() on sources, since capabilities are detected at request time with [Server][Capability] Split RegistryInterface by role and defer loading into any registry #686
  • custom loaders keep running against the real registry, since wrapping them would change what their reads and unregisters see
  • a custom loader may have written before it failed, so everything after it runs again on each retry
  • discovery still reads the registry to fill only gaps, as pre-populated entries have to survive - so has* and the $loading guard stay for now

Not in here: per-element isolation for reflected elements (#477), so one bad addTool() still skips all manually added elements. Also no caching decorator and no visibility seam yet. A source that stays down is called and logged on every read - not sure yet if that needs a backoff, WDYT?

@chr-hertel chr-hertel added the Server Issues & PRs related to the Server component label Nov 8, 2026
@chr-hertel chr-hertel added this to the 1.0.0 milestone Nov 8, 2026
@chr-hertel
chr-hertel requested a balanced review from Copilot November 8, 2026 13:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

An unavailable child causes every registry read to rerun healthy loaders, filesystem discovery, and schema reflection instead of retaining successful initialization work during retries.

1 open issue
What changed in this PR

Adds value-based element sources to the PHP SDK’s capability registry and isolates loading failures so healthy elements remain available while failed loads are retried.

Changes:

  • Introduces element collections, declared element kinds, and Builder::addSource().
  • Moves discovery onto the source adapter and deprecates DiscoveryLoader.
  • Adds partial-load handling, retry tests, and registration documentation.
File Description
tests/​Unit/​Server/​BuilderTest.php Tests source failures, capabilities, and discovery precedence.
tests/​Unit/​Capability/​Registry/​Source/​ElementSourceTest.php Tests source loading, retries, serialization, and discovery.
tests/​Unit/​Capability/​Registry/​Loader/​ChainLoaderTest.php Tests failure isolation and logging.
tests/​Unit/​Capability/​Registry/​LazyRegistryTest.php Tests pending loads after partial failures.
src/​Server/​Builder.php Integrates sources, capability declarations, and retryable loading.
src/​Exception/​PartialLoadException.php Introduces the incomplete-load exception.
src/​Capability/​Registry/​Source/​ElementSourceInterface.php Defines source provision and kind declarations.
src/​Capability/​Registry/​Source/​ElementKind.php Defines the four element kinds.
src/​Capability/​Registry/​Source/​ElementCollection.php Holds element references in a readonly collection.
src/​Capability/​Registry/​Source/​DiscoverySource.php Adapts discovery results into collections.
src/​Capability/​Registry/​Loader/​SourceLoader.php Registers source elements with optional gap-filling behavior.
src/​Capability/​Registry/​Loader/​DiscoveryLoader.php Adds a deprecation annotation.
src/​Capability/​Registry/​Loader/​ChainLoader.php Logs failures and continues remaining loaders.
src/​Capability/​Registry/​LazyRegistry.php Keeps partial loads pending and exposes load status.
src/​Capability/​Registry.php Serves partial results while retaining retry state.
src/​Capability/​DeferredRegistryInterface.php Adds load-status reporting.
docs/​servers/​registration.md Documents sources, precedence, and retries.
docs/​run/​server-builder.md Adds the source registration API reference.
CHANGELOG.md Records source APIs, failure-handling changes, and deprecation.

Review effort: Balanced

@chr-hertel
chr-hertel force-pushed the issue-495-capability-element-sources branch from 7105cab to f9cf392 Compare November 8, 2026 15:02
@chr-hertel
chr-hertel requested a balanced review from Copilot November 8, 2026 15:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A failing loader can overwrite a healthy loader’s handler on subsequent reads because later loaders are skipped despite the failed retry’s partial mutations.

1 open issue
1 resolved since last review

Review effort: Balanced

@chr-hertel
chr-hertel force-pushed the issue-495-capability-element-sources branch from f9cf392 to fa5a2d2 Compare November 8, 2026 15:39
@chr-hertel
chr-hertel requested a balanced review from Copilot November 8, 2026 15:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A source loader that fails during registration can cause retries to skip subsequent loaders, changing handler precedence and leaving the wrong handler active.

1 open issue
1 resolved since last review

Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Registry loading can advertise incomplete capabilities, while retry handling can break last-write-wins ordering and change read-dependent custom loaders’ derived registrations during recovery.

3 open issues
1 resolved since last review

Review effort: Balanced

Comment on lines +55 to +56
if (!$runRemaining && !isset($retry[$position])) {
continue;
Comment on lines +59 to +60
try {
$loader->load($registry);
Comment thread src/Server/Builder.php Resolved
@chr-hertel
chr-hertel force-pushed the issue-495-capability-element-sources branch from fa5a2d2 to a567732 Compare November 8, 2026 17:09
/**
* @param callable(string): bool $exists
*/
private function mayWrite(string $kind, string $key, callable $exists): bool

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

canWrite ?

@chr-hertel
chr-hertel force-pushed the issue-495-capability-element-sources branch from a567732 to efe0366 Compare November 10, 2026 00:28
@chr-hertel
chr-hertel force-pushed the issue-495-capability-element-sources branch from efe0366 to 176b86a Compare November 10, 2026 21:37

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Server Issues & PRs related to the Server component

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants