Files
lda-wf/docs/historical/superpowers/plans/2026-06-07-mcp-source-connection-seam.md
T

28 KiB

MCP Source Connection Seam 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: Introduce a typed MCP source connection seam in wf_sources_mcp so runtime/session code can stop depending on wf_mcp.broker.models.ConnectionConfig.metadata.

Architecture: This is the preparatory slice before moving MCP runtime/session code. Move low-level source ID validation and MCP transport models into focused wf_sources_mcp modules, then add McpSourceConnection plus explicit converters from the legacy broker DTO and source registry entries. Do not move runtime/factory.py, runtime/session.py, runtime/pool.py, or McpSdkAdapter in this plan.

Tech Stack: Python 3.14, dataclasses, Pydantic v2, pytest, ruff, basedpyright.


Why This Slice Exists

Persistent MCP connections are the real product need. Stdio MCP startup and HTTP session initialization are expensive and failure-prone, so runtime code needs one clear object that means:

one configured upstream MCP source account that can be opened, authenticated, catalogued, called, and eventually reused.

Today that object is implicitly ConnectionConfig plus metadata: dict[str, Any]. That keeps old code working, but it makes runtime/session extraction unsafe. This slice creates the typed seam first:

ConnectionConfig -> McpSourceConnection -> shared MCP session opener -> persistent runtime

After this slice, later runtime moves become mechanical instead of dragging broker config bags into wf_sources_mcp.


File Structure

Create:

  • src/wf_sources_mcp/ids.py

    • Owns source/connection ID validation for MCP upstream sources.
    • Exports CONNECTION_ID_PATTERN, RESERVED_CONNECTION_IDS, parse_connection_id.
  • src/wf_sources_mcp/transports.py

    • Owns StdioSourceTransport, HttpSourceTransport, SourceTransport.
    • Replaces transport model definitions currently embedded in source_registry.py.
  • src/wf_sources_mcp/connections.py

    • Owns McpSourceConnection.
    • Owns conversion helpers from legacy broker ConnectionConfig and registry entries.
  • tests/wf_sources_mcp/test_connections.py

    • Tests ID validation, transport parsing, legacy conversion, registry conversion, and package exports.

Modify:

  • src/wf_sources_mcp/source_registry.py

    • Import ID helpers from wf_sources_mcp.ids.
    • Import transport models from wf_sources_mcp.transports.
    • Keep existing public exports for compatibility.
  • src/wf_sources_mcp/auth.py

    • Make auth helpers accept McpSourceConnection / source-like objects instead of directly depending on ConnectionConfig.
  • src/wf_sources_mcp/sdk/protocols.py

    • Introduce a source-connection protocol/type alias for backend protocols.
    • Remove the TYPE_CHECKING dependency on wf_mcp.broker.models.ConnectionConfig.
  • src/wf_sources_mcp/__init__.py

    • Export new seam types lazily if needed to avoid circular imports.
  • src/wf_mcp/connections.py

    • Re-export CONNECTION_ID_PATTERN and parse_connection_id from wf_sources_mcp.ids.
    • Keep ConnectionRegistry and qualify_node_name behavior unchanged.
  • src/wf_mcp/shared/names.py

    • Import/re-export RESERVED_CONNECTION_IDS from wf_sources_mcp.ids.
    • Keep FastMCP namespace helpers unchanged.
  • tests/wf_mcp/test_compat_imports.py

    • Add identity checks for moved ID/transport exports where appropriate.
  • docs/current_roadmap.md

    • Add a status note for the typed MCP source connection seam.
  • docs/superpowers/specs/2026-06-03-long-lived-workflow-api-boundary.md

    • Add this slice to the MCP source provider package direction list.

Non-Goals

  • Do not move src/wf_mcp/runtime/factory.py.
  • Do not move src/wf_mcp/runtime/session.py.
  • Do not move src/wf_mcp/runtime/pool.py.
  • Do not move src/wf_mcp/sdk/adapter.py.
  • Do not change ConnectionConfig field shape.
  • Do not change on-disk registry/auth/catalog JSON shapes.
  • Do not change MCP proxy/frontend behavior.

Task 1: Move ID Validation Into wf_sources_mcp.ids

Files:

  • Create: src/wf_sources_mcp/ids.py

  • Modify: src/wf_mcp/connections.py

  • Modify: src/wf_mcp/shared/names.py

  • Test: tests/wf_sources_mcp/test_connections.py

  • Step 1: Write failing ID tests

Create tests/wf_sources_mcp/test_connections.py with these tests first:

import pytest

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


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"],
)
def test_parse_connection_id_rejects_unsafe_or_unqualified_ids(source_id: str) -> None:
    with pytest.raises(ValueError):
        parse_connection_id(source_id)


def test_reserved_connection_ids_are_source_provider_constants() -> None:
    assert "wf.admin" in RESERVED_CONNECTION_IDS
    assert "wf.mcp" in RESERVED_CONNECTION_IDS
    assert CONNECTION_ID_PATTERN.startswith("^")
  • Step 2: Run the failing tests

Run:

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

Expected: fail because wf_sources_mcp.ids does not exist.

  • Step 3: Implement wf_sources_mcp.ids

Create src/wf_sources_mcp/ids.py:

from __future__ import annotations

import re

CONNECTION_ID_PATTERN = r"^[A-Za-z0-9_][A-Za-z0-9_.-]*$"

RESERVED_CONNECTION_IDS = frozenset({"wf.admin", "wf.mcp"})
"""Source ids reserved by built-in workflow/MCP control surfaces."""


def parse_connection_id(connection_id: str) -> tuple[str, str]:
    """Validate and split one MCP source id into provider/account parts.

    Source ids also key persisted auth, registry, and catalog files. Keep this
    conservative so unsafe ids are rejected before reaching store boundaries.
    """

    if not re.fullmatch(CONNECTION_ID_PATTERN, connection_id):
        raise ValueError(
            "connection id must start with alphanumeric or underscore and contain "
            "only [A-Za-z0-9_.-]"
        )
    if "." not in connection_id:
        raise ValueError("connection id must look like '<server>.<account>'")
    server, account = connection_id.split(".", 1)
    if not server or not account:
        raise ValueError("connection id must look like '<server>.<account>'")
    return server, account


__all__ = [
    "CONNECTION_ID_PATTERN",
    "RESERVED_CONNECTION_IDS",
    "parse_connection_id",
]
  • Step 4: Update compatibility imports

In src/wf_mcp/connections.py, remove local re and CONNECTION_ID_PATTERN / parse_connection_id definitions. Import instead:

from wf_sources_mcp.ids import CONNECTION_ID_PATTERN, parse_connection_id

Keep qualify_node_name and ConnectionRegistry in wf_mcp.connections.

In src/wf_mcp/shared/names.py, replace local RESERVED_CONNECTION_IDS with:

from wf_sources_mcp.ids import RESERVED_CONNECTION_IDS

Keep ADMIN_NAMESPACE = "wf.admin" for MCP frontend namespace logic.

  • Step 5: Run focused tests

Run:

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

Expected: pass.


Task 2: Move Transport Models Into wf_sources_mcp.transports

Files:

  • Create: src/wf_sources_mcp/transports.py

  • Modify: src/wf_sources_mcp/source_registry.py

  • Modify: src/wf_sources_mcp/__init__.py

  • Test: tests/wf_sources_mcp/test_connections.py

  • Step 1: Add failing transport tests

Append to tests/wf_sources_mcp/test_connections.py:

from pydantic import TypeAdapter

from wf_sources_mcp.transports import (
    HttpSourceTransport,
    SourceTransport,
    StdioSourceTransport,
)


def test_stdio_source_transport_is_typed() -> None:
    transport = StdioSourceTransport(
        command="uvx",
        args=("mcp-server",),
        env={"TOKEN": "x"},
    )

    assert transport.kind == "stdio"
    assert transport.command == "uvx"
    assert transport.args == ("mcp-server",)
    assert transport.env == {"TOKEN": "x"}


def test_http_source_transport_is_typed() -> None:
    transport = HttpSourceTransport(url="http://127.0.0.1:8000/mcp")

    assert transport.kind == "http"
    assert str(transport.url) == "http://127.0.0.1:8000/mcp"


def test_source_transport_discriminated_union_parses() -> None:
    adapter = TypeAdapter(SourceTransport)

    transport = adapter.validate_python(
        {"kind": "stdio", "command": "pnpx", "args": ["-y", "server"]}
    )

    assert isinstance(transport, StdioSourceTransport)
    assert transport.args == ("-y", "server")
  • Step 2: Run failing tests

Run:

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

Expected: fail because wf_sources_mcp.transports does not exist.

  • Step 3: Implement wf_sources_mcp.transports

Create src/wf_sources_mcp/transports.py:

from __future__ import annotations

from typing import Annotated, Literal

from pydantic import AnyHttpUrl, Field

from wf_api.source_registry import SourceRegistryBaseModel


class StdioSourceTransport(SourceRegistryBaseModel):
    kind: Literal["stdio"] = "stdio"
    command: str = Field(min_length=1)
    args: tuple[str, ...] = ()
    env: dict[str, str] = Field(default_factory=dict)


class HttpSourceTransport(SourceRegistryBaseModel):
    kind: Literal["http"] = "http"
    url: AnyHttpUrl
    headers: dict[str, str] = Field(default_factory=dict)


SourceTransport = Annotated[
    StdioSourceTransport | HttpSourceTransport,
    Field(discriminator="kind"),
]


__all__ = [
    "HttpSourceTransport",
    "SourceTransport",
    "StdioSourceTransport",
]
  • Step 4: Update source_registry.py to use canonical transport models

In src/wf_sources_mcp/source_registry.py:

  • Remove local StdioSourceTransport, HttpSourceTransport, and SourceTransport definitions.
  • Remove now-unused imports Annotated, AnyHttpUrl.
  • Import:
from wf_sources_mcp.ids import RESERVED_CONNECTION_IDS, parse_connection_id
from wf_sources_mcp.transports import (
    HttpSourceTransport,
    SourceTransport,
    StdioSourceTransport,
)

Keep all three names in __all__ so existing imports from wf_sources_mcp.source_registry continue to work.

  • Step 5: Update package exports

In src/wf_sources_mcp/__init__.py, export or lazily expose:

HttpSourceTransport
SourceTransport
StdioSourceTransport

If direct imports create a circular dependency, use the existing lazy __getattr__ pattern.

  • Step 6: Run focused tests

Run:

uv run pytest tests/wf_sources_mcp/test_connections.py tests/wf_sources_mcp/test_source_registry.py tests/wf_mcp/test_source_registry.py -q

Expected: pass.


Task 3: Add McpSourceConnection And Converters

Files:

  • Create: src/wf_sources_mcp/connections.py

  • Modify: src/wf_sources_mcp/__init__.py

  • Test: tests/wf_sources_mcp/test_connections.py

  • Step 1: Add failing connection seam tests

Append to tests/wf_sources_mcp/test_connections.py:

from wf_sources_mcp.connections import (
    McpSourceConnection,
    mcp_source_connection_from_connection_config,
    mcp_source_connection_from_registry_entry,
)
from wf_sources_mcp.source_registry import McpSourceRegistryEntry


def test_mcp_source_connection_from_registry_entry() -> None:
    entry = McpSourceRegistryEntry.model_validate(
        {
            "id": "github.work",
            "provider": "github",
            "account": "work",
            "profile": "engineering",
            "transport": {
                "kind": "stdio",
                "command": "uvx",
                "args": ["github-mcp"],
                "env": {"A": "B"},
            },
            "auth_ref": "github.token",
            "metadata": {"team": "platform"},
        }
    )

    connection = mcp_source_connection_from_registry_entry(entry)

    assert connection == McpSourceConnection(
        id="github.work",
        provider="github",
        account="work",
        enabled=True,
        profile="engineering",
        transport=StdioSourceTransport(
            command="uvx",
            args=("github-mcp",),
            env={"A": "B"},
        ),
        auth_ref="github.token",
        metadata={"team": "platform"},
    )


def test_mcp_source_connection_from_legacy_connection_config_stdio() -> None:
    from wf_mcp.broker.models import ConnectionConfig

    legacy = ConnectionConfig(
        id="github.work",
        server="github",
        account="work",
        enabled=False,
        metadata={
            "transport": "stdio",
            "command": "uvx",
            "args": ["github-mcp"],
            "env": {"A": "B"},
            "auth_ref": "github.token",
            "profile": "engineering",
            "source_registry": True,
            "team": "platform",
        },
    )

    connection = mcp_source_connection_from_connection_config(legacy)

    assert connection.id == "github.work"
    assert connection.provider == "github"
    assert connection.account == "work"
    assert connection.enabled is False
    assert connection.profile == "engineering"
    assert connection.auth_ref == "github.token"
    assert connection.metadata == {"source_registry": True, "team": "platform"}
    assert isinstance(connection.transport, StdioSourceTransport)
    assert connection.transport.command == "uvx"
    assert connection.transport.args == ("github-mcp",)


def test_mcp_source_connection_from_legacy_connection_config_http() -> None:
    from wf_mcp.broker.models import ConnectionConfig

    legacy = ConnectionConfig(
        id="github.work",
        server="github",
        account="work",
        metadata={
            "transport": "streamable_http",
            "url": "http://127.0.0.1:8000/mcp",
            "headers": {"X-Test": "yes"},
        },
    )

    connection = mcp_source_connection_from_connection_config(legacy)

    assert isinstance(connection.transport, HttpSourceTransport)
    assert str(connection.transport.url) == "http://127.0.0.1:8000/mcp"
    assert connection.transport.headers == {"X-Test": "yes"}


def test_mcp_source_connection_rejects_missing_legacy_transport() -> None:
    from wf_mcp.broker.models import ConnectionConfig

    legacy = ConnectionConfig(
        id="github.work",
        server="github",
        account="work",
        metadata={},
    )

    with pytest.raises(ValueError, match="requires metadata.transport"):
        mcp_source_connection_from_connection_config(legacy)
  • Step 2: Run failing tests

Run:

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

Expected: fail because wf_sources_mcp.connections does not exist.

  • Step 3: Implement wf_sources_mcp.connections

Create src/wf_sources_mcp/connections.py:

from __future__ import annotations

from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Any

from wf_sources_mcp.ids import parse_connection_id
from wf_sources_mcp.source_registry import McpSourceRegistryEntry
from wf_sources_mcp.transports import (
    HttpSourceTransport,
    SourceTransport,
    StdioSourceTransport,
)

if TYPE_CHECKING:
    from wf_mcp.broker.models import ConnectionConfig

_FLAT_HTTP_TRANSPORTS = {"http", "streamable-http", "streamable_http", "sse"}
_CONNECTION_METADATA_KEYS = {
    "transport",
    "command",
    "args",
    "env",
    "cwd",
    "url",
    "headers",
    "profile",
    "auth_ref",
}


@dataclass(frozen=True, slots=True)
class McpSourceConnection:
    """Typed runtime-facing MCP source connection.

    This is the object runtime/session code should consume. Legacy broker
    `ConnectionConfig.metadata` remains at the compatibility edge only.
    """

    id: str
    provider: str
    account: str
    transport: SourceTransport
    enabled: bool = True
    profile: str | None = None
    auth_ref: str | None = None
    metadata: dict[str, object] = field(default_factory=dict)

    def __post_init__(self) -> None:
        provider, account = parse_connection_id(self.id)
        if not self.provider:
            raise ValueError("provider must not be empty")
        if not self.account:
            raise ValueError("account must not be empty")
        if provider != self.provider or account != self.account:
            raise ValueError(
                "MCP source connection id must match provider/account fields"
            )


def mcp_source_connection_from_registry_entry(
    entry: McpSourceRegistryEntry,
) -> McpSourceConnection:
    """Adapt persisted desired-source registry state to runtime source shape."""

    return McpSourceConnection(
        id=entry.id,
        provider=entry.provider,
        account=entry.account,
        enabled=entry.enabled,
        profile=entry.profile,
        transport=entry.transport,
        auth_ref=entry.auth_ref,
        metadata=dict(entry.metadata),
    )


def mcp_source_connection_from_connection_config(
    connection: ConnectionConfig,
) -> McpSourceConnection:
    """Adapt legacy broker connection config into typed source shape.

    Keep all metadata-bag reads in this compatibility converter. Runtime/session
    code should use `McpSourceConnection.transport` directly.
    """

    transport = _transport_from_connection_metadata(connection)
    profile = connection.metadata.get("profile")
    auth_ref = connection.metadata.get("auth_ref")
    metadata = {
        str(key): value
        for key, value in connection.metadata.items()
        if key not in _CONNECTION_METADATA_KEYS
    }
    return McpSourceConnection(
        id=connection.id,
        provider=connection.server,
        account=connection.account,
        enabled=connection.enabled,
        profile=profile if isinstance(profile, str) else None,
        transport=transport,
        auth_ref=auth_ref if isinstance(auth_ref, str) else None,
        metadata=metadata,
    )


def _transport_from_connection_metadata(connection: ConnectionConfig) -> SourceTransport:
    transport = connection.metadata.get("transport")
    if isinstance(transport, dict):
        kind = transport.get("kind")
        if kind == "stdio":
            return StdioSourceTransport.model_validate(transport)
        if kind == "http":
            return HttpSourceTransport.model_validate(transport)
        raise ValueError(
            f"connection {connection.id!r} has unsupported metadata.transport.kind {kind!r}"
        )
    if isinstance(transport, str):
        if transport == "stdio":
            return StdioSourceTransport(
                command=str(connection.metadata.get("command", "")),
                args=tuple(str(arg) for arg in connection.metadata.get("args", ())),
                env={
                    str(key): str(value)
                    for key, value in dict(connection.metadata.get("env", {})).items()
                },
            )
        if transport in _FLAT_HTTP_TRANSPORTS:
            return HttpSourceTransport(
                url=str(connection.metadata.get("url", "")),
                headers={
                    str(key): str(value)
                    for key, value in dict(
                        connection.metadata.get("headers", {})
                    ).items()
                },
            )
        raise ValueError(
            f"connection {connection.id!r} has unrecognized metadata.transport {transport!r}"
        )
    raise ValueError(f"connection {connection.id!r} requires metadata.transport")


__all__ = [
    "McpSourceConnection",
    "mcp_source_connection_from_connection_config",
    "mcp_source_connection_from_registry_entry",
]
  • Step 4: Export the new seam from the package

In src/wf_sources_mcp/__init__.py, export or lazily expose:

McpSourceConnection
mcp_source_connection_from_connection_config
mcp_source_connection_from_registry_entry
  • Step 5: Run focused tests

Run:

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

Expected: pass.


Task 4: Update Auth And SDK Protocols To Use The Source Seam

Files:

  • Modify: src/wf_sources_mcp/auth.py

  • Modify: src/wf_sources_mcp/sdk/protocols.py

  • Test: tests/wf_sources_mcp/test_auth.py

  • Test: tests/wf_sources_mcp/test_sdk_protocols.py

  • Test: tests/wf_sources_mcp/test_connections.py

  • Step 1: Add protocol/conformance tests

Append to tests/wf_sources_mcp/test_connections.py:

from typing import Protocol

from wf_sources_mcp.auth import auth_ref_for_connection
from wf_sources_mcp.sdk import BackendAdapter, ToolExecutor


class _ConnectionLike(Protocol):
    id: str
    auth_ref: str | None


def test_auth_ref_for_typed_mcp_source_connection() -> None:
    connection = McpSourceConnection(
        id="github.work",
        provider="github",
        account="work",
        transport=StdioSourceTransport(command="uvx"),
        auth_ref="github.token",
    )

    assert auth_ref_for_connection(connection) == "github.token"


def test_sdk_protocols_are_importable_without_broker_connection_config() -> None:
    assert BackendAdapter is not None
    assert ToolExecutor is not None
  • Step 2: Run focused tests

Run:

uv run pytest tests/wf_sources_mcp/test_connections.py tests/wf_sources_mcp/test_auth.py tests/wf_sources_mcp/test_sdk_protocols.py -q

Expected: likely fail until auth/protocols stop importing ConnectionConfig.

  • Step 3: Update auth.py

In src/wf_sources_mcp/auth.py:

  • Remove the TYPE_CHECKING import of wf_mcp.broker.models.ConnectionConfig.
  • Define a small protocol:
class SourceConnectionLike(Protocol):
    id: str
    auth_ref: str | None
  • Change:
def auth_ref_for_connection(connection: ConnectionConfig) -> str | None:
    auth_ref = connection.metadata.get("auth_ref")
    return auth_ref if isinstance(auth_ref, str) else None

to:

def auth_ref_for_connection(connection: SourceConnectionLike) -> str | None:
    return connection.auth_ref
  • Change connection_auth_diagnostic(connection: ConnectionConfig, ...) to accept SourceConnectionLike.

Important: this intentionally means callers that still hold ConnectionConfig must convert to McpSourceConnection before using auth diagnostics. If current production callers need a compatibility path, use mcp_source_connection_from_connection_config(connection) at that call site instead of reintroducing metadata reads in auth.py.

  • Step 4: Update sdk/protocols.py

In src/wf_sources_mcp/sdk/protocols.py:

  • Remove TYPE_CHECKING and ConnectionConfig.
  • Import:
from wf_sources_mcp.connections import McpSourceConnection
  • Change all connection: ConnectionConfig parameters in BackendAdapter and ToolExecutor to:
connection: McpSourceConnection

This is a type-only protocol change. Production adapters may need a follow-up slice to convert broker DTOs before calling the protocol.

  • Step 5: Run focused type/tests

Run:

uv run pytest tests/wf_sources_mcp/test_connections.py tests/wf_sources_mcp/test_auth.py tests/wf_sources_mcp/test_sdk_protocols.py -q
uv run basedpyright --level error src/wf_sources_mcp

Expected: pass or reveal call sites that still need explicit conversion. Fix call sites by converting at the broker boundary, not by weakening McpSourceConnection back into metadata.


Task 5: Update Current Broker Call Sites At The Boundary

Files:

  • Modify: src/wf_mcp/broker/service/upstream_transport.py

  • Modify: src/wf_mcp/broker/service/source_catalog.py

  • Modify: src/wf_mcp/runtime/factory.py

  • Modify: src/wf_mcp/runtime/session.py

  • Modify: src/wf_mcp/runtime/pool.py

  • Modify: src/wf_mcp/sdk/adapter.py

  • Test: existing focused tests

  • Step 1: Find all protocol call sites

Run:

rg -n 'BackendAdapter|ToolExecutor|call_tool\\(|list_tools\\(|list_resources\\(|list_prompts\\(|read_resource\\(|get_prompt\\(|invoke_method\\(|send_notification\\(' src\\wf_mcp src\\wf_sources_mcp

Inspect call sites that pass a ConnectionConfig into a BackendAdapter or ToolExecutor.

  • Step 2: Convert at the broker edge

Where broker services call source-provider protocols, convert with:

from wf_sources_mcp.connections import mcp_source_connection_from_connection_config

source_connection = mcp_source_connection_from_connection_config(connection)

Then pass source_connection to BackendAdapter / ToolExecutor methods.

Keep ConnectionConfig in broker services for registry/config ownership and source catalog behavior. Do not rewrite the whole broker service in this slice.

  • Step 3: Keep runtime files compiling without moving them

If PersistentMcpSession, McpRuntimePool, or McpSdkAdapter currently implement ToolExecutor / BackendAdapter, update their method signatures to accept McpSourceConnection where needed.

If their public callers still pass ConnectionConfig, convert at the public method boundary and keep a comment:

# Compatibility boundary: broker callers still pass ConnectionConfig. Runtime
# internals use McpSourceConnection so the session code can move to
# wf_sources_mcp in a later slice.
  • Step 4: Run focused tests

Run:

uv run pytest tests/wf_mcp/test_sdk_adapter.py tests/wf_mcp/test_stateful_runtime.py tests/wf_mcp/service/test_upstream_transport.py tests/wf_mcp/service/test_source_registry_admin.py tests/wf_sources_mcp -q
uv run basedpyright --level error src

Expected: pass.


Task 6: Documentation And Verification

Files:

  • Modify: docs/current_roadmap.md

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

  • Step 1: Update roadmap

In docs/current_roadmap.md, under the MCP source provider / long-lived API section, add a short note:

- Completed: typed MCP source connection seam is introduced in `wf_sources_mcp`.
  Source IDs, reserved IDs, transport models, and `McpSourceConnection` are now
  canonical source-provider concepts. Legacy broker `ConnectionConfig` remains
  intact and converts at compatibility edges; runtime/session files are not
  moved yet.
  • Step 2: Update long-lived boundary spec

In docs/superpowers/specs/2026-06-03-long-lived-workflow-api-boundary.md, extend the MCP source provider package direction list:

6. Complete: typed MCP source connection seam introduced. `McpSourceConnection`
   is the runtime-facing source object; legacy `ConnectionConfig` converts at
   broker edges.
7. Next: shared MCP session opener, then runtime/session/pool move.
  • Step 3: Run final verification

Run:

uv run pytest tests/wf_sources_mcp tests/wf_mcp/test_sdk_adapter.py tests/wf_mcp/test_stateful_runtime.py tests/wf_mcp/service/test_upstream_transport.py -q
uv run ruff check src tests
uv run basedpyright --level error src
git diff --check

Expected:

  • tests pass

  • ruff passes

  • basedpyright has 0 errors

  • no diff whitespace errors

  • Step 4: Report remaining future slices

Final report must explicitly state:

  • runtime/factory/session/pool were not moved
  • proxy/frontend MCP code was not touched
  • old ConnectionConfig shape is unchanged
  • next planned slice is shared session opener using McpSourceConnection

Future Slices After This Plan

  1. Shared MCP session opener

    • Create wf_sources_mcp.sdk.transport.open_mcp_session(connection, auth).
    • Replace duplicated session opening in wf_mcp/runtime/factory.py and wf_mcp/sdk/adapter.py.
  2. Move persistent runtime package

    • Move PersistentSessionFactory, PersistentMcpSession, and McpRuntimePool to wf_sources_mcp.runtime.
    • Keep wf_mcp.runtime.* shims.
  3. Move one-shot SDK adapter

    • Move McpSdkAdapter to wf_sources_mcp.sdk.adapter.
    • Keep wf_mcp.sdk.adapter shim.
  4. Eventually split MCP frontend transport

    • Move FastMCP server/proxy/admin/workflow tool registration toward wf_transport_mcp.
    • This is separate from upstream source runtime and should not block persistent connection work.

Self-Review Notes

  • This plan intentionally creates focused files before touching runtime. That keeps the first change testable and limits blast radius.
  • The plan does not attempt to phase out all 369 ConnectionConfig references. It converts only at source-provider protocol edges.
  • The likely implementation risk is type fallout after BackendAdapter / ToolExecutor signatures change. Resolve by explicit conversion at broker boundaries, not by weakening the typed seam.