fix(mcp): resolve workspace display names and tenant ids in qualified project routes#979
Merged
Merged
Conversation
… project routes The edit_note docstring (and write_note in PR #964) advertise that the workspace segment of a "workspace/project" route may be a slug, name, or tenant_id, but resolve_workspace_project_identifier() only matched against WorkspaceInfo.slug. Cloud routes using a display name or tenant UUID failed with "Workspace ... was not found" despite the documented contract. Extend the first-segment matching (only the matching logic; the overall resolution flow is unchanged) to honor, in priority order: 1. slug (casefold) — unchanged, checked first so working routes keep meaning 2. tenant_id — exact match on the opaque id 3. display name (casefold) — fails fast on collisions, listing candidate slugs A name that collides with another workspace's slug resolves to the slug owner. Unknown identifiers raise a not-found error naming the forms that were tried. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Drew Cain <groksrc@gmail.com>
groksrc
added a commit
that referenced
this pull request
Jun 11, 2026
…space Live prod QA found `bm cloud share ... --workspace <slug>` failed with an opaque 400: resolve_configured_workspace returns the explicit --workspace value verbatim, but the cloud's X-Workspace-ID resolver only accepts a workspace/tenant UUID. Users see slugs and display names (list-workspaces output, memory:// URLs), so the natural input never routed. The share commands now resolve the workspace header client-side: a UUID is forwarded verbatim (covers per-project config workspace_id and the default chain, zero extra API calls), while any other value is treated as a human identifier and mapped to the tenant UUID via a single get_available_workspaces lookup, matching with slug > tenant_id > name precedence (mirroring #979). Ambiguous and unknown identifiers fail fast with errors that name the candidate / available workspace slugs, and the list command now re-raises typer.Exit ahead of its broad handler so the resolution errors aren't re-wrapped as "Unexpected error". Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Drew Cain <groksrc@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up agreed in the #964 review discussion.
The
edit_notedocstring/ValueError text advertise that the workspace segment of a composedworkspace/projectroute may be a slug, name, or tenant_id (PR #964 copies the same wording intowrite_note). Butresolve_workspace_project_identifier()insrc/basic_memory/mcp/project_context.pyonly matched the first segment againstWorkspaceInfo.slug(casefold). Cloud routes whose display name or tenant UUID differs from the slug failed withWorkspace ... was not found, contradicting the documented contract.Per the maintainer's decision, this makes the resolver honor the documented contract rather than walking the docs back. It makes the
edit_note"slug, name, or tenant_id" promise real today, andwrite_noteonce #964 merges. Deliberately scoped to the resolver + tests; it does not touchwrite_note/edit_note, so it won't conflict with the unmerged #964.Matching precedence
The first-segment workspace match (and only the matching logic — the overall resolution flow is unchanged) now accepts, in priority order:
workspace_matches_exact_identifierprecedent).Ambiguity (fail fast): a name matching multiple workspaces raises a clear error listing the candidate slugs and telling the caller to use the slug or tenant_id.
Precedence: because slug is matched first, a workspace whose display name equals another workspace's slug yields to the slug owner.
Not found: unknown identifiers raise an extended error naming the forms that were tried (slug, tenant_id, name) plus the available slugs.
Tests
Added to
tests/mcp/test_project_context.py:The existing qualified-route/collision test stays green. Gates run: targeted
pytestforproject_context+edit_noterouting,ruff check/format --checkon changed files, andty check src tests test-int(full scope) — all pass.🤖 Generated with Claude Code