From ce2085bc6c1edb09698502a8230c3d38aedf2dcc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 5 Aug 2026 18:45:51 +0000 Subject: [PATCH 1/8] Update stacklok/toolhive to v0.42.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/upstream-projects.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/upstream-projects.yaml b/.github/upstream-projects.yaml index 4a2f7e91..4ceb3ee7 100644 --- a/.github/upstream-projects.yaml +++ b/.github/upstream-projects.yaml @@ -44,7 +44,7 @@ projects: - id: toolhive repo: stacklok/toolhive - version: v0.41.0 + version: v0.42.0 # toolhive is a monorepo covering the CLI, the Kubernetes # operator, and the vMCP gateway. It also introduces cross- # cutting features that land in concepts/, integrations/, From fd505ed2864b0489825b291d011ee66efbdf0edd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 5 Aug 2026 18:46:57 +0000 Subject: [PATCH 2/8] Refresh reference assets for toolhive v0.42.0 --- docs/toolhive/reference/cli/thv.md | 1 + docs/toolhive/reference/cli/thv_ai-plugin.md | 44 + .../reference/cli/thv_ai-plugin_build.md | 42 + .../reference/cli/thv_ai-plugin_builds.md | 41 + .../cli/thv_ai-plugin_builds_remove.md | 39 + .../reference/cli/thv_ai-plugin_info.md | 42 + .../reference/cli/thv_ai-plugin_install.md | 45 + .../reference/cli/thv_ai-plugin_list.md | 44 + .../reference/cli/thv_ai-plugin_push.md | 39 + .../reference/cli/thv_ai-plugin_uninstall.md | 41 + .../reference/cli/thv_ai-plugin_validate.md | 40 + docs/toolhive/reference/cli/thv_skill.md | 2 + .../reference/cli/thv_skill_install.md | 1 + docs/toolhive/reference/cli/thv_skill_sync.md | 59 + .../reference/cli/thv_skill_upgrade.md | 63 + static/api-specs/toolhive-api.yaml | 1080 ++++++++++++++++- .../toolhive-crds/mcpauthzconfigs.schema.json | 38 - .../mcpexternalauthconfigs.schema.json | 38 - .../toolhive-crds/mcpoidcconfigs.schema.json | 38 - .../mcptelemetryconfigs.schema.json | 32 - .../toolhive-crds/mcptoolconfigs.schema.json | 37 - .../mcpwebhookconfigs.schema.json | 32 - 22 files changed, 1566 insertions(+), 272 deletions(-) create mode 100644 docs/toolhive/reference/cli/thv_ai-plugin.md create mode 100644 docs/toolhive/reference/cli/thv_ai-plugin_build.md create mode 100644 docs/toolhive/reference/cli/thv_ai-plugin_builds.md create mode 100644 docs/toolhive/reference/cli/thv_ai-plugin_builds_remove.md create mode 100644 docs/toolhive/reference/cli/thv_ai-plugin_info.md create mode 100644 docs/toolhive/reference/cli/thv_ai-plugin_install.md create mode 100644 docs/toolhive/reference/cli/thv_ai-plugin_list.md create mode 100644 docs/toolhive/reference/cli/thv_ai-plugin_push.md create mode 100644 docs/toolhive/reference/cli/thv_ai-plugin_uninstall.md create mode 100644 docs/toolhive/reference/cli/thv_ai-plugin_validate.md create mode 100644 docs/toolhive/reference/cli/thv_skill_sync.md create mode 100644 docs/toolhive/reference/cli/thv_skill_upgrade.md diff --git a/docs/toolhive/reference/cli/thv.md b/docs/toolhive/reference/cli/thv.md index 74824dfa..170d95c2 100644 --- a/docs/toolhive/reference/cli/thv.md +++ b/docs/toolhive/reference/cli/thv.md @@ -35,6 +35,7 @@ thv [flags] ### SEE ALSO +* [thv ai-plugin](thv_ai-plugin.md) - Manage AI-tool plugins * [thv build](thv_build.md) - Build a container for an MCP server without running it * [thv client](thv_client.md) - Manage MCP clients * [thv config](thv_config.md) - Manage application configuration diff --git a/docs/toolhive/reference/cli/thv_ai-plugin.md b/docs/toolhive/reference/cli/thv_ai-plugin.md new file mode 100644 index 00000000..1df12af5 --- /dev/null +++ b/docs/toolhive/reference/cli/thv_ai-plugin.md @@ -0,0 +1,44 @@ +--- +title: thv ai-plugin +hide_title: true +description: Reference for ToolHive CLI command `thv ai-plugin` +last_update: + author: autogenerated +slug: thv_ai-plugin +mdx: + format: md +--- + +## thv ai-plugin + +Manage AI-tool plugins + +### Synopsis + +The ai-plugin command provides subcommands to manage plugins for AI tools +(e.g. Claude Code, Codex) — not plugins for ToolHive itself. + +### Options + +``` + -h, --help help for ai-plugin +``` + +### Options inherited from parent commands + +``` + --debug Enable debug mode +``` + +### SEE ALSO + +* [thv](thv.md) - ToolHive (thv) is a lightweight, secure, and fast manager for MCP servers +* [thv ai-plugin build](thv_ai-plugin_build.md) - Build an AI-tool plugin into a local OCI artifact +* [thv ai-plugin builds](thv_ai-plugin_builds.md) - List locally-built AI-tool plugin artifacts +* [thv ai-plugin info](thv_ai-plugin_info.md) - Show details of an AI-tool plugin +* [thv ai-plugin install](thv_ai-plugin_install.md) - Install an AI-tool plugin +* [thv ai-plugin list](thv_ai-plugin_list.md) - List installed AI-tool plugins +* [thv ai-plugin push](thv_ai-plugin_push.md) - Push a built AI-tool plugin to an OCI registry +* [thv ai-plugin uninstall](thv_ai-plugin_uninstall.md) - Uninstall an AI-tool plugin +* [thv ai-plugin validate](thv_ai-plugin_validate.md) - Validate an AI-tool plugin directory + diff --git a/docs/toolhive/reference/cli/thv_ai-plugin_build.md b/docs/toolhive/reference/cli/thv_ai-plugin_build.md new file mode 100644 index 00000000..094991b1 --- /dev/null +++ b/docs/toolhive/reference/cli/thv_ai-plugin_build.md @@ -0,0 +1,42 @@ +--- +title: thv ai-plugin build +hide_title: true +description: Reference for ToolHive CLI command `thv ai-plugin build` +last_update: + author: autogenerated +slug: thv_ai-plugin_build +mdx: + format: md +--- + +## thv ai-plugin build + +Build an AI-tool plugin into a local OCI artifact + +### Synopsis + +Build a plugin from a local directory into an OCI artifact that can be pushed to a registry. + +On success, prints the OCI reference of the built artifact to stdout. + +``` +thv ai-plugin build [path] [flags] +``` + +### Options + +``` + -h, --help help for build + -t, --tag string OCI tag for the built artifact +``` + +### Options inherited from parent commands + +``` + --debug Enable debug mode +``` + +### SEE ALSO + +* [thv ai-plugin](thv_ai-plugin.md) - Manage AI-tool plugins + diff --git a/docs/toolhive/reference/cli/thv_ai-plugin_builds.md b/docs/toolhive/reference/cli/thv_ai-plugin_builds.md new file mode 100644 index 00000000..b26da4a4 --- /dev/null +++ b/docs/toolhive/reference/cli/thv_ai-plugin_builds.md @@ -0,0 +1,41 @@ +--- +title: thv ai-plugin builds +hide_title: true +description: Reference for ToolHive CLI command `thv ai-plugin builds` +last_update: + author: autogenerated +slug: thv_ai-plugin_builds +mdx: + format: md +--- + +## thv ai-plugin builds + +List locally-built AI-tool plugin artifacts + +### Synopsis + +List all locally-built OCI plugin artifacts stored in the local OCI store. + +``` +thv ai-plugin builds [flags] +``` + +### Options + +``` + --format string Output format (json, text) (default "text") + -h, --help help for builds +``` + +### Options inherited from parent commands + +``` + --debug Enable debug mode +``` + +### SEE ALSO + +* [thv ai-plugin](thv_ai-plugin.md) - Manage AI-tool plugins +* [thv ai-plugin builds remove](thv_ai-plugin_builds_remove.md) - Remove a locally-built AI-tool plugin artifact + diff --git a/docs/toolhive/reference/cli/thv_ai-plugin_builds_remove.md b/docs/toolhive/reference/cli/thv_ai-plugin_builds_remove.md new file mode 100644 index 00000000..d265c16d --- /dev/null +++ b/docs/toolhive/reference/cli/thv_ai-plugin_builds_remove.md @@ -0,0 +1,39 @@ +--- +title: thv ai-plugin builds remove +hide_title: true +description: Reference for ToolHive CLI command `thv ai-plugin builds remove` +last_update: + author: autogenerated +slug: thv_ai-plugin_builds_remove +mdx: + format: md +--- + +## thv ai-plugin builds remove + +Remove a locally-built AI-tool plugin artifact + +### Synopsis + +Remove a locally-built OCI plugin artifact and its blobs from the local OCI store. + +``` +thv ai-plugin builds remove [flags] +``` + +### Options + +``` + -h, --help help for remove +``` + +### Options inherited from parent commands + +``` + --debug Enable debug mode +``` + +### SEE ALSO + +* [thv ai-plugin builds](thv_ai-plugin_builds.md) - List locally-built AI-tool plugin artifacts + diff --git a/docs/toolhive/reference/cli/thv_ai-plugin_info.md b/docs/toolhive/reference/cli/thv_ai-plugin_info.md new file mode 100644 index 00000000..107f371c --- /dev/null +++ b/docs/toolhive/reference/cli/thv_ai-plugin_info.md @@ -0,0 +1,42 @@ +--- +title: thv ai-plugin info +hide_title: true +description: Reference for ToolHive CLI command `thv ai-plugin info` +last_update: + author: autogenerated +slug: thv_ai-plugin_info +mdx: + format: md +--- + +## thv ai-plugin info + +Show details of an AI-tool plugin + +### Synopsis + +Display detailed information about a plugin, including metadata, version, and installation status. + +``` +thv ai-plugin info [plugin-name] [flags] +``` + +### Options + +``` + --format string Output format (json, text) (default "text") + -h, --help help for info + --project-root string Project root path for project-scoped plugins + --scope string Filter by scope (user, project) +``` + +### Options inherited from parent commands + +``` + --debug Enable debug mode +``` + +### SEE ALSO + +* [thv ai-plugin](thv_ai-plugin.md) - Manage AI-tool plugins + diff --git a/docs/toolhive/reference/cli/thv_ai-plugin_install.md b/docs/toolhive/reference/cli/thv_ai-plugin_install.md new file mode 100644 index 00000000..bb4c04e4 --- /dev/null +++ b/docs/toolhive/reference/cli/thv_ai-plugin_install.md @@ -0,0 +1,45 @@ +--- +title: thv ai-plugin install +hide_title: true +description: Reference for ToolHive CLI command `thv ai-plugin install` +last_update: + author: autogenerated +slug: thv_ai-plugin_install +mdx: + format: md +--- + +## thv ai-plugin install + +Install an AI-tool plugin + +### Synopsis + +Install a plugin by name or OCI reference. +The plugin will be fetched from a remote registry and installed locally. + +``` +thv ai-plugin install [plugin-name] [flags] +``` + +### Options + +``` + --clients string Comma-separated target client apps (e.g. claude-code,codex), or "all" for every available client + --force Overwrite existing plugin directory + --group string Group to add the plugin to after installation + -h, --help help for install + --project-root string Project root path for project-scoped installs + --scope string Installation scope (user, project) (default "user") +``` + +### Options inherited from parent commands + +``` + --debug Enable debug mode +``` + +### SEE ALSO + +* [thv ai-plugin](thv_ai-plugin.md) - Manage AI-tool plugins + diff --git a/docs/toolhive/reference/cli/thv_ai-plugin_list.md b/docs/toolhive/reference/cli/thv_ai-plugin_list.md new file mode 100644 index 00000000..8fa59900 --- /dev/null +++ b/docs/toolhive/reference/cli/thv_ai-plugin_list.md @@ -0,0 +1,44 @@ +--- +title: thv ai-plugin list +hide_title: true +description: Reference for ToolHive CLI command `thv ai-plugin list` +last_update: + author: autogenerated +slug: thv_ai-plugin_list +mdx: + format: md +--- + +## thv ai-plugin list + +List installed AI-tool plugins + +### Synopsis + +List all currently installed plugins and their status. + +``` +thv ai-plugin list [flags] +``` + +### Options + +``` + --client string Filter by client application + --format string Output format (json, text) (default "text") + --group string Filter by group + -h, --help help for list + --project-root string Project root path for project-scoped plugins + --scope string Filter by scope (user, project) +``` + +### Options inherited from parent commands + +``` + --debug Enable debug mode +``` + +### SEE ALSO + +* [thv ai-plugin](thv_ai-plugin.md) - Manage AI-tool plugins + diff --git a/docs/toolhive/reference/cli/thv_ai-plugin_push.md b/docs/toolhive/reference/cli/thv_ai-plugin_push.md new file mode 100644 index 00000000..56af0314 --- /dev/null +++ b/docs/toolhive/reference/cli/thv_ai-plugin_push.md @@ -0,0 +1,39 @@ +--- +title: thv ai-plugin push +hide_title: true +description: Reference for ToolHive CLI command `thv ai-plugin push` +last_update: + author: autogenerated +slug: thv_ai-plugin_push +mdx: + format: md +--- + +## thv ai-plugin push + +Push a built AI-tool plugin to an OCI registry + +### Synopsis + +Push a previously built plugin artifact to a remote OCI registry. + +``` +thv ai-plugin push [reference] [flags] +``` + +### Options + +``` + -h, --help help for push +``` + +### Options inherited from parent commands + +``` + --debug Enable debug mode +``` + +### SEE ALSO + +* [thv ai-plugin](thv_ai-plugin.md) - Manage AI-tool plugins + diff --git a/docs/toolhive/reference/cli/thv_ai-plugin_uninstall.md b/docs/toolhive/reference/cli/thv_ai-plugin_uninstall.md new file mode 100644 index 00000000..156267d1 --- /dev/null +++ b/docs/toolhive/reference/cli/thv_ai-plugin_uninstall.md @@ -0,0 +1,41 @@ +--- +title: thv ai-plugin uninstall +hide_title: true +description: Reference for ToolHive CLI command `thv ai-plugin uninstall` +last_update: + author: autogenerated +slug: thv_ai-plugin_uninstall +mdx: + format: md +--- + +## thv ai-plugin uninstall + +Uninstall an AI-tool plugin + +### Synopsis + +Remove a previously installed plugin by name. + +``` +thv ai-plugin uninstall [plugin-name] [flags] +``` + +### Options + +``` + -h, --help help for uninstall + --project-root string Project root path for project-scoped plugins + --scope string Scope to uninstall from (user, project) (default "user") +``` + +### Options inherited from parent commands + +``` + --debug Enable debug mode +``` + +### SEE ALSO + +* [thv ai-plugin](thv_ai-plugin.md) - Manage AI-tool plugins + diff --git a/docs/toolhive/reference/cli/thv_ai-plugin_validate.md b/docs/toolhive/reference/cli/thv_ai-plugin_validate.md new file mode 100644 index 00000000..6146f076 --- /dev/null +++ b/docs/toolhive/reference/cli/thv_ai-plugin_validate.md @@ -0,0 +1,40 @@ +--- +title: thv ai-plugin validate +hide_title: true +description: Reference for ToolHive CLI command `thv ai-plugin validate` +last_update: + author: autogenerated +slug: thv_ai-plugin_validate +mdx: + format: md +--- + +## thv ai-plugin validate + +Validate an AI-tool plugin directory + +### Synopsis + +Check that a plugin definition in the given directory is valid and well-formed. + +``` +thv ai-plugin validate [path] [flags] +``` + +### Options + +``` + --format string Output format (json, text) (default "text") + -h, --help help for validate +``` + +### Options inherited from parent commands + +``` + --debug Enable debug mode +``` + +### SEE ALSO + +* [thv ai-plugin](thv_ai-plugin.md) - Manage AI-tool plugins + diff --git a/docs/toolhive/reference/cli/thv_skill.md b/docs/toolhive/reference/cli/thv_skill.md index 3a93a62f..2717cddc 100644 --- a/docs/toolhive/reference/cli/thv_skill.md +++ b/docs/toolhive/reference/cli/thv_skill.md @@ -38,6 +38,8 @@ The skill command provides subcommands to manage skills. * [thv skill install](thv_skill_install.md) - Install a skill * [thv skill list](thv_skill_list.md) - List installed skills * [thv skill push](thv_skill_push.md) - Push a built skill +* [thv skill sync](thv_skill_sync.md) - Restore project skills to match the lock file (experimental) * [thv skill uninstall](thv_skill_uninstall.md) - Uninstall a skill +* [thv skill upgrade](thv_skill_upgrade.md) - Upgrade project skills to newer pinned content (experimental) * [thv skill validate](thv_skill_validate.md) - Validate a skill definition diff --git a/docs/toolhive/reference/cli/thv_skill_install.md b/docs/toolhive/reference/cli/thv_skill_install.md index 84ca857c..268829aa 100644 --- a/docs/toolhive/reference/cli/thv_skill_install.md +++ b/docs/toolhive/reference/cli/thv_skill_install.md @@ -25,6 +25,7 @@ thv skill install [skill-name] [flags] ### Options ``` + --allow-unsigned Allow installing a project-scoped skill without a verified signature (recorded in the lock file) --clients string Comma-separated target client apps (e.g. claude-code,opencode), or "all" for every available client --force Overwrite existing skill directory --group string Group to add the skill to after installation diff --git a/docs/toolhive/reference/cli/thv_skill_sync.md b/docs/toolhive/reference/cli/thv_skill_sync.md new file mode 100644 index 00000000..8cf0f6be --- /dev/null +++ b/docs/toolhive/reference/cli/thv_skill_sync.md @@ -0,0 +1,59 @@ +--- +title: thv skill sync +hide_title: true +description: Reference for ToolHive CLI command `thv skill sync` +last_update: + author: autogenerated +slug: thv_skill_sync +mdx: + format: md +--- + +## thv skill sync + +Restore project skills to match the lock file (experimental) + +### Synopsis + +Restore a project's installed skills to match toolhive.lock.yaml. + +Experimental: requires TOOLHIVE_SKILLS_LOCK_ENABLED=true on the ToolHive +server while the lock file feature rolls out. + +Missing or drifted skills are reinstalled at their pinned digest. Use +--check to report drift without installing anything (suitable for CI). +Use --adopt to record lock entries for existing unmanaged installs, and +--prune to remove installs no longer present in the lock file. + +Unless --check is set, sync prompts for confirmation before installing — +skill content is a set of AI-followed instructions. Pass --yes to skip the +prompt (required in non-interactive contexts such as CI). + +``` +thv skill sync [flags] +``` + +### Options + +``` + --adopt Write lock entries for existing unmanaged project-scope installs + --allow-unsigned Allow adopting skills whose signature state cannot be established (recorded as unsigned) + --check Report drift without installing, writing, or removing anything + --clients string Comma-separated target client apps (e.g. claude-code,opencode), or "all" for every available client + --format string Output format (json, text) (default "text") + -h, --help help for sync + --project-root string Project root path (default: auto-detected from the current directory) + --prune Remove installs no longer present in the lock file + --yes Skip the confirmation prompt (required when not running interactively) +``` + +### Options inherited from parent commands + +``` + --debug Enable debug mode +``` + +### SEE ALSO + +* [thv skill](thv_skill.md) - Manage skills + diff --git a/docs/toolhive/reference/cli/thv_skill_upgrade.md b/docs/toolhive/reference/cli/thv_skill_upgrade.md new file mode 100644 index 00000000..42118fbc --- /dev/null +++ b/docs/toolhive/reference/cli/thv_skill_upgrade.md @@ -0,0 +1,63 @@ +--- +title: thv skill upgrade +hide_title: true +description: Reference for ToolHive CLI command `thv skill upgrade` +last_update: + author: autogenerated +slug: thv_skill_upgrade +mdx: + format: md +--- + +## thv skill upgrade + +Upgrade project skills to newer pinned content (experimental) + +### Synopsis + +Re-resolve a project's lock entries and install newer content where available. + +Experimental: requires TOOLHIVE_SKILLS_LOCK_ENABLED=true on the ToolHive +server while the lock file feature rolls out. + +Skills pinned to an immutable reference (an OCI digest or a full git commit +hash) are reported not-upgradable — there is nothing newer to resolve to. +Use --preview to see what would change without persisting anything (OCI +sources are still fetched into the local artifact store to compare digests), +and --allow-ref-change to permit the resolved reference itself changing +(e.g. a registry entry repointed at a different repository). +--fail-on-changes evaluates the same plan and never installs: it is a CI +freshness gate. + +Unless --preview is set, upgrade prompts for confirmation before installing — +skill content is a set of AI-followed instructions. Pass --yes to skip the +prompt (required in non-interactive contexts such as CI). + +``` +thv skill upgrade [skill-name...] [flags] +``` + +### Options + +``` + --allow-ref-change Permit the resolved reference itself to change during upgrade + --allow-signer-change Permit upgrading to an artifact signed by a different identity; the new identity replaces the recorded one + --clients string Comma-separated target client apps (e.g. claude-code,opencode), or "all" for every available client + --fail-on-changes Report what would change without installing anything; a CI freshness gate + --format string Output format (json, text) (default "text") + -h, --help help for upgrade + --preview Report what would change without persisting anything (OCI sources are still fetched to compare digests) + --project-root string Project root path (default: auto-detected from the current directory) + --yes Skip the confirmation prompt (required when not running interactively) +``` + +### Options inherited from parent commands + +``` + --debug Enable debug mode +``` + +### SEE ALSO + +* [thv skill](thv_skill.md) - Manage skills + diff --git a/static/api-specs/toolhive-api.yaml b/static/api-specs/toolhive-api.yaml index 53225361..0969382e 100644 --- a/static/api-specs/toolhive-api.yaml +++ b/static/api-specs/toolhive-api.yaml @@ -946,6 +946,242 @@ components: type: array uniqueItems: false type: object + github_com_stacklok_toolhive_pkg_plugins.BuildResult: + properties: + reference: + description: Reference is the OCI reference of the built skill artifact. + type: string + type: object + github_com_stacklok_toolhive_pkg_plugins.ComponentInventory: + additionalProperties: + type: integer + description: |- + Components is the inventory of component types declared by the plugin + (e.g. {"commands": 3, "skills": 2}). Extracted from the OCI artifact. + type: object + github_com_stacklok_toolhive_pkg_plugins.ComponentType: + enum: + - commands + - agents + - skills + - hooks + - mcpServers + - lspServers + type: string + x-enum-varnames: + - ComponentCommands + - ComponentAgents + - ComponentSkills + - ComponentHooks + - ComponentMCP + - ComponentLSP + github_com_stacklok_toolhive_pkg_plugins.Dependency: + properties: + digest: + description: Digest is the OCI digest for upgrade detection. + type: string + name: + description: Name is the dependency name. + type: string + reference: + description: Reference is the OCI reference for the dependency. + type: string + type: object + github_com_stacklok_toolhive_pkg_plugins.InstallStatus: + description: Status is the current installation status. + enum: + - installed + - pending + - failed + type: string + x-enum-varnames: + - InstallStatusInstalled + - InstallStatusPending + - InstallStatusFailed + github_com_stacklok_toolhive_pkg_plugins.InstalledPlugin: + description: InstalledPlugin contains the full installation record. + properties: + clients: + description: Clients is the list of client identifiers the plugin is installed + for. + items: + type: string + type: array + uniqueItems: false + components: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.ComponentInventory' + dependencies: + description: Dependencies is the list of external plugin dependencies. + items: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.Dependency' + type: array + uniqueItems: false + digest: + description: Digest is the OCI digest (sha256:...) for upgrade detection. + type: string + installed_at: + description: InstalledAt is the timestamp when the plugin was installed. + type: string + metadata: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.PluginMetadata' + project_root: + description: ProjectRoot is the project root path for project-scoped plugins. + Empty for user-scoped. + type: string + reference: + description: Reference is the full OCI reference (e.g. ghcr.io/org/plugin:v1). + type: string + scope: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.Scope' + signature: + description: Signature is the optional signing signature for the plugin + artifact. + type: string + status: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.InstallStatus' + tag: + description: Tag is the OCI tag (e.g. v1.0.0). + type: string + type: object + github_com_stacklok_toolhive_pkg_plugins.LocalBuild: + properties: + description: + description: Description is the skill description extracted from the artifact + metadata, if available. + type: string + digest: + description: Digest is the OCI digest of the artifact (sha256:...). + type: string + name: + description: Name is the skill name extracted from the artifact metadata, + if available. + type: string + tag: + description: Tag is the OCI tag or name used to reference the artifact. + type: string + version: + description: Version is the skill version extracted from the artifact metadata, + if available. + type: string + type: object + github_com_stacklok_toolhive_pkg_plugins.PluginContent: + properties: + description: + description: Description is the plugin description from the OCI config labels. + type: string + files: + description: Files is the list of all files in the artifact with their sizes. + items: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.PluginFileEntry' + type: array + uniqueItems: false + license: + description: License is the SPDX license identifier from the OCI config + labels. + type: string + manifest: + description: Manifest is the raw .claude-plugin/plugin.json body. + type: string + name: + description: Name is the plugin name from the OCI config labels. + type: string + version: + description: Version is the plugin version from the OCI config labels. + type: string + type: object + github_com_stacklok_toolhive_pkg_plugins.PluginFileEntry: + properties: + path: + description: Path is the file path within the artifact. + type: string + size: + description: Size is the uncompressed file size in bytes. + type: integer + type: object + github_com_stacklok_toolhive_pkg_plugins.PluginInfo: + properties: + installed_plugin: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.InstalledPlugin' + metadata: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.PluginMetadata' + project_scope_degraded_clients: + description: |- + ProjectScopeDegradedClients lists the client types for which a + project-scoped install degraded (the adapter could only materialize at + user scope — e.g. Codex always writes to the user-scoped config.toml). + Populated by Info; empty for user-scoped installs. Recomputed at read + time from the stored scope + each adapter's capability, mirroring the + UnmaterializedComponents pattern (no persistence needed — the degradation + is deterministic from scope + client type). + items: + type: string + type: array + uniqueItems: false + unmaterialized_components: + additionalProperties: + items: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.ComponentType' + type: array + description: |- + UnmaterializedComponents lists, per client type, the component types the + plugin declares that the installed client adapter does NOT load. Populated + by Info by diffing InstalledPlugin.Components against each installed + client adapter's SupportedComponents. + type: object + type: object + github_com_stacklok_toolhive_pkg_plugins.PluginMetadata: + description: Metadata contains the plugin's metadata. + properties: + author: + description: Author is the plugin author or maintainer. + type: string + description: + description: Description is a human-readable description of the plugin. + type: string + keywords: + description: Keywords is a list of keywords for categorization/search. + items: + type: string + type: array + uniqueItems: false + license: + description: License is the SPDX license identifier for the plugin. + type: string + name: + description: Name is the unique name of the plugin (kebab-case). + type: string + version: + description: Version is the semantic version of the plugin. + type: string + type: object + github_com_stacklok_toolhive_pkg_plugins.Scope: + description: Scope for the installation + enum: + - user + - project + type: string + x-enum-varnames: + - ScopeUser + - ScopeProject + github_com_stacklok_toolhive_pkg_plugins.ValidationResult: + properties: + errors: + description: Errors is a list of validation errors, if any. + items: + type: string + type: array + uniqueItems: false + valid: + description: Valid indicates whether the skill definition is valid. + type: boolean + warnings: + description: Warnings is a list of non-blocking validation warnings, if + any. + items: + type: string + type: array + uniqueItems: false + type: object github_com_stacklok_toolhive_pkg_ratelimit_types.RateLimitBucket: description: |- PerUser token bucket configuration for this tool. @@ -1383,6 +1619,9 @@ components: - digest-missing - validation-rejected - lock-write-failed + - signature-invalid + - signer-mismatch + - unsigned-rejected - unknown type: string x-enum-varnames: @@ -1390,6 +1629,9 @@ components: - FailureReasonDigestMissing - FailureReasonValidationRejected - FailureReasonLockWriteFailed + - FailureReasonSignatureInvalid + - FailureReasonSignerMismatch + - FailureReasonUnsignedRejected - FailureReasonUnknown github_com_stacklok_toolhive_pkg_skills.InstallStatus: description: Status is the current installation status. @@ -1633,6 +1875,11 @@ components: new_resolved_reference: description: NewResolvedReference is the new resolvedReference when it changed. type: string + new_signer_identity: + description: |- + NewSignerIdentity is the candidate's signer identity when it differs + from the recorded one (empty when the candidate is unsigned). + type: string old_digest: description: OldDigest is the digest pinned in the lock file before this operation. @@ -1658,6 +1905,7 @@ components: - up-to-date - not-upgradable - ref-change-blocked + - signer-change-blocked - failed type: string x-enum-varnames: @@ -1665,6 +1913,7 @@ components: - UpgradeStatusUpToDate - UpgradeStatusNotUpgradable - UpgradeStatusRefChangeBlocked + - UpgradeStatusSignerChangeBlocked - UpgradeStatusFailed github_com_stacklok_toolhive_pkg_skills.ValidationResult: properties: @@ -2222,6 +2471,16 @@ components: type: array uniqueItems: false type: object + pkg_api_v1.buildPluginRequest: + description: Request to build a plugin from a local directory + properties: + path: + description: Path to the plugin definition directory + type: string + tag: + description: OCI tag for the built artifact + type: string + type: object pkg_api_v1.buildSkillRequest: description: Request to build a skill from a local directory properties: @@ -2533,9 +2792,51 @@ components: Use AddHeadersFromSecret for sensitive data like API keys. type: object type: object + pkg_api_v1.installPluginRequest: + description: Request to install a plugin + properties: + clients: + description: |- + Clients lists target client identifiers (e.g., "claude-code"), + or ["all"] to target every plugin-supporting client. + Omitting this field installs to all available clients. + items: + type: string + type: array + uniqueItems: false + force: + description: Force allows overwriting unmanaged plugin directories + type: boolean + group: + description: Group is the group name to add the plugin to after installation + type: string + name: + description: Name or OCI reference of the plugin to install + type: string + project_root: + description: ProjectRoot is the project root path for project-scoped installs + type: string + scope: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.Scope' + version: + description: Version to install (empty means latest) + type: string + type: object + pkg_api_v1.installPluginResponse: + description: Response after successfully installing a plugin + properties: + plugin: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.InstalledPlugin' + type: object pkg_api_v1.installSkillRequest: description: Request to install a skill properties: + allow_unsigned: + description: |- + AllowUnsigned permits installing a project-scoped skill without a + verified signature; the exception is recorded in the project's lock + file. + type: boolean clients: description: |- Clients lists target client identifiers (e.g., "claude-code"), @@ -2636,6 +2937,38 @@ components: description: Total is the total number of items matching the query type: integer type: object + pkg_api_v1.pluginBuildListResponse: + description: Response containing a list of locally-built OCI plugin artifacts + properties: + builds: + description: List of locally-built OCI plugin artifacts + items: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.LocalBuild' + type: array + uniqueItems: false + type: object + pkg_api_v1.pluginListResponse: + description: Response containing a list of installed plugins + properties: + plugins: + description: List of installed plugins + items: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.InstalledPlugin' + type: array + uniqueItems: false + type: object + pkg_api_v1.pluginsV01Response: + description: Paginated list of plugins from the registry + properties: + metadata: + $ref: '#/components/schemas/pkg_api_v1.paginationV01Metadata' + plugins: + description: Plugins is the list of plugins on the current page + items: + $ref: '#/components/schemas/registry.Plugin' + type: array + uniqueItems: false + type: object pkg_api_v1.providerCapabilitiesResponse: description: Capabilities of the secrets provider properties: @@ -2655,6 +2988,13 @@ components: description: Whether the provider can write secrets type: boolean type: object + pkg_api_v1.pushPluginRequest: + description: Request to push a built plugin artifact + properties: + reference: + description: OCI reference to push + type: string + type: object pkg_api_v1.pushSkillRequest: description: Request to push a built skill artifact properties: @@ -2838,6 +3178,11 @@ components: description: Adopt writes lock entries for existing unmanaged project-scope installs type: boolean + allow_unsigned: + description: |- + AllowUnsigned permits adopting skills whose signature state cannot be + established, recording them as unsigned + type: boolean check: description: Check verifies on-disk content against the lock file without installing or writing anything @@ -3033,6 +3378,11 @@ components: allow_ref_change: description: AllowRefChange permits resolvedReference changes during upgrade type: boolean + allow_signer_change: + description: |- + AllowSignerChange permits upgrading to an artifact signed by a + different identity than the recorded one + type: boolean clients: description: |- Clients lists target client identifiers. Empty means every @@ -3061,6 +3411,13 @@ components: be upgraded type: string type: object + pkg_api_v1.validatePluginRequest: + description: Request to validate a plugin definition + properties: + path: + description: Path to the plugin definition directory + type: string + type: object pkg_api_v1.validateSkillRequest: description: Request to validate a skill definition properties: @@ -3382,32 +3739,92 @@ components: Defaults to true for enhanced security type: boolean type: object - registry.Provenance: - description: Provenance contains verification and signing metadata + registry.Plugin: properties: - attestation: - $ref: '#/components/schemas/registry.VerifiedAttestation' - cert_issuer: - type: string - repository_ref: - type: string - repository_uri: - type: string - runner_environment: - type: string - signer_identity: - type: string - sigstore_url: + _meta: + additionalProperties: {} + description: Meta is an opaque payload with extended meta data details of + the plugin. + type: object + description: + description: Description is the description of the plugin. type: string - type: object - registry.Registry: - description: Full registry data - properties: - groups: - description: Groups is a slice of group definitions containing related MCP - servers + icons: + description: Icons is the list of icons for the plugin. items: - $ref: '#/components/schemas/registry.Group' + $ref: '#/components/schemas/registry.SkillIcon' + type: array + uniqueItems: false + license: + description: License is the SPDX license identifier of the plugin. + type: string + metadata: + additionalProperties: {} + description: |- + Metadata is the official metadata of the plugin as reported in the + plugin manifest file. + type: object + name: + description: |- + Name is the name of the plugin. + The format is that of identifiers, e.g. "my-plugin". + type: string + namespace: + description: |- + Namespace is the namespace of the plugin. + The format is reverse-DNS, e.g. "io.github.user". + type: string + packages: + description: Packages is the list of packages for the plugin. + items: + $ref: '#/components/schemas/registry.SkillPackage' + type: array + uniqueItems: false + repository: + $ref: '#/components/schemas/registry.SkillRepository' + status: + description: |- + Status is the status of the plugin. + Can be one of "active", "deprecated", or "archived". + type: string + title: + description: |- + Title is the title of the plugin. + This is for human consumption, not an identifier. + type: string + version: + description: |- + Version is the version of the plugin. + Any non-empty string is valid, but ideally it should be either a + semantic version or a commit hash. + type: string + type: object + registry.Provenance: + description: Provenance contains verification and signing metadata + properties: + attestation: + $ref: '#/components/schemas/registry.VerifiedAttestation' + cert_issuer: + type: string + repository_ref: + type: string + repository_uri: + type: string + runner_environment: + type: string + signer_identity: + type: string + sigstore_url: + type: string + type: object + registry.Registry: + description: Full registry data + properties: + groups: + description: Groups is a slice of group definitions containing related MCP + servers + items: + $ref: '#/components/schemas/registry.Group' type: array uniqueItems: false last_updated: @@ -4321,74 +4738,414 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/pkg_api_v1.groupListResponse' + $ref: '#/components/schemas/pkg_api_v1.groupListResponse' + description: OK + "500": + content: + application/json: + schema: + type: string + description: Internal Server Error + summary: List all groups + tags: + - groups + post: + description: Create a new group with the specified name + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + - $ref: '#/components/schemas/pkg_api_v1.createGroupRequest' + description: Group creation request + summary: group + description: Group creation request + required: true + responses: + "201": + content: + application/json: + schema: + $ref: '#/components/schemas/pkg_api_v1.createGroupResponse' + description: Created + "400": + content: + application/json: + schema: + type: string + description: Bad Request + "409": + content: + application/json: + schema: + type: string + description: Conflict + "500": + content: + application/json: + schema: + type: string + description: Internal Server Error + summary: Create a new group + tags: + - groups + /api/v1beta/groups/{name}: + delete: + description: Delete a group by name. + parameters: + - description: Group name + in: path + name: name + required: true + schema: + type: string + - description: 'Delete all workloads in the group (default: false, moves workloads + to default group)' + in: query + name: with-workloads + schema: + type: boolean + responses: + "204": + content: + application/json: + schema: + type: string + description: No Content + "404": + content: + application/json: + schema: + type: string + description: Not Found + "500": + content: + application/json: + schema: + type: string + description: Internal Server Error + summary: Delete a group + tags: + - groups + get: + description: Get details of a specific group + parameters: + - description: Group name + in: path + name: name + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_groups.Group' + description: OK + "404": + content: + application/json: + schema: + type: string + description: Not Found + "500": + content: + application/json: + schema: + type: string + description: Internal Server Error + summary: Get group details + tags: + - groups + /api/v1beta/plugins: + get: + description: Get a list of all installed plugins + parameters: + - description: Filter by scope (user or project) + in: query + name: scope + schema: + enum: + - user + - project + type: string + - description: Filter by client app + in: query + name: client + schema: + type: string + - description: Filter by project root path + in: query + name: project_root + schema: + type: string + - description: Filter by group name + in: query + name: group + schema: + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/pkg_api_v1.pluginListResponse' + description: OK + "500": + content: + application/json: + schema: + type: string + description: Internal Server Error + summary: List all installed plugins + tags: + - plugins + post: + description: Install a plugin from a remote source + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + - $ref: '#/components/schemas/pkg_api_v1.installPluginRequest' + description: Install request + summary: request + description: Install request + required: true + responses: + "201": + content: + application/json: + schema: + $ref: '#/components/schemas/pkg_api_v1.installPluginResponse' + description: Created + headers: + Location: + description: URI of the installed plugin resource + schema: + type: string + "400": + content: + application/json: + schema: + type: string + description: Bad Request + "401": + content: + application/json: + schema: + type: string + description: Unauthorized (registry refused credentials) + "404": + content: + application/json: + schema: + type: string + description: Not Found (artifact not present in registry) + "409": + content: + application/json: + schema: + type: string + description: Conflict + "429": + content: + application/json: + schema: + type: string + description: Too Many Requests (registry rate limit) + "500": + content: + application/json: + schema: + type: string + description: Internal Server Error + "502": + content: + application/json: + schema: + type: string + description: Bad Gateway (upstream registry failure) + "504": + content: + application/json: + schema: + type: string + description: Gateway Timeout (upstream pull timed out) + summary: Install a plugin + tags: + - plugins + /api/v1beta/plugins/{name}: + delete: + description: Remove an installed plugin + parameters: + - description: Plugin name + in: path + name: name + required: true + schema: + type: string + - description: Scope to uninstall from (user or project) + in: query + name: scope + schema: + enum: + - user + - project + type: string + - description: Project root path for project-scoped plugins + in: query + name: project_root + schema: + type: string + responses: + "204": + content: + application/json: + schema: + type: string + description: No Content + "400": + content: + application/json: + schema: + type: string + description: Bad Request + "404": + content: + application/json: + schema: + type: string + description: Not Found + "500": + content: + application/json: + schema: + type: string + description: Internal Server Error + summary: Uninstall a plugin + tags: + - plugins + get: + description: Get detailed information about a specific plugin + parameters: + - description: Plugin name + in: path + name: name + required: true + schema: + type: string + - description: Filter by scope (user or project) + in: query + name: scope + schema: + enum: + - user + - project + type: string + - description: Project root path for project-scoped plugins + in: query + name: project_root + schema: + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.PluginInfo' description: OK + "400": + content: + application/json: + schema: + type: string + description: Bad Request + "404": + content: + application/json: + schema: + type: string + description: Not Found "500": content: application/json: schema: type: string description: Internal Server Error - summary: List all groups + summary: Get plugin details tags: - - groups + - plugins + /api/v1beta/plugins/build: post: - description: Create a new group with the specified name + description: Build a plugin from a local directory requestBody: content: application/json: schema: oneOf: - type: object - - $ref: '#/components/schemas/pkg_api_v1.createGroupRequest' - description: Group creation request - summary: group - description: Group creation request + - $ref: '#/components/schemas/pkg_api_v1.buildPluginRequest' + description: Build request + summary: request + description: Build request required: true responses: - "201": + "200": content: application/json: schema: - $ref: '#/components/schemas/pkg_api_v1.createGroupResponse' - description: Created + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.BuildResult' + description: OK "400": content: application/json: schema: type: string description: Bad Request - "409": + "500": content: application/json: schema: type: string - description: Conflict + description: Internal Server Error + summary: Build a plugin + tags: + - plugins + /api/v1beta/plugins/builds: + get: + description: Get a list of all locally-built OCI plugin artifacts in the local + store + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/pkg_api_v1.pluginBuildListResponse' + description: OK "500": content: application/json: schema: type: string description: Internal Server Error - summary: Create a new group + summary: List locally-built plugin artifacts tags: - - groups - /api/v1beta/groups/{name}: + - plugins + /api/v1beta/plugins/builds/{tag}: delete: - description: Delete a group by name. + description: Remove a locally-built OCI plugin artifact and its blobs from the + local store parameters: - - description: Group name + - description: Artifact tag in: path - name: name + name: tag required: true schema: type: string - - description: 'Delete all workloads in the group (default: false, moves workloads - to default group)' - in: query - name: with-workloads - schema: - type: boolean responses: "204": content: @@ -4408,15 +5165,18 @@ paths: schema: type: string description: Internal Server Error - summary: Delete a group + summary: Delete a locally-built plugin artifact tags: - - groups + - plugins + /api/v1beta/plugins/content: get: - description: Get details of a specific group + description: |- + Retrieve the plugin.json body and file listing from an artifact + without installing it. Accepts OCI refs, git refs, or local tags. parameters: - - description: Group name - in: path - name: name + - description: OCI reference or local build tag + in: query + name: ref required: true schema: type: string @@ -4425,8 +5185,80 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_groups.Group' + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.PluginContent' description: OK + "400": + content: + application/json: + schema: + type: string + description: Bad Request + "401": + content: + application/json: + schema: + type: string + description: Unauthorized (registry refused credentials) + "404": + content: + application/json: + schema: + type: string + description: Not Found (artifact not present in registry) + "429": + content: + application/json: + schema: + type: string + description: Too Many Requests (registry rate limit) + "500": + content: + application/json: + schema: + type: string + description: Internal Server Error + "502": + content: + application/json: + schema: + type: string + description: Bad Gateway (upstream registry or git resolver failure) + "504": + content: + application/json: + schema: + type: string + description: Gateway Timeout (upstream pull timed out) + summary: Get plugin content + tags: + - plugins + /api/v1beta/plugins/push: + post: + description: Push a built plugin artifact to a remote registry + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + - $ref: '#/components/schemas/pkg_api_v1.pushPluginRequest' + description: Push request + summary: request + description: Push request + required: true + responses: + "204": + content: + application/json: + schema: + type: string + description: No Content + "400": + content: + application/json: + schema: + type: string + description: Bad Request "404": content: application/json: @@ -4439,9 +5271,45 @@ paths: schema: type: string description: Internal Server Error - summary: Get group details + summary: Push a plugin tags: - - groups + - plugins + /api/v1beta/plugins/validate: + post: + description: Validate a plugin definition + requestBody: + content: + application/json: + schema: + oneOf: + - type: object + - $ref: '#/components/schemas/pkg_api_v1.validatePluginRequest' + description: Validate request + summary: request + description: Validate request + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.ValidationResult' + description: OK + "400": + content: + application/json: + schema: + type: string + description: Bad Request + "500": + content: + application/json: + schema: + type: string + description: Internal Server Error + summary: Validate a plugin + tags: + - plugins /api/v1beta/registry: get: description: Get a list of the current registries @@ -6238,6 +7106,104 @@ paths: summary: Get a registry server tags: - registry-servers + /registry/{registryName}/v0.1/x/dev.toolhive/plugins: + get: + description: Get a paginated list of plugins from the registry. Supports optional + full-text search and pagination. + parameters: + - description: Registry name (currently ignored, uses the default provider) + in: path + name: registryName + required: true + schema: + type: string + - description: Search filter — matches against plugin name, namespace, and description + in: query + name: q + schema: + type: string + - description: 'Page number, 1-based (default: 1)' + in: query + name: page + schema: + type: integer + - description: 'Items per page, max 200 (default: 50)' + in: query + name: limit + schema: + type: integer + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/pkg_api_v1.pluginsV01Response' + description: OK + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/pkg_api_v1.registryErrorResponse' + description: Internal server error + "503": + content: + application/json: + schema: + $ref: '#/components/schemas/pkg_api_v1.registryErrorResponse' + description: Registry authentication required or upstream registry unavailable + summary: List available registry plugins + tags: + - registry-plugins + /registry/{registryName}/v0.1/x/dev.toolhive/plugins/{namespace}/{pluginName}: + get: + description: Retrieve a single plugin by its namespace and name from the registry. + parameters: + - description: Registry name (currently ignored, uses the default provider) + in: path + name: registryName + required: true + schema: + type: string + - description: Plugin namespace in reverse-DNS format (e.g. io.github.stacklok) + in: path + name: namespace + required: true + schema: + type: string + - description: Plugin name + in: path + name: pluginName + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/registry.Plugin' + description: OK + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/pkg_api_v1.registryErrorResponse' + description: Plugin not found + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/pkg_api_v1.registryErrorResponse' + description: Internal server error + "503": + content: + application/json: + schema: + $ref: '#/components/schemas/pkg_api_v1.registryErrorResponse' + description: Registry authentication required or upstream registry unavailable + summary: Get a registry plugin + tags: + - registry-plugins /registry/{registryName}/v0.1/x/dev.toolhive/skills: get: description: Get a paginated list of skills from the registry. Supports optional diff --git a/static/api-specs/toolhive-crds/mcpauthzconfigs.schema.json b/static/api-specs/toolhive-crds/mcpauthzconfigs.schema.json index cc17050f..b9dc444b 100644 --- a/static/api-specs/toolhive-crds/mcpauthzconfigs.schema.json +++ b/static/api-specs/toolhive-crds/mcpauthzconfigs.schema.json @@ -101,44 +101,6 @@ "description": "ObservedGeneration is the most recent generation observed for this MCPAuthzConfig.", "format": "int64", "type": "integer" - }, - "referenceCount": { - "description": "ReferenceCount is the number of workloads referencing this config.", - "format": "int32", - "type": "integer" - }, - "referencingWorkloads": { - "description": "ReferencingWorkloads is a list of workload resources that reference this MCPAuthzConfig.\nEach entry identifies the workload by kind and name. The map key is the\n(kind, name) pair so two workloads of different kinds that share a name\n(e.g., an MCPServer \"foo\" and a VirtualMCPServer \"foo\") are distinct\nentries rather than colliding under merge-patch semantics.", - "items": { - "description": "WorkloadReference identifies a workload that references a shared configuration resource.\nNamespace is implicit — cross-namespace references are not supported.", - "properties": { - "kind": { - "description": "Kind is the type of workload resource", - "enum": [ - "MCPServer", - "VirtualMCPServer", - "MCPRemoteProxy" - ], - "type": "string" - }, - "name": { - "description": "Name is the name of the workload resource", - "minLength": 1, - "type": "string" - } - }, - "required": [ - "kind", - "name" - ], - "type": "object" - }, - "type": "array", - "x-kubernetes-list-map-keys": [ - "kind", - "name" - ], - "x-kubernetes-list-type": "map" } }, "type": "object" diff --git a/static/api-specs/toolhive-crds/mcpexternalauthconfigs.schema.json b/static/api-specs/toolhive-crds/mcpexternalauthconfigs.schema.json index 4b75a27e..d5ad9f87 100644 --- a/static/api-specs/toolhive-crds/mcpexternalauthconfigs.schema.json +++ b/static/api-specs/toolhive-crds/mcpexternalauthconfigs.schema.json @@ -1270,44 +1270,6 @@ "description": "ObservedGeneration is the most recent generation observed for this MCPExternalAuthConfig.\nIt corresponds to the MCPExternalAuthConfig's generation, which is updated on mutation by the API Server.", "format": "int64", "type": "integer" - }, - "referenceCount": { - "description": "ReferenceCount is the number of workloads referencing this config.", - "format": "int32", - "type": "integer" - }, - "referencingWorkloads": { - "description": "ReferencingWorkloads is a list of workload resources that reference this MCPExternalAuthConfig.\nEach entry identifies the workload by kind and name. The map key is the\n(kind, name) pair so two workloads of different kinds that share a name\n(e.g., an MCPServer \"foo\" and a VirtualMCPServer \"foo\") are distinct\nentries rather than colliding under merge-patch semantics.", - "items": { - "description": "WorkloadReference identifies a workload that references a shared configuration resource.\nNamespace is implicit — cross-namespace references are not supported.", - "properties": { - "kind": { - "description": "Kind is the type of workload resource", - "enum": [ - "MCPServer", - "VirtualMCPServer", - "MCPRemoteProxy" - ], - "type": "string" - }, - "name": { - "description": "Name is the name of the workload resource", - "minLength": 1, - "type": "string" - } - }, - "required": [ - "kind", - "name" - ], - "type": "object" - }, - "type": "array", - "x-kubernetes-list-map-keys": [ - "kind", - "name" - ], - "x-kubernetes-list-type": "map" } }, "type": "object" diff --git a/static/api-specs/toolhive-crds/mcpoidcconfigs.schema.json b/static/api-specs/toolhive-crds/mcpoidcconfigs.schema.json index 587815b8..5658182e 100644 --- a/static/api-specs/toolhive-crds/mcpoidcconfigs.schema.json +++ b/static/api-specs/toolhive-crds/mcpoidcconfigs.schema.json @@ -230,44 +230,6 @@ "description": "ObservedGeneration is the most recent generation observed for this MCPOIDCConfig.", "format": "int64", "type": "integer" - }, - "referenceCount": { - "description": "ReferenceCount is the number of workloads referencing this config.", - "format": "int32", - "type": "integer" - }, - "referencingWorkloads": { - "description": "ReferencingWorkloads is a list of workload resources that reference this MCPOIDCConfig.\nEach entry identifies the workload by kind and name. The map key is the\n(kind, name) pair so two workloads of different kinds that share a name\n(e.g., an MCPServer \"foo\" and a VirtualMCPServer \"foo\") are distinct\nentries rather than colliding under merge-patch semantics.", - "items": { - "description": "WorkloadReference identifies a workload that references a shared configuration resource.\nNamespace is implicit — cross-namespace references are not supported.", - "properties": { - "kind": { - "description": "Kind is the type of workload resource", - "enum": [ - "MCPServer", - "VirtualMCPServer", - "MCPRemoteProxy" - ], - "type": "string" - }, - "name": { - "description": "Name is the name of the workload resource", - "minLength": 1, - "type": "string" - } - }, - "required": [ - "kind", - "name" - ], - "type": "object" - }, - "type": "array", - "x-kubernetes-list-map-keys": [ - "kind", - "name" - ], - "x-kubernetes-list-type": "map" } }, "type": "object" diff --git a/static/api-specs/toolhive-crds/mcptelemetryconfigs.schema.json b/static/api-specs/toolhive-crds/mcptelemetryconfigs.schema.json index 4f299679..42815ff3 100644 --- a/static/api-specs/toolhive-crds/mcptelemetryconfigs.schema.json +++ b/static/api-specs/toolhive-crds/mcptelemetryconfigs.schema.json @@ -241,38 +241,6 @@ "description": "ObservedGeneration is the most recent generation observed for this MCPTelemetryConfig.", "format": "int64", "type": "integer" - }, - "referencingWorkloads": { - "description": "ReferencingWorkloads lists workloads that reference this MCPTelemetryConfig", - "items": { - "description": "WorkloadReference identifies a workload that references a shared configuration resource.\nNamespace is implicit — cross-namespace references are not supported.", - "properties": { - "kind": { - "description": "Kind is the type of workload resource", - "enum": [ - "MCPServer", - "VirtualMCPServer", - "MCPRemoteProxy" - ], - "type": "string" - }, - "name": { - "description": "Name is the name of the workload resource", - "minLength": 1, - "type": "string" - } - }, - "required": [ - "kind", - "name" - ], - "type": "object" - }, - "type": "array", - "x-kubernetes-list-map-keys": [ - "name" - ], - "x-kubernetes-list-type": "map" } }, "type": "object" diff --git a/static/api-specs/toolhive-crds/mcptoolconfigs.schema.json b/static/api-specs/toolhive-crds/mcptoolconfigs.schema.json index a4c8354f..08287d14 100644 --- a/static/api-specs/toolhive-crds/mcptoolconfigs.schema.json +++ b/static/api-specs/toolhive-crds/mcptoolconfigs.schema.json @@ -140,43 +140,6 @@ "description": "ObservedGeneration is the most recent generation observed for this MCPToolConfig.\nIt corresponds to the MCPToolConfig's generation, which is updated on mutation by the API Server.", "format": "int64", "type": "integer" - }, - "referenceCount": { - "description": "ReferenceCount is the number of workloads referencing this config.", - "format": "int32", - "type": "integer" - }, - "referencingWorkloads": { - "description": "ReferencingWorkloads is a list of workload resources that reference this MCPToolConfig.\nEach entry identifies the workload by kind and name.", - "items": { - "description": "WorkloadReference identifies a workload that references a shared configuration resource.\nNamespace is implicit — cross-namespace references are not supported.", - "properties": { - "kind": { - "description": "Kind is the type of workload resource", - "enum": [ - "MCPServer", - "VirtualMCPServer", - "MCPRemoteProxy" - ], - "type": "string" - }, - "name": { - "description": "Name is the name of the workload resource", - "minLength": 1, - "type": "string" - } - }, - "required": [ - "kind", - "name" - ], - "type": "object" - }, - "type": "array", - "x-kubernetes-list-map-keys": [ - "name" - ], - "x-kubernetes-list-type": "map" } }, "type": "object" diff --git a/static/api-specs/toolhive-crds/mcpwebhookconfigs.schema.json b/static/api-specs/toolhive-crds/mcpwebhookconfigs.schema.json index 2e006ed3..463a71ee 100644 --- a/static/api-specs/toolhive-crds/mcpwebhookconfigs.schema.json +++ b/static/api-specs/toolhive-crds/mcpwebhookconfigs.schema.json @@ -335,38 +335,6 @@ "description": "ObservedGeneration is the last observed generation corresponding to the current status", "format": "int64", "type": "integer" - }, - "referencingWorkloads": { - "description": "ReferencingWorkloads is a list of workload resources that reference this MCPWebhookConfig.\nEach entry identifies the workload by kind and name.", - "items": { - "description": "WorkloadReference identifies a workload that references a shared configuration resource.\nNamespace is implicit — cross-namespace references are not supported.", - "properties": { - "kind": { - "description": "Kind is the type of workload resource", - "enum": [ - "MCPServer", - "VirtualMCPServer", - "MCPRemoteProxy" - ], - "type": "string" - }, - "name": { - "description": "Name is the name of the workload resource", - "minLength": 1, - "type": "string" - } - }, - "required": [ - "kind", - "name" - ], - "type": "object" - }, - "type": "array", - "x-kubernetes-list-map-keys": [ - "name" - ], - "x-kubernetes-list-type": "map" } }, "type": "object" From e94060694efb915f3c008dda2183a70d376a09a7 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Wed, 5 Aug 2026 18:59:22 +0000 Subject: [PATCH 3/8] Document ai-plugin, skills signing, and CRD status removal for v0.42.0 - Add guide for the new thv ai-plugin surface (Claude Code, Codex) - Add sync, upgrade, and signature verification sections to the skills management guide behind the experimental TOOLHIVE_SKILLS_LOCK_ENABLED gate - Document that Cedar authorization now evaluates the post-mutation request - Sweep removed config-CRD status fields (referencingWorkloads, REFERENCES column) out of K8s guides; replace with workload-side queries Co-Authored-By: Claude Opus 4.7 --- SUMMARY.md | 27 ++ docs/toolhive/guides-cli/ai-plugins.mdx | 341 ++++++++++++++++++ .../toolhive/guides-cli/skills-management.mdx | 164 +++++++++ docs/toolhive/guides-cli/webhooks.mdx | 32 ++ docs/toolhive/guides-k8s/auth-k8s.mdx | 14 +- .../toolhive/guides-k8s/authorization-k8s.mdx | 5 +- .../guides-k8s/migrate-to-v1beta1.mdx | 31 +- .../guides-k8s/telemetry-and-metrics.mdx | 11 +- .../reference/crds/mcpauthzconfig.mdx | 2 +- scripts/lib/crd-intros.mjs | 2 +- sidebars.ts | 1 + 11 files changed, 613 insertions(+), 17 deletions(-) create mode 100644 SUMMARY.md create mode 100644 docs/toolhive/guides-cli/ai-plugins.mdx diff --git a/SUMMARY.md b/SUMMARY.md new file mode 100644 index 00000000..f7f6efa6 --- /dev/null +++ b/SUMMARY.md @@ -0,0 +1,27 @@ +- Added AI-tool plugins guide at `docs/toolhive/guides-cli/ai-plugins.mdx` for + the new `thv ai-plugin` surface (build, validate, push, install, list, info, + uninstall, builds), including the manifest format, Claude Code / Codex + install paths, and troubleshooting. +- Added a sidebar entry for the new AI-tool plugins guide in `sidebars.ts`. +- Updated `docs/toolhive/guides-cli/skills-management.mdx` with three new + sections covering the experimental lock file: pin-and-reconcile with + `thv skill sync`, upgrades with `thv skill upgrade`, and Sigstore signature + verification (`--allow-unsigned`, `--allow-signer-change`, coverage + differences between OCI and Git installs). Added a matching troubleshooting + entry. +- Added "Ordering with Cedar authorization and audit" to + `docs/toolhive/guides-cli/webhooks.mdx` documenting that Cedar policies, + audit events, telemetry, and usage metrics see the post-mutation request, + plus the new 400/500 fail-closed responses and the tool-filter and header + gaps to be aware of. +- Swept the removed config-CRD status fields + (`status.referencingWorkloads`, `status.referenceCount`, and the + `REFERENCES` printer column) out of three K8s guides and the + `MCPAuthzConfig` CRD intro, replacing them with workload-side `jq` queries + where a "which workloads reference this?" pattern was needed. Updated the + CRD intro at the source (`scripts/lib/crd-intros.mjs`) and synced the + generated `mcpauthzconfig.mdx`. +- Added a v0.42.0 removal note to the `referencingServers` / + `referencingWorkloads` section of `docs/toolhive/guides-k8s/migrate-to-v1beta1.mdx` + so readers of that migration guide learn that both fields are now gone and + see the current workload-query pattern. diff --git a/docs/toolhive/guides-cli/ai-plugins.mdx b/docs/toolhive/guides-cli/ai-plugins.mdx new file mode 100644 index 00000000..8ab769c5 --- /dev/null +++ b/docs/toolhive/guides-cli/ai-plugins.mdx @@ -0,0 +1,341 @@ +--- +title: Manage AI-tool plugins +sidebar_label: AI-tool plugins +description: + How to install, distribute, and manage plugins for AI coding tools such as + Claude Code and Codex with the ToolHive CLI. +--- + +An **AI-tool plugin** is a bundle of commands, agents, skills, hooks, and MCP or +LSP server declarations that extends an AI coding tool. ToolHive builds these +plugins into portable OCI artifacts, publishes them to any OCI registry, and +installs them into the target client's plugins directory. + +Plugins are for the AI tool itself, not for ToolHive. A plugin ships everything +that lives inside the AI tool's own extension surface (commands, agents, skills, +and so on); ToolHive is the delivery mechanism. + +:::note[Supported clients] + +The `thv ai-plugin` commands install into two clients today: + +- **Claude Code**: `~/.claude/plugins/` for user scope, + `/.claude/plugins/` for project scope +- **Codex**: `~/.agents/plugins/toolhive/` for user scope, + `/.agents/plugins/toolhive/` for project scope + +Other supported clients may install skills, MCP servers, or both; only these two +currently accept plugins. See the +[client compatibility reference](../reference/client-compatibility.mdx). + +::: + +## Prerequisites + +- The [ToolHive API server](./api-server.mdx) must be running. Start it in a + separate terminal window (the command blocks while running): + + ```bash + thv serve + ``` + + The server must remain running while you use `thv ai-plugin` commands. + + :::tip[Using the ToolHive desktop app?] + + If the ToolHive desktop app is already running, the API server is available + automatically. You can skip the `thv serve` step and use `thv ai-plugin` + commands directly. + + ::: + +- Claude Code or Codex installed on your machine. + +## Install a plugin + +You can install plugins by plain name (resolved through the configured +registry), by OCI reference, by Git URL, or from a local build: + +```bash +thv ai-plugin install my-plugin +thv ai-plugin install ghcr.io/my-org/plugins/my-plugin:v1.0.0 +thv ai-plugin install git://github.com/my-org/plugins@main#packages/my-plugin +``` + +If the plain name matches an artifact you built locally with +`thv ai-plugin build`, ToolHive resolves it from the local OCI store; otherwise +it looks up the name in the configured Registry Server. + +### Target a specific client + +If both Claude Code and Codex are installed, ToolHive installs the plugin for +the first supported client it detects. To pick explicitly, use the `--clients` +flag: + +```bash +thv ai-plugin install my-plugin --clients claude-code +thv ai-plugin install my-plugin --clients claude-code,codex +thv ai-plugin install my-plugin --clients all +``` + +Valid values are `claude-code`, `codex`, or `all`. + +### Choose a scope + +Plugins support two installation scopes, matching skills: + +- **User scope** (default) - installs the plugin into your home directory, so it + is available across all projects. +- **Project scope** - installs the plugin into the project directory. The + project root must be a Git repository. + +```bash +# User scope (default) +thv ai-plugin install my-plugin + +# Project scope +thv ai-plugin install my-plugin --scope project \ + --project-root /path/to/project +``` + +### Overwrite or group + +Pass `--force` to replace an existing installation of the same plugin, or +`--group` to add the plugin to a named group for later batch operations: + +```bash +thv ai-plugin install my-plugin --force +thv ai-plugin install my-plugin --group development +``` + +## List installed plugins + +```bash +thv ai-plugin list +``` + +Filter by client, scope, or group: + +```bash +thv ai-plugin list --client claude-code +thv ai-plugin list --scope project --project-root /path/to/project +thv ai-plugin list --group development +``` + +For JSON output: + +```bash +thv ai-plugin list --format json +``` + +## Inspect a plugin + +To see metadata, version, source, and declared contents for an installed plugin: + +```bash +thv ai-plugin info my-plugin +``` + +For project-scoped plugins, pass `--scope project --project-root`. + +## Uninstall a plugin + +```bash +thv ai-plugin uninstall my-plugin +``` + +For a project-scoped install: + +```bash +thv ai-plugin uninstall my-plugin --scope project \ + --project-root /path/to/project +``` + +## Author a plugin + +A plugin is a directory with a manifest at `.claude-plugin/plugin.json`. At a +minimum, the manifest needs a `name`; a `version` is recommended and becomes the +default OCI tag at build time. + +```json title="my-plugin/.claude-plugin/plugin.json" +{ + "name": "my-plugin", + "version": "1.0.0", + "description": "What this plugin does and when to use it.", + "author": { + "name": "Your Team", + "email": "team@example.com" + }, + "license": "Apache-2.0", + "keywords": ["review", "python"], + "commands": ["./commands/review.md"], + "agents": ["./agents/reviewer.md"], + "skills": ["./skills/code-review"], + "hooks": ["./hooks/post-tool-use.js"] +} +``` + +Content-path fields (`commands`, `agents`, `skills`, `hooks`) must be relative +paths beginning with `./`. Path traversal (`..`) is rejected, each group is +capped at 100 entries, and the manifest itself is capped at 64 KB. The +`keywords` field must be a JSON array of strings. + +MCP and LSP server declarations (`mcpServers`, `lspServers`) are recorded in the +manifest for the AI tool to consume; ToolHive does not lifecycle-manage them +from the plugin. `thv ai-plugin info` reports declared servers as "Declared (not +managed by ToolHive)". + +### Naming conventions + +Use kebab-case for the plugin name - lowercase letters, numbers, and hyphens. +The name must match the directory the plugin ships in and appears in the default +OCI tag. + +### Validate + +Before building, check the manifest and directory structure: + +```bash +thv ai-plugin validate ./my-plugin +``` + +For JSON output: + +```bash +thv ai-plugin validate ./my-plugin --format json +``` + +### Build an OCI artifact + +Package the plugin into an OCI artifact stored in the local OCI store: + +```bash +thv ai-plugin build ./my-plugin +``` + +The command prints the OCI reference of the built artifact to stdout. Pass +`--tag` to override the tag (default: `:` from the manifest, or +the raw digest if `version` is omitted): + +```bash +thv ai-plugin build ./my-plugin --tag ghcr.io/my-org/plugins/my-plugin:v1.0.0 +``` + +### Push to a registry + +After building, push to a remote OCI registry: + +```bash +thv ai-plugin push ghcr.io/my-org/plugins/my-plugin:v1.0.0 +``` + +Push uses your existing container registry credentials (for example, from +`docker login` or `podman login`). Authenticate before pushing. + +## Manage local builds + +The `builds` subcommand exposes the local OCI store where `thv ai-plugin build` +writes artifacts. + +### List locally-built artifacts + +```bash +thv ai-plugin builds +``` + +Output shows the tag, digest, name, and version for each artifact. Add +`--format json` for machine-readable output. + +### Remove a locally-built artifact + +```bash +thv ai-plugin builds remove ghcr.io/my-org/plugins/my-plugin:v1.0.0 +``` + +Blobs are retained on disk until every tag pointing to their digest is removed. + +## Next steps + +- [Configure your AI client](./client-configuration.mdx) to register clients + with ToolHive so plugins install to the right location automatically +- [Manage agent skills](./skills-management.mdx) - the sibling workflow for + distributing skill bundles across a wider set of clients + +## Related information + +- [`thv ai-plugin` command reference](../reference/cli/thv_ai-plugin.md) +- [Client compatibility](../reference/client-compatibility.mdx) +- [ToolHive API reference](../reference/api.mdx) - the `/api/v1beta/plugins` + routes expose the same operations for scripting and integration + +## Troubleshooting + +
+`thv ai-plugin install` reports "plugin not found in local store or registry" + +ToolHive looks up plain names first in the local OCI store (populated by +`thv ai-plugin build`) and then in the configured Registry Server. If both miss, +install the plugin directly by OCI reference: + +```bash +thv ai-plugin install ghcr.io//: +``` + +Confirm the Registry Server is configured (see +[Registry configuration](./registry.mdx)) and that the plugin has been published +to it. + +
+ +
+Installed plugin isn't visible to the AI tool + +1. Verify the install landed: + + ```bash + thv ai-plugin list + thv ai-plugin info + ``` + +2. Confirm the plugin files exist in the expected directory: + - **Claude Code**: `~/.claude/plugins//` (user) or + `/.claude/plugins//` (project) + - **Codex**: `~/.agents/plugins/toolhive//` (user) or + `/.agents/plugins/toolhive//` (project) + +3. Restart the AI tool to trigger plugin discovery. + +
+ +
+Manifest validation fails + +Run `thv ai-plugin validate ./my-plugin` to see the specific error. Common +issues: + +- Missing `.claude-plugin/plugin.json` or missing `name` field +- `keywords` is a string instead of a JSON array +- A content-path entry (in `commands`, `agents`, `skills`, or `hooks`) does not + start with `./` or contains `..` +- More than 100 entries in one content-path group +- The manifest file exceeds 64 KB + +
+ +
+Push to registry fails with authentication error + +`thv ai-plugin push` uses your existing container registry credentials. Log in +first: + +```bash +# For GitHub Container Registry +echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin + +# For Docker Hub +docker login +``` + +Then retry the push. + +
diff --git a/docs/toolhive/guides-cli/skills-management.mdx b/docs/toolhive/guides-cli/skills-management.mdx index 3df6f137..a74c6abf 100644 --- a/docs/toolhive/guides-cli/skills-management.mdx +++ b/docs/toolhive/guides-cli/skills-management.mdx @@ -239,6 +239,149 @@ thv skill uninstall my-skill --scope project --project-root /path/to/project This removes the skill files from all associated client directories and deletes the database record. +## Pin and reconcile project skills + +Project-scoped skills can be pinned to a lock file (`toolhive.lock.yaml` at the +project root) that records each installed skill's resolved reference and digest. +The lock file lets you commit the exact set of skills a project depends on, +reinstall them deterministically on another machine, and gate upgrades in CI. + +:::info[Experimental] + +The lock file, `thv skill sync`, and `thv skill upgrade` are experimental. Set +`TOOLHIVE_SKILLS_LOCK_ENABLED=true` on the environment that runs `thv serve` (or +the ToolHive desktop app) to enable them. With the flag unset, +`thv skill install` behaves as before and the sync and upgrade commands return +an error. + +::: + +Project scope is required. User-scoped skills are not tracked by the lock file. + +### Reconcile installs against the lock file + +Use `thv skill sync` to restore a project's installed skills to match the lock +file. This is the typical entry point after cloning a project or checking out a +branch that changed which skills are pinned: + +```bash +cd /path/to/project +thv skill sync +``` + +Missing or drifted skills are reinstalled at their pinned digest. Sync prompts +for confirmation before installing because skill content is a set of +instructions that AI agents follow; pass `--yes` to skip the prompt in +non-interactive contexts such as CI. + +To report drift without changing anything (a CI freshness check): + +```bash +thv skill sync --check +``` + +Exit code `2` indicates drift or missing entries; `3` indicates a real failure. + +To record lock entries for existing unmanaged installs, or to remove installs no +longer present in the lock file: + +```bash +thv skill sync --adopt +thv skill sync --prune +``` + +### Upgrade project skills + +Use `thv skill upgrade` to re-resolve pinned entries and install newer content +where available: + +```bash +thv skill upgrade +``` + +Pass one or more skill names to limit the upgrade to a subset. Skills pinned to +an immutable reference (an OCI digest or a full Git commit hash) are reported as +not upgradable - there is nothing newer to resolve to. + +To see what would change without persisting anything: + +```bash +thv skill upgrade --preview +``` + +For a CI freshness gate that fails when newer content is available but never +installs: + +```bash +thv skill upgrade --fail-on-changes +``` + +## Verify skill signatures + +When the lock file is enabled, ToolHive verifies signatures on project-scoped +skill installs and re-verifies them on every `thv skill sync`. This gates the +skill supply chain: a skill whose content or signer has changed since it was +pinned will not silently replace the pinned version. + +Verification is transparent - `thv skill install my-skill` for a signed OCI +artifact succeeds without extra flags and records the signer identity in the +lock file. The following sections cover the cases where you have to make an +explicit choice. + +### Install an unsigned skill + +By default, ToolHive rejects unsigned project-scoped installs with an error +like: + +```text +unsigned skill "my-skill" rejected; set allow_unsigned +(--allow-unsigned) to record an exception +``` + +To allow the install and record the exception in the lock file: + +```bash +thv skill install my-skill --scope project \ + --project-root /path/to/project --allow-unsigned +``` + +Subsequent syncs of the same entry treat the recorded exception as the expected +state; they do not re-prompt for the flag. + +### Upgrade to a differently signed skill + +`thv skill upgrade` refuses to move a pinned skill to an artifact signed by a +different identity, or to an unsigned artifact. The status column in the output +reports the reason as `signer-change-blocked`. + +To allow the upgrade and replace the recorded signer identity with the new one: + +```bash +thv skill upgrade my-skill --allow-signer-change +``` + +Rotate trust deliberately - a signer change is the expected way a skill +distribution transfers between publishers, but it also matches the pattern of a +compromised release. + +### Verification coverage + +- **OCI-installed skills** carry a Sigstore bundle. ToolHive verifies the bundle + against the public-good Sigstore instance, requiring a signed certificate + timestamp, a transparency log entry, and an observer timestamp. The lock file + records the signer's identity, certificate issuer, and optionally the + repository URI and Sigstore instance URL. +- **Git-installed skills** are verified against a `gitsign` commit signature. + The signing time is checked against the leaf certificate's validity window. + ToolHive does not yet validate the embedded Rekor transparency-log proof for + Git installs, so the recorded provenance for these entries carries less + assurance than the OCI equivalent. + +Verification uses embedded Fulcio and Rekor roots, so it works offline once the +skill and its bundle are on disk. `thv skill sync` re-verifies each entry +offline against the recorded identity, and reports a signature mismatch as +drift. + ## Create a skill Every skill requires a `SKILL.md` file at the root of its directory. At a @@ -377,6 +520,8 @@ pointing to that digest are removed. - [Manage agent skills in the ToolHive UI](../guides-ui/skills.mdx) to browse, install, and build skills without leaving the app - [`thv skill` command reference](../reference/cli/thv_skill.md) +- [`thv skill sync` command reference](../reference/cli/thv_skill_sync.md) +- [`thv skill upgrade` command reference](../reference/cli/thv_skill_upgrade.md) - [`thv serve` command reference](../reference/cli/thv_serve.md) - [Agent Skills specification](https://agentskills.io/specification) @@ -440,6 +585,25 @@ Common issues include: +
+Signature verification errors on install or sync + +Signature verification runs on project-scoped installs when +`TOOLHIVE_SKILLS_LOCK_ENABLED=true` is set on the ToolHive server. + +- **`unsigned skill ... rejected`**: The artifact has no Sigstore bundle or Git + signature. Pass `--allow-unsigned` to record the exception in the lock file, + or use a signed release. +- **`signer-change-blocked` on upgrade**: The candidate artifact is signed by a + different identity than the recorded one, or is unsigned. Confirm the change + is expected, then re-run with `--allow-signer-change` to rotate trust. +- **Sync reports a signature mismatch as drift**: The stored bundle no longer + verifies against the recorded identity. Run `thv skill sync` (without + `--check`) to reinstall from the pinned reference, which re-runs install-time + verification. + +
+
Push to registry fails with authentication error diff --git a/docs/toolhive/guides-cli/webhooks.mdx b/docs/toolhive/guides-cli/webhooks.mdx index fc1d0d84..0e552924 100644 --- a/docs/toolhive/guides-cli/webhooks.mdx +++ b/docs/toolhive/guides-cli/webhooks.mdx @@ -43,6 +43,38 @@ two middleware types in order: If a validating webhook denies the request, ToolHive returns an error to the client without calling the MCP server. +### Ordering with Cedar authorization and audit + +When Cedar authorization runs alongside a mutating webhook, Cedar evaluates the +**post-mutation** request. Audit events, telemetry, and usage metrics report the +same shape the MCP server actually executes. + +Write Cedar policies against the post-mutation shape - the tool name and +arguments the backend receives, not the original client request. If your +mutating webhook rewrites `params.name` or `params.arguments`, both your Cedar +`resource == MCP::Tool::"..."` matchers and any `context.arg_*` clauses need to +describe the rewritten values. + +Two error responses replace what would previously have reached the backend when +a webhook produces a malformed body: + +- **400 Bad Request** if a webhook rewrites a single JSON-RPC request into a + batch. +- **500 Internal Server Error** if a webhook emits a body that is not a valid + JSON-RPC request. + +:::note[Gaps to be aware of] + +- The tool-call filter (`--tools` flag) and the rate limiter decide against the + request as received, not the post-mutation shape. A mutating webhook that + renames a tool can therefore bypass tool filtering. +- The `Mcp-Method` and `Mcp-Name` headers forwarded to the backend still name + the original tool. A conformant Modern-revision MCP backend rejects the + mismatch and fails closed, so mutating webhooks should not rename tools on the + Modern path. + +::: + ## Create a webhook configuration file Webhook configuration is defined in a YAML or JSON file. The file has two diff --git a/docs/toolhive/guides-k8s/auth-k8s.mdx b/docs/toolhive/guides-k8s/auth-k8s.mdx index b7eb9657..161ed99d 100644 --- a/docs/toolhive/guides-k8s/auth-k8s.mdx +++ b/docs/toolhive/guides-k8s/auth-k8s.mdx @@ -129,15 +129,21 @@ by identity provider - consult your provider's documentation for interactive user login (OAuth 2.0 Authorization Code flow), service-to-service login (Client Credentials flow), or API token generation. -Check the `MCPOIDCConfig` status to confirm it's valid and see which workloads -reference it: +Check the `MCPOIDCConfig` status to confirm it's valid: ```bash kubectl get mcpoidc -n toolhive-system ``` -The `REFERENCES` column shows which workloads use this config. The `VALID` -column confirms validation passed. +The `VALID` column confirms validation passed. To see which workloads reference +this config, query workloads by their `oidcConfigRef`: + +```bash +kubectl get mcpservers,mcpremoteproxies,virtualmcpservers -n toolhive-system \ + -o json | jq -r --arg n production-oidc '.items[] + | select((.spec.oidcConfigRef.name // .spec.incomingAuth.oidcConfigRef.name) == $n) + | "\(.kind)/\(.metadata.name)"' +``` :::note[Upgrading from before v0.21.0?] diff --git a/docs/toolhive/guides-k8s/authorization-k8s.mdx b/docs/toolhive/guides-k8s/authorization-k8s.mdx index 7033cce3..f53b656e 100644 --- a/docs/toolhive/guides-k8s/authorization-k8s.mdx +++ b/docs/toolhive/guides-k8s/authorization-k8s.mdx @@ -230,9 +230,8 @@ the inline field's Go struct on the CRD. To reuse the same policy set across multiple MCPServer, MCPRemoteProxy, or VirtualMCPServer resources, define it once as an [`MCPAuthzConfig`](../reference/crds/mcpauthzconfig.mdx) and reference it by -name. The operator validates the policy bundle once, tracks the references in -`MCPAuthzConfig.status.referencingWorkloads`, and blocks deletion while any -workload still references it. +name. The operator validates the policy bundle once and blocks deletion while +any workload still references it. ```yaml title="mcp-authz-shared.yaml" apiVersion: toolhive.stacklok.dev/v1beta1 diff --git a/docs/toolhive/guides-k8s/migrate-to-v1beta1.mdx b/docs/toolhive/guides-k8s/migrate-to-v1beta1.mdx index 84a649e9..2a445f0a 100644 --- a/docs/toolhive/guides-k8s/migrate-to-v1beta1.mdx +++ b/docs/toolhive/guides-k8s/migrate-to-v1beta1.mdx @@ -182,11 +182,31 @@ spec: ### `referencingServers` replaced with `referencingWorkloads` -The `status.referencingServers` field (a plain `[]string`) has been replaced -with `status.referencingWorkloads` (an array of `{kind, name}` objects) on four +The `status.referencingServers` field (a plain `[]string`) was replaced with +`status.referencingWorkloads` (an array of `{kind, name}` objects) on four shared configuration CRDs: MCPOIDCConfig, MCPToolConfig, MCPExternalAuthConfig, and MCPTelemetryConfig. +:::info[Both fields removed in v0.42.0] + +`status.referencingWorkloads` and `status.referenceCount` were removed from all +six configuration CRDs (`MCPOIDCConfig`, `MCPAuthzConfig`, +`MCPExternalAuthConfig`, `MCPToolConfig`, `MCPWebhookConfig`, +`MCPTelemetryConfig`), along with the `REFERENCES` printer column. Deletion +protection is unchanged - each config controller still blocks deletion while any +workload references it, exposed through the `DeletionBlocked` condition. + +To list workloads that reference a config, query them by their config-ref field: + +```bash +kubectl get mcpservers,mcpremoteproxies,virtualmcpservers -n toolhive-system \ + -o json | jq -r --arg n my-oidc '.items[] + | select((.spec.oidcConfigRef.name // .spec.incomingAuth.oidcConfigRef.name) == $n) + | "\(.kind)/\(.metadata.name)"' +``` + +::: + ```yaml # Before status: @@ -194,7 +214,7 @@ status: - 'my-server' - 'my-other-server' -# After +# After (v0.15.0 through v0.41.x) status: referencingWorkloads: - kind: MCPServer @@ -203,9 +223,8 @@ status: name: my-other-server ``` -Update any scripts, monitoring, or tooling that reads -`.status.referencingServers` to read `.status.referencingWorkloads[].name` (and -optionally `.kind`). +Any scripts, monitoring, or tooling that reads either field must switch to a +workload query as shown above. ### Expanded Cedar policy enforcement diff --git a/docs/toolhive/guides-k8s/telemetry-and-metrics.mdx b/docs/toolhive/guides-k8s/telemetry-and-metrics.mdx index 8cf1fae7..de2d08da 100644 --- a/docs/toolhive/guides-k8s/telemetry-and-metrics.mdx +++ b/docs/toolhive/guides-k8s/telemetry-and-metrics.mdx @@ -106,8 +106,15 @@ kubectl apply -f mcpserver-with-shared-otel.yaml kubectl get mcpotel -n toolhive-system ``` -The `REFERENCES` column shows which workloads use this config. The `READY` -column confirms validation passed. +The `READY` column confirms validation passed. To see which workloads reference +this config, query workloads by their `telemetryConfigRef`: + +```bash +kubectl get mcpservers,mcpremoteproxies,virtualmcpservers -n toolhive-system \ + -o json | jq -r --arg n shared-otel '.items[] + | select(.spec.telemetryConfigRef.name == $n) + | "\(.kind)/\(.metadata.name)"' +``` #### Configuration details diff --git a/docs/toolhive/reference/crds/mcpauthzconfig.mdx b/docs/toolhive/reference/crds/mcpauthzconfig.mdx index 6f2aa282..39002519 100644 --- a/docs/toolhive/reference/crds/mcpauthzconfig.mdx +++ b/docs/toolhive/reference/crds/mcpauthzconfig.mdx @@ -7,7 +7,7 @@ toc_max_heading_level: 4 `MCPAuthzConfig` defines a reusable authorization policy that is decoupled from a particular authorizer backend. [MCPServer](./mcpserver.mdx), [MCPRemoteProxy](./mcpremoteproxy.mdx), and [VirtualMCPServer](./virtualmcpserver.mdx) reference an `MCPAuthzConfig` via `spec.authzConfigRef` (or `spec.incomingAuth.authzConfigRef` on `VirtualMCPServer`), mutually exclusive with the inline `authzConfig` field. -From v0.30.1, workload controllers resolve `authzConfigRef` into a runtime authorization config and apply it to the proxy alongside the existing reference-tracking (deletion protection and `status.referencingWorkloads`). For walkthroughs, see [Share policies across resources with MCPAuthzConfig](../../guides-k8s/authorization-k8s.mdx#share-policies-across-resources-with-mcpauthzconfig). +Workload controllers resolve `authzConfigRef` into a runtime authorization config and apply it to the proxy, and each config controller blocks deletion while any workload still references it. For walkthroughs, see [Share policies across resources with MCPAuthzConfig](../../guides-k8s/authorization-k8s.mdx#share-policies-across-resources-with-mcpauthzconfig). :::note[VirtualMCPServer is Cedar-only] diff --git a/scripts/lib/crd-intros.mjs b/scripts/lib/crd-intros.mjs index ab50129f..0730a504 100644 --- a/scripts/lib/crd-intros.mjs +++ b/scripts/lib/crd-intros.mjs @@ -212,6 +212,6 @@ export const intros = { description: 'Schema reference for MCPAuthzConfig, which configures backend-agnostic authorization policy for MCP servers and proxies.', intro: - '`MCPAuthzConfig` defines a reusable authorization policy that is decoupled from a particular authorizer backend. [MCPServer](./mcpserver.mdx), [MCPRemoteProxy](./mcpremoteproxy.mdx), and [VirtualMCPServer](./virtualmcpserver.mdx) reference an `MCPAuthzConfig` via `spec.authzConfigRef` (or `spec.incomingAuth.authzConfigRef` on `VirtualMCPServer`), mutually exclusive with the inline `authzConfig` field.\n\nFrom v0.30.1, workload controllers resolve `authzConfigRef` into a runtime authorization config and apply it to the proxy alongside the existing reference-tracking (deletion protection and `status.referencingWorkloads`). For walkthroughs, see [Share policies across resources with MCPAuthzConfig](../../guides-k8s/authorization-k8s.mdx#share-policies-across-resources-with-mcpauthzconfig).\n\n:::note[VirtualMCPServer is Cedar-only]\n\n`VirtualMCPServer.spec.incomingAuth.authzConfigRef` only supports MCPAuthzConfig resources with `spec.type: cedarv1`. Referencing a non-Cedar config (for example, `httpv1`) fails reconciliation with a clear condition message because the vMCP runtime authorization middleware is Cedar-only.\n\n:::', + '`MCPAuthzConfig` defines a reusable authorization policy that is decoupled from a particular authorizer backend. [MCPServer](./mcpserver.mdx), [MCPRemoteProxy](./mcpremoteproxy.mdx), and [VirtualMCPServer](./virtualmcpserver.mdx) reference an `MCPAuthzConfig` via `spec.authzConfigRef` (or `spec.incomingAuth.authzConfigRef` on `VirtualMCPServer`), mutually exclusive with the inline `authzConfig` field.\n\nWorkload controllers resolve `authzConfigRef` into a runtime authorization config and apply it to the proxy, and each config controller blocks deletion while any workload still references it. For walkthroughs, see [Share policies across resources with MCPAuthzConfig](../../guides-k8s/authorization-k8s.mdx#share-policies-across-resources-with-mcpauthzconfig).\n\n:::note[VirtualMCPServer is Cedar-only]\n\n`VirtualMCPServer.spec.incomingAuth.authzConfigRef` only supports MCPAuthzConfig resources with `spec.type: cedarv1`. Referencing a non-Cedar config (for example, `httpv1`) fails reconciliation with a clear condition message because the vMCP runtime authorization middleware is Cedar-only.\n\n:::', }, }; diff --git a/sidebars.ts b/sidebars.ts index 2d0be563..2da3b0a9 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -106,6 +106,7 @@ const mcpSidebar: SidebarsConfig[string] = [ }, 'toolhive/guides-cli/client-configuration', 'toolhive/guides-cli/skills-management', + 'toolhive/guides-cli/ai-plugins', { type: 'category', label: 'Permissions and security', From 48c61ff0e1ab4ae660caffdc3c51e2d600d8f1a6 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Wed, 5 Aug 2026 19:06:11 +0000 Subject: [PATCH 4/8] Editorial fixes for v0.42.0 release docs - ai-plugins: default build tag is , not : - skills-management: distinguish sync exit codes 1, 2, and 3 - migrate-to-v1beta1: reflect that MCPWebhookConfig and MCPTelemetryConfig never had referenceCount, and MCPTelemetryConfig never had the printer column Co-Authored-By: Claude Opus 4.7 --- docs/toolhive/guides-cli/ai-plugins.mdx | 11 +++++----- .../toolhive/guides-cli/skills-management.mdx | 4 +++- .../guides-k8s/migrate-to-v1beta1.mdx | 22 ++++++++++++------- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/docs/toolhive/guides-cli/ai-plugins.mdx b/docs/toolhive/guides-cli/ai-plugins.mdx index 8ab769c5..e803c7d4 100644 --- a/docs/toolhive/guides-cli/ai-plugins.mdx +++ b/docs/toolhive/guides-cli/ai-plugins.mdx @@ -154,8 +154,9 @@ thv ai-plugin uninstall my-plugin --scope project \ ## Author a plugin A plugin is a directory with a manifest at `.claude-plugin/plugin.json`. At a -minimum, the manifest needs a `name`; a `version` is recommended and becomes the -default OCI tag at build time. +minimum, the manifest needs a `name`, which is used as the default OCI tag at +build time. A `version` is recommended so `thv ai-plugin builds` and +`thv ai-plugin info` can report it. ```json title="my-plugin/.claude-plugin/plugin.json" { @@ -213,9 +214,9 @@ Package the plugin into an OCI artifact stored in the local OCI store: thv ai-plugin build ./my-plugin ``` -The command prints the OCI reference of the built artifact to stdout. Pass -`--tag` to override the tag (default: `:` from the manifest, or -the raw digest if `version` is omitted): +The command prints the OCI reference of the built artifact to stdout. By +default, the built artifact is tagged with the plugin `name` from the manifest, +or the raw digest if the manifest has no `name`. Pass `--tag` to override: ```bash thv ai-plugin build ./my-plugin --tag ghcr.io/my-org/plugins/my-plugin:v1.0.0 diff --git a/docs/toolhive/guides-cli/skills-management.mdx b/docs/toolhive/guides-cli/skills-management.mdx index a74c6abf..6929d653 100644 --- a/docs/toolhive/guides-cli/skills-management.mdx +++ b/docs/toolhive/guides-cli/skills-management.mdx @@ -280,7 +280,9 @@ To report drift without changing anything (a CI freshness check): thv skill sync --check ``` -Exit code `2` indicates drift or missing entries; `3` indicates a real failure. +Exit code `2` means drift or missing entries were found (nothing was installed). +Exit code `3` means one or more skills failed while others succeeded, so results +are mixed. A generic error (exit code `1`) means the command could not run. To record lock entries for existing unmanaged installs, or to remove installs no longer present in the lock file: diff --git a/docs/toolhive/guides-k8s/migrate-to-v1beta1.mdx b/docs/toolhive/guides-k8s/migrate-to-v1beta1.mdx index 2a445f0a..6a271fc0 100644 --- a/docs/toolhive/guides-k8s/migrate-to-v1beta1.mdx +++ b/docs/toolhive/guides-k8s/migrate-to-v1beta1.mdx @@ -187,14 +187,20 @@ The `status.referencingServers` field (a plain `[]string`) was replaced with shared configuration CRDs: MCPOIDCConfig, MCPToolConfig, MCPExternalAuthConfig, and MCPTelemetryConfig. -:::info[Both fields removed in v0.42.0] - -`status.referencingWorkloads` and `status.referenceCount` were removed from all -six configuration CRDs (`MCPOIDCConfig`, `MCPAuthzConfig`, -`MCPExternalAuthConfig`, `MCPToolConfig`, `MCPWebhookConfig`, -`MCPTelemetryConfig`), along with the `REFERENCES` printer column. Deletion -protection is unchanged - each config controller still blocks deletion while any -workload references it, exposed through the `DeletionBlocked` condition. +:::info[Removed in v0.42.0] + +The reference-tracking status fields (`status.referencingWorkloads` and, where +present, `status.referenceCount`) were removed from every configuration CRD: +`MCPOIDCConfig`, `MCPAuthzConfig`, `MCPExternalAuthConfig`, `MCPToolConfig`, +`MCPWebhookConfig`, and `MCPTelemetryConfig`. The `REFERENCES` printer column +was removed from the CRDs that carried it. `MCPWebhookConfig` and +`MCPTelemetryConfig` only ever had `referencingWorkloads`, and +`MCPTelemetryConfig` never had the printer column, so its `kubectl get` output +is unchanged. + +Deletion protection is unchanged - each config controller still blocks deletion +while any workload references it, exposed through the `DeletionBlocked` +condition. To list workloads that reference a config, query them by their config-ref field: From bf3ff9c02973d93ccb92e33b52f40c6697cca0ac Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Wed, 5 Aug 2026 19:06:55 +0000 Subject: [PATCH 5/8] Add upstream-release-docs content for toolhive v0.42.0 --- SUMMARY.md | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 SUMMARY.md diff --git a/SUMMARY.md b/SUMMARY.md deleted file mode 100644 index f7f6efa6..00000000 --- a/SUMMARY.md +++ /dev/null @@ -1,27 +0,0 @@ -- Added AI-tool plugins guide at `docs/toolhive/guides-cli/ai-plugins.mdx` for - the new `thv ai-plugin` surface (build, validate, push, install, list, info, - uninstall, builds), including the manifest format, Claude Code / Codex - install paths, and troubleshooting. -- Added a sidebar entry for the new AI-tool plugins guide in `sidebars.ts`. -- Updated `docs/toolhive/guides-cli/skills-management.mdx` with three new - sections covering the experimental lock file: pin-and-reconcile with - `thv skill sync`, upgrades with `thv skill upgrade`, and Sigstore signature - verification (`--allow-unsigned`, `--allow-signer-change`, coverage - differences between OCI and Git installs). Added a matching troubleshooting - entry. -- Added "Ordering with Cedar authorization and audit" to - `docs/toolhive/guides-cli/webhooks.mdx` documenting that Cedar policies, - audit events, telemetry, and usage metrics see the post-mutation request, - plus the new 400/500 fail-closed responses and the tool-filter and header - gaps to be aware of. -- Swept the removed config-CRD status fields - (`status.referencingWorkloads`, `status.referenceCount`, and the - `REFERENCES` printer column) out of three K8s guides and the - `MCPAuthzConfig` CRD intro, replacing them with workload-side `jq` queries - where a "which workloads reference this?" pattern was needed. Updated the - CRD intro at the source (`scripts/lib/crd-intros.mjs`) and synced the - generated `mcpauthzconfig.mdx`. -- Added a v0.42.0 removal note to the `referencingServers` / - `referencingWorkloads` section of `docs/toolhive/guides-k8s/migrate-to-v1beta1.mdx` - so readers of that migration guide learn that both fields are now gone and - see the current workload-query pattern. From a73fa4420134ba4d9a726fb8ae6a174c4812d6d5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 5 Aug 2026 19:14:14 +0000 Subject: [PATCH 6/8] Apply remaining changes Co-authored-by: ChrisJBurns <29541485+ChrisJBurns@users.noreply.github.com> --- docs/toolhive/guides-k8s/migrate-to-v1beta1.mdx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/docs/toolhive/guides-k8s/migrate-to-v1beta1.mdx b/docs/toolhive/guides-k8s/migrate-to-v1beta1.mdx index 6a271fc0..a2dae519 100644 --- a/docs/toolhive/guides-k8s/migrate-to-v1beta1.mdx +++ b/docs/toolhive/guides-k8s/migrate-to-v1beta1.mdx @@ -180,13 +180,6 @@ spec: key: ca.crt ``` -### `referencingServers` replaced with `referencingWorkloads` - -The `status.referencingServers` field (a plain `[]string`) was replaced with -`status.referencingWorkloads` (an array of `{kind, name}` objects) on four -shared configuration CRDs: MCPOIDCConfig, MCPToolConfig, MCPExternalAuthConfig, -and MCPTelemetryConfig. - :::info[Removed in v0.42.0] The reference-tracking status fields (`status.referencingWorkloads` and, where @@ -229,7 +222,7 @@ status: name: my-other-server ``` -Any scripts, monitoring, or tooling that reads either field must switch to a +Any scripts, monitoring, or tooling that reads these fields must switch to a workload query as shown above. ### Expanded Cedar policy enforcement From 456d1bbf9247b135a0415bc96be53e327813be3f Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 07:52:11 +0000 Subject: [PATCH 7/8] Remove experimental skills signing docs The lock-file, sync, upgrade, and Sigstore signature verification content is gated behind TOOLHIVE_SKILLS_LOCK_ENABLED. Remove it until the flag is dropped and the feature is documented as generally available. Co-authored-by: Samuele V <4377202+samuv@users.noreply.github.com> --- .../toolhive/guides-cli/skills-management.mdx | 166 ------------------ 1 file changed, 166 deletions(-) diff --git a/docs/toolhive/guides-cli/skills-management.mdx b/docs/toolhive/guides-cli/skills-management.mdx index 6929d653..3df6f137 100644 --- a/docs/toolhive/guides-cli/skills-management.mdx +++ b/docs/toolhive/guides-cli/skills-management.mdx @@ -239,151 +239,6 @@ thv skill uninstall my-skill --scope project --project-root /path/to/project This removes the skill files from all associated client directories and deletes the database record. -## Pin and reconcile project skills - -Project-scoped skills can be pinned to a lock file (`toolhive.lock.yaml` at the -project root) that records each installed skill's resolved reference and digest. -The lock file lets you commit the exact set of skills a project depends on, -reinstall them deterministically on another machine, and gate upgrades in CI. - -:::info[Experimental] - -The lock file, `thv skill sync`, and `thv skill upgrade` are experimental. Set -`TOOLHIVE_SKILLS_LOCK_ENABLED=true` on the environment that runs `thv serve` (or -the ToolHive desktop app) to enable them. With the flag unset, -`thv skill install` behaves as before and the sync and upgrade commands return -an error. - -::: - -Project scope is required. User-scoped skills are not tracked by the lock file. - -### Reconcile installs against the lock file - -Use `thv skill sync` to restore a project's installed skills to match the lock -file. This is the typical entry point after cloning a project or checking out a -branch that changed which skills are pinned: - -```bash -cd /path/to/project -thv skill sync -``` - -Missing or drifted skills are reinstalled at their pinned digest. Sync prompts -for confirmation before installing because skill content is a set of -instructions that AI agents follow; pass `--yes` to skip the prompt in -non-interactive contexts such as CI. - -To report drift without changing anything (a CI freshness check): - -```bash -thv skill sync --check -``` - -Exit code `2` means drift or missing entries were found (nothing was installed). -Exit code `3` means one or more skills failed while others succeeded, so results -are mixed. A generic error (exit code `1`) means the command could not run. - -To record lock entries for existing unmanaged installs, or to remove installs no -longer present in the lock file: - -```bash -thv skill sync --adopt -thv skill sync --prune -``` - -### Upgrade project skills - -Use `thv skill upgrade` to re-resolve pinned entries and install newer content -where available: - -```bash -thv skill upgrade -``` - -Pass one or more skill names to limit the upgrade to a subset. Skills pinned to -an immutable reference (an OCI digest or a full Git commit hash) are reported as -not upgradable - there is nothing newer to resolve to. - -To see what would change without persisting anything: - -```bash -thv skill upgrade --preview -``` - -For a CI freshness gate that fails when newer content is available but never -installs: - -```bash -thv skill upgrade --fail-on-changes -``` - -## Verify skill signatures - -When the lock file is enabled, ToolHive verifies signatures on project-scoped -skill installs and re-verifies them on every `thv skill sync`. This gates the -skill supply chain: a skill whose content or signer has changed since it was -pinned will not silently replace the pinned version. - -Verification is transparent - `thv skill install my-skill` for a signed OCI -artifact succeeds without extra flags and records the signer identity in the -lock file. The following sections cover the cases where you have to make an -explicit choice. - -### Install an unsigned skill - -By default, ToolHive rejects unsigned project-scoped installs with an error -like: - -```text -unsigned skill "my-skill" rejected; set allow_unsigned -(--allow-unsigned) to record an exception -``` - -To allow the install and record the exception in the lock file: - -```bash -thv skill install my-skill --scope project \ - --project-root /path/to/project --allow-unsigned -``` - -Subsequent syncs of the same entry treat the recorded exception as the expected -state; they do not re-prompt for the flag. - -### Upgrade to a differently signed skill - -`thv skill upgrade` refuses to move a pinned skill to an artifact signed by a -different identity, or to an unsigned artifact. The status column in the output -reports the reason as `signer-change-blocked`. - -To allow the upgrade and replace the recorded signer identity with the new one: - -```bash -thv skill upgrade my-skill --allow-signer-change -``` - -Rotate trust deliberately - a signer change is the expected way a skill -distribution transfers between publishers, but it also matches the pattern of a -compromised release. - -### Verification coverage - -- **OCI-installed skills** carry a Sigstore bundle. ToolHive verifies the bundle - against the public-good Sigstore instance, requiring a signed certificate - timestamp, a transparency log entry, and an observer timestamp. The lock file - records the signer's identity, certificate issuer, and optionally the - repository URI and Sigstore instance URL. -- **Git-installed skills** are verified against a `gitsign` commit signature. - The signing time is checked against the leaf certificate's validity window. - ToolHive does not yet validate the embedded Rekor transparency-log proof for - Git installs, so the recorded provenance for these entries carries less - assurance than the OCI equivalent. - -Verification uses embedded Fulcio and Rekor roots, so it works offline once the -skill and its bundle are on disk. `thv skill sync` re-verifies each entry -offline against the recorded identity, and reports a signature mismatch as -drift. - ## Create a skill Every skill requires a `SKILL.md` file at the root of its directory. At a @@ -522,8 +377,6 @@ pointing to that digest are removed. - [Manage agent skills in the ToolHive UI](../guides-ui/skills.mdx) to browse, install, and build skills without leaving the app - [`thv skill` command reference](../reference/cli/thv_skill.md) -- [`thv skill sync` command reference](../reference/cli/thv_skill_sync.md) -- [`thv skill upgrade` command reference](../reference/cli/thv_skill_upgrade.md) - [`thv serve` command reference](../reference/cli/thv_serve.md) - [Agent Skills specification](https://agentskills.io/specification) @@ -587,25 +440,6 @@ Common issues include:
-
-Signature verification errors on install or sync - -Signature verification runs on project-scoped installs when -`TOOLHIVE_SKILLS_LOCK_ENABLED=true` is set on the ToolHive server. - -- **`unsigned skill ... rejected`**: The artifact has no Sigstore bundle or Git - signature. Pass `--allow-unsigned` to record the exception in the lock file, - or use a signed release. -- **`signer-change-blocked` on upgrade**: The candidate artifact is signed by a - different identity than the recorded one, or is unsigned. Confirm the change - is expected, then re-run with `--allow-signer-change` to rotate trust. -- **Sync reports a signature mismatch as drift**: The stored bundle no longer - verifies against the recorded identity. Run `thv skill sync` (without - `--check`) to reinstall from the pinned reference, which re-runs install-time - verification. - -
-
Push to registry fails with authentication error From 69974540600d35927ed0909ac30b9d6f9ea48ff1 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 15:16:34 +0000 Subject: [PATCH 8/8] Weave AI-tool plugins into the CLI journey The AI-tool plugins guide was reachable only from the sidebar, with no inbound prose links, so the CLI journey skipped past it. Add forward links from the CLI index, skills management, and client configuration pages, and update CLI-scoped descriptions that named only MCP servers and skills to include plugins. Co-authored-by: Dan Barr <6922515+danbarr@users.noreply.github.com> --- docs/toolhive/guides-cli/client-configuration.mdx | 2 ++ docs/toolhive/guides-cli/index.mdx | 5 ++++- docs/toolhive/guides-cli/skills-management.mdx | 2 ++ docs/toolhive/index.mdx | 3 ++- sidebars.ts | 3 ++- 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/toolhive/guides-cli/client-configuration.mdx b/docs/toolhive/guides-cli/client-configuration.mdx index a9a6e6f4..f1f592f8 100644 --- a/docs/toolhive/guides-cli/client-configuration.mdx +++ b/docs/toolhive/guides-cli/client-configuration.mdx @@ -140,6 +140,8 @@ ToolHive provides. - [Manage agent skills](./skills-management.mdx) to install reusable skills for your AI clients +- [Manage AI-tool plugins](./ai-plugins.mdx) to install command, agent, and + skill bundles into Claude Code and Codex - [Set up custom permissions](./custom-permissions.mdx) to control filesystem and network access for your servers - [Secure your servers](./auth.mdx) with OIDC authentication and Cedar policies diff --git a/docs/toolhive/guides-cli/index.mdx b/docs/toolhive/guides-cli/index.mdx index 5286053f..1bf74b9b 100644 --- a/docs/toolhive/guides-cli/index.mdx +++ b/docs/toolhive/guides-cli/index.mdx @@ -2,7 +2,7 @@ title: Using the ToolHive CLI description: How-to guides for using the ToolHive command-line interface to run and manage - MCP servers. + MCP servers, agent skills, and AI-tool plugins. --- import DocCardList from '@theme/DocCardList'; @@ -42,6 +42,9 @@ both installed. [Use the registry](./registry.mdx). - **Managing agent skills?** See [Manage agent skills](./skills-management.mdx) to install and publish reusable skills. +- **Extending your AI coding tools?** See + [Manage AI-tool plugins](./ai-plugins.mdx) to build, distribute, and install + plugins for Claude Code and Codex. - **Building or automating?** See advanced workflows for [auth](./auth.mdx), [CI/CD](./advanced-cicd.mdx), [container builds](./build-containers.mdx), and more. diff --git a/docs/toolhive/guides-cli/skills-management.mdx b/docs/toolhive/guides-cli/skills-management.mdx index 3df6f137..9c0a5752 100644 --- a/docs/toolhive/guides-cli/skills-management.mdx +++ b/docs/toolhive/guides-cli/skills-management.mdx @@ -366,6 +366,8 @@ pointing to that digest are removed. ## Next steps +- [Manage AI-tool plugins](./ai-plugins.mdx) to distribute commands, agents, + skills, and hooks as portable bundles for Claude Code and Codex - [Configure your AI client](./client-configuration.mdx) to register clients with ToolHive for automatic MCP server and skill configuration - [Manage skills in the registry](../guides-registry/skills.mdx) to publish diff --git a/docs/toolhive/index.mdx b/docs/toolhive/index.mdx index 76a7f6fe..a7f3b2ff 100644 --- a/docs/toolhive/index.mdx +++ b/docs/toolhive/index.mdx @@ -144,7 +144,8 @@ use cases: - [**ToolHive CLI**](./guides-cli/index.mdx): A command line interface to deploy and manage MCP servers on your local machine or in development environments. It allows quick deployment of MCP servers and supports advanced features like - agent skills, telemetry, and fine-grained authorization policies. + agent skills, AI-tool plugins, telemetry, and fine-grained authorization + policies. - [**ToolHive Kubernetes Operator**](./guides-k8s/index.mdx): A Kubernetes operator for teams and enterprises to run and manage MCP servers in multi-user diff --git a/sidebars.ts b/sidebars.ts index 2da3b0a9..272d34d2 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -77,7 +77,8 @@ const mcpSidebar: SidebarsConfig[string] = [ { type: 'category', label: 'ToolHive CLI', - description: 'How to use the ToolHive CLI for managing MCP servers', + description: + 'How to use the ToolHive CLI for managing MCP servers, skills, and plugins', link: { type: 'doc', id: 'toolhive/guides-cli/index',