fix(mcp): pass workspace parameter through client factory#722
fix(mcp): pass workspace parameter through client factory#722phernandez merged 1 commit intomainfrom
Conversation
The factory mode (used by cloud MCP server) silently dropped the workspace parameter, making per-tool workspace switching impossible. Every MCP tool already accepts a workspace parameter and passes it to get_project_client(), but in factory mode the value was discarded. - Update factory type from Callable[[], ...] to Callable[..., ...] to accept optional workspace kwarg - Pass workspace through get_client() to the factory - Pass workspace through get_project_client() in factory mode - Update test factories to accept workspace parameter Closes basicmachines-co/basic-memory-cloud#460 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: phernandez <paul@basicmachines.co>
|
Claude finished @phernandez's task in 1m 14s —— View job Code Review
The fix is correct and minimal. Both drop sites are patched ( Issues1. Type annotation weakened without need (
from typing import Protocol
class ClientFactory(Protocol):
def __call__(self, *, workspace: Optional[str] = None) -> AbstractAsyncContextManager[AsyncClient]: ...Or at minimum the docstring for 2. No test asserting workspace is actually forwarded (
@pytest.mark.asyncio
async def test_get_client_forwards_workspace_to_factory(monkeypatch):
received = {}
@asynccontextmanager
async def factory(workspace=None):
received["workspace"] = workspace
async with httpx.AsyncClient(base_url="https://example.test") as client:
yield client
set_client_factory(factory)
async with get_client(workspace="tenant-abc") as client:
pass
assert received["workspace"] == "tenant-abc"Same gap exists in 3. Minor: double space in comment ( Two spaces before "See". Cosmetic but easy to fix. Checklist
SummaryThe core fix is right and the diff is appropriately small. Two things worth addressing before merge: the type annotation (a |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: db5014fd85
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ): | ||
| logger.debug("Using injected client factory for project routing") | ||
| async with get_client() as client: | ||
| async with get_client(workspace=workspace) as client: |
There was a problem hiding this comment.
Invalidate cached project when workspace override changes
This new factory-mode call path now forwards workspace, but get_active_project() still reuses active_project cache entries keyed only by project identifier, not workspace. In one MCP session, a call for project="..." in workspace A followed by workspace B can return the cached project from A, so downstream tools use the wrong external_id under the new workspace header and may operate on the wrong project (or fail with confusing 404/authorization errors). The cache should be re-keyed or bypassed when the requested workspace differs.
Useful? React with 👍 / 👎.
| """ | ||
| if _client_factory: | ||
| async with _client_factory() as client: | ||
| async with _client_factory(workspace=workspace) as client: |
There was a problem hiding this comment.
Preserve compatibility with no-arg client factories
get_client() now unconditionally calls the injected factory with workspace=..., which breaks existing factories that implement the previous zero-argument contract and are still valid according to prior versions of set_client_factory. Those integrations will now fail at runtime with an unexpected-keyword TypeError before any request handling. Please keep a compatibility path for factories that do not accept the new keyword.
Useful? React with 👍 / 👎.
Summary
workspaceparameter, making per-tool workspace switching impossible in the cloud MCP serverworkspaceand passes it toget_project_client(), but in factory mode the value was discarded at two points:get_client()andget_project_client()workspacekwargContext
Addresses basicmachines-co/basic-memory-cloud#460 — users connecting a single MCP remote endpoint cannot switch between personal and team workspaces. The companion PR in basic-memory-cloud updates the transport to read workspace from inner request headers.
Test plan
tests/mcp/test_async_client_modes.py— 20/20 passing (factory tests updated)tests/mcp/test_project_context.py— factory test updated🤖 Generated with Claude Code