Files
lda-wf/docs/historical/superpowers/plans/2026-06-08-wf-sources-mcp-source-id-ownership.md
T

12 KiB

MCP Source ID Ownership Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Complete ownership of MCP source ID validation in wf_sources_mcp.ids and remove remaining wf_sources_mcp imports from legacy wf_mcp ID modules.

Architecture: wf_sources_mcp.ids is the canonical home for MCP upstream source ID rules: accepted characters, provider/account splitting, and reserved source IDs. Legacy wf_mcp modules may import from it, but wf_sources_mcp must not import wf_mcp.connections or wf_mcp.shared.names. This slice is intentionally small: it does not move broker DTOs or ConnectionConfig conversions.

Tech Stack: Python 3.14, pytest, ruff, basedpyright, AST import guards.


Why This Pattern Is Correct

Source IDs are used by upstream MCP source-provider code before the broker gets involved:

  • registry entries use source IDs;
  • catalog snapshots use source IDs;
  • auth records are referenced by source IDs;
  • filesystem stores must reject unsafe source IDs before building paths.

That makes ID parsing a low-level source-provider invariant. wf_mcp can keep compatibility imports, but it should not be the authority for these rules.


Hard Boundaries

  • Do not move ConnectionConfig or broker DTOs in this slice.
  • Do not change accepted ID syntax.
  • Do not change reserved ID values.
  • Do not change on-disk file layout.
  • Do not import wf_mcp from src/wf_sources_mcp/ids.py.
  • Remove the wf_sources_mcp.storage.store lazy import from wf_mcp.connections.
  • Keep wf_mcp.connections.parse_connection_id and wf_mcp.shared.names.RESERVED_CONNECTION_IDS import-compatible.
  • Do not commit unless the caller explicitly asks for a commit.

File Map

  • Modify src/wf_sources_mcp/ids.py: add explicit validate_connection_id() helper and keep parse_connection_id().
  • Modify src/wf_sources_mcp/storage/store.py: import ID validation from wf_sources_mcp.ids, not wf_mcp.connections.
  • Modify src/wf_mcp/connections.py: keep compatibility import from wf_sources_mcp.ids.
  • Modify src/wf_mcp/shared/names.py: keep compatibility import from wf_sources_mcp.ids.
  • Modify or create tests/wf_sources_mcp/test_ids.py: canonical ID tests.
  • Modify tests/wf_sources_mcp/test_import_direction_guard.py: forbid old ID helper imports from wf_sources_mcp.
  • Modify docs: docs/current_roadmap.md and docs/superpowers/specs/2026-06-03-long-lived-workflow-api-boundary.md.
  • Move this plan to docs/historical/superpowers/plans/ after implementation is verified.

Task 1: Add Canonical Source ID Tests

Files:

  • Create: tests/wf_sources_mcp/test_ids.py

  • Optionally modify: tests/wf_sources_mcp/test_connections.py

  • Step 1: Create focused ID tests

Create tests/wf_sources_mcp/test_ids.py:

from __future__ import annotations

import pytest

from wf_sources_mcp.ids import (
    CONNECTION_ID_PATTERN,
    RESERVED_CONNECTION_IDS,
    parse_connection_id,
    validate_connection_id,
)


def test_validate_connection_id_returns_valid_id() -> None:
    assert validate_connection_id("github.work") == "github.work"
    assert validate_connection_id("my_source.default") == "my_source.default"


def test_parse_connection_id_splits_provider_and_account() -> None:
    assert parse_connection_id("github.work") == ("github", "work")


@pytest.mark.parametrize(
    "source_id",
    ["", "github", ".github.work", "github.", "github/work", "github work", "../bad"],
)
def test_validate_connection_id_rejects_unsafe_or_unqualified_ids(source_id: str) -> None:
    with pytest.raises(ValueError):
        validate_connection_id(source_id)


def test_reserved_connection_ids_are_canonical_source_constants() -> None:
    assert "wf.admin" in RESERVED_CONNECTION_IDS
    assert "wf.mcp" in RESERVED_CONNECTION_IDS
    assert CONNECTION_ID_PATTERN.startswith("^")
  • Step 2: Remove duplicate assertions if needed

If tests/wf_sources_mcp/test_connections.py now duplicates the exact parse_connection_id tests, either leave the overlap if it is small or reduce it to connection-conversion behavior. Do not remove coverage unless test_ids.py has equal or stronger assertions.

  • Step 3: Run the new tests and verify the expected failure

Run:

uv run pytest tests/wf_sources_mcp/test_ids.py -q

Expected: fail because validate_connection_id does not exist yet.


Task 2: Add validate_connection_id() to wf_sources_mcp.ids

Files:

  • Modify: src/wf_sources_mcp/ids.py

  • Step 1: Implement the helper without changing parsing rules

Update src/wf_sources_mcp/ids.py:

def validate_connection_id(connection_id: str) -> str:
    """Validate one MCP source id and return it unchanged.

    Use this when callers need path-safety and shape validation but do not need
    provider/account pieces. `parse_connection_id()` remains the splitter.
    """

    parse_connection_id(connection_id)
    return connection_id

Add it to __all__.

  • Step 2: Run canonical ID tests

Run:

uv run pytest tests/wf_sources_mcp/test_ids.py tests/wf_sources_mcp/test_connections.py -q

Expected: pass.


Task 3: Remove Legacy ID Import From wf_sources_mcp.storage

Files:

  • Modify: src/wf_sources_mcp/storage/store.py

  • Step 1: Replace lazy legacy import

In FileCatalogStore._connection_path, replace:

from wf_mcp.connections import parse_connection_id

parse_connection_id(connection_id)

with a canonical import:

from wf_sources_mcp.ids import validate_connection_id

validate_connection_id(connection_id)

If import cycles allow it, prefer a top-level import near the other wf_sources_mcp imports. If a cycle appears, keep it as a local import and add a short comment explaining why.

  • Step 2: Run storage tests

Run:

uv run pytest tests/wf_sources_mcp tests/wf_mcp/test_store.py -q

Expected: pass.


Task 4: Add Import Guard for Old ID Modules

Files:

  • Modify: tests/wf_sources_mcp/test_import_direction_guard.py

  • Step 1: Add forbidden old ID helper import test

Append:

def test_wf_sources_mcp_does_not_import_old_wf_mcp_id_modules() -> None:
    root = Path(__file__).resolve().parents[2] / "src" / "wf_sources_mcp"
    forbidden = {"wf_mcp.connections", "wf_mcp.shared.names"}
    violations: list[str] = []

    for py_file in sorted(root.rglob("*.py")):
        rel = py_file.relative_to(root.parent)
        module = str(rel.with_suffix("")).replace("/", ".").replace("\\", ".")
        tree = ast.parse(py_file.read_text(encoding="utf-8"), filename=str(py_file))
        for node in ast.walk(tree):
            if isinstance(node, ast.ImportFrom) and node.module in forbidden:
                violations.append(f"{module}:{node.lineno}: from {node.module} import ...")
            elif isinstance(node, ast.Import):
                for alias in node.names:
                    if alias.name in forbidden:
                        violations.append(f"{module}:{node.lineno}: import {alias.name}")

    assert violations == [], (
        "wf_sources_mcp still imports old wf_mcp source ID modules:\n"
        + "\n".join(f"  {violation}" for violation in violations)
    )
  • Step 2: Run import guard

Run:

uv run pytest tests/wf_sources_mcp/test_import_direction_guard.py -q

Expected: pass.


Task 5: Verify Legacy Compatibility Imports Still Work

Files:

  • Modify: tests/wf_mcp/test_compat_imports.py

  • Step 1: Add identity tests for legacy paths

Append:

def test_wf_mcp_connection_id_helpers_reexport_wf_sources_mcp_ids() -> None:
    from wf_mcp.connections import parse_connection_id as compat_parse_connection_id
    from wf_mcp.shared.names import RESERVED_CONNECTION_IDS as compat_reserved_ids
    from wf_sources_mcp.ids import RESERVED_CONNECTION_IDS, parse_connection_id

    assert compat_parse_connection_id is parse_connection_id
    assert compat_reserved_ids is RESERVED_CONNECTION_IDS
  • Step 2: Run compatibility tests

Run:

uv run pytest tests/wf_mcp/test_compat_imports.py tests/wf_mcp/test_store.py -q

Expected: pass.


Task 6: Update Docs and Archive Plan

Files:

  • Modify: docs/current_roadmap.md

  • Modify: docs/superpowers/specs/2026-06-03-long-lived-workflow-api-boundary.md

  • Move: docs/superpowers/plans/2026-06-08-wf-sources-mcp-source-id-ownership.md to docs/historical/superpowers/plans/2026-06-08-wf-sources-mcp-source-id-ownership.md

  • Step 1: Update docs/current_roadmap.md

Under the wf_sources_mcp cleanup section, add:

      MCP source ID validation is canonical in `wf_sources_mcp.ids`.
      `wf_sources_mcp` no longer imports legacy `wf_mcp.connections` or
      `wf_mcp.shared.names` for source ID/path-safety checks.
  • Step 2: Update the long-lived boundary spec

In docs/superpowers/specs/2026-06-03-long-lived-workflow-api-boundary.md, add a completed numbered item after the adapter-helper item:

22. Complete: MCP source ID validation and reserved source IDs are canonical in
    `wf_sources_mcp.ids`; legacy `wf_mcp.connections` / `wf_mcp.shared.names`
    remain compatibility consumers.

Renumber the pending broad item if needed.

  • Step 3: Archive the plan

Run:

git mv docs/superpowers/plans/2026-06-08-wf-sources-mcp-source-id-ownership.md docs/historical/superpowers/plans/2026-06-08-wf-sources-mcp-source-id-ownership.md

Expected: git status --short shows the plan under docs/historical/....


Task 7: Final Verification

Files:

  • No code edits unless verification finds a real issue.

  • Step 1: Run focused tests

Run:

uv run pytest tests/wf_sources_mcp/test_ids.py tests/wf_sources_mcp/test_import_direction_guard.py tests/wf_sources_mcp tests/wf_mcp/test_compat_imports.py tests/wf_mcp/test_store.py -q

Expected: all selected tests pass.

  • Step 2: Run lint

Run:

uv run ruff check src/wf_sources_mcp/ids.py src/wf_sources_mcp/storage/store.py src/wf_mcp/connections.py src/wf_mcp/shared/names.py tests/wf_sources_mcp/test_ids.py tests/wf_sources_mcp/test_import_direction_guard.py tests/wf_mcp/test_compat_imports.py

Expected: All checks passed!

  • Step 3: Run typecheck

Run:

uv run basedpyright --level error src/wf_sources_mcp/ids.py src/wf_sources_mcp/storage/store.py src/wf_mcp/connections.py src/wf_mcp/shared/names.py tests/wf_sources_mcp/test_ids.py tests/wf_mcp/test_compat_imports.py

Expected: 0 errors, 0 warnings, 0 notes.

  • Step 4: Check remaining old ID helper imports

Run:

rg -n "wf_mcp\\.connections|wf_mcp\\.shared\\.names|parse_connection_id|RESERVED_CONNECTION_IDS|validate_connection_id" src/wf_sources_mcp src/wf_mcp tests/wf_sources_mcp tests/wf_mcp

Expected:

  • src/wf_sources_mcp imports source ID helpers only from wf_sources_mcp.ids.

  • src/wf_mcp/connections.py and src/wf_mcp/shared/names.py may import from wf_sources_mcp.ids for compatibility.

  • Tests may reference legacy paths only for compatibility assertions.

  • Step 5: Check whitespace

Run:

git diff --check

Expected: no whitespace errors. CRLF warnings on Windows are acceptable.


Expected Final Report

The implementer should report:

  • Files created, modified, and moved.
  • Exact verification commands and pass/fail output.
  • Confirmation that wf_sources_mcp.ids owns source ID validation.
  • Confirmation that wf_sources_mcp.storage.store no longer imports wf_mcp.connections.
  • Confirmation that legacy wf_mcp ID paths still work.
  • Any deviations from this plan.

Do not claim "full suite passed" unless the full suite was actually run.