Skip to content

v0.41.36.0 feat(mcp): publish agent skills (list_skills / get_skill) for thin clients#1661

Merged
garrytan merged 10 commits into
masterfrom
garrytan/mcp-publish-agent-skills
May 30, 2026
Merged

v0.41.36.0 feat(mcp): publish agent skills (list_skills / get_skill) for thin clients#1661
garrytan merged 10 commits into
masterfrom
garrytan/mcp-publish-agent-skills

Conversation

@garrytan

Copy link
Copy Markdown
Owner

Summary

Publishes the agent repo's skills over MCP so thin clients (Codex desktop, Claude Code, Claude Cowork, Perplexity) can discover and follow them. Skills are fat-markdown instruction sets, not executable code — "using" one means fetching its prose and then calling the search/query/put_page tools the same gbrain serve already exposes. This is PR1 (the read-only catalog); the downloadable tarball/install surface is PR2, deferred and tracked in TODOS.md.

New MCP surface (read-scope, non-localOnly — auto-exposed over stdio MCP, HTTP MCP, and thin-client routing with zero dispatcher changes):

  • list_skills(section?) — flat catalog: per-skill name, one-line description, triggers, declared tools, and usable_tools / unavailable_tools cross-referenced against this server's op set AND the caller's scope (so the catalog never points a read-only client at a write tool). Carries an instructions envelope telling the client these are prose to follow, not programs to run.
  • get_skill(name) — one skill's prose body + an allowlisted frontmatter projection + client_guidance. Prose only, size-capped.
  • gbrain skills / gbrain skill <name> CLI surfaces via cliHints.

New module src/core/skill-catalog.ts — skills-dir resolution, catalog assembly, single-skill fetch, the publish gate, and the security boundary (manifest-vetted name lookup → realpath + relative containment → regular-file/SKILL.md check), frontmatter allowlist, 256KB response cap, and D7 tool cross-reference. The ops dynamic-import it to avoid an import cycle.

Config (GBrainConfig.mcp):

  • mcp.publish_skills — gates both ops for remote callers. Runtime absent → OFF (no silent capability grant on upgrade). gbrain init writes it true for new installs; gbrain upgrade prompts existing installs once, strongly recommending opt-in and stating that SKILL.md contents become readable by authorized remote MCP callers. Reads DB plane first (what gbrain config set writes), file plane as fallback. Local CLI always bypasses the gate.
  • mcp.skills_dir — explicit override so daemon/container deployments are deterministic; the response echoes the resolved skills_dir_source.

Test Coverage

CODE PATHS (src/core/skill-catalog.ts)
  ├── resolveSkillsDir          [★★★] config override / autodetect (remote excludes install_path) / no-dir storage_error
  ├── resolveSkillMdPath        [★★★] slash/../null/>128 reject, unknown-name page_not_found, manifest-path traversal, symlink escape, non-SKILL.md
  ├── confineManifestPath       [★★★] realpath + relative containment on every call
  ├── buildSkillCatalog         [★★★] one entry/skill, _conventions excluded, malformed→derived+no-throw, section filter, D7 split, empty dir
  ├── getSkillDetail            [★★★] prose body, frontmatter allowlist (drops writes_to/sources), oversize→payload_too_large, D7 mirror
  ├── crossReferenceTools / availableBrainTools [★★★] read vs admin vs local scope
  ├── readMcp{PublishSkills,SkillsDir} + assertPublishEnabled [★★★] DB-plane-first, file fallback, local bypass
  └── ops over dispatchToolCall [★★★] remote gate-off→permission_denied, local bypass, scope-aware D7, frontmatter sanitized end-to-end

COVERAGE: all new code paths tested. 40 new cases + 6 description pins.

Tests: test/skill-catalog.test.ts (15), test/skill-catalog-security.test.ts (17 — traversal/symlink/poisoned-manifest/oversize/non-SKILL.md/gate), test/skill-catalog-transports.test.ts (8 — real dispatchToolCall gate+scope+plane), test/operations-descriptions.test.ts (+6 pins). Fixture tree at test/fixtures/skill-catalog/.

Full unit suite green on the merged tree: 3001 + 2927 + 3142 + 2464 pass, 0 real failures (one transient failure was a self-inflicted race — package.json mutated mid-run by the version bump; cli.test.ts re-confirmed 18/0 on the stable tree). bun run verify: 29/29.

Pre-Landing Review

Covered before /ship by /plan-eng-review (CLEAR — 1 architecture finding resolved, scope phased into PR1/PR2) plus two independent outside-voice adversarial passes:

  • Claude subagent found 4 P0s, all folded in: read-scope defended via the mitigation stack; default-ON silent-grant → absent=OFF + init=ON + migration prompt; raw frontmatter leak → allowlist; manifest-path traversal → realpath confinement; catalog tool honesty → D7; install_path disclosure → excluded for remote.
  • Codex found 7 more (disjoint set), all folded or deferred: response-size cap, file-type confinement, get_skill tool-split mirror, explicit migration consent, per-transport gate tests landed in PR1; include_skillpacks confinement + name disambiguation deferred to PR2.

Design Review

No frontend files changed — design review skipped.

Eval Results

No prompt-related files changed — evals skipped.

Plan Completion

Plan: ~/.claude/plans/system-instruction-you-are-working-async-tarjan.md. All PR1 tasks DONE (T1 core module, T2 ops, T3 config+init+migration, T4 transport/security tests). PR2 (tarball/install + include_skillpacks) intentionally deferred per plan decisions D1 + D8 — tracked in TODOS.md.

TODOS

Added a "MCP skillpack distribution — PR2" section: build_skillpack + download endpoint, include_skillpacks merge, catalog cache, envelope routing-eval, and a stray malformed ~/.agents SKILL.md cleanup.

Documentation

  • CLAUDE.md — added the src/core/skill-catalog.ts Key-files annotation (v0.41.36.0): the two new ops, the mcp.publish_skills/mcp.skills_dir keys, the trust-boundary mitigation stack, D7 tool-honesty, dual-plane config reads, and init/upgrade wiring.
  • llms-full.txt — regenerated via bun run build:llms to match (CI drift gate passes).
  • CHANGELOG.md / TODOS.md / VERSION / package.json all at 0.41.36.0.

Test plan

  • bun run verify — 29/29
  • Full unit suite — 0 real failures (race re-confirmed clean)
  • 40 new skill-catalog cases + 6 description pins
  • Live CLI smoke: gbrain skills lists 48 skills with D7 honesty; gbrain skill brain-ops returns prose with writes_to/sources stripped; unknown → page_not_found

🤖 Generated with Claude Code

garrytan and others added 10 commits May 30, 2026 10:32
New src/core/skill-catalog.ts resolves the agent repo's skills dir, builds a
flat catalog, fetches one skill's prose, and gates publishing. Path confinement
(manifest-vetted lookup + realpath + SKILL.md file-type check), 256KB response
cap, frontmatter allowlist, and D7 tool cross-reference live here. config.ts
gains the mcp.publish_skills / mcp.skills_dir keys (+ KNOWN_CONFIG entries).
…covery

Two read-scope, non-localOnly ops (dynamic-import skill-catalog to avoid the
cycle) let Codex/Claude Code/Perplexity discover and follow the agent's skills
over gbrain serve. Descriptions + the instructional envelope constants are
pinned in operations-descriptions.ts.
…upgrade

gbrain init writes mcp.publish_skills:true (file plane) so new installs publish
by default. gbrain upgrade prompts existing installs once (DB plane), strongly
recommending opt-in, showing the resolved skills dir + that SKILL.md contents
become readable by authorized remote MCP callers.
…escription pins

40 cases: buildSkillCatalog/getSkillDetail/D7 split (skill-catalog.test.ts),
path traversal + symlink + poisoned-manifest + oversize + non-SKILL.md +
gate (skill-catalog-security.test.ts), and real dispatchToolCall gate+scope+plane
coverage (skill-catalog-transports.test.ts). Plus list_skills/get_skill
description + envelope pins.
MCP skill catalog (list_skills / get_skill) — thin clients can discover and
follow the agent repo's skills over gbrain serve. PR2 (tarball/install) filed
in TODOS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…) for v0.41.36.0

Add the src/core/skill-catalog.ts Key-files annotation to CLAUDE.md covering the
two new read-scope MCP ops, the mcp.publish_skills / mcp.skills_dir config keys,
the full trust-boundary mitigation stack, and the init/upgrade wiring.
Regenerate llms-full.txt to match (CI build-llms drift gate).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…h-agent-skills

# Conflicts:
#	CHANGELOG.md
#	TODOS.md
#	VERSION
#	package.json
…h-agent-skills

# Conflicts:
#	CHANGELOG.md
#	TODOS.md
#	VERSION
#	package.json
…h-agent-skills

# Conflicts:
#	CHANGELOG.md
#	VERSION
#	package.json
@garrytan garrytan merged commit ca13f40 into master May 30, 2026
21 checks passed
mgunnin added a commit to mgunnin/gbrain that referenced this pull request Jun 3, 2026
* upstream/master:
  v0.41.36.0 feat(mcp): publish agent skills (list_skills / get_skill) for thin clients (garrytan#1661)
  v0.41.35.0 feat(guardrails): vendor-neutral content guardrail seams (supersedes garrytan#1652) (garrytan#1660)
  v0.41.34.0 feat(search): retrieval cathedral — max-pool + title + alias + evidence (garrytan#1657)
  v0.41.33.0 feat(search): intent-aware adaptive return-sizing + agent-facing query param (garrytan#1640)
  v0.41.32.0 fix(staleness): commit-relative sync staleness (supersedes garrytan#1623) (garrytan#1656)
  v0.41.31.0 feat(embed): delta-aware sync --all cost gate + real stale-embedding semantics (garrytan#1632)
  v0.41.30.0 fix(brainstorm/lsd): --save writes the advertised .md file via canonical ingestion path (garrytan#1655)

# Conflicts:
#	src/core/operations.ts
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