Skip to content

fix(mcp): let a prompt reach the capability services through its IServiceProvider - #110

Open
carldebilly wants to merge 2 commits into
mainfrom
dev/cdb/mcp-prompt-capability-services
Open

carldebilly wants to merge 2 commits into
mainfrom
dev/cdb/mcp-prompt-capability-services

Conversation

@carldebilly

@carldebilly carldebilly commented Sep 22, 2026

Copy link
Copy Markdown
Member

Closes #96.

Before any change, I measured each row of #96's table against current main:

Handler Before After
(IMcpSampling sampling) => … (declared directly) already works works, now pinned
(IServiceProvider sp) => sp.GetService(typeof(IMcpSampling)) sp-null resolved

The real defect is narrower than the issue said. McpServiceProviderOverlay puts the four capability services in front of the provider it wraps. When asked for IServiceProvider, though, it returned that wrapped provider, and that container knows none of the four. It now returns itself, as it already does for IServiceProviderIsService. This applies to mcp serve and to the reusable BuildMcpServerOptions() path; both are tested.

Declaring a capability directly already worked because McpExplicitPrompt swaps in the session's overlay for request.Services before the SDK binds the handler. It also binds the flowing request there, which covers the issue's third point. I added a test for that case, since the issue reported it as failing and nothing covered it.

I did not make the overlay an IServiceScopeFactory, which the issue floated. McpExplicitPrompt throws away the SDK's per-request scope either way, so that change would have no observable effect.

Test plan

  • The two IServiceProvider tests (mcp serve and reusable options) were red first, with sp-null.
  • The direct-parameter test was green on main before any change, measured rather than assumed.
  • Review follow-up: the overlay's IsService now also reports IServiceProvider and IServiceProviderIsService, in step with GetService. When_APromptDeclaresIServiceProviderWithoutAnAppProvider_Then_ItIsBoundAsADependency covers ICoreReplApp.BuildMcpServerOptions() without an app provider. It passed before that change, because the SDK binds an IServiceProvider parameter itself, so it guards the path rather than reproducing a failure.
  • Repl.Tests 803, Repl.IntegrationTests 641 (+10 skipped), Repl.McpTests 326 (+1 skipped, run twice), Repl.SpectreTests 17.

…viceProvider

McpServiceProviderOverlay layers IMcpSampling, IMcpClientRoots, IMcpElicitation and
IMcpFeedback in front of the provider it wraps, but answered a request for IServiceProvider
with that wrapped provider. A handler that declares IServiceProvider and resolves a
capability from it therefore got a container that knew none of them: an explicitly
registered prompt asking for IMcpSampling that way got null, on both mcp serve and the
reusable BuildMcpServerOptions() path. The overlay now answers IServiceProvider with itself,
as it already does for IServiceProviderIsService.

The defect turned out narrower than #96's table. Declaring a capability service directly as a
parameter already works: McpExplicitPrompt replaces request.Services with the session's
overlay before the SDK binds the handler, which is also where the request is bound, the
issue's third point. That case is pinned now too, since #96 reported it failing and it had
no test. Making the overlay an IServiceScopeFactory, as the issue floated, would change
nothing observable: McpExplicitPrompt discards the SDK's per-request scope either way.

TDD: both IServiceProvider tests red first with "sp-null"; the direct-parameter test green on
main from the start, measured before any change.

Refs #96
@carldebilly carldebilly added this to the 0.12.0 milestone Sep 22, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 22, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-22T22:41:57.240819Z a71a11b New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b70bec8851

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/Repl.Mcp/McpServiceProviderOverlay.cs
The overlay now answers IServiceProvider with itself, but IsService still asked the wrapped
provider about it. The IServiceProviderIsService contract is that IsService reports what
GetService can supply, so IsService now counts IServiceProvider and IServiceProviderIsService
as well.

Raised in review on #110, which predicted that a prompt declaring IServiceProvider would be
classified as a client-supplied argument on ICoreReplApp.BuildMcpServerOptions() without an app
provider, where the wrapped provider is empty. That did not reproduce: the new test for that
path passed before this change, because the SDK binds an IServiceProvider parameter itself
without asking IsService. The test stays as a guard for the path, and says so; it is not a
reproduction.

Refs #96
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.

mcp: explicitly registered prompts cannot inject the MCP capability services

1 participant