UAT: SkillService._schema_to_skill_dict() silently drops MCP server connection details — transport, command, args, url, headers lost on skill registration #2893

Open
opened 2026-04-05 02:43:47 +00:00 by freemo · 1 comment
Owner

Metadata

  • Branch: fix/skill-mcp-server-connection-details-lost
  • Commit Message: fix(skills): preserve MCP server transport, command, args, url, and headers in _schema_to_skill_dict()
  • Milestone: v3.7.0
  • Parent Epic: #393

Bug Report

Feature Area

Skills System — MCP server tool exposure (SkillService._schema_to_skill_dict() / SkillMcpSource domain model)

What Was Tested

The SkillService._schema_to_skill_dict() method in src/cleveragents/application/services/skill_service.py was analyzed against the skill YAML schema and spec requirements for MCP server tool exposure.

Expected Behavior (from spec)

The spec defines that skills can expose MCP server tools. The skill YAML schema (docs/schema/skill.schema.yaml) defines MCP servers with: name, transport, command, args, env, url, headers, tool_filter. The SkillMcpServerSchema in src/cleveragents/skills/schema.py captures all these fields. When a skill is registered, all MCP server connection details should be preserved in the domain model so that the runtime can establish the correct transport connection to the MCP server.

Actual Behavior (from code analysis)

In src/cleveragents/application/services/skill_service.py, the _schema_to_skill_dict() method maps MCP servers as:

mcp_dict: dict[str, Any] = {"server": mcp.name}
if mcp.tool_filter and mcp.tool_filter.include:
    mcp_dict["tools"] = list(mcp.tool_filter.include)
data["mcp_servers"].append(mcp_dict)

Only name (mapped to server) and tool_filter.include (mapped to tools) are preserved. The following fields are silently dropped:

  • transport (stdio/sse/streamable-http) — required to know HOW to connect
  • command — required for stdio transport
  • args — command-line arguments for the server
  • env — environment variables for the server
  • url — required for sse/streamable-http transport
  • headers — HTTP headers for remote connections
  • tool_filter.exclude — blacklist of tools to hide

Furthermore, the SkillMcpSource domain model in src/cleveragents/domain/models/core/skill.py only has server, tools, and env fields — it is missing transport, command, args, url, and headers entirely.

This means any skill that uses MCP servers with transport: stdio and a command (like the composed.yaml example which uses npx -y @modelcontextprotocol/server-github) will have its connection configuration silently discarded. The skill will be registered but the MCP server can never be connected to because the transport and command information is gone.

Steps to Reproduce

  1. Create a skill YAML with an MCP server using stdio transport:
name: local/git-github
description: "Git and GitHub integration"
mcp_servers:
  - name: github
    transport: stdio
    command: npx
    args: ["-y", "@modelcontextprotocol/server-github"]
    env:
      GITHUB_PERSONAL_ACCESS_TOKEN: "${GITHUB_TOKEN}"
  1. Register the skill: agents skill add --config composed.yaml
  2. Inspect the registered skill: agents skill show local/git-github
  3. Observe that transport, command, args, env, and url are all missing from the stored skill

Code Locations

  • src/cleveragents/application/services/skill_service.py_schema_to_skill_dict() method (lines ~230–250): drops transport, command, args, url, headers, and tool_filter.exclude
  • src/cleveragents/domain/models/core/skill.pySkillMcpSource class: missing transport, command, args, url, headers fields
  • src/cleveragents/skills/schema.pySkillMcpServerSchema class: correctly captures all fields (source of truth)
  • examples/skills/composed.yaml — example that demonstrates the issue (uses stdio transport with npx command)

Severity

High — MCP-backed skills are a core spec feature. Any skill using MCP servers with stdio transport (the most common case) will silently lose its connection configuration, making the skill non-functional at runtime. The schema correctly captures the data but the service layer discards it before it reaches the domain model.

Subtasks

  • Extend SkillMcpSource domain model in src/cleveragents/domain/models/core/skill.py to add transport, command, args, url, and headers fields (all optional, matching the YAML schema types)
  • Update _schema_to_skill_dict() in src/cleveragents/application/services/skill_service.py to map all SkillMcpServerSchema fields: transport, command, args, env, url, headers, and tool_filter.exclude
  • Ensure the mcp_dict builder preserves tool_filter.exclude in addition to tool_filter.include
  • Verify that SkillMcpSource is correctly reconstructed from the dict representation (round-trip: schema → dict → domain model → dict)
  • Add Behave BDD unit test scenarios covering: stdio transport with command+args preserved, sse transport with url+headers preserved, env vars preserved, tool_filter.exclude preserved, missing optional fields default to None
  • Add/update Robot Framework integration test for agents skill add + agents skill show verifying MCP server connection details are stored and displayed
  • Run nox -e typecheck to verify all new fields are correctly typed (Pyright must pass with no suppressions)
  • Ensure all nox stages pass

Definition of Done

  • SkillMcpSource domain model contains all MCP server connection fields: server, transport, command, args, env, url, headers, tools (include list), and exclude (exclude list)
  • SkillService._schema_to_skill_dict() maps all fields from SkillMcpServerSchema to the dict representation without dropping any connection details
  • agents skill show displays MCP server transport, command, args, url, and headers when present
  • Behave BDD scenarios cover stdio transport, sse/streamable-http transport, env vars, and tool_filter.exclude with ≥5 scenarios
  • Robot Framework integration test validates end-to-end skill registration and retrieval of MCP server connection details
  • All nox stages pass
  • Coverage >= 97%

Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: ca-uat-tester

## Metadata - **Branch**: `fix/skill-mcp-server-connection-details-lost` - **Commit Message**: `fix(skills): preserve MCP server transport, command, args, url, and headers in _schema_to_skill_dict()` - **Milestone**: v3.7.0 - **Parent Epic**: #393 ## Bug Report ### Feature Area Skills System — MCP server tool exposure (`SkillService._schema_to_skill_dict()` / `SkillMcpSource` domain model) ### What Was Tested The `SkillService._schema_to_skill_dict()` method in `src/cleveragents/application/services/skill_service.py` was analyzed against the skill YAML schema and spec requirements for MCP server tool exposure. ### Expected Behavior (from spec) The spec defines that skills can expose MCP server tools. The skill YAML schema (`docs/schema/skill.schema.yaml`) defines MCP servers with: `name`, `transport`, `command`, `args`, `env`, `url`, `headers`, `tool_filter`. The `SkillMcpServerSchema` in `src/cleveragents/skills/schema.py` captures all these fields. When a skill is registered, all MCP server connection details should be preserved in the domain model so that the runtime can establish the correct transport connection to the MCP server. ### Actual Behavior (from code analysis) In `src/cleveragents/application/services/skill_service.py`, the `_schema_to_skill_dict()` method maps MCP servers as: ```python mcp_dict: dict[str, Any] = {"server": mcp.name} if mcp.tool_filter and mcp.tool_filter.include: mcp_dict["tools"] = list(mcp.tool_filter.include) data["mcp_servers"].append(mcp_dict) ``` Only `name` (mapped to `server`) and `tool_filter.include` (mapped to `tools`) are preserved. The following fields are **silently dropped**: - `transport` (stdio/sse/streamable-http) — required to know HOW to connect - `command` — required for stdio transport - `args` — command-line arguments for the server - `env` — environment variables for the server - `url` — required for sse/streamable-http transport - `headers` — HTTP headers for remote connections - `tool_filter.exclude` — blacklist of tools to hide Furthermore, the `SkillMcpSource` domain model in `src/cleveragents/domain/models/core/skill.py` only has `server`, `tools`, and `env` fields — it is missing `transport`, `command`, `args`, `url`, and `headers` entirely. This means any skill that uses MCP servers with `transport: stdio` and a `command` (like the `composed.yaml` example which uses `npx -y @modelcontextprotocol/server-github`) will have its connection configuration silently discarded. The skill will be registered but the MCP server can never be connected to because the transport and command information is gone. ### Steps to Reproduce 1. Create a skill YAML with an MCP server using stdio transport: ```yaml name: local/git-github description: "Git and GitHub integration" mcp_servers: - name: github transport: stdio command: npx args: ["-y", "@modelcontextprotocol/server-github"] env: GITHUB_PERSONAL_ACCESS_TOKEN: "${GITHUB_TOKEN}" ``` 2. Register the skill: `agents skill add --config composed.yaml` 3. Inspect the registered skill: `agents skill show local/git-github` 4. Observe that `transport`, `command`, `args`, `env`, and `url` are all missing from the stored skill ### Code Locations - `src/cleveragents/application/services/skill_service.py` — `_schema_to_skill_dict()` method (lines ~230–250): drops transport, command, args, url, headers, and tool_filter.exclude - `src/cleveragents/domain/models/core/skill.py` — `SkillMcpSource` class: missing `transport`, `command`, `args`, `url`, `headers` fields - `src/cleveragents/skills/schema.py` — `SkillMcpServerSchema` class: correctly captures all fields (source of truth) - `examples/skills/composed.yaml` — example that demonstrates the issue (uses stdio transport with npx command) ### Severity **High** — MCP-backed skills are a core spec feature. Any skill using MCP servers with stdio transport (the most common case) will silently lose its connection configuration, making the skill non-functional at runtime. The schema correctly captures the data but the service layer discards it before it reaches the domain model. ## Subtasks - [ ] Extend `SkillMcpSource` domain model in `src/cleveragents/domain/models/core/skill.py` to add `transport`, `command`, `args`, `url`, and `headers` fields (all optional, matching the YAML schema types) - [ ] Update `_schema_to_skill_dict()` in `src/cleveragents/application/services/skill_service.py` to map all `SkillMcpServerSchema` fields: `transport`, `command`, `args`, `env`, `url`, `headers`, and `tool_filter.exclude` - [ ] Ensure the `mcp_dict` builder preserves `tool_filter.exclude` in addition to `tool_filter.include` - [ ] Verify that `SkillMcpSource` is correctly reconstructed from the dict representation (round-trip: schema → dict → domain model → dict) - [ ] Add Behave BDD unit test scenarios covering: stdio transport with command+args preserved, sse transport with url+headers preserved, env vars preserved, tool_filter.exclude preserved, missing optional fields default to None - [ ] Add/update Robot Framework integration test for `agents skill add` + `agents skill show` verifying MCP server connection details are stored and displayed - [ ] Run `nox -e typecheck` to verify all new fields are correctly typed (Pyright must pass with no suppressions) - [ ] Ensure all nox stages pass ## Definition of Done - [ ] `SkillMcpSource` domain model contains all MCP server connection fields: `server`, `transport`, `command`, `args`, `env`, `url`, `headers`, `tools` (include list), and `exclude` (exclude list) - [ ] `SkillService._schema_to_skill_dict()` maps all fields from `SkillMcpServerSchema` to the dict representation without dropping any connection details - [ ] `agents skill show` displays MCP server transport, command, args, url, and headers when present - [ ] Behave BDD scenarios cover stdio transport, sse/streamable-http transport, env vars, and tool_filter.exclude with ≥5 scenarios - [ ] Robot Framework integration test validates end-to-end skill registration and retrieval of MCP server connection details - [ ] All nox stages pass - [ ] Coverage >= 97% --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-uat-tester
freemo added this to the v3.7.0 milestone 2026-04-05 02:43:55 +00:00
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • Priority: High (confirmed) — MCP server connection details silently dropped during skill registration means skills that depend on MCP servers cannot function correctly.
  • MoSCoW: Should Have — Skill MCP integration is spec-required but the basic skill registration works for non-MCP tools.

Valid UAT finding. The silent data loss during skill registration is a significant bug.


Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: ca-project-owner

Issue triaged by project owner: - **State**: Verified - **Priority**: High (confirmed) — MCP server connection details silently dropped during skill registration means skills that depend on MCP servers cannot function correctly. - **MoSCoW**: Should Have — Skill MCP integration is spec-required but the basic skill registration works for non-MCP tools. Valid UAT finding. The silent data loss during skill registration is a significant bug. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Blocks
#393 Epic: Skill & Tool Lifecycle
cleveragents/cleveragents-core
Reference
cleveragents/cleveragents-core#2893
No description provided.