hex-mcp MCP server
A MCP server for Hex that implements orchestration, monitoring, cell content access, permission management, collection organization, and group management tools.
What This Does (And Doesn't Do)
Practical Use Cases
Orchestration and Automation:
Trigger Hex project runs from external systems (Airflow DAGs, CI/CD pipelines)
Monitor run status programmatically
Cancel long-running or stuck executions
Discover and search projects across workspaces
Operational Monitoring:
Check if scheduled runs completed successfully
Get run history for auditing
Programmatic access to project metadata (owner, last edited, description)
Cell Content Access (NEW):
Read notebook structure and cell metadata
Read SQL query source code from SQL cells
Read Python/R code from CODE cells
Good for query migration, code analysis, and content auditing
Permission Management (NEW):
Programmatically manage user and group access to projects
Bulk update permissions across multiple projects
Manage workspace-wide and public access settings
Add or remove projects from collections
Collection Organization (NEW):
Create and manage collections for organizing projects
Organize projects by department, team, or topic
Control collection visibility and access
Bulk organize projects into collections
Group Management (NEW):
Create and manage user groups for permission management
Add and remove users from groups in bulk
Use groups to simplify permission management across projects
Maintain organized team structures
Data Connection Management (NEW):
List and manage database and warehouse connections
Create connections for BigQuery, Snowflake, Postgres, Redshift, Athena, Databricks
Update connection configurations and credentials
Control data connection sharing across workspace
Critical Limitations
Limited notebook content access:
✅ Can read SQL and CODE cell source content
❌ Cannot read MARKDOWN, INPUT, or visualization cells
❌ Cannot create or delete cells
❌ Cannot modify notebook structure
❌ Cannot view query results or charts
❌ Cannot manage notebook dependencies or parameters
Not suitable for:
Building or authoring notebooks from scratch
Collaborative notebook development
Debugging queries or code execution
Full notebook backup (only SQL/CODE cells accessible)
Reading markdown documentation or input parameters
When to Use This
Use hex-mcp when you need to:
Orchestrate Hex executions from external systems
Monitor run status and history
Read SQL queries and code from existing notebooks
Audit or migrate SQL/CODE content across projects
Manage permissions and access control across projects
Automate bulk permission updates for users, groups, and collections
Organize projects into collections by department, team, or topic
Maintain user groups for simplified permission management
Standardize workspace organization across your Hex instance
Manage data connections and database integrations programmatically
Automate connection setup for new workspaces or environments
For full notebook development and editing, use the Hex web UI directly.
Related MCP server: Unity MCP Integration
Available Tools
Project Operations
list_hex_projects: Lists available Hex projects
search_hex_projects: Search for Hex projects by pattern
get_hex_project: Get detailed information about a specific project
Project Execution
run_hex_project: Execute a Hex project
get_hex_run_status: Check the status of a project run
get_hex_project_runs: Get the history of project runs
cancel_hex_run: Cancel a running project
Cell Operations (NEW)
Permission Management (NEW)
update_hex_project_user_sharing: Grant or revoke user access to projects
update_hex_project_group_sharing: Grant or revoke group access to projects
update_hex_project_collection_sharing: Add or remove projects from collections
update_hex_project_workspace_sharing: Update workspace-wide and public access
Collection Management (NEW)
list_hex_collections: List all collections in the workspace
get_hex_collection: Get detailed information about a specific collection
create_hex_collection: Create a new collection with optional sharing settings
update_hex_collection: Update collection name, description, or sharing settings
Group Management (NEW)
list_hex_groups: List all groups in the workspace
get_hex_group: Get detailed information about a specific group
create_hex_group: Create a new group with optional initial members
update_hex_group: Update group name and/or membership (add/remove users)
delete_hex_group: Delete a group from the workspace
Data Connection Management (NEW)
list_hex_data_connections: List all data connections in the workspace
get_hex_data_connection: Get detailed information about a specific data connection
create_hex_data_connection: Create a new database/warehouse connection
update_hex_data_connection: Update connection configuration, credentials, or sharing
Installation
Using uv is the recommended way to install hex-mcp:
Or using pip:
To confirm it's working, you can run:
Configuration
Using the config command (recommended)
The easiest way to configure hex-mcp is by using the config command and passing your API key and API URL (optional and defaults to https://app.hex.tech/api/v1):
hex-mcp config --api-key "your_hex_api_key" --api-url "https://app.hex.tech/api/v1"
NOTE
This saves your configuration to a file in your home directory (e.g.~/.hex-mcp/config.yml), making it available for all hex-mcp invocations.
Using environment variables
Alternatively, the Hex MCP server can be configured with environment variables:
When setting up environment variables for MCP servers they need to be either global for Cursor to pick them up or make use of uv's --env-file flag when invoking the server.
Using with Cursor
Cursor allows AI agents to interact with Hex via the MCP protocol. Follow these steps to set up and use hex-mcp with Cursor. You can create a .cursor/mcp.json file in your project root with the following content:
{
"mcpServers": {
"hex-mcp": {
"command": "uv",
"args": ["run", "hex-mcp", "run"]
}
}
}
Alternatively, you can use the hex-mcp command directly if it's in your PATH:
{
"mcpServers": {
"hex-mcp": {
"command": "hex-mcp",
"args": ["run"]
}
}
}
Once it's up and running, you can use it in Cursor by initiating a new AI (Agent) conversation and ask it to list or run a Hex project.
IMPORTANT
The MCP server and CLI is still in development and subject to breaking changes.
Usage Examples
Reading Cell Content
Use list_hex_cells to read the structure and source code of a Hex notebook:
# List all cells in a project
cells = list_hex_cells(project_id="your-project-uuid")
# The response includes cell metadata and source code for SQL/CODE cells
# Example response structure:
{
"values": [
{
"id": "cell-uuid-123",
"staticId": "static-id-456",
"cellType": "SQL",
"label": "Load Customer Data",
"dataConnectionId": "connection-uuid-789",
"contents": {
"sqlCell": {
"source": "SELECT * FROM customers WHERE active = true"
},
"codeCell": null
}
},
{
"id": "cell-uuid-456",
"cellType": "CODE",
"label": "Process Data",
"dataConnectionId": null,
"contents": {
"sqlCell": null,
"codeCell": {
"source": "import pandas as pd\ndf = df.dropna()"
}
}
},
{
"id": "cell-uuid-789",
"cellType": "MARKDOWN",
"label": "Documentation",
"dataConnectionId": null,
"contents": {
"sqlCell": null,
"codeCell": null
}
}
],
"pagination": {
"next": null,
"previous": null
}
}
Note: Only SQL and CODE cells include source content. MARKDOWN, INPUT, and visualization cells return null for both sqlCell and codeCell.
For projects with many cells, use pagination:
# First page
page1 = list_hex_cells(project_id="your-project-uuid", limit=50)
# Next page using cursor
if page1["pagination"]["next"]:
page2 = list_hex_cells(
project_id="your-project-uuid",
limit=50,
after=page1["pagination"]["next"]
)
# Previous page
if page2["pagination"]["previous"]:
page1_again = list_hex_cells(
project_id="your-project-uuid",
limit=50,
before=page2["pagination"]["previous"]
)
Updating Cell Content
Update SQL or CODE cells programmatically:
# Update SQL cell source code
result = update_hex_cell(
cell_id="cell-uuid-123",
sql_source="SELECT * FROM updated_table WHERE active = true"
)
# Update CODE cell source code
result = update_hex_cell(
cell_id="cell-uuid-456",
code_source="import pandas as pd\ndf = df.dropna()"
)
# Update SQL cell data connection (without changing source)
result = update_hex_cell(
cell_id="cell-uuid-123",
data_connection_id="new-connection-uuid"
)
# Update both SQL source and connection in one call
result = update_hex_cell(
cell_id="cell-uuid-123",
sql_source="SELECT * FROM production.customers",
data_connection_id="production-connection-uuid"
)
Important:
Can only update SQL and CODE cell types
Cannot update MARKDOWN, INPUT, or visualization cells
Requires EDIT_PROJECT_CONTENTS permission
Cannot update both sql_source and code_source in same call (cells are either SQL or CODE)
Query Migration Example
Extract and update SQL queries across projects:
import json
# Get all cells from source project
cells_response = list_hex_cells(project_id="source-project-uuid")
cells = json.loads(cells_response)
# Filter for SQL cells
sql_cells = [
cell for cell in cells["values"]
if cell["cellType"] == "SQL" and cell["contents"]["sqlCell"]
]
# Migrate queries to new data connection
new_connection_id = "production-bigquery-connection"
for cell in sql_cells:
original_query = cell["contents"]["sqlCell"]["source"]
# Update table references (example: dev -> prod)
updated_query = original_query.replace("dev.schema", "prod.schema")
# Update the cell with new query and connection
result = update_hex_cell(
cell_id=cell["id"],
sql_source=updated_query,
data_connection_id=new_connection_id
)
print(f"Updated cell: {cell['label']}")
print(f"Migrated {len(sql_cells)} SQL cells to production")
Code Refactoring Example
Bulk update Python code across multiple cells:
import json
# Get all CODE cells
cells_response = list_hex_cells(project_id="project-uuid")
cells = json.loads(cells_response)
code_cells = [
cell for cell in cells["values"]
if cell["cellType"] == "CODE" and cell["contents"]["codeCell"]
]
# Update import statements
for cell in code_cells:
original_code = cell["contents"]["codeCell"]["source"]
# Replace deprecated import
if "from old_library" in original_code:
updated_code = original_code.replace(
"from old_library import func",
"from new_library import func"
)
# Update the cell
result = update_hex_cell(
cell_id=cell["id"],
code_source=updated_code
)
print(f"Updated cell: {cell['label']}")
Managing Project Permissions
Control access to Hex projects programmatically using the sharing endpoints.
Grant User Access
from hex_mcp.server import update_hex_project_user_sharing
# Grant edit access to a single user
result = update_hex_project_user_sharing(
project_id="project-123",
user_permissions=[
{"user_id": "user-456", "access": "CAN_EDIT"}
]
)
# Grant access to multiple users with different permissions
result = update_hex_project_user_sharing(
project_id="project-123",
user_permissions=[
{"user_id": "user-001", "access": "CAN_VIEW"},
{"user_id": "user-002", "access": "CAN_EDIT"},
{"user_id": "user-003", "access": "FULL_ACCESS"}
]
)
# Revoke user access
result = update_hex_project_user_sharing(
project_id="project-123",
user_permissions=[
{"user_id": "user-456", "access": "NONE"}
]
)
Access Levels:
NONE: Revoke all access
APP_ONLY: Access only within apps (published versions)
CAN_VIEW: View project in logic view (read-only)
CAN_EDIT: Edit project contents
FULL_ACCESS: Edit contents and manage project settings/permissions
Grant Group Access
from hex_mcp.server import update_hex_project_group_sharing
# Grant access to a group
result = update_hex_project_group_sharing(
project_id="project-123",
group_permissions=[
{"group_id": "group-789", "access": "CAN_VIEW"}
]
)
# Grant access to multiple groups
result = update_hex_project_group_sharing(
project_id="project-123",
group_permissions=[
{"group_id": "analytics-team", "access": "CAN_EDIT"},
{"group_id": "leadership-team", "access": "CAN_VIEW"}
]
)
Add Projects to Collections
from hex_mcp.server import update_hex_project_collection_sharing
# Add project to a collection
result = update_hex_project_collection_sharing(
project_id="project-123",
collection_permissions=[
{"collection_id": "collection-456", "access": "CAN_VIEW"}
]
)
# Add to multiple collections with different access levels
result = update_hex_project_collection_sharing(
project_id="project-123",
collection_permissions=[
{"collection_id": "public-dashboards", "access": "APP_ONLY"},
{"collection_id": "internal-analytics", "access": "CAN_EDIT"}
]
)
# Remove from collection
result = update_hex_project_collection_sharing(
project_id="project-123",
collection_permissions=[
{"collection_id": "collection-456", "access": "NONE"}
]
)
Manage Workspace and Public Access
from hex_mcp.server import update_hex_project_workspace_sharing
# Make project viewable by entire workspace
result = update_hex_project_workspace_sharing(
project_id="project-123",
workspace_access="CAN_VIEW"
)
# Make project publicly accessible
result = update_hex_project_workspace_sharing(
project_id="project-123",
public_access="APP_ONLY"
)
# Update both workspace and public access
result = update_hex_project_workspace_sharing(
project_id="project-123",
workspace_access="CAN_EDIT",
public_access="APP_ONLY"
)
# Revoke public access (keep workspace access)
result = update_hex_project_workspace_sharing(
project_id="project-123",
public_access="NONE"
)
Bulk Permission Management Example
Standardize permissions across multiple projects:
import json
from hex_mcp.server import (
list_hex_projects,
update_hex_project_user_sharing,
update_hex_project_workspace_sharing
)
# Get all projects
projects_response = list_hex_projects()
projects = json.loads(projects_response)
# Define standard access policies
analytics_team_users = ["user-001", "user-002", "user-003"]
leadership_users = ["user-100", "user-101"]
for project in projects:
project_id = project["projectId"]
# Grant analytics team edit access
update_hex_project_user_sharing(
project_id=project_id,
user_permissions=[
{"user_id": user_id, "access": "CAN_EDIT"}
for user_id in analytics_team_users
]
)
# Grant leadership view access
update_hex_project_user_sharing(
project_id=project_id,
user_permissions=[
{"user_id": user_id, "access": "CAN_VIEW"}
for user_id in leadership_users
]
)
# Make viewable by workspace, not public
update_hex_project_workspace_sharing(
project_id=project_id,
workspace_access="CAN_VIEW",
public_access="NONE"
)
print(f"Updated permissions for: {project['name']}")
Important Notes:
All sharing operations require appropriate workspace permissions
User/group IDs must exist in your Hex workspace
Collection IDs must be valid collections you have access to
Workspace access applies to all workspace members
Public access (publicWeb) allows anyone with the link to access
Managing Collections
Organize projects into collections for better workspace organization.
List Collections
from hex_mcp.server import list_hex_collections
import json
# List all collections
collections = list_hex_collections()
data = json.loads(collections)
for collection in data["values"]:
print(f"{collection['name']}: {collection['id']}")
print(f" Created by: {collection.get('creator', {}).get('email', 'N/A')}")
# List with pagination
page1 = list_hex_collections(limit=10)
data = json.loads(page1)
if data["pagination"]["next"]:
page2 = list_hex_collections(limit=10, after=data["pagination"]["next"])
Get Collection Details
from hex_mcp.server import get_hex_collection
import json
# Get specific collection
collection = get_hex_collection(collection_id="collection-123")
data = json.loads(collection)
print(f"Collection: {data['name']}")
print(f"Description: {data.get('description', 'No description')}")
print(f"Sharing with {len(data['sharing'].get('users', []))} users")
print(f"Sharing with {len(data['sharing'].get('groups', []))} groups")
Create Collections
from hex_mcp.server import create_hex_collection
import json
# Create simple collection
collection = create_hex_collection(
name="Q4 2026 Analytics",
description="Analytics projects for Q4 2026"
)
data = json.loads(collection)
print(f"Created collection: {data['id']}")
# Create with sharing settings
collection = create_hex_collection(
name="Executive Dashboards",
description="Dashboards for executive team",
sharing_users=[
{"id": "user-ceo", "access": "CAN_VIEW"},
{"id": "user-cfo", "access": "CAN_VIEW"}
],
workspace_access="NONE" # Only specified users can access
)
# Create with group access
collection = create_hex_collection(
name="Finance Reports",
description="Financial reporting and analysis",
sharing_groups=[
{"id": "finance-team", "access": "CAN_EDIT"}
],
workspace_access="CAN_VIEW"
)
Update Collections
from hex_mcp.server import update_hex_collection
import json
# Update collection name and description
result = update_hex_collection(
collection_id="collection-123",
name="Q1 2027 Analytics",
description="Updated for Q1 2027"
)
# Update sharing settings
result = update_hex_collection(
collection_id="collection-123",
sharing_users=[
{"id": "user-456", "access": "CAN_EDIT"}
],
workspace_access="CAN_VIEW"
)
# Update multiple fields at once
result = update_hex_collection(
collection_id="collection-123",
name="Updated Collection Name",
description="Updated description",
sharing_groups=[
{"id": "analytics-team", "access": "CAN_EDIT"}
],
workspace_access="CAN_VIEW"
)
Collection Organization Example
Organize all projects by department:
import json
from hex_mcp.server import (
list_hex_projects,
list_hex_collections,
create_hex_collection,
update_hex_project_collection_sharing
)
# Define department structure
departments = {
"Engineering": ["user-eng-lead", "group-engineering"],
"Finance": ["user-fin-lead", "group-finance"],
"Marketing": ["user-mkt-lead", "group-marketing"]
}
# Create collections for each department
collection_ids = {}
for dept_name, members in departments.items():
# Create collection
collection = create_hex_collection(
name=f"{dept_name} Projects",
description=f"All {dept_name} department projects",
workspace_access="CAN_VIEW"
)
data = json.loads(collection)
collection_ids[dept_name] = data["id"]
print(f"Created collection for {dept_name}: {data['id']}")
# Get all projects
projects = list_hex_projects()
projects_data = json.loads(projects)
# Organize projects into collections based on name patterns
for project in projects_data:
project_id = project["projectId"]
project_name = project["name"].lower()
# Determine which collection(s) this project belongs to
if "engineering" in project_name or "technical" in project_name:
update_hex_project_collection_sharing(
project_id=project_id,
collection_permissions=[
{"collection_id": collection_ids["Engineering"], "access": "CAN_EDIT"}
]
)
print(f"Added '{project['name']}' to Engineering collection")
elif "finance" in project_name or "revenue" in project_name:
update_hex_project_collection_sharing(
project_id=project_id,
collection_permissions=[
{"collection_id": collection_ids["Finance"], "access": "CAN_EDIT"}
]
)
print(f"Added '{project['name']}' to Finance collection")
elif "marketing" in project_name or "campaign" in project_name:
update_hex_project_collection_sharing(
project_id=project_id,
collection_permissions=[
{"collection_id": collection_ids["Marketing"], "access": "CAN_EDIT"}
]
)
print(f"Added '{project['name']}' to Marketing collection")
print("Collection organization complete!")
Collection Management Notes:
Collections help organize projects by team, department, or topic
Collections can have their own sharing settings independent of projects
A project can belong to multiple collections
Workspace access on collections controls who can see the collection exists
Creating collections requires appropriate workspace permissions
Managing Groups
Organize users into groups for simplified permission management.
List Groups
from hex_mcp.server import list_hex_groups
import json
# List all groups
groups = list_hex_groups()
data = json.loads(groups)
for group in data["values"]:
print(f"{group['name']}: {group['id']}")
print(f" Created: {group['createdAt']}")
# List with pagination and sorting
page1 = list_hex_groups(
limit=10,
sort_by="name",
sort_direction="asc"
)
data = json.loads(page1)
if data["pagination"]["next"]:
page2 = list_hex_groups(limit=10, after=data["pagination"]["next"])
Get Group Details
from hex_mcp.server import get_hex_group
import json
# Get specific group
group = get_hex_group(group_id="group-123")
data = json.loads(group)
print(f"Group: {data['name']}")
print(f"ID: {data['id']}")
print(f"Created: {data['createdAt']}")
Create Groups
from hex_mcp.server import create_hex_group
import json
# Create simple group
group = create_hex_group(name="Analytics Team")
data = json.loads(group)
print(f"Created group: {data['id']}")
# Create with initial members
group = create_hex_group(
name="Finance Team",
member_user_ids=[
"user-123",
"user-456",
"user-789"
]
)
data = json.loads(group)
print(f"Created group with 3 members: {data['id']}")
Update Groups
from hex_mcp.server import update_hex_group
import json
# Update group name
result = update_hex_group(
group_id="group-123",
name="Senior Analytics Team"
)
# Add members to group
result = update_hex_group(
group_id="group-123",
add_member_user_ids=["user-new-1", "user-new-2"]
)
# Remove members from group
result = update_hex_group(
group_id="group-123",
remove_member_user_ids=["user-old-1"]
)
# Update name and membership together
result = update_hex_group(
group_id="group-123",
name="Lead Analytics Team",
add_member_user_ids=["user-lead"],
remove_member_user_ids=["user-junior"]
)
Delete Groups
from hex_mcp.server import delete_hex_group
# Delete a group (does not delete the users, only the group)
result = delete_hex_group(group_id="group-old-team")
print(result) # "Group deleted successfully"
Bulk Group Management Example
Create department-based groups and assign users:
import json
from hex_mcp.server import (
create_hex_group,
update_hex_group,
update_hex_project_group_sharing
)
# Define department structure with user lists
departments = {
"Engineering": {
"leads": ["user-eng-lead-1", "user-eng-lead-2"],
"members": ["user-eng-1", "user-eng-2", "user-eng-3"]
},
"Data Science": {
"leads": ["user-ds-lead"],
"members": ["user-ds-1", "user-ds-2", "user-ds-3", "user-ds-4"]
},
"Analytics": {
"leads": ["user-analytics-lead"],
"members": ["user-analyst-1", "user-analyst-2"]
}
}
# Create groups for each department
group_ids = {}
for dept_name, users in departments.items():
# Create main department group
all_members = users["leads"] + users["members"]
group = create_hex_group(
name=f"{dept_name} Team",
member_user_ids=all_members
)
data = json.loads(group)
group_ids[dept_name] = data["id"]
print(f"Created {dept_name} Team: {data['id']} ({len(all_members)} members)")
# Create leadership sub-group
lead_group = create_hex_group(
name=f"{dept_name} Leadership",
member_user_ids=users["leads"]
)
lead_data = json.loads(lead_group)
group_ids[f"{dept_name}_Leadership"] = lead_data["id"]
print(f"Created {dept_name} Leadership: {lead_data['id']} ({len(users['leads'])} members)")
# Grant group access to relevant projects
# Engineering team gets edit access to technical projects
update_hex_project_group_sharing(
project_id="technical-project-123",
group_permissions=[
{"group_id": group_ids["Engineering"], "access": "CAN_EDIT"}
]
)
# Analytics team gets view access to all dashboards
update_hex_project_group_sharing(
project_id="dashboard-project-456",
group_permissions=[
{"group_id": group_ids["Analytics"], "access": "CAN_VIEW"}
]
)
# Leadership groups get view access to executive dashboards
for dept in ["Engineering", "Data Science", "Analytics"]:
leadership_group_id = group_ids[f"{dept}_Leadership"]
update_hex_project_group_sharing(
project_id="executive-dashboard-789",
group_permissions=[
{"group_id": leadership_group_id, "access": "CAN_VIEW"}
]
)
print("Group-based permission management complete!")
Team Reorganization Example
Handle team changes by updating group memberships:
import json
from hex_mcp.server import (
list_hex_groups,
update_hex_group
)
# Get all groups
groups = list_hex_groups()
groups_data = json.loads(groups)
# Find specific groups that need updates
engineering_group = None
for group in groups_data["values"]:
if group["name"] == "Engineering Team":
engineering_group = group
break
if engineering_group:
# New hires joining
new_engineers = ["user-new-eng-1", "user-new-eng-2"]
# Engineers leaving
departing_engineers = ["user-old-eng-1"]
# Update group membership
result = update_hex_group(
group_id=engineering_group["id"],
add_member_user_ids=new_engineers,
remove_member_user_ids=departing_engineers
)
print(f"Updated {engineering_group['name']}")
print(f" Added: {len(new_engineers)} members")
print(f" Removed: {len(departing_engineers)} members")
Group Management Notes:
Groups simplify permission management by allowing you to grant access to multiple users at once
A user can belong to multiple groups
Maximum 100 users can be added or removed in a single update operation
Deleting a group does not delete the users, only the group itself
Group permissions are inherited by all group members
Use groups with project sharing endpoints to grant team-wide access
Managing Data Connections
Manage database and warehouse connections for Hex projects.
List Data Connections
from hex_mcp.server import list_hex_data_connections
import json
# List all data connections
connections = list_hex_data_connections()
data = json.loads(connections)
for conn in data["values"]:
print(f"{conn['name']} ({conn['type']}): {conn['id']}")
if conn.get('description'):
print(f" Description: {conn['description']}")
# List with pagination and sorting
page1 = list_hex_data_connections(
limit=10,
sort_by="NAME",
sort_direction="asc"
)
data = json.loads(page1)
if data["pagination"]["next"]:
page2 = list_hex_data_connections(limit=10, after=data["pagination"]["next"])
Get Data Connection Details
from hex_mcp.server import get_hex_data_connection
import json
# Get specific connection
connection = get_hex_data_connection(connection_id="conn-123")
data = json.loads(connection)
print(f"Connection: {data['name']}")
print(f"Type: {data['type']}")
print(f"Description: {data.get('description', 'N/A')}")
print(f"Include Magic: {data.get('includeMagic', False)}")
print(f"Allow Writeback: {data.get('allowWritebackCells', False)}")
# Check sharing settings
if 'sharing' in data:
workspace = data['sharing'].get('workspace', {})
print(f"Workspace Access: {workspace.get('members', 'None')}")
Create Data Connections
from hex_mcp.server import create_hex_data_connection
import json
# Create BigQuery connection
bigquery_conn = create_hex_data_connection(
name="Production BigQuery",
connection_type="bigquery",
connection_details={
"bigquery": {
"serviceAccountJsonConfig": json.dumps(service_account_config),
"projectId": "my-gcp-project",
"enableStorageApi": True,
"enableDriveAccess": False
}
},
description="Production data warehouse for analytics",
include_magic=True,
allow_writeback_cells=False,
sharing={
"workspace": {
"members": "CAN_USE"
}
}
)
data = json.loads(bigquery_conn)
print(f"Created BigQuery connection: {data['id']}")
# Create Snowflake connection
snowflake_conn = create_hex_data_connection(
name="Snowflake Analytics",
connection_type="snowflake",
connection_details={
"snowflake": {
"account": "my-account",
"warehouse": "ANALYTICS_WH",
"database": "ANALYTICS_DB",
"schema": "PUBLIC",
"username": "hex_service",
"password": "secure_password"
}
},
description="Snowflake warehouse for analytics",
include_magic=True
)
data = json.loads(snowflake_conn)
print(f"Created Snowflake connection: {data['id']}")
# Create Postgres connection
postgres_conn = create_hex_data_connection(
name="Application Database",
connection_type="postgres",
connection_details={
"postgres": {
"hostname": "db.example.com",
"port": 5432,
"database": "app_db",
"username": "readonly_user",
"password": "secure_password",
"ssl": True
}
},
description="Production application database (read-only)",
connect_via_ssh=False,
include_magic=True,
allow_writeback_cells=False
)
data = json.loads(postgres_conn)
print(f"Created Postgres connection: {data['id']}")
Update Data Connections
from hex_mcp.server import update_hex_data_connection
import json
# Update connection name and description
result = update_hex_data_connection(
connection_id="conn-123",
name="Updated Production BigQuery",
description="Updated production data warehouse for analytics and reporting"
)
data = json.loads(result)
print(f"Updated connection: {data['name']}")
# Update connection settings
result = update_hex_data_connection(
connection_id="conn-123",
include_magic=False,
allow_writeback_cells=True
)
print("Updated connection settings")
# Update connection sharing
result = update_hex_data_connection(
connection_id="conn-123",
sharing={
"workspace": {
"members": "CAN_USE",
"guests": "NONE"
},
"groups": {
"upsert": [
{"group": {"id": "analytics-team-group-id"}, "access": "CAN_USE"},
{"group": {"id": "data-eng-group-id"}, "access": "CAN_ADMIN"}
]
}
}
)
print("Updated connection sharing")
# Rotate credentials by updating connection details
result = update_hex_data_connection(
connection_id="conn-123",
connection_details={
"bigquery": {
"serviceAccountJsonConfig": json.dumps(new_service_account),
"projectId": "my-gcp-project",
"enableStorageApi": True,
"enableDriveAccess": False
}
}
)
print("Rotated connection credentials")
Bulk Connection Setup
Automate connection setup for new workspaces or environments:
from hex_mcp.server import create_hex_data_connection
import json
# Define standard connections for a workspace
connection_configs = {
"Production BigQuery": {
"type": "bigquery",
"details": {
"bigquery": {
"serviceAccountJsonConfig": json.dumps(prod_bq_creds),
"projectId": "prod-project",
"enableStorageApi": True
}
},
"description": "Production BigQuery warehouse"
},
"Staging BigQuery": {
"type": "bigquery",
"details": {
"bigquery": {
"serviceAccountJsonConfig": json.dumps(staging_bq_creds),
"projectId": "staging-project",
"enableStorageApi": True
}
},
"description": "Staging BigQuery warehouse"
},
"Production Snowflake": {
"type": "snowflake",
"details": {
"snowflake": {
"account": "prod-account",
"warehouse": "PROD_WH",
"database": "PROD_DB",
"username": "hex_prod",
"password": prod_sf_password
}
},
"description": "Production Snowflake warehouse"
},
"Application DB": {
"type": "postgres",
"details": {
"postgres": {
"hostname": "prod-db.example.com",
"port": 5432,
"database": "app_db",
"username": "readonly",
"password": postgres_password,
"ssl": True
}
},
"description": "Application database (read-only)"
}
}
# Create all connections
created_connections = {}
for name, config in connection_configs.items():
connection = create_hex_data_connection(
name=name,
connection_type=config["type"],
connection_details=config["details"],
description=config["description"],
include_magic=True,
allow_writeback_cells=False,
sharing={
"workspace": {
"members": "CAN_USE"
}
}
)
data = json.loads(connection)
created_connections[name] = data["id"]
print(f"Created {name}: {data['id']}")
print(f"\nCreated {len(created_connections)} data connections")
Data Connection Management Notes:
Supported connection types: BigQuery, Snowflake, Postgres, Redshift, Athena, Databricks
Each connection type has specific configuration requirements in connection_details
Connection credentials are stored securely by Hex
Use sharing settings to control who can use each connection
CAN_USE access allows users to query data, CAN_ADMIN allows configuration changes
SSH tunneling supported via connect_via_ssh parameter for secure connections
Consider using connection-level access control for sensitive data sources
About This Fork
This fork extends the upstream hex-mcp package with bug fixes and new cell operations functionality.
Bug Fixes (v0.1.10 upstream)
Five tools declared -> str return type but returned Python dicts/lists
Caused pydantic validation errors in Claude Code MCP integration
Fixed by adding json.dumps() to return statements in src/hex_mcp/server.py
Fixed Tools (lines 74, 172, 187, 206, 229):
list_hex_projects()
get_hex_project()
get_hex_run_status()
get_hex_project_runs()
run_hex_project()
New Features
Cell Operations (Phase 1 of complete Hex API implementation):
list_hex_cells() - Read notebook structure and cell source code (SQL/CODE cells)
update_hex_cell() - Update SQL/CODE cell source and data connections
Comprehensive test suite with 29 passing tests (all mocked, no credentials required)
Full documentation with usage examples for query migration and code refactoring
Permission Management (Phase 2 of complete Hex API implementation):
update_hex_project_user_sharing() - Grant or revoke user access to projects
update_hex_project_group_sharing() - Grant or revoke group access to projects
update_hex_project_collection_sharing() - Add or remove projects from collections
update_hex_project_workspace_sharing() - Manage workspace-wide and public access
18 additional passing tests for all sharing scenarios
Complete examples for bulk permission management
Collection Management (Phase 3 of complete Hex API implementation):
list_hex_collections() - List all collections in workspace
get_hex_collection() - Get collection details with sharing settings
create_hex_collection() - Create collections with optional sharing
update_hex_collection() - Update collection metadata and sharing
18 additional passing tests for collection CRUD operations
Complete examples for workspace organization by department
Group Management (Phase 4 of complete Hex API implementation):
list_hex_groups() - List all groups in workspace
get_hex_group() - Get group details
create_hex_group() - Create groups with optional initial members
update_hex_group() - Update group name and membership (add/remove up to 100 users)
delete_hex_group() - Delete groups from workspace
21 additional passing tests for full group CRUD operations
Complete examples for department-based group management and team reorganization
All functions include comprehensive Google-style docstrings
Data Connection Management (Phase 5 of complete Hex API implementation):
list_hex_data_connections() - List all data connections with pagination and sorting
get_hex_data_connection() - Get connection details including credentials and sharing
create_hex_data_connection() - Create BigQuery, Snowflake, Postgres, Redshift, Athena, Databricks connections
update_hex_data_connection() - Update connection configuration, credentials, and sharing settings
18 additional passing tests for data connection CRUD operations
Complete examples for connection setup, credential rotation, and bulk deployment
Support for all 6 major database/warehouse connection types
Full Google-style docstrings with detailed connection type specifications
Testing Infrastructure:
Comprehensive test fixtures with mocked authentication
105 passing tests, 0 skipped (all mocked, no credentials required)
Test coverage growing with each phase
Security checks to prevent production credentials in tests
pytest, pytest-asyncio, pytest-cov integration
Fixed backoff handler to work in both production and test environments
Documentation:
Complete OpenAPI spec analysis (see OPENAPI-VALIDATION.md)
Detailed implementation plan (see IMPLEMENTATION-PLAN.md)
Test strategy guide (see TEST-STRATEGY.md)
Usage examples for all new features
Upstream: https://github.com/franccesco/hex-mcp
Status: Branch bugfix/fast-mcp-return-types includes both bug fixes and new cell operations functionality. Ready for upstream PR submission if desired.