Skip to content

Restrict interactive MCP picker to MCP services for consumer access - #474

Open
sunishsheth2009 wants to merge 3 commits into
databricks:mainfrom
sunishsheth2009:consumer-access-v2-mcp
Open

Restrict interactive MCP picker to MCP services for consumer access#474
sunishsheth2009 wants to merge 3 commits into
databricks:mainfrom
sunishsheth2009:consumer-access-v2-mcp

Conversation

@sunishsheth2009

@sunishsheth2009 sunishsheth2009 commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

What did you change, and why?

Change: The interactive MCP picker (ucode configure mcp / ucode mcp add) no longer offers V2 AI Gateway sources — Vector Search, UC Functions, external connections, Genie spaces, and Databricks apps (everything under /api/2.0/mcp/*). It now offers only MCP services (the /ai-gateway/mcp-services/ path) and skips the source-selection step since that's the sole source. Workspace users can still add a V2 server on request, non-interactively, by naming it in --services with a typed selector:

  • vector-search:<catalog>.<schema>
  • uc-functions:<catalog>.<schema>
  • external:<connection>
  • genie-space:<space-id>
  • app:<name>

Why: Consumer-only identities lack the workspace-access entitlement and can't use the V2 AI Gateway, so offering those sources in the default flow leads to failures. MCP services is the consumer-safe path. This implements the team "Option 4" decision and the AIGTWY-4471 graceful-skip pattern.

On consumer access (deliberately simple): I checked the server side — the workspace-access entitlement 403 is emitted only by guarded AI Gateway / Model Serving inference and model-listing paths, which ucode already exercises when it sets up models. The listing calls this flow uses (GET /api/2.0/apps, UC catalogs, vector-search endpoints, ai-gateway/v2/endpoints) are not guarded — a consumer gets an empty list or a generic ACL denial, with no reliable, matchable signal. So this PR does not try to detect consumer-vs-missing-grant at MCP-add time (there's no sound signal, and a consumer is already gated upstream at model setup). PermissionDeniedError is used only so discovery skips a 403 gracefully instead of aborting; an app: add that 403s gives an actionable "needs workspace access" error.

How do you know it works?

Testing: uv run ruff check ., uv run ruff format --check, and the test_mcp.py / test_databricks.py suites all pass. Added tests cover: the picker offering only MCP services and skipping the source prompt (allow_back=False); the typed V2 --services selectors registering the right server URL; V2 selectors rejected when combined with --location/plain names; list_databricks_apps raising PermissionDeniedError on a 403 (vs a generic error otherwise); discovery skipping PermissionDeniedError quietly while still warning on other errors; and an app: add surfacing an actionable error on a permission failure.

Notes

  • Follow-up (separate PR): remove the now-dead V2 discovery functions in mcp.py and the underlying list_* helpers in databricks.py. It's interwoven — the VS/UC-Fn walk shares helpers with the retained mcp-services walk, and ~40 test monkeypatch stubs reference the discover_* names — so it needs its own diff + test refactor.

@sunishsheth2009
sunishsheth2009 marked this pull request as ready for review September 4, 2026 22:08
sunishsheth2009 and others added 3 commits September 4, 2026 22:09
The interactive picker previously offered V2 AI Gateway sources (Vector
Search, UC Functions, external connections, Genie, Databricks apps, all
served under /api/2.0/mcp/*). Consumer-only identities lack the
workspace-access entitlement and can't reach those, so the picker now
offers only MCP services (the consumer-safe /ai-gateway/mcp-services path)
and skips the source-selection step when it's the sole source.

Workspace users still add a V2 server on request non-interactively by
naming it in --services with a typed selector (vector-search:cat.schema,
uc-functions:cat.schema, external:conn, genie-space:id, app:name).

Consumer detection uses the authoritative signal: the AI Gateway's
WorkspaceAccessGuard returns a 403 whose message names the
`workspace-access` entitlement, which is the only thing distinguishing a
consumer-only identity from a workspace user missing a specific grant.
PermissionDeniedError carries consumer_only accordingly, discovery skips
it gracefully, and the two cases get different, accurate error messages.

Co-authored-by: Isaac <no-reply@databricks.com>
Verified against universe: the `workspace-access` entitlement 403 marker is
emitted only by guarded AI Gateway / Model Serving inference + model-listing
paths (which ucode already exercises at model setup) — NOT by the Apps / UC /
Vector Search / ai-gateway-v2-endpoints listing calls the MCP flow uses, which
return an empty list or a generic ACL denial for a consumer. So there is no
reliable consumer signal at MCP-add time, and a consumer is gated upstream.

Remove the marker-based detection that can't work here: drop
consumer_access_reason (it probed an unguarded listing and never fired) and the
preemptive block, and stop classifying PermissionDeniedError as consumer_only.
Keep the graceful skip on any 403; an app: add that 403s now gives an
actionable "needs workspace access" error without misattributing the cause.

Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
@sunishsheth2009
sunishsheth2009 marked this pull request as draft September 4, 2026 22:12
@sunishsheth2009
sunishsheth2009 marked this pull request as ready for review September 4, 2026 22:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant