Skip to content

feat(mcp): expose server prompts as dynamic skills - #1813

Open
Aaronontheweb wants to merge 8 commits into
devfrom
feature/mcp-prompt-skills
Open

feat(mcp): expose server prompts as dynamic skills#1813
Aaronontheweb wants to merge 8 commits into
devfrom
feature/mcp-prompt-skills

Conversation

@Aaronontheweb

Copy link
Copy Markdown
Collaborator

Summary

  • Discover MCP prompts when a server connects.
  • Publish prompt descriptors through the existing skill index.
  • Load prompt content through skill_load with validated arguments.
  • Preserve the existing MCP permission policy and progressive tool discovery.
  • Extend catalog refresh fingerprints with prompt metadata.

Scope

This PR implements issue #1806 from epic #1805.

MCP resource reads remain in #1807. Proactive catalog subscriptions remain in #1808.

Verification

  • dotnet build Netclaw.slnx --no-restore --nologo -v:minimal
  • 108 focused actor tests passed.
  • 35 focused daemon tests passed.
  • Two real stdio smoke theory cases passed.
  • dotnet slopwatch analyze
  • pwsh ./scripts/Add-FileHeaders.ps1 -Verify
  • openspec validate add-mcp-prompt-skills --strict
  • git diff --check

The model behavior eval did not run. The environment lacks the required evaluator provider variables.

Closes #1806.

Comment thread src/Netclaw.Actors/Skills/SkillRegistry.cs Fixed
// Resolve the full path and verify it's within the skill directory
var fullPath = Path.GetFullPath(Path.Combine(skill.SkillDirectory, resourcePath));
var skillDirFull = Path.GetFullPath(skill.SkillDirectory);
var fullPath = Path.GetFullPath(Path.Combine(fileSource.SkillDirectory, resourcePath));
Comment on lines +74 to +79
[Path.Combine(
SmokeMcpServerLocator.LocateRepositoryRoot(),
"evals",
"fixtures",
"mcp",
"prompt_server.py")],
Assert.NotNull(repo);

var projectDir = Path.Combine(repo!.FullName, "tests", "Netclaw.SmokeMcpServer");
var projectDir = Path.Combine(LocateRepositoryRoot(), "tests", "Netclaw.SmokeMcpServer");
public static string LocateRepositoryRoot()
{
var repo = new DirectoryInfo(AppContext.BaseDirectory);
while (repo is not null && !File.Exists(Path.Combine(repo.FullName, "Netclaw.slnx")))
@Aaronontheweb

Copy link
Copy Markdown
Collaborator Author

Adversarial review

I reviewed the protocol, permission, lifecycle, service construction, output, and compatibility paths.

Fixed findings

  • The unknown-skill fallback exposed every MCP prompt name from the global registry.
  • A denied session could learn a private server or prompt name through that error.
  • Commit d1626c9b now lists only file skills in the fallback.
  • A Team and Personal theory proves that remote names remain hidden.
  • The design assigned prompt output bounds to the loader.
  • Commit a731e1f5 now identifies the shared dispatcher as the existing bound and spill owner.

Deferred hardening

Verified boundaries

  • MCP SDK 2.0 prompt list and get contracts match the adapter.
  • Prompt discovery checks the advertised server capability.
  • Tools and prompts share one immutable server generation.
  • A stale prompt descriptor fails before prompts/get.
  • The existing MCP server profile controls index visibility and prompt use.
  • A prompt does not grant or invoke an MCP tool directly.
  • A transport failure reconnects without replay of the prompt request.
  • Unsupported content fails instead of silent omission.
  • The post-build skill registration does not create a dependency cycle.
  • The shared dispatcher bounds, redacts, and spills prompt tool results.

Verification after review fixes

  • 49 focused SkillToolTests passed.
  • The solution build passed with zero warnings and zero errors.
  • OpenSpec strict validation passed.
  • Slopwatch found zero issues.
  • File header verification passed.
  • git diff --check passed.

The model behavior eval remains incomplete. The environment lacks the required evaluator provider variables.

@Aaronontheweb

Copy link
Copy Markdown
Collaborator Author

CI found a stale native smoke assertion.

The daemon now reports the full MCP catalog as (4 tools, 1 prompts). The scenario still expected (4 tools).

Commit 2e08343e updates the assertion. The focused mcp-setup native smoke scenario now passes with five checks.

@Aaronontheweb
Aaronontheweb force-pushed the feature/mcp-prompt-skills branch from 2e08343 to 9671f97 Compare August 9, 2026 01:36
Comment on lines +232 to +241
foreach (var skill in promptSkills)
{
if (skill.Source is not McpPromptSkillSource source
|| !string.Equals(source.ServerName, serverName, StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException(
$"Skill '{skill.Name}' is not an MCP prompt from server '{serverName}'.",
nameof(skills));
}
}
@Aaronontheweb
Aaronontheweb force-pushed the feature/mcp-prompt-skills branch from 9671f97 to cbca71a Compare August 9, 2026 13:20
@Aaronontheweb
Aaronontheweb force-pushed the feature/mcp-prompt-skills branch from cbca71a to de1b124 Compare August 9, 2026 14:20
@Aaronontheweb
Aaronontheweb marked this pull request as ready for review August 9, 2026 14:36
@Aaronontheweb Aaronontheweb added mcp Model context protocol server / client issues. skills Skill loading, handling, authoring, indexing, and evals. labels Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mcp Model context protocol server / client issues. skills Skill loading, handling, authoring, indexing, and evals.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expose MCP prompts as transient Netclaw skills

1 participant