Skip to content

feat: actionable hint when an OBO agent tool lacks its scope - #634

Open
MarioCadenas wants to merge 1 commit into
mainfrom
feat/agent-obo-scope-error-hint
Open

MarioCadenas wants to merge 1 commit into
mainfrom
feat/agent-obo-scope-error-hint

Conversation

@MarioCadenas

Copy link
Copy Markdown
Collaborator

What

Plugin-toolkit and MCP agent tools run on behalf of the user (OBO). When an app is scaffolded as service-principal with no user_api_scopes, the forwarded user token lacks the resource scope and the platform rejects the tool call with a raw message:

Statement failed: Provided OAuth token does not have required scopes: sql

That failure is correct and fail-closed (it never silently falls back to the service principal), but it doesn't tell the developer how to fix it.

Change

dispatchToolCall now rewraps that specific failure into an actionable hint that names the plugin, the missing scope, and points at user_api_scopes:

Agent tool 'analytics.query' (from the 'analytics' plugin) runs on behalf of the user, but the user's token is missing the required scope(s): sql. Add sql to user_api_scopes in your app's databricks.yml and redeploy so the Databricks Apps proxy forwards a token with that scope.

  • Only the OBO sources (toolkit, mcp) are rewrapped. function tools run as the service principal, so the hint would be wrong for them and they are left untouched.
  • The original error is preserved as cause, and still logged with its full stack for operators.
  • The scope name is read straight from the platform message, so it stays correct for any scope without a lookup table.

Why

This is the "DX cliff" surfaced during execution-identity testing: an agents + analytics app scaffolded in SP mode gets no user_api_scopes, so wiring a plugin toolkit into an agent fails at runtime with an opaque error. The stock scaffold is unaffected (its agent tools are dependency-free). A fuller pre-deploy check in apps validate is tracked as a separate follow-up.

Test

Added dispatchToolCall — missing-OBO-scope hint:

  • a toolkit scope rejection is rewrapped with the plugin / scope / user_api_scopes hint and preserves the cause
  • a non-scope toolkit error is left untouched
  • a function (service-principal) tool with a scope-shaped message is NOT rewrapped

Verified live on dogfood (app a2, agents + analytics, SP mode, no scopes): the analytics.query agent tool fails closed with the scope error, while the model call and hand-rolled tools run as the service principal.

This pull request and its description were written by Isaac.

Plugin-toolkit and MCP agent tools run on behalf of the user. In an app
scaffolded as service-principal with no user_api_scopes, the user's token
lacks the resource scope and the platform rejects the call with a raw
"does not have required scopes: sql" message that never says how to fix it.

Rewrap that specific failure into an actionable hint naming the plugin, the
missing scope, and user_api_scopes in databricks.yml, keeping the original
error as the cause. Only the OBO sources (toolkit, mcp) are rewrapped;
function tools run as the service principal and are left untouched.

Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
@MarioCadenas
MarioCadenas requested a review from a team as a code owner October 7, 2026 10:51
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

📦 Bundle size report

Compared against bundle-size-baseline.json (main).

@databricks/appkit

npm tarball (packed): 1.2 MB (+1.4 KB) — gzipped download (dist + bin; excludes release-only docs/NOTICE).

dist raw gzip
JS (runtime) 1.2 MB (+1.4 KB) 442 KB (+557 B)
Type declarations 455 KB 165 KB (-2 B)
Source maps 2.4 MB (+2.4 KB) 829 KB (+926 B)
Other 11 KB 3.7 KB
Total 4.1 MB (+3.8 KB) 1.4 MB (+1.4 KB)
Per-entry composition (own code — deps external (as shipped))
Entry Initial (gz) Lazy (gz) Total (gz) node_modules (min) Own code (min)
. 101 KB (-1 B) 2.5 KB (-1 B) 103 KB (-2 B) external 328 KB
./beta 97 KB (+257 B) 484 B 97 KB (+257 B) external 293 KB (+579 B)
./testing 42 KB 32 KB (+3 B) 74 KB (+3 B) external 214 KB
./tsdown 520 B 0 B 520 B external 813 B
./type-generator 23 KB 0 B 23 KB external 65 KB

Chunks:

Entry Chunk Load Size (gz)
. index.js initial 96 KB
. utils.js initial 4.6 KB
. remote-tunnel-manager.js lazy 2.5 KB
./beta beta.js initial 80 KB
./beta stream-manager.js initial 5.9 KB
./beta service-context.js initial 4.2 KB
./beta databricks.js initial 3.3 KB
./beta wide-event-emitter.js initial 3.2 KB
./beta client.js initial 595 B
./beta index.js initial 20 B
./beta supervisor-api.js lazy 192 B
./beta databricks.js lazy 177 B
./beta index.js lazy 115 B
./testing manifest.js initial 29 KB
./testing index.js initial 10 KB
./testing wide-event-emitter.js initial 2.9 KB
./testing index.js lazy 28 KB
./testing remote-tunnel-manager.js lazy 2.5 KB
./testing utils.js lazy 1.8 KB
./tsdown index.js initial 520 B
./type-generator index.js initial 23 KB

@databricks/appkit-ui

npm tarball (packed): 350 KB — gzipped download (dist + bin; excludes release-only docs/NOTICE).

dist raw gzip
JS (runtime) 395 KB 132 KB
Type declarations 229 KB 84 KB
Source maps 766 KB 253 KB
CSS 16 KB 3.2 KB
Total 1.4 MB 472 KB
Per-entry composition (consumer bundle — deps bundled, peerDeps external)
Entry Initial (gz) Lazy (gz) Total (gz) node_modules (min) Own code (min)
./js 5.3 KB 49 KB 55 KB 208 KB 14 KB
./js/beta 20 B 0 B 20 B 0 B 0 B
./react 432 KB 49 KB 481 KB 1.3 MB 177 KB
./react/beta 1.0 KB 0 B 1.0 KB 0 B 1.9 KB

Chunks:

Entry Chunk Load Size (gz)
./js index.js initial 5.2 KB
./js chunk initial 120 B
./js apache-arrow lazy 49 KB
./js/beta beta.js initial 20 B
./react index.js initial 430 KB
./react tslib initial 2.1 KB
./react apache-arrow lazy 49 KB
./react/beta beta.js initial 1.0 KB

@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

🤖 AppKit PR bot

🔬 Run evals

Start an eval for this PR from the evals-monitor app: Go to Evals Monitor →

📦 Try this PR's app template

Scaffolds a new app from this PR's SDK build. Run it in any folder (requires the GitHub CLI — gh auth login — and the Databricks CLI):

gh run download 37610127083 -R databricks/appkit -n appkit-template-0.84.0-pr.84fd388-feat-agent-obo-scope-error-hint-634 -D appkit-pr-634 \
  && unzip -o "appkit-pr-634/appkit-template-0.84.0-pr.84fd388-feat-agent-obo-scope-error-hint-634.zip" -d "appkit-pr-634" \
  && databricks apps init --template "appkit-pr-634"

The template pins @databricks/appkit and @databricks/appkit-ui to tarballs built from this branch, so the scaffolded app runs against this PR's code.

This branch has not been deployed

No deployments
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