Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 93 additions & 10 deletions experimental/apps-mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,38 +17,50 @@ A Model Context Protocol (MCP) server for working with Databricks through natura
- **Conversational interface**: Work with Databricks using natural language instead of memorizing CLI commands
- **Context-aware**: Get relevant command suggestions based on your workspace configuration
- **Unified workflow**: Combine data exploration, bundle management, and app deployment in one tool
- **Transparency**: Every MCP tool call displays clear, branded output so you always know when Databricks MCP is working

Perfect for data engineers and developers who want to streamline their Databricks workflows with AI-powered assistance.

**Visual Feedback:**
When using Databricks MCP, you'll see distinctive branded headers in your chat:
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
πŸš€ Databricks MCP: App scaffolded successfully
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```

This makes it immediately clear you're using the Databricks MCP server, not just plain Claude or Cursor. If you don't see these headers, the MCP server isn't connected (see Troubleshooting below).

---

## Getting Started

### Quick Setup (Recommended)

1. **Set up Databricks credentials** (required for Databricks tools):
```bash
export DATABRICKS_HOST="https://your-workspace.databricks.com"
export DATABRICKS_TOKEN="dapi..."
export DATABRICKS_WAREHOUSE_ID="your-warehouse-id"
```

2. **Install the MCP server automatically:**
1. **Install the MCP server automatically:**
```bash
databricks experimental apps-mcp install
```

This interactive command will:
- Automatically detect Claude Code and Cursor installations
- Configure the MCP server with proper settings
- Configure the MCP server with proper settings (including credentials)
- Set up the server at user scope (available in all projects)
- Show manual instructions for other agents if needed

3. **Restart your MCP client** (Claude Code, Cursor, etc.) for changes to take effect.
2. **Restart your MCP client** (Claude Code, Cursor, etc.) for changes to take effect.

3. **Verify the connection:**
```
claude /mcp
```

The databricks MCP server should be listed in "connected" state. If it doesn't show up or appears disconnected, see the Troubleshooting section below.

4. **Create your first Databricks app:**

Try this in your MCP client:

```
Explore my Databricks workspace and show me what catalogs are available
```
Expand All @@ -69,6 +81,13 @@ Perfect for data engineers and developers who want to streamline their Databrick

If you prefer to configure manually or the automatic installation doesn't work:

**Set up Databricks credentials** (required for Databricks tools):
```bash
export DATABRICKS_HOST="https://your-workspace.databricks.com"
export DATABRICKS_TOKEN="dapi..."
export DATABRICKS_WAREHOUSE_ID="your-warehouse-id"
```

**Add to your MCP config file** (e.g., `~/.claude.json` for global scope):
```json
{
Expand All @@ -90,6 +109,70 @@ Then restart your MCP client for changes to take effect

---

### Troubleshooting

#### 🚨 Not seeing Databricks MCP headers in your chat?

If you ask about Databricks or apps but **don't see the distinctive headers** like:
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
πŸš€ Databricks MCP: App scaffolded successfully
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```

**You're using plain Claude/Cursor, not the Databricks MCP server!** This means:
- ❌ No access to Databricks data or tools
- ❌ Generic AI responses instead of actual app generation
- ❌ No scaffolding, validation, or deployment capabilities

**Fix it:** Follow the troubleshooting steps below to connect the MCP server.

---

#### General Troubleshooting

If the MCP server doesn't connect or shows errors:

1. **Check MCP server status:**
```
claude /mcp
```
Look for the databricks server - it should show "connected"

2. **Verify credentials:** Make sure your environment variables are set correctly:
```bash
echo $DATABRICKS_HOST
echo $DATABRICKS_WAREHOUSE_ID
# Don't echo token for security
```

3. **Check configuration file:** Verify the MCP server is properly configured in your `~/.claude.json`:
```bash
cat ~/.claude.json | grep -A 10 databricks
```

4. **Restart your MCP client:** After making configuration changes, always restart your client

5. **Check Databricks CLI:** Verify the CLI is installed and accessible:
```bash
databricks --version
databricks experimental apps-mcp --help
```

6. **Test authentication:** Try listing catalogs to verify credentials work:
```bash
databricks catalogs list
```

7. **Ask Claude for help:** Claude can often diagnose and fix MCP connection issues. Try:
```
My databricks MCP server isn't connecting. Can you help troubleshoot?
```

If issues persist, please report them at https://github.com/databricks/cli/issues

---

## Features

The Databricks MCP server provides CLI-based tools for workspace interaction:
Expand Down
22 changes: 22 additions & 0 deletions experimental/apps-mcp/cmd/init_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"path/filepath"

"github.com/databricks/cli/cmd/root"
"github.com/databricks/cli/experimental/apps-mcp/lib/common"
"github.com/databricks/cli/libs/cmdio"
"github.com/databricks/cli/libs/template"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -204,6 +205,27 @@ See https://docs.databricks.com/en/dev-tools/bundles/templates.html for more inf
}
tmpl.Writer.LogTelemetry(ctx)

// Show branded success message
templateName := "bundle"
if templatePathOrUrl != "" {
templateName = filepath.Base(templatePathOrUrl)
}
outputPath := outputDir
if outputPath == "" {
outputPath = "."
}
// Count files if we can
fileCount := 0
if absPath, err := filepath.Abs(outputPath); err == nil {
_ = filepath.Walk(absPath, func(path string, info os.FileInfo, err error) error {
if err == nil && !info.IsDir() {
fileCount++
}
return nil
})
}
cmdio.LogString(ctx, common.FormatScaffoldSuccess(templateName, outputPath, fileCount))

// Try to read and display CLAUDE.md if present
readClaudeMd(ctx, configFile)

Expand Down
47 changes: 47 additions & 0 deletions experimental/apps-mcp/lib/common/output.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package common

import "fmt"

const (
headerLine = "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
)

// FormatBrandedHeader creates a branded header with the given emoji and message.
func FormatBrandedHeader(emoji, message string) string {
return fmt.Sprintf("%s\n%s Databricks MCP: %s\n%s\n\n",
headerLine, emoji, message, headerLine)
}

// FormatScaffoldSuccess formats a success message for app scaffolding.
func FormatScaffoldSuccess(templateName, workDir string, filesCopied int) string {
header := FormatBrandedHeader("πŸš€", "App scaffolded successfully")
return fmt.Sprintf("%sβœ… Created %s application at %s\n\nFiles copied: %d\n\nTemplate: %s\n",
header, templateName, workDir, filesCopied, templateName)
}

// FormatValidationSuccess formats a success message for validation.
func FormatValidationSuccess(message string) string {
header := FormatBrandedHeader("πŸ”", "Validating your app")
return fmt.Sprintf("%sβœ… %s\n", header, message)
}

// FormatValidationFailure formats a failure message for validation.
func FormatValidationFailure(message string, exitCode int, stdout, stderr string) string {
header := FormatBrandedHeader("πŸ”", "Validating your app")
return fmt.Sprintf("%s❌ %s\n\nExit code: %d\n\nStdout:\n%s\n\nStderr:\n%s\n",
header, message, exitCode, stdout, stderr)
}

// FormatDeploymentSuccess formats a success message for deployment.
func FormatDeploymentSuccess(appName, appURL string) string {
header := FormatBrandedHeader("🚒", "Deploying to production")
return fmt.Sprintf("%sβœ… App '%s' deployed successfully!\n\n🌐 URL: %s\n",
header, appName, appURL)
}

// FormatDeploymentFailure formats a failure message for deployment.
func FormatDeploymentFailure(appName, message string) string {
header := FormatBrandedHeader("🚒", "Deploying to production")
return fmt.Sprintf("%s❌ Deployment failed for '%s'\n\n%s\n",
header, appName, message)
}
110 changes: 110 additions & 0 deletions experimental/apps-mcp/lib/common/output_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package common

import (
"strings"
"testing"
)

func TestFormatBrandedHeader(t *testing.T) {
result := FormatBrandedHeader("πŸš€", "Test message")

// Check for key components
if !strings.Contains(result, "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━") {
t.Error("Missing header line")
}
if !strings.Contains(result, "πŸš€ Databricks MCP: Test message") {
t.Error("Missing branded message")
}
}

func TestFormatScaffoldSuccess(t *testing.T) {
result := FormatScaffoldSuccess("appkit", "/path/to/app", 42)

// Check for key components
if !strings.Contains(result, "πŸš€ Databricks MCP") {
t.Error("Missing branded header")
}
if !strings.Contains(result, "βœ…") {
t.Error("Missing success checkmark")
}
if !strings.Contains(result, "appkit") {
t.Error("Missing template name")
}
if !strings.Contains(result, "/path/to/app") {
t.Error("Missing work directory")
}
if !strings.Contains(result, "42") {
t.Error("Missing file count")
}
}

func TestFormatValidationSuccess(t *testing.T) {
result := FormatValidationSuccess("All checks passed")

if !strings.Contains(result, "πŸ” Databricks MCP") {
t.Error("Missing branded header")
}
if !strings.Contains(result, "βœ…") {
t.Error("Missing success checkmark")
}
if !strings.Contains(result, "All checks passed") {
t.Error("Missing success message")
}
}

func TestFormatValidationFailure(t *testing.T) {
result := FormatValidationFailure("Build failed", 1, "stdout output", "stderr output")

if !strings.Contains(result, "πŸ” Databricks MCP") {
t.Error("Missing branded header")
}
if !strings.Contains(result, "❌") {
t.Error("Missing failure mark")
}
if !strings.Contains(result, "Build failed") {
t.Error("Missing failure message")
}
if !strings.Contains(result, "Exit code: 1") {
t.Error("Missing exit code")
}
if !strings.Contains(result, "stdout output") {
t.Error("Missing stdout")
}
if !strings.Contains(result, "stderr output") {
t.Error("Missing stderr")
}
}

func TestFormatDeploymentSuccess(t *testing.T) {
result := FormatDeploymentSuccess("my-app", "https://example.com/app")

if !strings.Contains(result, "🚒 Databricks MCP") {
t.Error("Missing branded header")
}
if !strings.Contains(result, "βœ…") {
t.Error("Missing success checkmark")
}
if !strings.Contains(result, "my-app") {
t.Error("Missing app name")
}
if !strings.Contains(result, "https://example.com/app") {
t.Error("Missing app URL")
}
}

func TestFormatDeploymentFailure(t *testing.T) {
result := FormatDeploymentFailure("my-app", "Connection timeout")

if !strings.Contains(result, "🚒 Databricks MCP") {
t.Error("Missing branded header")
}
if !strings.Contains(result, "❌") {
t.Error("Missing failure mark")
}
if !strings.Contains(result, "my-app") {
t.Error("Missing app name")
}
if !strings.Contains(result, "Connection timeout") {
t.Error("Missing error message")
}
}
12 changes: 7 additions & 5 deletions experimental/apps-mcp/lib/providers/doc.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
/*
Package providers contains MCP tool providers.

Each provider implements a set of related tools:
The clitools provider implements CLI-based tools for Databricks integration:

- databricks: Databricks API integration
- io: Project scaffolding and validation
- clitools: CLI exploration and invocation
- deployment: Application deployment (optional)
- explore: Discover workspace resources and get workflow recommendations
- invoke_databricks_cli: Execute Databricks CLI commands
- databricks_configure_auth: Configure workspace authentication

Provider Interface:

Expand All @@ -16,5 +15,8 @@ Provider Interface:

Providers are registered with the MCP server during initialization
and their tools become available to AI agents.

The CLI-based approach leverages existing bundle commands for app
scaffolding, validation, and deployment rather than duplicating API logic.
*/
package providers
Loading