Source code for ralph.mcp.artifacts.plan._skills_mcp

"""Skills-and-MCPs section of a plan artifact.

Declares the skill bundles and MCP servers an executor should load
before running the plan. Skill names are normalized and deduplicated.
"""

from __future__ import annotations

from pydantic import ConfigDict, Field, field_validator

from ralph.pydantic_compat import RalphBaseModel


[docs] class SkillsMcp(RalphBaseModel): """Required skills and optional MCP servers for executing the plan.""" model_config = ConfigDict(extra="forbid") skills: list[str] = Field(..., min_length=1, max_length=100) mcps: list[str] = Field(default_factory=list, max_length=50) @field_validator("skills", mode="before") @classmethod def normalize_skill_names(cls, skills: object) -> object: if not isinstance(skills, list): return skills deduped: list[str] = [] seen: set[str] = set() for name in skills: if not isinstance(name, str): return skills stripped = name.strip() if not stripped or stripped in seen: continue seen.add(stripped) deduped.append(stripped) if not deduped: msg = "skills_mcp.skills must contain at least one skill name" raise ValueError(msg) return deduped @field_validator("mcps") @classmethod def normalize_mcp_names(cls, mcps: list[str]) -> list[str]: deduped: list[str] = [] seen: set[str] = set() for name in mcps: stripped = name.strip() if not stripped or stripped in seen: continue seen.add(stripped) deduped.append(stripped) return deduped