Skip to content

workbench-jupyter-with-llm app with MCP features#409

Merged
pantherman594 merged 103 commits into
masterfrom
mcp-app
May 15, 2026
Merged

workbench-jupyter-with-llm app with MCP features#409
pantherman594 merged 103 commits into
masterfrom
mcp-app

Conversation

@pantherman594
Copy link
Copy Markdown
Contributor

@pantherman594 pantherman594 commented May 13, 2026

Imported from NavidZ@9844615

NavidZ and others added 30 commits January 26, 2026 16:12
- New feature: llm-context - generates CLAUDE.md for Claude Code auto-discovery
- Includes generate-context.sh script with embedded skill files
- Auto-runs on container startup to provide workspace context
- Updated workbench-jupyter-with-llm app to include the new feature

The CLAUDE.md file includes:
- Workspace metadata (name, ID, cloud platform, role)
- Resource paths and environment variables
- Data exploration cheatsheet
- Data persistence guidance
- MCP vs CLI usage guide
- Custom app creation skill
- Updated generate-context.sh with latest improvements
- Fixed devcontainer-feature.json (removed problematic postStartCommand)
- Improved install.sh with:
  - Auto-install jq if missing
  - Better error handling
  - Auto-run via .bashrc (runs in background on first terminal)
  - Checks if workspace is set before generating
- Updated README with usage examples
- Version 1.1.0
- Added .devcontainer/features/ symlinks for all features
- Added startupscript symlink
- Removed autorun option (now handled by feature's .bashrc trigger)
- App now uses the llm-context devcontainer feature

To test: Deploy with folder src/workbench-jupyter-with-llm
- Updated install.sh to match workbench-tools/gemini/wb-mcp-server patterns:
  - Added WORKDIR with cleanup trap
  - Added apt_get_update() and check_packages() helpers
  - Consistent variable naming and structure
  - Banner-style output messages

- Updated devcontainer-feature.json:
  - Removed containerEnv (not used by other features)
  - Updated userHomeDir default to match pattern
  - Bumped version to 1.2.0

- Updated README.md:
  - Added Options table matching gemini feature format
  - Added MCP Integration section
  - Added File Locations table
  - Consistent structure with other features
Features referenced as ./.devcontainer/features/xxx in .devcontainer.json
are resolved from repo root, not the app folder. This matches the original
NavidZ repo structure.

- Created .devcontainer/features/ at repo root with symlinks to features/src/
- Removed .devcontainer/features/ from app folder (was incorrect location)
Issues fixed:
1. Bucket mounting: Removed startupscript symlink from app folder.
   Paths like ./startupscript/ resolve from repo root, not app folder.

2. Context generation timing: Now runs via postStartCommand AFTER
   startup scripts complete (auth + workspace setup done first).
   Removed .bashrc auto-trigger which ran too early.

Changes:
- Removed src/workbench-jupyter-with-llm/startupscript symlink
- Updated .devcontainer.json postStartCommand to run context generation
- Simplified install.sh (aliases only, no bashrc auto-trigger)
- Updated README with correct integration instructions
Bug: postStartCommand runs as root, so $HOME = /root. The script was
creating /root/.workbench/CLAUDE.md instead of /home/jupyter/.workbench/CLAUDE.md

Fix: generate-context.sh now accepts home directory as first argument.
Priority: 1) $LLM_CONTEXT_HOME, 2) first arg, 3) /home/jupyter fallback, 4) $HOME

Updated:
- generate-context.sh: Accept home dir arg, smart fallback to /home/jupyter
- .devcontainer.json: Pass /home/jupyter to generate-context.sh
- install.sh: Set LLM_CONTEXT_HOME env var, aliases pass home dir
- README.md: Document the home directory argument
The remount-on-restart.sh script may return non-zero exit code even
when successful, which breaks the && chain. Changed to:
- Use ; instead of && (run regardless of previous exit code)
- Added || true to prevent postStartCommand failure
Added:
- Detailed validation table with specific files and what to check
- Common mistakes section
- Validation commands to run before deploy
- LLM response template for consistent validation output
- Clear instruction for LLM to verify ALL items before suggesting deploy
The postStartCommand was running but context generation wasn't working.
Moving it to postCreateCommand ensures it runs AFTER post-startup.sh
completes authentication and workspace setup.

Also added echo statements to make it visible in logs.
Learning from wb-mcp-server: create the file during install.sh so Claude
finds it immediately. The stub:
- Tells Claude it's in Workbench
- Instructs to run 'generate-llm-context' for full context
- Lists available MCP tools
- Provides basic CLI commands

postCreateCommand still tries to generate full context, but if it fails,
Claude has the stub to work with.

This ensures ~/CLAUDE.md exists as soon as the container starts.
Architecture:
- llm-context feature installs script to /opt/llm-context/
- post-startup.sh checks if feature is installed
- If yes, runs generate-context.sh AFTER auth is complete
- Uses RUN_AS_LOGIN_USER for correct file ownership

This ensures context generation runs at the right time (after auth)
while still using the devcontainer feature for installation.

Changes:
- startupscript/post-startup.sh: Added LLM context generation section
- Removed stub CLAUDE.md from install.sh (not needed)
- Simplified postCreateCommand
- postStartCommand still runs context gen for app restarts
Based on working llm-context-feature branch, adds:
- 4 app templates (flask-api, streamlit-dashboard, rshiny-dashboard, file-processor)
- APP_TEMPLATES.md skill for template selection guidance
- Updated generate-context.sh with both skills embedded
- Updated CLAUDE.md template with decision flow for app creation
When generating URLs for apps/proxies inside Workbench, must use:
https://workbench.verily.com/app/[UUID]/proxy/[PORT]/[PATH]

Common mistake: Using localhost or custom domain patterns which fail
with 'Bad Request' error.
New tool that answers: 'What data collections exist and what resources belong to them?'

Implementation:
1. Gets all resources and identifies their sourceWorkspaceId
2. Looks up each source workspace to get the actual data collection name
3. Groups resources by their source data collection
4. Shows resources created directly in this workspace (no source)

Returns structured JSON with:
- dataCollections: map of collection name -> {sourceWorkspaceId, resources[]}
- localResources: resources created in this workspace
- summary: statistics

This eliminates the need for LLMs to manually piece together
resource lineage information.
CLAUDE.md changes:
- Renamed section: 'Workbench URLs, Dashboards & Interactive Content'
- Explains why file:// URLs don't work (JS blocked by browser)
- Shows how to use Python HTTP server for HTML dashboards
- Quick recipe for building interactive visualizations
- Common ports table and pro tips

CUSTOM_APP.md changes:
- Added file:// to list of wrong URL formats
- Added reference to CLAUDE.md for dashboard guidance

This helps users who ask to 'build a dashboard' or 'visualize data'
understand that they need an HTTP server, not direct file access.
…tep API flow

- Updated CLAUDE.md template to use correct MCP tool names:
  - get_resource -> workspace_list_data_collections
  - list_resources -> workspace_list_resources
  - query_bigquery -> bq_execute
  - run_workflow -> workflow_job_run

- Enhanced workspace_list_data_collections to use two-step API approach:
  1. List all resources to get IDs
  2. Get detailed info for each resource (includes resourceLineage)
  3. Look up source workspace names for data collection grouping

- URL construction matches existing MCP tools pattern
The wb status output may return userFacingId instead of UUID.
Now uses resolveWorkspaceId() like other working tools to properly
convert the workspace ID to UUID before making API calls.
…de metadata

Key fixes:
- resourceLineage is an ARRAY, not an object
- resourceLineage is inside metadata, not at the top level
- Simplified: removed two-step approach since list endpoint includes lineage
- Now matches the working workspace_list_resources pattern
- Added 'How to Get the App UUID' section with command to get running app
- Added ⚡ LLM INSTRUCTION to never ask user for UUID, always get it automatically
- Updated Python dashboard example to show automatic UUID retrieval
- Removed duplicate Pro Tip about UUID
Templates now use minimal devcontainer config without:
- postCreateCommand referencing non-existent startupscript/
- Features referencing non-existent .devcontainer/features/

This makes templates truly standalone and deployable from any repo.

Fixed templates:
- streamlit-dashboard
- rshiny-dashboard
- file-processor (created .devcontainer.json)
- flask-api (already minimal)
New skill includes:
- Critical proxy URL rules and common issues
- Flask server configuration (0.0.0.0, threaded, debug=False)
- Working templates with BigQuery integration
- Comprehensive troubleshooting guide
- Lessons learned from real debugging sessions

Also:
- Streamlined CLAUDE.md with prominent skill triggers
- Temporarily removed APP_TEMPLATES from active skills (kept for future)
- Updated skill selection guide for clarity
Key fixes:
- devcontainer.json MUST be in .devcontainer/ folder (not root)
- Added proxyTargetPort requirement in customizations.workbench
- Fixed dockerComposeFile path (../docker-compose.yaml)
- Added volume mount for live code updates
- Added reference to create-custom-app.sh quick start script
- Added Common Mistakes Checklist
- Simplified directory structure to match working pattern
aculotti-verily and others added 10 commits May 12, 2026 10:42
DATA_DISCOVERY skill improvements — ranking
…_list_data_collections

The tool was making one sequential API call per data collection to resolve
its display name, causing timeouts on workspaces with 5+ collections.

Fix: one batch POST to /api/workspaces/v2/filtered builds a uuid->name map
upfront. Resources are then grouped by display name in memory. Falls back
to UUID as group key if the batch call fails.

Co-authored-by: Cursor <cursoragent@cursor.com>
fix(mcp): resolve workspace_list_data_collections timeout + skill refinements
…eWorkspaceId calls

workspace_list_data_collections was calling wb status (CLI subprocess) and
resolveWorkspaceId (fetches all 5000 workspaces) on every invocation, adding
2-3 expensive operations before any real work.

Fix: cache the workspace UUID once in initializeConfig() from the wb status
output already fetched at startup. workspace_list_data_collections now starts
directly with the resources API call — 2 total calls instead of 4+.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Add requireString/requireStrings helpers to MCP server to prevent
  panics from unchecked type assertions on missing tool arguments
- Extract ~2,150 lines of embedded skill heredocs from generate-context.sh
  into standalone files copied at install time, establishing skills/ as
  the single source of truth
- Create standalone AWS skill variants (WORKFLOW_TROUBLESHOOT, DASHBOARD_BUILDER)
  previously only available as heredocs
- Merge heredoc-unique content into standalone skills (Quick Start in
  CUSTOM_APP, "Be Proactive" behavior in WORKFLOW_TROUBLESHOOT)
- Replace personal repo reference in APP_TEMPLATES with org repo and
  add fork guidance
- Detect architecture dynamically in wb-mcp-server install (amd64/arm64)
- Bump Go from 1.21 to 1.25 to match rest of repo
- Fix path references in llm-context README (~/.workbench -> ~/.claude)
- Fix app README listing non-existent template options
- Add .bashrc idempotency guards to both install scripts
- Fix cp -r reinstall nesting issue in llm-context install

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
pantherman594 and others added 10 commits May 14, 2026 10:23
ws[id] from wb status is the userFacingId (e.g. test-1), not the UUID.
Call resolveWorkspaceId once at startup after workspaceBaseURL is set,
cache the resulting UUID, and reuse it in workspace_list_data_collections.

Co-authored-by: Cursor <cursoragent@cursor.com>
…_collections

Root causes of repeated failures:
1. UUID cached only at startup — any timing issue made it permanently empty
2. resolveWorkspaceId fetched all 5000 workspaces — slow and failure-prone
3. No recovery path if startup resolution failed

New getCurrentWorkspaceUUID() — called lazily at each tool invocation:
  Layer 1: return cachedWorkspaceUUID if already set (instant)
  Layer 2: wb workspace describe --format=json — direct CLI call, checks
    for uuid field, or id if it is UUID format, or userFacingId
  Layer 3: wb status --format=json for userFacingId fallback, then
    workspace list with limit=100 first (avoids 5000-item scan for
    most users), expanding to 5000 only if not found in first page

resolveWorkspaceId() kept (with same small-page-first improvement) for
tools that resolve user-supplied workspaceId parameters.

workspace_list_data_collections now returns a readable guidance message
instead of a hard error so Claude can relay fix instructions to the user.

Also fixed: UUID cache call in initializeConfig was inside the wrong
else-branch (server-not-found), now correctly at the outer level.

Co-authored-by: Cursor <cursoragent@cursor.com>
fix: robust workspace UUID resolution for workspace_list_data_collections
@pantherman594 pantherman594 marked this pull request as ready for review May 15, 2026 16:06
@pantherman594 pantherman594 requested review from a team as code owners May 15, 2026 16:06
@pantherman594
Copy link
Copy Markdown
Contributor Author

Imported from NavidZ@9844615

LGTM with a few minor changes

@pantherman594 pantherman594 merged commit 299a514 into master May 15, 2026
16 of 17 checks passed
@pantherman594 pantherman594 deleted the mcp-app branch May 15, 2026 16:35
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.

4 participants