Repository: openops-cloud/openops
Pull request #579: Add superset-mcp and connect chatbot to it
Author: login: MarceloRGonc
Created: 2025-05-13T08:40:38Z | Merged: 2025-05-14T15:34:53Z

Fixes OPS-1723 and OPS-1743.




Diff:
diff --git a/Dockerfile b/Dockerfile
index 092165b7de..e64051cba0 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -7,10 +7,21 @@ ENV LC_ALL=en_US.UTF-8
 ENV NODE_ENV=production
 
 # Use a cache mount for apt to speed up the process
-RUN apk add --no-cache openssh-client python3 g++ git musl libcap-dev nginx gettext wget py3-setuptools make bash findutils && \
-    yarn config set python /usr/bin/python3 && \
-    npm install -g node-gyp npm@9.3.1 cross-env@7.0.3 mint-mcp && \
+RUN <<-```
+    set -ex
+    apk add --no-cache openssh-client python3 g++ git musl libcap-dev nginx gettext wget py3-setuptools make bash findutils
+    yarn config set python /usr/bin/python3
+    npm install -g node-gyp npm@9.3.1 cross-env@7.0.3 mint-mcp
     npx -y mint-mcp add docs.openops.com
+```
+
+WORKDIR /root/.mcp/superset
+RUN <<-```
+    set -ex
+    git clone --depth 1 https://github.com/openops-cloud/superset-mcp .
+    wget -qO- https://astral.sh/uv/install.sh | sh && source $HOME/.local/bin/env
+    uv venv && uv pip install .
+```
 
 # Set up backend
 WORKDIR /usr/src/app
diff --git a/ai-prompts/mcp.txt b/ai-prompts/mcp.txt
index fa6f76bb15..46c916d6da 100644
--- a/ai-prompts/mcp.txt
+++ b/ai-prompts/mcp.txt
@@ -4,7 +4,9 @@ OpenOps is a No-Code FinOps automation platform. It provides customizable workfl
 Core responsibilities:
 1. Parse and understand structured context from OpenOps tools and systems
 2. Maintain consistent context across interactions
-3. If needed, handle invoking different OpenOps MCP (model context protocol) tools (Mintlify Search, OpenOps Tables, OpenOps Analytics, etc.) and process and respond according to MCP protocol specifications
+3. If needed, handle invoking different OpenOps MCP (model context protocol) tools and process and respond according to MCP protocol specifications
+    - Mintlify Search
+    - OpenOps Analytics: An Apache Superset instance
 
 Context handling:
 - Maintain awareness of current block context
@@ -22,4 +24,14 @@ Focus areas:
 - Data platform operations
 - System integrations
 
-Always operate within OpenOps FinOps boundaries while maintaining accurate context awareness for platform operations.
\ No newline at end of file
+Always operate within OpenOps FinOps boundaries while maintaining accurate context awareness for platform operations.
+
+OpenOps Analytics Integration
+When invoking the OpenOps Analytics MCP, you must understand and the Apache Superset REST API. Specifically:
+You must know how to:
+- Query datasets, charts, dashboards, and their metadata
+- Create and update charts or dashboards using appropriate endpoints
+- Format payloads (e.g., params, query_context, position_json) according to Superset's requirements
+- Do not assume column or metric names. Always ensure:
+- Field names match exactly with the dataset schema (case-sensitive)
+- No inferred or aliased column names are used unless explicitly confirmed
diff --git a/packages/server/api/src/app/ai/mcp/mcp-tools.ts b/packages/server/api/src/app/ai/mcp/mcp-tools.ts
index d285517df3..d18d86375a 100644
--- a/packages/server/api/src/app/ai/mcp/mcp-tools.ts
+++ b/packages/server/api/src/app/ai/mcp/mcp-tools.ts
@@ -1,5 +1,5 @@
 import { ToolSet } from 'ai';
-
+import { getSupersetTools } from './superset-tools';
 // import { getDocsTools } from './docs-tools';
 
 let toolSet: ToolSet;
@@ -9,6 +9,7 @@ export const getMCPTools = async (): Promise<ToolSet> => {
   }
 
   toolSet = {
+    ...(await getSupersetTools()),
     // ...(await getDocsTools()),
   };
 
diff --git a/packages/server/api/src/app/ai/mcp/superset-tools.ts b/packages/server/api/src/app/ai/mcp/superset-tools.ts
new file mode 100644
index 0000000000..c50ced1097
--- /dev/null
+++ b/packages/server/api/src/app/ai/mcp/superset-tools.ts
@@ -0,0 +1,33 @@
+import { AppSystemProp, system } from '@openops/server-shared';
+import { experimental_createMCPClient, ToolSet } from 'ai';
+import { Experimental_StdioMCPTransport } from 'ai/mcp-stdio';
+import path from 'path';
+
+export async function getSupersetTools(): Promise<ToolSet> {
+  const basePath = system.get<string>(AppSystemProp.SUPERSET_MCP_SERVER_PATH);
+
+  if (!basePath) {
+    return {};
+  }
+
+  const pythonPath = path.join(basePath, '.venv', 'bin', 'python');
+  const serverPath = path.join(basePath, 'main.py');
+
+  const baseUrl =
+    system.get(AppSystemProp.ANALYTICS_PRIVATE_URL) + '/openops-analytics';
+  const password = system.getOrThrow(AppSystemProp.ANALYTICS_ADMIN_PASSWORD);
+
+  const supersetClient = await experimental_createMCPClient({
+    transport: new Experimental_StdioMCPTransport({
+      command: pythonPath,
+      args: [serverPath],
+      env: {
+        SUPERSET_BASE_URL: baseUrl,
+        SUPERSET_USERNAME: 'admin',
+        SUPERSET_PASSWORD: password,
+      },
+    }),
+  });
+
+  return supersetClient.tools();
+}
diff --git a/packages/server/shared/src/lib/system/system-prop.ts b/packages/server/shared/src/lib/system/system-prop.ts
index 9900ac2de1..0cecf61f6e 100644
--- a/packages/server/shared/src/lib/system/system-prop.ts
+++ b/packages/server/shared/src/lib/system/system-prop.ts
@@ -102,6 +102,7 @@ export enum AppSystemProp {
 
   AI_PROMPTS_LOCATION = 'AI_PROMPTS_LOCATION',
 
+  SUPERSET_MCP_SERVER_PATH = 'SUPERSET_MCP_SERVER_PATH',
   DOCS_MCP_SERVER_PATH = 'DOCS_MCP_SERVER_PATH',
 }
 
diff --git a/packages/server/shared/src/lib/system/system.ts b/packages/server/shared/src/lib/system/system.ts
index 01ec6de599..c6f386d543 100644
--- a/packages/server/shared/src/lib/system/system.ts
+++ b/packages/server/shared/src/lib/system/system.ts
@@ -85,6 +85,7 @@ const systemPropDefaultValues: Partial<Record<SystemProp, string>> = {
   [SharedSystemProp.INTERNAL_PARALLEL_LOOP_ITERATIONS_LIMIT]: '1',
   [AppSystemProp.AI_PROMPTS_LOCATION]:
     'https://raw.githubusercontent.com/openops-cloud/openops/main/ai-prompts',
+  [AppSystemProp.SUPERSET_MCP_SERVER_PATH]: '/root/.mcp/superset',
   [AppSystemProp.DOCS_MCP_SERVER_PATH]: '/root/.mcp/docs.openops.com',
 };
 


Reviews:
user: login: MarceloRGonc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T13:59:14Z
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR introduces support for the Superset MCP server by adding a new system property and integrating a new MCP tools module.  
- Added a new system property (SUPERSET_MCP_SERVER_PATH) with a default value in the system configuration.  
- Implemented the getSupersetTools function to create an MCP client using a defined base path.  
- Refactored the AI chat controller to use getMCPTools instead of a stubbed function.

### Reviewed Changes

Copilot reviewed 5 out of 7 changed files in this pull request and generated 1 comment.

<details>
<summary>Show a summary per file</summary>

| File                                                           | Description                                                      |
| -------------------------------------------------------------- | ---------------------------------------------------------------- |
| packages/server/shared/src/lib/system/system.ts                | Added the new system property for the Superset MCP server path.  |
| packages/server/shared/src/lib/system/system-prop.ts           | Introduced the SUPSERSET_MCP_SERVER_PATH enum value.             |
| packages/server/api/src/app/ai/mcp/superset-tools.ts            | Implemented getSupersetTools to create and return a toolset.       |
| packages/server/api/src/app/ai/mcp/mcp-tools.ts                  | Created a caching layer that wraps getSupersetTools.             |
| packages/server/api/src/app/ai/chat/ai-mcp-chat.controller.ts     | Updated the controller to use the new MCP tools function.         |
</details>


<details>
<summary>Files not reviewed (2)</summary>

* **Dockerfile**: Language not supported
* **ai-prompts/mcp.txt**: Language not supported
</details>



state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T14:09:35Z
user: login: rita-gorokhod
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T15:01:34Z

Review comments:
diff_hunk: @@ -4,7 +4,9 @@ OpenOps is a No-Code FinOps automation platform. It provides customizable workfl
 Core responsibilities:
 1. Parse and understand structured context from OpenOps tools and systems
 2. Maintain consistent context across interactions
-3. If needed, handle invoking different OpenOps MCP (model context protocol) tools (Mintlify Search, OpenOps Tables, OpenOps Analytics, etc.) and process and respond according to MCP protocol specifications
+3. If needed, handle invoking different OpenOps MCP (model context protocol) tools and process and respond according to MCP protocol specifications
path: ai-prompts/mcp.txt
user: login: MarceloRGonc
body: I need to improve this. But we will do it in other PR
created_at: 2025-05-14T13:58:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,24 @@
+import { AppSystemProp, system } from '@openops/server-shared';
+import { experimental_createMCPClient, ToolSet } from 'ai';
+import { Experimental_StdioMCPTransport } from 'ai/mcp-stdio';
+import path from 'path';
+
+export async function getSupersetTools(): Promise<ToolSet> {
+  const basePath = system.get<string>(AppSystemProp.SUPERSET_MCP_SERVER_PATH);
+
+  if (!basePath) {
path: packages/server/api/src/app/ai/mcp/superset-tools.ts
user: login: Copilot
body: [nitpick] Consider logging a warning or error when basePath is undefined to aid in debugging production issues instead of silently returning an empty toolset.
```suggestion
  if (!basePath) {
    console.warn('Warning: basePath is undefined. Returning an empty toolset.');
```
created_at: 2025-05-14T14:09:35Z
author_association: CONTRIBUTOR

PR comments:
user: login: linear[bot]
created_at: 2025-05-13T08:40:43Z
body: <p><a href="https://linear.app/openops/issue/OPS-1723/connect-chatbot-to-supersets-mcp">OPS-1723 Connect chatbot to superset's MCP</a></p>
author_association: NONE
user: login: linear[bot]
created_at: 2025-05-14T14:17:51Z
body: <p><a href="https://linear.app/openops/issue/OPS-1743/add-superset-mcp-to-main-app-container">OPS-1743 Add superset-mcp to main app container</a></p>
author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-05-14T15:26:09Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=openops-cloud_openops&pullRequest=579) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=openops-cloud_openops&pullRequest=579&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=openops-cloud_openops&pullRequest=579&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=openops-cloud_openops&pullRequest=579&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=openops-cloud_openops&pullRequest=579&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=openops-cloud_openops&pullRequest=579&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=openops-cloud_openops&pullRequest=579)


author_association: NONE