Skip to content

feat(mcp): serve skills via tools - #23

Merged
rnovatorov merged 13 commits into
mainfrom
rnovatorov/skill-plugins
Jul 13, 2026
Merged

feat(mcp): serve skills via tools#23
rnovatorov merged 13 commits into
mainfrom
rnovatorov/skill-plugins

Conversation

@rnovatorov

@rnovatorov rnovatorov commented Jul 10, 2026

Copy link
Copy Markdown
Member

This PR replaces FastMCP resource-based skill delivery with a first-class read_skill MCP tool, and introduces a file-backed API adapter for local/agent-driven testing — all gated behind config flags with no changes to the production HTTP path.

Replace resources-based skill surface with a single read_skill tool.
Skills are model-invoked, not client-gated behind manual selection.

- Skill plugins dir (--skill-plugins) with dynamic <namespace>:<skill>
  discovery; Docker COPY controls which skills ship in the image
- ServerConfig.skills_enabled gates tool registration
- PurePosixPath file keys (no custom normalization), exact-match only
- create_rule/edit_rule docstrings direct agents to load the skill first
- Client.list_resources and CLI command retained as protocol tools

BREAKING CHANGE: skills are no longer served as MCP resources.
- Add read_skill to Related tools in create_rule/edit_rule docstrings
- Warn (not raise) when from_directory discovers no skills
- Expand read_skill description with disclosure ladder guidance
Copilot AI review requested due to automatic review settings July 10, 2026 18:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR shifts skill delivery from FastMCP resources to a first-class read_skill MCP tool (gated by config), and introduces a file-backed filesystem.EnapterAPI plus CLI wiring to select adapters by URL scheme (filetree:// vs http(s)://). The goal is to make skill content reliably accessible to clients via tool calls and enable local/dev workflows without hitting the real Enapter Cloud API.

Changes:

  • Add read_skill tool in mcp.Server, delegating to core.ApplicationServer + a pluggable SkillProvider, and gate registration via ServerConfig.skills_enabled.
  • Add filesystem.SkillProvider (skill discovery/loading) and filesystem.EnapterAPI (YAML-backed EnapterAPI adapter) with supporting pydantic models + tests.
  • Update CLI/Docker/Makefile/integration schema snapshots to wire --skill-plugins, tool counts, and filetree:// adapter selection.

Reviewed changes

Copilot reviewed 48 out of 51 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/unit/mcp/test_server.py Updates MCP unit tests to cover read_skill tool delegation and registration gating.
tests/unit/filesystem/test_skill_provider.py Adds unit tests for directory-based skill discovery/loading.
tests/unit/filesystem/test_enapter_api.py Adds extensive unit tests for the file-backed filesystem.EnapterAPI.
tests/unit/filesystem/models/test_site.py Adds round-trip tests for filesystem Site/SiteAggregate models.
tests/unit/filesystem/models/test_rule.py Adds round-trip tests for filesystem Rule/RuleScript models.
tests/unit/filesystem/models/test_rule_engine.py Adds round-trip tests for filesystem RuleEngine/aggregate models.
tests/unit/filesystem/models/test_device.py Adds round-trip tests for filesystem Device model conversions.
tests/unit/filesystem/models/init.py Initializes filesystem model test package.
tests/unit/filesystem/init.py Initializes filesystem unit test package.
tests/unit/domain/test_skill.py Adds tests for domain.Skill.read path handling and miss errors.
tests/unit/cli/test_serve_command.py Adds tests for CLI adapter selection based on URL scheme.
tests/integration/test_mcp.py Updates integration expectations for tool counts and read_skill schema/annotations.
tests/integration/schemas/read_skill.json Adds schema snapshot for the new read_skill tool.
tests/integration/schemas/edit_rule.json Updates tool description snapshot to reference read_skill and namespaced skill.
tests/integration/schemas/delete_rule.json Updates formatting/content snapshot for delete_rule description.
tests/integration/schemas/create_rule.json Updates tool description snapshot to reference read_skill and namespaced skill.
src/enapter_mcp_server/mcp/server.py Adds read_skill tool and removes prior FastMCP resource-based skill registration.
src/enapter_mcp_server/mcp/server_config.py Replaces rule_creator_skill_path with skills_enabled flag.
src/enapter_mcp_server/filesystem/skill_provider.py Implements skill discovery/loading from a plugins directory.
src/enapter_mcp_server/filesystem/models/site.py Adds pydantic model for filesystem Site with domain conversions.
src/enapter_mcp_server/filesystem/models/site_status.py Adds pydantic model for filesystem SiteStatus with domain conversions.
src/enapter_mcp_server/filesystem/models/site_aggregate.py Adds pydantic aggregate model for site + devices YAML layout.
src/enapter_mcp_server/filesystem/models/rule.py Adds pydantic model for filesystem Rule with domain conversions.
src/enapter_mcp_server/filesystem/models/rule_state.py Adds literal alias for rule state serialization.
src/enapter_mcp_server/filesystem/models/rule_script.py Adds pydantic model for rule scripts with domain conversions.
src/enapter_mcp_server/filesystem/models/rule_runtime_version.py Adds literal alias for rule runtime version serialization.
src/enapter_mcp_server/filesystem/models/rule_engine.py Adds pydantic model for rule engine with domain conversions.
src/enapter_mcp_server/filesystem/models/rule_engine_state.py Adds literal alias for rule engine state serialization.
src/enapter_mcp_server/filesystem/models/rule_engine_aggregate.py Adds pydantic aggregate model for rule engine + rules YAML layout.
src/enapter_mcp_server/filesystem/models/device.py Adds pydantic model for filesystem Device with domain conversions.
src/enapter_mcp_server/filesystem/models/device_type.py Adds literal alias for device type serialization.
src/enapter_mcp_server/filesystem/models/connectivity_status.py Adds literal alias for connectivity status serialization.
src/enapter_mcp_server/filesystem/models/access_role.py Adds literal alias for access role serialization.
src/enapter_mcp_server/filesystem/models/init.py Exposes filesystem models from a central package module.
src/enapter_mcp_server/filesystem/enapter_api.py Implements file-backed EnapterAPI adapter using YAML aggregates and atomic writes.
src/enapter_mcp_server/filesystem/init.py Exposes filesystem adapters (EnapterAPI, SkillProvider).
src/enapter_mcp_server/domain/skill.py Introduces domain Skill entity with file read invariant.
src/enapter_mcp_server/domain/errors.py Adds SkillFileNotFound and SkillNotFound domain errors.
src/enapter_mcp_server/domain/init.py Updates domain exports to include skill types/errors (and currently re-exports a core error).
src/enapter_mcp_server/core/skill_provider.py Adds core.SkillProvider protocol (port) for skill loading.
src/enapter_mcp_server/core/errors.py Adds core-layer not-found/conflict errors used by adapters.
src/enapter_mcp_server/core/application_server.py Adds read_skill orchestration via optional injected skill provider.
src/enapter_mcp_server/core/init.py Exposes newly added core errors and SkillProvider.
src/enapter_mcp_server/cli/serve_command.py Wires --skill-plugins and URL-scheme adapter selection into server startup.
specs/SPEC-012-cli-filetree-wiring.md Documents the CLI scheme-based adapter selection decision.
specs/SPEC-011-filesystem-api-adapter.md Documents filesystem EnapterAPI adapter design and constraints.
specs/SPEC-010-serve-skills-as-tool.md Documents serving skills via a read_skill tool instead of resources.
Pipfile.lock Updates lockfile (adds types-pyyaml).
Pipfile Adds types-pyyaml to dev dependencies.
Makefile Updates make serve to build/run the Docker image.
Dockerfile Updates skill plugin path and copies vendored skill into image; defines entrypoint/cmd.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/enapter_mcp_server/domain/__init__.py Outdated
Comment thread src/enapter_mcp_server/domain/__init__.py Outdated
Comment thread src/enapter_mcp_server/filesystem/skill_provider.py
…annotation

- Remove RuleSlugConflict import and __all__ entry from domain (violates
  domain→core layering rule; unused re-export)
- Replace forward-reference SkillProvider return type with typing.Self
  in filesystem.SkillProvider.from_directory
Copilot AI review requested due to automatic review settings July 11, 2026 17:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 55 out of 58 changed files in this pull request and generated 1 comment.

Comment thread src/enapter_mcp_server/filesystem/enapter_api.py Outdated
Copilot AI review requested due to automatic review settings July 11, 2026 17:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 55 out of 58 changed files in this pull request and generated 5 comments.

Comment thread tests/unit/mcp/test_server.py
Comment thread src/enapter_mcp_server/filesystem/models/site_aggregate.py Outdated
Comment thread src/enapter_mcp_server/filesystem/models/rule_engine_aggregate.py Outdated
Comment thread src/enapter_mcp_server/filesystem/enapter_api.py Outdated
Comment thread src/enapter_mcp_server/filesystem/enapter_api.py Outdated
Introduce fake.EnapterAPI: a programmable fake whose behavior is ordinary
Python and whose data lives in tests, never in the package. Replaces the
file-tree approach (SPEC-011/012), which cannot express command-execution
behavior without hard-coded mocks.

- fake.State: mutable bag of domain objects (data only)
- fake.Policy (Protocol) + DefaultPolicy: behavior; reads implemented against
  State, read-write methods raise NotImplementedError
- fake.EnapterAPI: dispatcher delegating every core.EnapterAPI method to
  policy.method(state, ...); from_url parses fake://?state=&policy= module
  paths via importlib

SPEC-015 (CLI fake:// wiring + filesystem.EnapterAPI removal) and SPEC-016
(agent test migration) are included as design docs for the follow-on work.
…C-015)

Replace the filetree:// adapter with fake.EnapterAPI (SPEC-014) in CLI
adapter selection. filetree:// now raises ValueError (unknown scheme).

- serve_command._make_enapter_api: fake branch + return type updated
- delete filesystem/enapter_api.py and filesystem/models/ (dead code that
  duplicated http.EnapterDataMapper and could not express command behavior)
- filesystem/__init__.py exports only SkillProvider (production code, kept)
- tests/unit/cli/test_serve_command.py: fake test replaces filetree test

Supersedes SPEC-011 and SPEC-012.
The suite moves off the filetree backend — which could not express command-execution behavior without hard-coded mocks — onto the programmable fake. The three layers exist solely for MCP inheritance: the worker reaches the server only through its parent orchestrator, which requires the meta-supervisor to have already started the server, so the meta-supervisor owns the per-scenario server lifecycle while the orchestrator runs one scenario at a time. Verification is logs-only because the worker has no channel to affect the world except tool calls, all logged.
Copilot AI review requested due to automatic review settings July 13, 2026 07:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 47 out of 54 changed files in this pull request and generated 4 comments.

Comment thread src/enapter_mcp_server/domain/skill.py
Comment thread src/enapter_mcp_server/filesystem/skill_provider.py
Comment thread src/enapter_mcp_server/filesystem/skill_provider.py
Comment thread src/enapter_mcp_server/cli/serve_command.py Outdated
Copilot AI review requested due to automatic review settings July 13, 2026 07:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 47 out of 54 changed files in this pull request and generated 3 comments.

Comment thread src/enapter_mcp_server/fake/policy.py
Comment thread src/enapter_mcp_server/fake/policy.py
Comment thread src/enapter_mcp_server/cli/serve_command.py
@rnovatorov
rnovatorov merged commit 87bdf35 into main Jul 13, 2026
4 checks passed
@rnovatorov
rnovatorov deleted the rnovatorov/skill-plugins branch July 13, 2026 08:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants