vet_skill_directory
Audit installed skills by running all security scanners on each skill in the directory, generating an aggregate report with per-skill findings and risk level counts.
Instructions
Run all scanners on every skill in the configured directory and return an aggregate report (per-skill VetReports + counts by risk level). Use this for a periodic audit of installed skills.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- Core handler function: vets every skill in a directory and aggregates results into a DirectoryVetReport. Calls vet_skill() for each skill, sorts by risk_score descending, and counts by risk level.
def vet_skill_directory(skills: list[Skill], directory: str) -> DirectoryVetReport: """Vet every skill in a directory and aggregate.""" reports = [vet_skill(s) for s in skills] reports.sort(key=lambda r: r.risk_score, reverse=True) by_level = Counter(r.risk_level for r in reports) return DirectoryVetReport( captured_at=datetime.now(UTC), directory=directory, skill_count=len(reports), skills=reports, aggregate_block_count=by_level[RiskLevel.BLOCK], aggregate_review_count=by_level[RiskLevel.REVIEW], aggregate_caution_count=by_level[RiskLevel.CAUTION], aggregate_clean_count=by_level[RiskLevel.CLEAN], aggregate_unknown_count=by_level[RiskLevel.UNKNOWN], ) - DirectoryVetReport model: the return type of vet_skill_directory, containing captured_at, directory, skill_count, per-skill VetReports, and aggregate counts by risk level.
class DirectoryVetReport(BaseModel): """Aggregate report across all skills in a directory.""" model_config = ConfigDict(frozen=True) captured_at: datetime directory: str skill_count: int skills: list[VetReport] """Per-skill reports, sorted by risk_score descending.""" aggregate_block_count: int aggregate_review_count: int aggregate_caution_count: int aggregate_clean_count: int aggregate_unknown_count: int - src/openclaw_skill_vetter_mcp/server.py:67-75 (registration)Tool registration in list_tools(): defines the 'vet_skill_directory' Tool with description and empty inputSchema (no required arguments).
Tool( name="vet_skill_directory", description=( "Run all scanners on every skill in the configured directory and return " "an aggregate report (per-skill VetReports + counts by risk level). " "Use this for a periodic audit of installed skills." ), inputSchema={"type": "object", "properties": {}, "required": []}, ), - src/openclaw_skill_vetter_mcp/server.py:147-150 (registration)Tool dispatch in call_tool(): when name=='vet_skill_directory', fetches skills and directory from backend, calls vet_skill_directory(), and serializes the result.
if name == "vet_skill_directory": skills = await backend.get_skills() directory = await backend.get_directory() return _serialize(vet_skill_directory(skills, directory)) - Helper _serialize(): converts any Pydantic model to MCP TextContent (JSON-indented) for the response.
def _serialize(model: Any) -> list[TextContent]: """Pydantic model → MCP TextContent (single block, JSON-serialized).""" return [TextContent(type="text", text=model.model_dump_json(indent=2))]