OpenBB-finance/OpenBB · error · ValueError

The 'files' dict must include a 'SKILL.md' entry as the main

Error message

The 'files' dict must include a 'SKILL.md' entry as the main skill file.

What it means

Raised by the MCP server's install_skill tool when the provided files dict lacks a 'SKILL.md' key. A skill is defined by its SKILL.md manifest; supporting files alone are meaningless, so the server refuses the install before touching the filesystem. It is a strict contract check on the tool arguments.

Source

Thrown at openbb_platform/extensions/mcp_server/openbb_mcp_server/app/app.py:783

            Field(
                description=(
                    "Target skills provider to install into. "
                    "Use 'bundled' for the server's built-in skills directory, "
                    "or a vendor name: "
                    + ", ".join(f"'{k}'" for k in _VENDOR_SKILLS_PROVIDERS)
                    + "."
                ),
            ),
        ] = "bundled",
    ) -> dict:
        """Install a skill (SKILL.md + supporting files) into a SkillsDirectoryProvider.

        Creates the skill directory if needed, writes all files,
        and registers the new skill with the target provider so it becomes
        immediately available via list_resources / read_resource.
        """
        if "SKILL.md" not in files:
            raise ValueError(
                "The 'files' dict must include a 'SKILL.md' entry as the main skill file."
            )

        # Find the target SkillsDirectoryProvider
        target_key = target.lower().strip()
        target_provider: SkillsDirectoryProvider | None = None

        for provider in mcp.providers:
            if not isinstance(provider, SkillsDirectoryProvider):
                continue

            if target_key == "bundled":
                if settings.default_skills_dir:
                    bundled_root = Path(settings.default_skills_dir).resolve()
                    if bundled_root in provider._roots:  # noqa: SLF001
                        target_provider = provider
                        break
            else:

View on GitHub (pinned to 3e071fcc2c)

Solutions

  1. Add a 'SKILL.md' entry (exact key) to the files dict with the skill's frontmatter and instructions.
  2. Verify the key's casing is exactly 'SKILL.md' before calling the tool.
  3. When uploading from a directory, fail fast locally if SKILL.md is absent rather than sending partial files.

Example fix

# before
await install_skill(skill_name="my-skill", target="bundled", files={"helper.py": "..."})

# after
await install_skill(
    skill_name="my-skill",
    target="bundled",
    files={"SKILL.md": "---\nname: my-skill\ndescription: ...\n---\nDo X", "helper.py": "..."},
)
Defensive patterns

Strategy: validation

Validate before calling

def validate_skill_files(files: dict[str, str]) -> None:
    if "SKILL.md" not in files:
        raise ValueError("files must contain exactly 'SKILL.md' as the manifest key")
    if not files["SKILL.md"].strip():
        raise ValueError("SKILL.md content is empty")

Type guard

def is_installable_skill(files: dict) -> bool:
    return isinstance(files, dict) and "SKILL.md" in files and bool(str(files["SKILL.md"]).strip())

Try / catch

try:
    await install_skill(skill_name=name, target=target, files=files)
except ValueError as e:
    if "SKILL.md" in str(e):
        files = {**files, "SKILL.md": default_manifest(name)}
        await install_skill(skill_name=name, target=target, files=files)
    else:
        raise

Prevention

When it happens

Trigger: Calling install_skill(files={'README.md': '...'}, ...) with no SKILL.md entry; keying the manifest as 'skill.md' (lowercase) or 'SKILL.MD'; passing an empty or malformed files dict.

Common situations: Automated skill-upload scripts that iterate a directory but skip or rename SKILL.md; case-mismatched filenames on case-sensitive checks; clients copying example payloads that omit the manifest.

Related errors


AI-assisted analysis of OpenBB-finance/OpenBB@3e071fcc2c (2026-08-14). Data as JSON: /api/errors/a5a56053667fbf92. Report an issue: GitHub.