Skip to content

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

Merged
Aaronontheweb merged 9 commits into
devfrom
feature/mcp-prompt-skills
Aug 9, 2026
Merged

feat(mcp): expose server prompts as dynamic skills#1813
Aaronontheweb merged 9 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
@Aaronontheweb
Aaronontheweb enabled auto-merge (squash) August 9, 2026 19:33
@Aaronontheweb
Aaronontheweb merged commit 665abbb into dev Aug 9, 2026
36 checks passed
@Aaronontheweb
Aaronontheweb deleted the feature/mcp-prompt-skills branch August 9, 2026 19:53
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