@dbx-app/mcp-server 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +64 -28
  2. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -2,22 +2,31 @@
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { z } from "zod";
5
+ import { readFile } from "node:fs/promises";
6
+ import { join } from "node:path";
7
+ import { homedir, platform } from "node:os";
5
8
  import { loadConnections, findConnection } from "./connections.js";
6
9
  import { listTables, describeTable, executeQuery } from "./database.js";
10
+ function text(s) {
11
+ return { content: [{ type: "text", text: s }] };
12
+ }
13
+ function mdTable(headers, rows) {
14
+ const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] || "").length), 3));
15
+ const header = `| ${headers.map((h, i) => h.padEnd(widths[i])).join(" | ")} |`;
16
+ const sep = `| ${widths.map((w) => "-".repeat(w)).join(" | ")} |`;
17
+ const body = rows.map((r) => `| ${r.map((c, i) => (c || "").padEnd(widths[i])).join(" | ")} |`).join("\n");
18
+ return `${header}\n${sep}\n${body}`;
19
+ }
7
20
  const server = new McpServer({
8
21
  name: "dbx",
9
- version: "0.1.0",
22
+ version: "0.1.1",
10
23
  });
11
24
  server.tool("dbx_list_connections", "List all database connections configured in DBX", {}, async () => {
12
25
  const connections = await loadConnections();
13
- const list = connections.map((c) => ({
14
- name: c.name,
15
- type: c.db_type,
16
- host: c.host,
17
- port: c.port,
18
- database: c.database || "",
19
- }));
20
- return { content: [{ type: "text", text: JSON.stringify(list, null, 2) }] };
26
+ if (connections.length === 0)
27
+ return text("No connections configured in DBX.");
28
+ const rows = connections.map((c) => [c.name, c.db_type, c.host, String(c.port), c.database || ""]);
29
+ return text(mdTable(["Name", "Type", "Host", "Port", "Database"], rows));
21
30
  });
22
31
  server.tool("dbx_list_tables", "List tables and views for a database connection", {
23
32
  connection_name: z.string().describe("Name of the DBX connection"),
@@ -25,9 +34,12 @@ server.tool("dbx_list_tables", "List tables and views for a database connection"
25
34
  }, async ({ connection_name, schema }) => {
26
35
  const config = await findConnection(connection_name);
27
36
  if (!config)
28
- return { content: [{ type: "text", text: `Connection "${connection_name}" not found` }] };
37
+ return text(`Connection "${connection_name}" not found`);
29
38
  const tables = await listTables(config, schema);
30
- return { content: [{ type: "text", text: JSON.stringify(tables, null, 2) }] };
39
+ if (tables.length === 0)
40
+ return text("No tables found.");
41
+ const rows = tables.map((t) => [t.name, t.type]);
42
+ return text(mdTable(["Table", "Type"], rows));
31
43
  });
32
44
  server.tool("dbx_describe_table", "Get column definitions for a table", {
33
45
  connection_name: z.string().describe("Name of the DBX connection"),
@@ -36,9 +48,18 @@ server.tool("dbx_describe_table", "Get column definitions for a table", {
36
48
  }, async ({ connection_name, table, schema }) => {
37
49
  const config = await findConnection(connection_name);
38
50
  if (!config)
39
- return { content: [{ type: "text", text: `Connection "${connection_name}" not found` }] };
51
+ return text(`Connection "${connection_name}" not found`);
40
52
  const columns = await describeTable(config, table, schema);
41
- return { content: [{ type: "text", text: JSON.stringify(columns, null, 2) }] };
53
+ if (columns.length === 0)
54
+ return text("No columns found.");
55
+ const rows = columns.map((c) => [
56
+ c.is_primary_key ? `${c.name} (PK)` : c.name,
57
+ c.data_type,
58
+ c.is_nullable ? "YES" : "NO",
59
+ c.column_default ?? "",
60
+ c.comment ?? "",
61
+ ]);
62
+ return text(mdTable(["Column", "Type", "Nullable", "Default", "Comment"], rows));
42
63
  });
43
64
  server.tool("dbx_execute_query", "Execute a SQL query on a database connection (max 100 rows returned)", {
44
65
  connection_name: z.string().describe("Name of the DBX connection"),
@@ -46,19 +67,26 @@ server.tool("dbx_execute_query", "Execute a SQL query on a database connection (
46
67
  }, async ({ connection_name, sql }) => {
47
68
  const config = await findConnection(connection_name);
48
69
  if (!config)
49
- return { content: [{ type: "text", text: `Connection "${connection_name}" not found` }] };
70
+ return text(`Connection "${connection_name}" not found`);
50
71
  try {
51
72
  const result = await executeQuery(config, sql);
52
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
73
+ if (result.columns.length === 0)
74
+ return text(`Query executed. ${result.row_count} row(s) affected.`);
75
+ const rows = result.rows.map((r) => result.columns.map((c) => formatCell(r[c])));
76
+ return text(`${mdTable(result.columns, rows)}\n\n${result.row_count} row(s)`);
53
77
  }
54
78
  catch (e) {
55
79
  const msg = e instanceof Error ? e.message : String(e);
56
- return { content: [{ type: "text", text: `Query error: ${msg}` }] };
80
+ return text(`Query error: ${msg}`);
57
81
  }
58
82
  });
59
- import { readFile } from "node:fs/promises";
60
- import { join } from "node:path";
61
- import { homedir, platform } from "node:os";
83
+ function formatCell(value) {
84
+ if (value === null || value === undefined)
85
+ return "NULL";
86
+ if (typeof value === "object")
87
+ return JSON.stringify(value);
88
+ return String(value);
89
+ }
62
90
  function appDataDir() {
63
91
  const home = homedir();
64
92
  switch (platform()) {
@@ -81,23 +109,31 @@ server.tool("dbx_open_table", "Open a table in DBX desktop app UI. Requires DBX
81
109
  database: z.string().optional().describe("Database name"),
82
110
  schema: z.string().optional().describe("Schema name"),
83
111
  }, async ({ connection_name, table, database, schema }) => {
112
+ return bridgeRequest("/open-table", { connection_name, table, database, schema }, `Opened ${table} in DBX`);
113
+ });
114
+ server.tool("dbx_execute_and_show", "Execute a SQL query in DBX desktop app UI and show results there. Requires DBX to be running.", {
115
+ connection_name: z.string().describe("Name of the DBX connection"),
116
+ sql: z.string().describe("SQL query to execute"),
117
+ database: z.string().optional().describe("Database name"),
118
+ }, async ({ connection_name, sql, database }) => {
119
+ return bridgeRequest("/execute-query", { connection_name, sql, database }, "Query sent to DBX");
120
+ });
121
+ async function bridgeRequest(path, body, successMsg) {
84
122
  try {
85
123
  const bridgeUrl = await getBridgeUrl();
86
- const res = await fetch(`${bridgeUrl}/open-table`, {
124
+ const res = await fetch(`${bridgeUrl}${path}`, {
87
125
  method: "POST",
88
126
  headers: { "Content-Type": "application/json" },
89
- body: JSON.stringify({ connection_name, table, database, schema }),
127
+ body: JSON.stringify(body),
90
128
  });
91
- if (res.ok) {
92
- return { content: [{ type: "text", text: `Opened ${table} in DBX` }] };
93
- }
94
- const text = await res.text();
95
- return { content: [{ type: "text", text: `Failed: ${text}` }] };
129
+ if (res.ok)
130
+ return text(successMsg);
131
+ return text(`Failed: ${await res.text()}`);
96
132
  }
97
133
  catch {
98
- return { content: [{ type: "text", text: "DBX is not running. Please start DBX first." }] };
134
+ return text("DBX is not running. Please start DBX first.");
99
135
  }
100
- });
136
+ }
101
137
  async function main() {
102
138
  const transport = new StdioServerTransport();
103
139
  await server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@dbx-app/mcp-server",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
+ "mcpName": "io.github.t8y2/dbx",
4
5
  "description": "MCP server for DBX — query databases from Claude Code, Cursor, and other AI agents",
5
6
  "type": "module",
6
7
  "bin": {