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