fmt markdown

DO NOT GLOB ALL **/*.md oh hell nah
This commit is contained in:
lda
2026-06-12 08:44:00 +07:00 Verified
parent 7c74feb600
commit 4bd321e905
7 changed files with 61 additions and 6 deletions
+4 -1
View File
@@ -63,10 +63,13 @@ they see old plans.
## (caution: unstable) markdown formatting ## (caution: unstable) markdown formatting
use `pnpx markdownlint-cli --fix '(glob the md)'` use `pnpx markdownlint-cli(2) --fix '(glob the md)'`
<!-- ill need to setup cli2 -->
Note that this will mess things up, if you dont already follow the strict rules of markdownlint Note that this will mess things up, if you dont already follow the strict rules of markdownlint
use `git restore docs/historical` afterwards
### pitfall ### pitfall
all about indenting. all about indenting.
-1
View File
@@ -146,4 +146,3 @@ Then add:
Do not add source-family branches inside `wf_api` run execution. Source-specific Do not add source-family branches inside `wf_api` run execution. Source-specific
logic belongs in the provider package or server composition layer. logic belongs in the provider package or server composition layer.
@@ -135,6 +135,7 @@ This DTO is imported by:
**File:** `src/wf_mcp/connections.py:11-25` **File:** `src/wf_mcp/connections.py:11-25`
Used by: Used by:
- `wf_sources_mcp.source_registry` (runtime import, line 32) - `wf_sources_mcp.source_registry` (runtime import, line 32)
- `wf_sources_mcp.storage.store` (runtime import inside `_connection_path`, line 132) - `wf_sources_mcp.storage.store` (runtime import inside `_connection_path`, line 132)
- `wf_mcp.connections` (canonical home) - `wf_mcp.connections` (canonical home)
@@ -150,6 +151,7 @@ RESERVED_CONNECTION_IDS = frozenset({ADMIN_NAMESPACE, "wf.mcp"})
``` ```
Used by: Used by:
- `wf_sources_mcp.source_registry` (runtime import, line 33) - `wf_sources_mcp.source_registry` (runtime import, line 33)
- `wf_mcp.broker.service.connection_service` (runtime import, line 14) - `wf_mcp.broker.service.connection_service` (runtime import, line 14)
@@ -158,10 +160,12 @@ Used by:
### Blocker 4: `McpSdkAdapter` transport-opening duplication ### Blocker 4: `McpSdkAdapter` transport-opening duplication
**Files:** **Files:**
- `src/wf_mcp/runtime/factory.py:43-90` (`_create_with_stack`) - `src/wf_mcp/runtime/factory.py:43-90` (`_create_with_stack`)
- `src/wf_mcp/sdk/adapter.py:34-75` (`_session`) - `src/wf_mcp/sdk/adapter.py:34-75` (`_session`)
Both methods contain nearly identical logic for: Both methods contain nearly identical logic for:
- Reading `connection.metadata["transport"]` to select stdio vs streamable HTTP - Reading `connection.metadata["transport"]` to select stdio vs streamable HTTP
- Creating `StdioServerParameters` and calling `stdio_client` - Creating `StdioServerParameters` and calling `stdio_client`
- Creating `httpx.AsyncClient` and calling `streamable_http_client` - Creating `httpx.AsyncClient` and calling `streamable_http_client`
@@ -185,6 +189,7 @@ The difference: factory.py owns the session long-term (persistent actor pattern)
**File:** `src/wf_mcp/events/models.py` **File:** `src/wf_mcp/events/models.py`
`McpEvent` is used by: `McpEvent` is used by:
- `UpstreamTransportService` (event_sink) - `UpstreamTransportService` (event_sink)
- `SourceCatalogService` (emit_event) - `SourceCatalogService` (emit_event)
- `BrokerEventRecorder` (event_bus) - `BrokerEventRecorder` (event_bus)
@@ -218,6 +223,7 @@ The transport-opening logic appears in two places:
- Used for one-shot per-call sessions (discovery, admin operations) - Used for one-shot per-call sessions (discovery, admin operations)
Both import from the same MCP SDK modules: Both import from the same MCP SDK modules:
- `mcp.client.stdio.StdioServerParameters`, `stdio_client` - `mcp.client.stdio.StdioServerParameters`, `stdio_client`
- `mcp.client.streamable_http.streamable_http_client` - `mcp.client.streamable_http.streamable_http_client`
- `mcp.client.session.ClientSession` - `mcp.client.session.ClientSession`
@@ -226,6 +232,7 @@ Both import from the same MCP SDK modules:
#### Which client operations are supported by one-shot adapter but not persistent runtime? #### Which client operations are supported by one-shot adapter but not persistent runtime?
The `BackendAdapter` protocol (`wf_sources_mcp.sdk.protocols:26-88`) defines: The `BackendAdapter` protocol (`wf_sources_mcp.sdk.protocols:26-88`) defines:
- `list_tools`, `list_resources`, `list_prompts` - `list_tools`, `list_resources`, `list_prompts`
- `get_connection_metadata` - `get_connection_metadata`
- `read_resource`, `get_prompt` - `read_resource`, `get_prompt`
@@ -233,10 +240,12 @@ The `BackendAdapter` protocol (`wf_sources_mcp.sdk.protocols:26-88`) defines:
- `call_tool` - `call_tool`
The `PersistentMcpSession` (`runtime/session.py:19-49`) only exposes: The `PersistentMcpSession` (`runtime/session.py:19-49`) only exposes:
- `call_tool` - `call_tool`
- `close` - `close`
The `McpRuntimePool` (`runtime/pool.py:43-96`) only exposes: The `McpRuntimePool` (`runtime/pool.py:43-96`) only exposes:
- `get_session` (returns `PersistentMcpSession`) - `get_session` (returns `PersistentMcpSession`)
- `call_tool` - `call_tool`
- `close_connection`, `close_all` - `close_connection`, `close_all`
@@ -248,11 +257,13 @@ This is intentional -- persistent sessions exist for workflow execution (tool ca
#### What common `McpClientSession` / `McpClientSessionFactory` interface should exist? #### What common `McpClientSession` / `McpClientSessionFactory` interface should exist?
Both factory.py and adapter.py share: Both factory.py and adapter.py share:
1. Transport selection logic (stdio vs streamable HTTP) 1. Transport selection logic (stdio vs streamable HTTP)
2. Auth application (env vars for stdio, headers for HTTP) 2. Auth application (env vars for stdio, headers for HTTP)
3. Session creation and initialization 3. Session creation and initialization
A shared `open_mcp_session` helper should: A shared `open_mcp_session` helper should:
- Accept a connection descriptor (transport type, command/url, env/headers) and optional auth - Accept a connection descriptor (transport type, command/url, env/headers) and optional auth
- Return an initialized `ClientSession` (or yield it) - Return an initialized `ClientSession` (or yield it)
- Be used by both `PersistentSessionFactory._create_with_stack` and `McpSdkAdapter._session` - Be used by both `PersistentSessionFactory._create_with_stack` and `McpSdkAdapter._session`
@@ -272,6 +283,7 @@ The connection descriptor should NOT be `ConnectionConfig` directly -- it should
#### What is truly MCP-source-provider logic vs broker/catalog projection logic? #### What is truly MCP-source-provider logic vs broker/catalog projection logic?
**MCP-source-provider logic** (belongs in `wf_sources_mcp`): **MCP-source-provider logic** (belongs in `wf_sources_mcp`):
- Transport opening (stdio, streamable HTTP) -- currently in `factory.py` and `adapter.py` - Transport opening (stdio, streamable HTTP) -- currently in `factory.py` and `adapter.py`
- Auth application (env vars, headers) -- already in `wf_sources_mcp.auth` - Auth application (env vars, headers) -- already in `wf_sources_mcp.auth`
- `BackendAdapter` protocol and `ToolExecutor` protocol -- already in `wf_sources_mcp.sdk` - `BackendAdapter` protocol and `ToolExecutor` protocol -- already in `wf_sources_mcp.sdk`
@@ -282,6 +294,7 @@ The connection descriptor should NOT be `ConnectionConfig` directly -- it should
- Source registry models -- already in `wf_sources_mcp.source_registry` - Source registry models -- already in `wf_sources_mcp.source_registry`
**Broker/catalog projection logic** (stays in `wf_mcp`): **Broker/catalog projection logic** (stays in `wf_mcp`):
- `UpstreamTransportService` -- wraps `BackendAdapter` with auth loading, event recording, catalog refresh orchestration - `UpstreamTransportService` -- wraps `BackendAdapter` with auth loading, event recording, catalog refresh orchestration
- `SourceCatalogService` -- manages `CapabilitySource` registrations, catalog hydration, source inventory - `SourceCatalogService` -- manages `CapabilitySource` registrations, catalog hydration, source inventory
- `discover_connection_capabilities` -- orchestrates adapter calls and wraps results - `discover_connection_capabilities` -- orchestrates adapter calls and wraps results
@@ -342,6 +355,7 @@ The runtime code (`factory.py`, `adapter.py`) reads these fields from `Connectio
| `url` | `factory.py:71`, `adapter.py:62` | HTTP transport URL | | `url` | `factory.py:71`, `adapter.py:62` | HTTP transport URL |
A `SourceTransport` union type already exists in `wf_sources_mcp.source_registry:53-69`: A `SourceTransport` union type already exists in `wf_sources_mcp.source_registry:53-69`:
```python ```python
class StdioSourceTransport(SourceRegistryBaseModel): class StdioSourceTransport(SourceRegistryBaseModel):
kind: Literal["stdio"] = "stdio" kind: Literal["stdio"] = "stdio"
@@ -356,6 +370,7 @@ class HttpSourceTransport(SourceRegistryBaseModel):
``` ```
The runtime code should consume a `SourceConnection` protocol that exposes: The runtime code should consume a `SourceConnection` protocol that exposes:
- `id: str` - `id: str`
- `transport: StdioSourceTransport | HttpSourceTransport` (or a discriminated union) - `transport: StdioSourceTransport | HttpSourceTransport` (or a discriminated union)
- No `metadata: dict[str, Any]` bag - No `metadata: dict[str, Any]` bag
@@ -378,6 +393,7 @@ This would eliminate the `connection.metadata.get("transport", "stdio")` pattern
#### What is MCP frontend transport vs old compatibility facade? #### What is MCP frontend transport vs old compatibility facade?
**MCP frontend transport** (FastMCP server + proxy + tool registration): **MCP frontend transport** (FastMCP server + proxy + tool registration):
- `server/core.py` -- creates `FastMCP` server, wires everything - `server/core.py` -- creates `FastMCP` server, wires everything
- `proxy/runtime.py` -- `ProxyRuntime` mounts upstream connections as FastMCP proxies - `proxy/runtime.py` -- `ProxyRuntime` mounts upstream connections as FastMCP proxies
- `proxy/mounts.py` -- `ProxyMountRegistry`, `create_proxy_mount`, `ResilientFastMCPProxy` - `proxy/mounts.py` -- `ProxyMountRegistry`, `create_proxy_mount`, `ResilientFastMCPProxy`
@@ -388,6 +404,7 @@ This would eliminate the `connection.metadata.get("transport", "stdio")` pattern
- `shared/names.py` -- `ProxyNamespace`, `ADMIN_NAMESPACE`, namespace helpers - `shared/names.py` -- `ProxyNamespace`, `ADMIN_NAMESPACE`, namespace helpers
**Old compatibility facade** (re-export shims and `WfMcpService`): **Old compatibility facade** (re-export shims and `WfMcpService`):
- `auth.py` -- re-exports from `wf_sources_mcp.auth` - `auth.py` -- re-exports from `wf_sources_mcp.auth`
- `models.py` -- re-exports broker models - `models.py` -- re-exports broker models
- `capabilities.py` -- re-exports from `wf_sources_mcp.catalog.entries` - `capabilities.py` -- re-exports from `wf_sources_mcp.catalog.entries`
@@ -442,22 +459,26 @@ Ordered smallest-safe-first.
**Goal:** Break the TYPE_CHECKING dependency from `wf_sources_mcp.sdk.protocols` and `wf_sources_mcp.auth` on `wf_mcp.broker.models.ConnectionConfig` by defining a transport-level protocol that captures what runtime code actually needs. **Goal:** Break the TYPE_CHECKING dependency from `wf_sources_mcp.sdk.protocols` and `wf_sources_mcp.auth` on `wf_mcp.broker.models.ConnectionConfig` by defining a transport-level protocol that captures what runtime code actually needs.
**Files likely touched:** **Files likely touched:**
- `src/wf_sources_mcp/sdk/protocols.py` -- add `SourceConnection` protocol, update `BackendAdapter` and `ToolExecutor` signatures - `src/wf_sources_mcp/sdk/protocols.py` -- add `SourceConnection` protocol, update `BackendAdapter` and `ToolExecutor` signatures
- `src/wf_sources_mcp/auth.py` -- update `auth_ref_for_connection` and `connection_auth_diagnostic` to accept protocol - `src/wf_sources_mcp/auth.py` -- update `auth_ref_for_connection` and `connection_auth_diagnostic` to accept protocol
- `src/wf_sources_mcp/source_registry.py` -- update TYPE_CHECKING import - `src/wf_sources_mcp/source_registry.py` -- update TYPE_CHECKING import
- `src/wf_mcp/broker/models.py` -- make `ConnectionConfig` implement the protocol (no structural change needed, just verify compatibility) - `src/wf_mcp/broker/models.py` -- make `ConnectionConfig` implement the protocol (no structural change needed, just verify compatibility)
**Tests likely needed:** **Tests likely needed:**
- Protocol conformance test: `ConnectionConfig` satisfies `SourceConnection` - Protocol conformance test: `ConnectionConfig` satisfies `SourceConnection`
- Verify `BackendAdapter` and `ToolExecutor` protocols still typecheck with `ConnectionConfig` - Verify `BackendAdapter` and `ToolExecutor` protocols still typecheck with `ConnectionConfig`
**What must NOT change:** **What must NOT change:**
- `ConnectionConfig` fields/shape - `ConnectionConfig` fields/shape
- `BackendAdapter` method signatures (only the type of `connection` parameter changes) - `BackendAdapter` method signatures (only the type of `connection` parameter changes)
- Any broker service code - Any broker service code
- Any proxy/server code - Any proxy/server code
**Migration/shim strategy:** **Migration/shim strategy:**
- `SourceConnection` is a new protocol, not a replacement. `ConnectionConfig` already satisfies it structurally. - `SourceConnection` is a new protocol, not a replacement. `ConnectionConfig` already satisfies it structurally.
- Existing `TYPE_CHECKING` imports in `wf_sources_mcp` become `SourceConnection` protocol imports. - Existing `TYPE_CHECKING` imports in `wf_sources_mcp` become `SourceConnection` protocol imports.
- If any runtime code needs fields beyond the protocol (e.g., `source_config_ownership`), those stay on `ConnectionConfig` and are accessed through a cast or separate parameter. - If any runtime code needs fields beyond the protocol (e.g., `source_config_ownership`), those stay on `ConnectionConfig` and are accessed through a cast or separate parameter.
@@ -469,6 +490,7 @@ Ordered smallest-safe-first.
**Goal:** Remove the runtime import dependency from `wf_sources_mcp` on `wf_mcp.connections` and `wf_mcp.shared.names`. **Goal:** Remove the runtime import dependency from `wf_sources_mcp` on `wf_mcp.connections` and `wf_mcp.shared.names`.
**Files likely touched:** **Files likely touched:**
- `src/wf_sources_mcp/source_registry.py` -- replace imports, move validation logic - `src/wf_sources_mcp/source_registry.py` -- replace imports, move validation logic
- `src/wf_sources_mcp/storage/store.py` -- replace `parse_connection_id` import - `src/wf_sources_mcp/storage/store.py` -- replace `parse_connection_id` import
- `src/wf_mcp/connections.py` -- make `parse_connection_id` a re-export shim - `src/wf_mcp/connections.py` -- make `parse_connection_id` a re-export shim
@@ -476,15 +498,18 @@ Ordered smallest-safe-first.
- `src/wf_mcp/broker/service/connection_service.py` -- update import path - `src/wf_mcp/broker/service/connection_service.py` -- update import path
**Tests likely needed:** **Tests likely needed:**
- Existing tests for `parse_connection_id` should still pass - Existing tests for `parse_connection_id` should still pass
- Verify `FileCatalogStore._connection_path` still validates connection IDs - Verify `FileCatalogStore._connection_path` still validates connection IDs
**What must NOT change:** **What must NOT change:**
- Validation logic (same regex, same error messages) - Validation logic (same regex, same error messages)
- `RESERVED_CONNECTION_IDS` values - `RESERVED_CONNECTION_IDS` values
- Any broker service behavior - Any broker service behavior
**Migration/shim strategy:** **Migration/shim strategy:**
- Move `CONNECTION_ID_PATTERN`, `parse_connection_id` to `wf_sources_mcp.source_registry` or a new `wf_sources_mcp.validation` module. - Move `CONNECTION_ID_PATTERN`, `parse_connection_id` to `wf_sources_mcp.source_registry` or a new `wf_sources_mcp.validation` module.
- `wf_mcp.connections` becomes a re-export shim: `from wf_sources_mcp.source_registry import parse_connection_id` - `wf_mcp.connections` becomes a re-export shim: `from wf_sources_mcp.source_registry import parse_connection_id`
- `RESERVED_CONNECTION_IDS` moves to `wf_sources_mcp.source_registry` (it's already imported there). - `RESERVED_CONNECTION_IDS` moves to `wf_sources_mcp.source_registry` (it's already imported there).
@@ -498,17 +523,20 @@ Ordered smallest-safe-first.
**Goal:** Eliminate the transport-opening duplication between `runtime/factory.py` and `sdk/adapter.py` by extracting a shared helper. **Goal:** Eliminate the transport-opening duplication between `runtime/factory.py` and `sdk/adapter.py` by extracting a shared helper.
**Files likely touched:** **Files likely touched:**
- New: `src/wf_sources_mcp/sdk/transport.py` -- `open_mcp_session` async context manager - New: `src/wf_sources_mcp/sdk/transport.py` -- `open_mcp_session` async context manager
- `src/wf_mcp/runtime/factory.py` -- use `open_mcp_session` in `_create_with_stack` - `src/wf_mcp/runtime/factory.py` -- use `open_mcp_session` in `_create_with_stack`
- `src/wf_mcp/sdk/adapter.py` -- use `open_mcp_session` in `_session` - `src/wf_mcp/sdk/adapter.py` -- use `open_mcp_session` in `_session`
**Tests likely needed:** **Tests likely needed:**
- Unit test for `open_mcp_session` with mock transport - Unit test for `open_mcp_session` with mock transport
- Verify `PersistentSessionFactory` still creates persistent sessions correctly - Verify `PersistentSessionFactory` still creates persistent sessions correctly
- Verify `McpSdkAdapter` still creates one-shot sessions correctly - Verify `McpSdkAdapter` still creates one-shot sessions correctly
- Test error handling (unsupported transport, auth failures) - Test error handling (unsupported transport, auth failures)
**What must NOT change:** **What must NOT change:**
- `PersistentMcpSession` API - `PersistentMcpSession` API
- `McpRuntimePool` behavior - `McpRuntimePool` behavior
- `McpSdkAdapter` method signatures - `McpSdkAdapter` method signatures
@@ -516,6 +544,7 @@ Ordered smallest-safe-first.
- Event emission patterns - Event emission patterns
**Migration/shim strategy:** **Migration/shim strategy:**
- `open_mcp_session` accepts a `SourceConnection` (from Slice 0) and `AuthRecord | None`. - `open_mcp_session` accepts a `SourceConnection` (from Slice 0) and `AuthRecord | None`.
- Returns an async context manager yielding `ClientSession`. - Returns an async context manager yielding `ClientSession`.
- Both `factory.py` and `adapter.py` call this helper instead of duplicating transport logic. - Both `factory.py` and `adapter.py` call this helper instead of duplicating transport logic.
@@ -528,6 +557,7 @@ Ordered smallest-safe-first.
**Goal:** Move the persistent MCP runtime into the source provider package where it belongs. **Goal:** Move the persistent MCP runtime into the source provider package where it belongs.
**Files likely touched:** **Files likely touched:**
- New: `src/wf_sources_mcp/runtime/__init__.py` -- package init - New: `src/wf_sources_mcp/runtime/__init__.py` -- package init
- New: `src/wf_sources_mcp/runtime/factory.py` -- moved from `wf_mcp/runtime/factory.py` - New: `src/wf_sources_mcp/runtime/factory.py` -- moved from `wf_mcp/runtime/factory.py`
- New: `src/wf_sources_mcp/runtime/session.py` -- moved from `wf_mcp/runtime/session.py` - New: `src/wf_sources_mcp/runtime/session.py` -- moved from `wf_mcp/runtime/session.py`
@@ -540,11 +570,13 @@ Ordered smallest-safe-first.
- `src/wf_mcp/broker/service/core.py` -- update import path (if any) - `src/wf_mcp/broker/service/core.py` -- update import path (if any)
**Tests likely needed:** **Tests likely needed:**
- All existing `test_stateful_runtime.py` tests must pass unchanged - All existing `test_stateful_runtime.py` tests must pass unchanged
- Verify `CrashingSessionFactory` subclass still works - Verify `CrashingSessionFactory` subclass still works
- Verify `McpRuntimePool` fingerprint logic still works - Verify `McpRuntimePool` fingerprint logic still works
**What must NOT change:** **What must NOT change:**
- `PersistentMcpSession` API (connection, auth, call_tool, close) - `PersistentMcpSession` API (connection, auth, call_tool, close)
- `McpRuntimePool` API (get_session, call_tool, close_connection, close_all) - `McpRuntimePool` API (get_session, call_tool, close_connection, close_all)
- `PersistentSessionFactory.create` signature - `PersistentSessionFactory.create` signature
@@ -552,6 +584,7 @@ Ordered smallest-safe-first.
- Any event emission or broker orchestration - Any event emission or broker orchestration
**Migration/shim strategy:** **Migration/shim strategy:**
- `wf_mcp.runtime` becomes a re-export shim: `from wf_sources_mcp.runtime import ...` - `wf_mcp.runtime` becomes a re-export shim: `from wf_sources_mcp.runtime import ...`
- `wf_mcp.runtime.protocols.ToolExecutor` already re-exports from `wf_sources_mcp.sdk` - `wf_mcp.runtime.protocols.ToolExecutor` already re-exports from `wf_sources_mcp.sdk`
- Tests import from `wf_mcp.runtime` still work via shims - Tests import from `wf_mcp.runtime` still work via shims
@@ -564,6 +597,7 @@ Ordered smallest-safe-first.
**Goal:** Consolidate the one-shot MCP adapter into the source provider SDK. **Goal:** Consolidate the one-shot MCP adapter into the source provider SDK.
**Files likely touched:** **Files likely touched:**
- New: `src/wf_sources_mcp/sdk/adapter.py` -- moved from `wf_mcp/sdk/adapter.py` - New: `src/wf_sources_mcp/sdk/adapter.py` -- moved from `wf_mcp/sdk/adapter.py`
- `src/wf_mcp/sdk/adapter.py` -- becomes re-export shim - `src/wf_mcp/sdk/adapter.py` -- becomes re-export shim
- `src/wf_mcp/sdk/__init__.py` -- update re-exports - `src/wf_mcp/sdk/__init__.py` -- update re-exports
@@ -571,15 +605,18 @@ Ordered smallest-safe-first.
- `src/wf_mcp/server/core.py` -- update import path - `src/wf_mcp/server/core.py` -- update import path
**Tests likely needed:** **Tests likely needed:**
- Existing `test_sdk_adapter.py` tests must pass - Existing `test_sdk_adapter.py` tests must pass
- Verify `McpSdkAdapter` still implements `BackendAdapter` - Verify `McpSdkAdapter` still implements `BackendAdapter`
**What must NOT change:** **What must NOT change:**
- `McpSdkAdapter` method signatures - `McpSdkAdapter` method signatures
- `BackendAdapter` protocol - `BackendAdapter` protocol
- Any broker service code - Any broker service code
**Migration/shim strategy:** **Migration/shim strategy:**
- `wf_mcp.sdk.adapter.McpSdkAdapter` re-exports from `wf_sources_mcp.sdk.adapter` - `wf_mcp.sdk.adapter.McpSdkAdapter` re-exports from `wf_sources_mcp.sdk.adapter`
- `wf_mcp.sdk.__init__` keeps exporting `McpSdkAdapter` - `wf_mcp.sdk.__init__` keeps exporting `McpSdkAdapter`
@@ -590,6 +627,7 @@ Ordered smallest-safe-first.
**Goal:** Replace the `metadata: dict[str, Any]` bag in `ConnectionConfig` with a typed transport DTO for source-provider code. **Goal:** Replace the `metadata: dict[str, Any]` bag in `ConnectionConfig` with a typed transport DTO for source-provider code.
**Files likely touched:** **Files likely touched:**
- `src/wf_sources_mcp/source_registry.py` -- add `SourceConnection` dataclass - `src/wf_sources_mcp/source_registry.py` -- add `SourceConnection` dataclass
- `src/wf_mcp/runtime/factory.py` -- accept `SourceConnection` instead of `ConnectionConfig` - `src/wf_mcp/runtime/factory.py` -- accept `SourceConnection` instead of `ConnectionConfig`
- `src/wf_mcp/sdk/adapter.py` -- accept `SourceConnection` instead of `ConnectionConfig` - `src/wf_mcp/sdk/adapter.py` -- accept `SourceConnection` instead of `ConnectionConfig`
@@ -597,16 +635,19 @@ Ordered smallest-safe-first.
- Conversion helpers in `wf_sources_mcp.source_registry` - Conversion helpers in `wf_sources_mcp.source_registry`
**Tests likely needed:** **Tests likely needed:**
- Conversion test: `ConnectionConfig` -> `SourceConnection` - Conversion test: `ConnectionConfig` -> `SourceConnection`
- Round-trip test for fingerprint stability - Round-trip test for fingerprint stability
- Verify `McpRuntimePool` fingerprint changes correctly - Verify `McpRuntimePool` fingerprint changes correctly
**What must NOT change:** **What must NOT change:**
- `ConnectionConfig` shape (it's still the broker DTO) - `ConnectionConfig` shape (it's still the broker DTO)
- Broker service behavior - Broker service behavior
- Proxy/server behavior - Proxy/server behavior
**Migration/shim strategy:** **Migration/shim strategy:**
- `SourceConnection` is a new typed DTO in `wf_sources_mcp`. - `SourceConnection` is a new typed DTO in `wf_sources_mcp`.
- `ConnectionConfig` gains a `to_source_connection() -> SourceConnection` method or a standalone converter. - `ConnectionConfig` gains a `to_source_connection() -> SourceConnection` method or a standalone converter.
- Runtime code (`factory.py`, `adapter.py`, `pool.py`) accepts `SourceConnection`. - Runtime code (`factory.py`, `adapter.py`, `pool.py`) accepts `SourceConnection`.
@@ -620,6 +661,7 @@ Ordered smallest-safe-first.
**Goal:** Remove all compatibility re-export shims from `wf_mcp` once all callers import from canonical packages. **Goal:** Remove all compatibility re-export shims from `wf_mcp` once all callers import from canonical packages.
**Files likely touched:** **Files likely touched:**
- `src/wf_mcp/auth.py` -- delete or leave empty - `src/wf_mcp/auth.py` -- delete or leave empty
- `src/wf_mcp/capabilities.py` -- delete or leave empty - `src/wf_mcp/capabilities.py` -- delete or leave empty
- `src/wf_mcp/source_registry.py` -- delete or leave empty - `src/wf_mcp/source_registry.py` -- delete or leave empty
@@ -629,14 +671,17 @@ Ordered smallest-safe-first.
- `src/wf_mcp/__init__.py` -- simplify - `src/wf_mcp/__init__.py` -- simplify
**Tests likely needed:** **Tests likely needed:**
- Verify all existing imports still work (or update them) - Verify all existing imports still work (or update them)
- `test_compat_imports.py` should pass or be updated - `test_compat_imports.py` should pass or be updated
**What must NOT change:** **What must NOT change:**
- Any runtime behavior - Any runtime behavior
- Any broker service behavior - Any broker service behavior
**Migration/shim strategy:** **Migration/shim strategy:**
- This is the final cleanup after all other slices are complete. - This is the final cleanup after all other slices are complete.
- Search for all `from wf_mcp.auth import` etc. and update to canonical paths. - Search for all `from wf_mcp.auth import` etc. and update to canonical paths.
- Leave shims in place for one release cycle, then remove. - Leave shims in place for one release cycle, then remove.
@@ -648,11 +693,13 @@ Ordered smallest-safe-first.
**No.** A typed client/session seam must come first. **No.** A typed client/session seam must come first.
Reasons: Reasons:
1. `PersistentSessionFactory._create_with_stack` reads `connection.metadata["transport"]`, `connection.metadata["command"]`, etc. These are `dict[str, Any]` bag accesses that should be replaced by typed protocol access. 1. `PersistentSessionFactory._create_with_stack` reads `connection.metadata["transport"]`, `connection.metadata["command"]`, etc. These are `dict[str, Any]` bag accesses that should be replaced by typed protocol access.
2. `PersistentMcpSession` holds `connection: ConnectionConfig` directly. If factory moves to `wf_sources_mcp`, it drags `ConnectionConfig` (and therefore `wf_mcp.broker.models`) into the source provider package at runtime. 2. `PersistentMcpSession` holds `connection: ConnectionConfig` directly. If factory moves to `wf_sources_mcp`, it drags `ConnectionConfig` (and therefore `wf_mcp.broker.models`) into the source provider package at runtime.
3. The `PersistentSessionFactory.create` method returns `PersistentMcpSession` which stores `connection: ConnectionConfig`. Without the protocol, this creates a circular import. 3. The `PersistentSessionFactory.create` method returns `PersistentMcpSession` which stores `connection: ConnectionConfig`. Without the protocol, this creates a circular import.
**Correct order:** **Correct order:**
1. Slice 0: Define `SourceConnection` protocol 1. Slice 0: Define `SourceConnection` protocol
2. Slice 1: Move `parse_connection_id` / `RESERVED_CONNECTION_IDS` 2. Slice 1: Move `parse_connection_id` / `RESERVED_CONNECTION_IDS`
3. Slice 2: Extract `open_mcp_session` helper 3. Slice 2: Extract `open_mcp_session` helper
@@ -108,7 +108,7 @@ These shims exist solely for the test_compat_imports.py regression suite. They c
These are `wf_mcp` modules (not shims) that import from `wf_sources_mcp` directly but could instead import through the shim or vice versa. The inconsistency means some internal callers use the shim while the "real" code uses canonical. This is fine architecturally but creates confusion. These are `wf_mcp` modules (not shims) that import from `wf_sources_mcp` directly but could instead import through the shim or vice versa. The inconsistency means some internal callers use the shim while the "real" code uses canonical. This is fine architecturally but creates confusion.
### Production imports currently going through shims (should switch to canonical): ### Production imports currently going through shims (should switch to canonical)
| File | Current Import | Should Import From | | File | Current Import | Should Import From |
|---|---|---| |---|---|---|
@@ -127,7 +127,7 @@ These are `wf_mcp` modules (not shims) that import from `wf_sources_mcp` directl
| `wf_mcp.server.core` | `from wf_sources_mcp.sdk import McpSdkAdapter` | Already canonical | | `wf_mcp.server.core` | `from wf_sources_mcp.sdk import McpSdkAdapter` | Already canonical |
| `wf_mcp.server.core` | `from wf_sources_mcp.source_registry import FileSourceRegistryStore` | Already canonical | | `wf_mcp.server.core` | `from wf_sources_mcp.source_registry import FileSourceRegistryStore` | Already canonical |
### Production imports that are already canonical (no change needed): ### Production imports that are already canonical (no change needed)
- `wf_mcp.broker.config``wf_sources_mcp.runtime`, `wf_sources_mcp.sdk`, `wf_sources_mcp.source_registry`, `wf_sources_mcp.storage` - `wf_mcp.broker.config``wf_sources_mcp.runtime`, `wf_sources_mcp.sdk`, `wf_sources_mcp.source_registry`, `wf_sources_mcp.storage`
- `wf_mcp.broker.server``wf_sources_mcp.sdk`, `wf_sources_mcp.source_registry` - `wf_mcp.broker.server``wf_sources_mcp.sdk`, `wf_sources_mcp.source_registry`
@@ -159,6 +159,7 @@ These three changes remove the internal dependency chain where `wf_mcp.broker.se
**Goal:** Mark shims that have NO production callers (only test_compat_imports) as deprecated. **Goal:** Mark shims that have NO production callers (only test_compat_imports) as deprecated.
Candidates: Candidates:
- `wf_mcp.sdk.base` - `wf_mcp.sdk.base`
- `wf_mcp.sdk.converters` - `wf_mcp.sdk.converters`
- `wf_mcp.runtime.protocols` - `wf_mcp.runtime.protocols`
@@ -17,6 +17,7 @@ self-contained** -- it imports nothing from `wf_mcp` at runtime or
`TYPE_CHECKING`. The dependency direction is exclusively `wf_mcp` -> `wf_sources_mcp`. `TYPE_CHECKING`. The dependency direction is exclusively `wf_mcp` -> `wf_sources_mcp`.
Key achievements since the 2026-06-07 research map: Key achievements since the 2026-06-07 research map:
- `parse_connection_id` and `RESERVED_CONNECTION_IDS` are canonical in - `parse_connection_id` and `RESERVED_CONNECTION_IDS` are canonical in
`wf_sources_mcp.ids` (no more `wf_mcp.connections` or `wf_mcp.shared.names` `wf_sources_mcp.ids` (no more `wf_mcp.connections` or `wf_mcp.shared.names`
dependency). dependency).
@@ -288,6 +289,7 @@ scan the early items.
**File:** `docs/superpowers/research/2026-06-07-wf-mcp-runtime-source-provider-map.md` **File:** `docs/superpowers/research/2026-06-07-wf-mcp-runtime-source-provider-map.md`
**Lines 549-650 (Slice 0-6):** The recommended next slices are now mostly completed: **Lines 549-650 (Slice 0-6):** The recommended next slices are now mostly completed:
- Slice 0 (SourceConnection protocol): Completed via `McpSourceConnection` - Slice 0 (SourceConnection protocol): Completed via `McpSourceConnection`
- Slice 1 (parse_connection_id move): Completed to `wf_sources_mcp.ids` - Slice 1 (parse_connection_id move): Completed to `wf_sources_mcp.ids`
- Slice 2 (open_mcp_session): Completed in `wf_sources_mcp.client.transport` - Slice 2 (open_mcp_session): Completed in `wf_sources_mcp.client.transport`
@@ -26,6 +26,7 @@ JSON-RPC request
``` ```
**Key files:** **Key files:**
- `src/wf_transport_rpc_http/methods_capabilities.py` - RPC entry point - `src/wf_transport_rpc_http/methods_capabilities.py` - RPC entry point
- `src/wf_mcp/broker/service/workflow_operation_context.py:78-86` - context_from_service - `src/wf_mcp/broker/service/workflow_operation_context.py:78-86` - context_from_service
- `src/wf_mcp/broker/service/source_catalog.py:257-298` - spec_from_snapshot_entry (hydrated specs) - `src/wf_mcp/broker/service/source_catalog.py:257-298` - spec_from_snapshot_entry (hydrated specs)
@@ -46,6 +47,7 @@ ContentAccessService.read_resource(qualified_name)
``` ```
**Key files:** **Key files:**
- `src/wf_mcp/broker/service/content_access.py:30-52` - read_resource() - `src/wf_mcp/broker/service/content_access.py:30-52` - read_resource()
- `src/wf_mcp/broker/service/upstream_transport.py:97-126` - read_resource() - `src/wf_mcp/broker/service/upstream_transport.py:97-126` - read_resource()
@@ -61,6 +63,7 @@ ContentAccessService.render_prompt(qualified_name, arguments)
``` ```
**Key files:** **Key files:**
- `src/wf_mcp/broker/service/content_access.py:54-82` - render_prompt() - `src/wf_mcp/broker/service/content_access.py:54-82` - render_prompt()
- `src/wf_mcp/broker/service/upstream_transport.py:128-163` - render_prompt() - `src/wf_mcp/broker/service/upstream_transport.py:128-163` - render_prompt()
@@ -264,6 +267,7 @@ uv run ruff format
**Gap:** No JSON-RPC-specific test proves this reuse. Existing tests cover MCP client path and unit-level pool behavior, but not the full RPC transport stack. **Gap:** No JSON-RPC-specific test proves this reuse. Existing tests cover MCP client path and unit-level pool behavior, but not the full RPC transport stack.
**Smallest Fix:** Add one e2e test in `test_mcp_backed_server_rpc.py` that: **Smallest Fix:** Add one e2e test in `test_mcp_backed_server_rpc.py` that:
1. Builds server from config 1. Builds server from config
2. Makes two `call_capability` RPC requests 2. Makes two `call_capability` RPC requests
3. Asserts pool has exactly 1 session (not 2) 3. Asserts pool has exactly 1 session (not 2)
@@ -129,4 +129,3 @@ Still deferred:
- hot reload - hot reload
- reducer exports - reducer exports
- sandboxing/untrusted code - sandboxing/untrusted code