Skip to content

fix(mcp): resolve the agent resource provider structurally, not nominally - #21

Merged
Snider merged 1 commit into
mainfrom
fix/duck-typed-resource-provider
Aug 8, 2026
Merged

fix(mcp): resolve the agent resource provider structurally, not nominally#21
Snider merged 1 commit into
mainfrom
fix/duck-typed-resource-provider

Conversation

@Snider

@Snider Snider commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Pairs with dAppCore/agent#22, which binds the provider. Together they turn the plans:// and sessions:// HTTP endpoints back on.

The interim that had no end

#19 moved that rendering behind AgentResourceProvider and I described the dead endpoints as an interim, waiting on dappcore/agent to depend on this package and implement the interface.

That day doesn't come. Agent maintains its own copy of Core\Mcp rather than depending on this package, so it can never name the interface in an implements clause. An interim with no end is a decision that hasn't been made — so it's made here.

Structural resolution

The controller now accepts any object bound under the interface name that provides read():

  • a provider that can name the interface still implements it and is accepted nominally
  • one that cannot binds and satisfies the method

Both work, neither package imports the other. Half a contract is rejected rather than accepted: an object with neither read() nor the interface returns null, so the controller answers a clean not-found instead of fatalling mid-request.

The contract loses entries()

Nothing in this package ever called it — GET servers/{id}/resources lists a server's own configured resources, a different concept. It was a method an implementer had to satisfy for no consumer.

Providers remain free to offer listing for their own transports; agent's registry does, for its stdio server. This package asks only for what it uses.

Verification

result
new tests 4 passed — duck-typed binding with no implements, nominal implementation, object missing read(), nothing bound
suite 21 failed, 303 passed — from 21 / 299

Existing failures unchanged; the delta is exactly these four tests.

🤖 Generated with Claude Code
Co-Authored-By: Virgil virgil@lethean.io

Summary by CodeRabbit

  • New Features

    • Resource providers can now be supplied through compatible implementations that expose a read() capability, even without explicitly implementing the provider interface.
    • Providers are treated as read-only; listing resources remains optional.
  • Bug Fixes

    • Invalid provider bindings are rejected safely.
    • Missing provider bindings now resolve cleanly without errors.
  • Tests

    • Added coverage for compatible providers, formal implementations, invalid bindings, and missing providers.

…ally

#19 moved the plans:// and sessions:// rendering behind AgentResourceProvider
and I described the dead endpoints as an interim, waiting on dappcore/agent to
depend on this package and implement the interface. That day does not come:
agent maintains its own copy of Core\Mcp rather than depending on this package,
so it can never name the interface in an implements clause. An interim with no
end is a decision that has not been made, so it is made here.

The controller now accepts any object bound under the interface name that
provides read(). A provider able to name the interface still implements it and
is accepted nominally; one that cannot binds and satisfies the method. Both
work, neither package imports the other, and two endpoints that would otherwise
have stayed dead permanently come back on as soon as agent binds.

Half a contract is rejected rather than accepted: an object with neither read()
nor the interface returns null, so the controller answers a clean not-found
instead of fatalling mid-request.

The contract also loses entries(). Nothing in this package ever called it —
GET servers/{id}/resources lists a server's own configured resources, which is
a different concept — so it was a method an implementer had to satisfy for no
consumer. Providers are still free to offer listing for their own transports;
agent's registry does, for its stdio server. This package asks only for what it
uses.

Four tests cover the resolution: a duck-typed binding with no implements
clause, a nominal implementation, an object missing read(), and nothing bound
at all.

Suite: 21 failed, 303 passed, from 21 failed, 299 passed — the four new tests,
no change to the existing failures.

Co-Authored-By: Virgil <virgil@lethean.io>
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bf616f64-34c1-4aaa-bc5d-3e403aa2419c

📥 Commits

Reviewing files that changed from the base of the PR and between ad44a48 and 299ed76.

📒 Files selected for processing (3)
  • php/src/Mcp/Controllers/McpApiController.php
  • php/src/Mcp/Resources/Contracts/AgentResourceProvider.php
  • php/tests/Feature/AgentResourceProviderBindingTest.php

📝 Walkthrough

Walkthrough

The controller now resolves nominal and duck-typed resource providers with a read() method. The provider interface no longer requires entries(). Feature tests cover valid, invalid, and missing bindings.

Changes

Agent resource provider resolution

Layer / File(s) Summary
Provider contract and resolution
php/src/Mcp/Resources/Contracts/AgentResourceProvider.php, php/src/Mcp/Controllers/McpApiController.php
AgentResourceProvider now requires only read(). agentResourceProvider() accepts compatible objects and returns null for missing or invalid bindings.
Provider resolution validation
php/tests/Feature/AgentResourceProviderBindingTest.php
Feature tests cover duck-typed providers, nominal implementations, objects without read(), and missing bindings.

Sequence Diagram(s)

sequenceDiagram
  participant McpApiController
  participant Container
  participant ResourceProvider
  McpApiController->>Container: Resolve provider binding
  Container-->>McpApiController: Return bound value
  McpApiController->>ResourceProvider: Check read()
  ResourceProvider-->>McpApiController: Provide readable resource
Loading

Warning

Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Snider
Snider merged commit 5282367 into main Aug 8, 2026
0 of 3 checks passed
@Snider
Snider deleted the fix/duck-typed-resource-provider branch August 8, 2026 11:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant