Skip to content

fix(skills): relay native Skills through gateway - #467

Merged
jmagar merged 9 commits into
mainfrom
fix/native-skills-relay-20260820
Aug 20, 2026
Merged

jmagar merged 9 commits into
mainfrom
fix/native-skills-relay-20260820

Conversation

@jmagar

@jmagar jmagar commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • preserve native Skills custom results through rmcp instead of misclassifying them as tool results
  • keep strict Skills list/get/read validation and digest verification while reporting discovered vs exposed counts accurately
  • preserve strict gateway action params and make API/MCP runtime provenance authoritative on mutations
  • bound hostile invalid-skill floods with a separate candidate-processing ceiling

Live proof

Depot advertises 497 skills over native MCP. Through live Labby, native skills/list, skills/get, and resources/read succeed. A proxied SKILL.md read matched its manifest SHA-256 exactly. Current strict validation exposes 163 Depot skills plus 2 first-party Labby skills and reports excludedSkills=334.

Validation

  • Skills module: 32/32 pass
  • forged API provenance regression: pass
  • forged MCP provenance regression: pass
  • gateway library suite on reviewed head: 872 passed, 0 failed, 4 ignored
  • formatting and diff check: clean
  • full Labby all-features rerun and final Clippy gates are in progress locally while CI starts

Adversarial review fixes

  1. Prevent authenticated callers from forging transport-owned runtime owner/origin audit provenance.
  2. Add MAX_SKILL_CANDIDATES_PER_UPSTREAM=1024 so invalid entries cannot grow rejection state until only page/time limits engage.
  3. Confirm gateway status is admin-only, so shared operator catalog counts do not leak subject-private Skills state.
  4. Keep the 256 validated-skill retention ceiling as a deliberate hostile-upstream memory bound; downstream completeness is signaled with truncated metadata.

SDK dependency

Temporarily pins rmcp to dinglebear-ai/rust-sdk revision c9c3e518ce94b8d715519657c88195515978bda4. The decoder fix will be proposed upstream so this pin has a clean exit path.

@github-actions github-actions Bot added the dependencies Pull requests that update a dependency file label Aug 20, 2026
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Aug 20, 2026
@github-actions github-actions Bot removed the documentation Improvements or additions to documentation label Aug 20, 2026
@jmagar

jmagar commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator Author

Final adversarial review / validation checkpoint for head f5badaa1d5d8b00637eceb34db76867420332e6b.

Native Skills proof

  • Depot native catalog advertises 497 skill candidates.
  • Labby native relay is proven end-to-end without the depot.skills.* compatibility facade: skills/list -> skills/get -> resources/read.
  • Live proxied resource proof: skill://depot/skill/agent-browser/agent-browser/SKILL.md, 3263 bytes, expected and actual digest both sha256:00709861067d0cbb634609778b1be0469de6d6cef5293fcd24cbd469faaae42c.
  • Strict validation intentionally exposes 163 Depot skills today; 334 exclusions are surfaced via completeness metadata rather than silently normalized: 329 non-string allowed-tools, 2 non-string metadata values, 2 resource manifests above the host cap, 1 description above the 1024-char Agent Skills limit.
  • Status accounting now distinguishes observed from accepted catalogs, so Depot reports 497 discovered / 163 exposed after deployment.

Adversarial review findings addressed

  1. rmcp untagged-result collision: protocol-generic resultType + _meta could make extension responses decode as CallToolResult and discard Skills fields. Pinned decoder fix requires a tool-specific field (content, structuredContent, or isError). Regression preserves both CustomResult and real CallToolResult behavior.
  2. Strict operator params: API/MCP transport provenance is injected only into gateway actions that consume it; read-only actions such as gateway.skills.list retain strict schemas.
  3. Forged audit provenance: caller-supplied gateway mutation owner/origin can no longer override authenticated API/MCP provenance. API and MCP regressions pass.
  4. Invalid-skill resource exhaustion: added independent 1024-candidate processing cap while retaining the intentional 256 validated-skill memory ceiling. Flood regression proves no next page is fetched once the candidate cap engages.
  5. Process-global Code Mode test state: added an RAII/mutex test guard so plain parallel cargo test no longer relies on nextest process isolation. Previously failing stateless app-state, in-process peer, and process-flag tests now pass.
  6. Supply-chain policy: no vendored SDK blob and no broad Git exception. rmcp is pinned to immutable fork SHA c9c3e518ce94b8d715519657c88195515978bda4; unknown-git = deny remains, with one exact repository allow entry. Local Cargo Deny passes. Upstream removal path is fix: preserve custom results with generic metadata modelcontextprotocol/rust-sdk#1197.

Local gates

  • Skills module: 32/32 pass.
  • Reviewed labby-gateway library: 872 passed, 0 failed, 4 ignored.
  • Forged API provenance regression: pass.
  • Forged MCP provenance regression: pass.
  • stateless_http_fresh_tools_list_observes_code_mode_app_state_changes: pass.
  • in_process_peer_lists_its_service_under_process_code_mode: pass.
  • process_code_mode_flag_round_trips: pass.
  • codemode_read_rejects_mutating_upstream_before_dispatch: pass.
  • codemode_read_rejects_artifact_writes_through_the_mcp_surface: pass.
  • fmt / diff-check / locked metadata: pass.
  • local Cargo Deny: pass.

CI is still authoritative for the remaining full repository gates. No unresolved code review threads were present at this checkpoint.

@jmagar
jmagar merged commit 90cab5b into main Aug 20, 2026
38 checks passed
@jmagar
jmagar deleted the fix/native-skills-relay-20260820 branch August 20, 2026 12:15
@jmagar jmagar mentioned this pull request Oct 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant