drizzle-cube 0.4.44 → 0.4.45
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.
- package/dist/adapters/express/index.cjs +1 -1
- package/dist/adapters/express/index.js +23 -22
- package/dist/adapters/fastify/index.cjs +1 -1
- package/dist/adapters/fastify/index.js +23 -22
- package/dist/adapters/hono/index.cjs +1 -1
- package/dist/adapters/hono/index.js +25 -24
- package/dist/adapters/mcp-tools.cjs +1 -1
- package/dist/adapters/mcp-tools.d.ts +2 -0
- package/dist/adapters/mcp-tools.js +39 -29
- package/dist/adapters/mcp-transport-DbLtza1I.cjs +70 -0
- package/dist/adapters/{mcp-transport--zhJJHJc.js → mcp-transport-DoNg50eG.js} +122 -59
- package/dist/adapters/mcp-transport.d.ts +61 -1
- package/dist/adapters/nextjs/index.cjs +1 -1
- package/dist/adapters/nextjs/index.js +25 -24
- package/dist/adapters/utils.d.ts +2 -0
- package/dist/mcp-app/mcp-app.html +186 -0
- package/package.json +7 -2
- package/dist/adapters/mcp-transport-MOoCDu2M.cjs +0 -58
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drizzle-cube",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.45",
|
|
4
4
|
"description": "Drizzle ORM-first semantic layer with Cube.js compatibility. Type-safe analytics and dashboards with SQL injection protection.",
|
|
5
5
|
"main": "./dist/server/index.js",
|
|
6
6
|
"types": "./dist/server/index.d.ts",
|
|
@@ -99,7 +99,9 @@
|
|
|
99
99
|
"dev:build": "concurrently \"npm run dev:build-server\" \"npm run dev:build-client\"",
|
|
100
100
|
"dev:build-server": "vite build src/server --watch --mode development",
|
|
101
101
|
"dev:build-client": "vite build src/client --watch --mode development",
|
|
102
|
-
"
|
|
102
|
+
"dev:mcp-app": "vite build --config vite.config.mcp-app.ts --watch",
|
|
103
|
+
"build": "npm run build:server && npm run build:mcp-app && npm run build:client && npm run build:adapters && npm run build:cli",
|
|
104
|
+
"build:mcp-app": "vite build --config vite.config.mcp-app.ts",
|
|
103
105
|
"build:server": "vite build --config vite.config.server.ts",
|
|
104
106
|
"build:client": "vite build --config vite.config.client.ts",
|
|
105
107
|
"analyze:client": "vite build --config vite.config.client.ts && open dist/client-bundle-stats.html",
|
|
@@ -358,6 +360,7 @@
|
|
|
358
360
|
"typescript": "^5.0.0",
|
|
359
361
|
"vite": "^8.0.0",
|
|
360
362
|
"vite-plugin-dts": "^4.0.0",
|
|
363
|
+
"vite-plugin-singlefile": "^2.3.2",
|
|
361
364
|
"vitest": "^4.0.0",
|
|
362
365
|
"zod": "^4.0.0"
|
|
363
366
|
},
|
|
@@ -368,6 +371,8 @@
|
|
|
368
371
|
}
|
|
369
372
|
},
|
|
370
373
|
"dependencies": {
|
|
374
|
+
"@modelcontextprotocol/ext-apps": "^1.3.2",
|
|
375
|
+
"@modelcontextprotocol/sdk": "^1.28.0",
|
|
371
376
|
"@tanstack/react-query": "^5.90.12",
|
|
372
377
|
"highlight.js": "^11.9.0",
|
|
373
378
|
"lz-string": "^1.5.0",
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
const e=require(`./utils-tNZ6Cvzw.cjs`),t=require(`./mcp-prompts-DsAkafVn.cjs`);var n=[`2025-11-25`,`2025-06-18`,`2025-03-26`],r=`2025-11-25`;function i(e){let t=h(e[`mcp-protocol-version`])||`2025-11-25`;return{ok:n.includes(t),negotiated:n.includes(t)?t:null,supported:n}}function a(e){if(!e)return!1;let t=e.split(`,`).map(e=>e.trim().toLowerCase()),n=t.includes(`text/event-stream`),r=t.includes(`application/json`);return n&&!r}var o=`mcp-session-id`;function s(e){if(!e)return!1;let t=e.split(`,`).map(e=>e.trim().toLowerCase().split(`;`)[0]),n=t.some(e=>e===`application/json`),r=t.some(e=>e===`text/event-stream`);return n&&r}function c(e,t={}){let{allowMissingOrigin:n=!0,allowedOrigins:r}=t;if(!e)return n?{valid:!0}:{valid:!1,reason:`Origin header is required`};if(!r||r.length===0)return{valid:!0};let i;try{i=new URL(e)}catch{return{valid:!1,reason:`Invalid Origin header format`}}return r.map(e=>{try{return new URL(e).origin}catch{return e}}).includes(i.origin)?{valid:!0}:{valid:!1,reason:`Origin not in allowed list`}}function l(e,t,n){let r=[];return t&&r.push(`id: ${t}`),n&&n>0&&r.push(`retry: ${n}`),r.push(`event: message`),r.push(`data: ${JSON.stringify(e)}`),r.push(``),r.join(`
|
|
2
|
-
`)}function u(e,t,n,r){return{jsonrpc:`2.0`,id:e??null,error:{code:t,message:n,...r===void 0?{}:{data:r}}}}function d(e,t){return{jsonrpc:`2.0`,id:e??null,result:t}}function f(e){if(!e||typeof e!=`object`)return null;let t=e;return t.jsonrpc!==`2.0`||typeof t.method!=`string`?null:{jsonrpc:`2.0`,method:t.method,id:t.id,params:t.params}}async function p(t,i,a){let{semanticLayer:o,extractSecurityContext:s,rawRequest:c,rawResponse:l}=a,u=a.prompts??x,d=a.resources??S;switch(t){case`initialize`:{let e=i?.protocolVersion,t;return t=e&&n.includes(e)?e:r,{protocolVersion:t,capabilities:{tools:{listChanged:!1},resources:{listChanged:!1},prompts:{listChanged:!1},sampling:{}},sessionId:_(),serverInfo:{name:`drizzle-cube`,version:typeof process<`u`?process.env?.npm_package_version||`dev`:`worker`}}}case`list_tools`:case`tools/list`:return{tools:v(),nextCursor:``};case`call_tool`:case`tools/call`:return y(i,a);case`resources/list`:return{resources:d.map(({uri:e,name:t,description:n,mimeType:r})=>({uri:e,name:t,description:n,mimeType:r})),nextCursor:``};case`resources/templates/list`:return{resourceTemplates:[],nextCursor:``};case`resources/read`:{let e=i?.uri,t=d.find(t=>t.uri===e)||d[0];if(!t)throw m(-32602,`resource not found`);return{contents:[{uri:t.uri,mimeType:t.mimeType,text:t.text}]}}case`prompts/list`:return{prompts:u.map(({name:e,description:t})=>({name:e,description:t})),nextCursor:``};case`ping`:return{};case`notifications/initialized`:return{};case`prompts/get`:{let e=i?.name,t=u.find(t=>t.name===e)||u[0];if(!t)throw m(-32602,`prompt not found`);return{name:t.name,description:t.description,messages:t.messages}}case`discover`:return e.d(o,i||{});case`validate`:{let t=i||{};if(!t.query)throw m(-32602,`query is required`);return e.h(o,t)}case`load`:{let t=i||{};if(!t.query)throw m(-32602,`query is required`);return e.p(o,await s(c,l),t)}default:throw m(-32601,`Unknown MCP method: ${t}`)}}function m(e,t,n){let r=Error(t);return r.code=e,n!==void 0&&(r.data=n),r}function h(e){return e?Array.isArray(e)?e[0]||null:e:null}function g(e){return e.id===void 0||e.id===null}function _(){return`evt-${e.c()}`}function v(){return[{name:`discover`,description:`Find relevant cubes based on topic or intent. Call this FIRST to understand available data.
|
|
3
|
-
|
|
4
|
-
Returns cubes with:
|
|
5
|
-
- All measures and dimensions with their types
|
|
6
|
-
- Relationship information (joins) showing how cubes connect
|
|
7
|
-
- Metadata hints (eventStream for funnels, etc.)
|
|
8
|
-
|
|
9
|
-
IMPORTANT: The 'joins' property shows relationships between cubes. You can include dimensions from ANY related cube in your query - the system auto-joins them.
|
|
10
|
-
|
|
11
|
-
Example: If Productivity has a join to Employees, you can query:
|
|
12
|
-
{ "measures": ["Productivity.totalPullRequests"], "dimensions": ["Employees.name"] }`,inputSchema:{type:`object`,properties:{topic:{type:`string`,description:`Keyword to search (e.g., "sales", "employees")`},intent:{type:`string`,description:`Natural language goal (e.g., "analyze productivity trends")`},limit:{type:`number`,description:`Max results (default: 10)`},minScore:{type:`number`,description:`Min relevance 0-1 (default: 0.1)`}}}},{name:`validate`,description:`Validate a query and get auto-corrections for issues.
|
|
13
|
-
|
|
14
|
-
Checks:
|
|
15
|
-
- Field existence (measures, dimensions exist in schema)
|
|
16
|
-
- Filter syntax and operators
|
|
17
|
-
- Cross-cube join validity
|
|
18
|
-
|
|
19
|
-
Returns corrected query if issues found.`,inputSchema:{type:`object`,required:[`query`],properties:{query:{type:`object`,description:`CubeQuery to validate`}}}},{name:`load`,description:`Execute a semantic query and return aggregated results.
|
|
20
|
-
|
|
21
|
-
QUERY CONSTRUCTION RULES:
|
|
22
|
-
|
|
23
|
-
1. CROSS-CUBE JOINS (use dimensions from related cubes!)
|
|
24
|
-
Check 'joins' in discover results. Include dimensions from ANY related cube.
|
|
25
|
-
Example - get employee names with their productivity:
|
|
26
|
-
{
|
|
27
|
-
"measures": ["Productivity.totalPullRequests"],
|
|
28
|
-
"dimensions": ["Employees.name"],
|
|
29
|
-
"filters": [{ "member": "Productivity.date", "operator": "inDateRange", "values": ["last 3 months"] }]
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
2. DATE FILTERING vs TIME GROUPING
|
|
33
|
-
For AGGREGATED TOTALS: use 'filters' with 'inDateRange' (NOT timeDimensions)
|
|
34
|
-
{
|
|
35
|
-
"measures": ["Productivity.totalPullRequests"],
|
|
36
|
-
"dimensions": ["Employees.name"],
|
|
37
|
-
"filters": [{ "member": "Productivity.date", "operator": "inDateRange", "values": ["last 3 months"] }],
|
|
38
|
-
"order": { "Productivity.totalPullRequests": "desc" },
|
|
39
|
-
"limit": 5
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
For TIME SERIES: use 'timeDimensions' WITH 'granularity'
|
|
43
|
-
{
|
|
44
|
-
"measures": ["Productivity.totalPullRequests"],
|
|
45
|
-
"timeDimensions": [{ "dimension": "Productivity.date", "dateRange": "last 3 months", "granularity": "month" }]
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
WARNING: timeDimensions WITHOUT granularity groups by day, returning many rows!
|
|
49
|
-
|
|
50
|
-
3. TOP N PATTERN: filters + order + limit`,inputSchema:{type:`object`,required:[`query`],properties:{query:{type:`object`,description:`CubeQuery object with:
|
|
51
|
-
- measures: string[] - Aggregations (from any cube)
|
|
52
|
-
- dimensions: string[] - Grouping fields (can be from RELATED cubes via joins)
|
|
53
|
-
- filters: [{ member, operator, values }] - Use 'inDateRange' for date filtering
|
|
54
|
-
- timeDimensions: [{ dimension, granularity, dateRange }] - ONLY for time series
|
|
55
|
-
- order: { "Cube.field": "asc"|"desc" }
|
|
56
|
-
- limit: number`}}}}]}async function y(t,n){let{semanticLayer:r,extractSecurityContext:i,rawRequest:a,rawResponse:o}=n,s=t||{};if(!s.name)throw m(-32602,`name is required for tools/call`);let c=s.arguments;switch(s.name){case`discover`:return b(await e.d(r,c||{}));case`validate`:{let t=c||{};if(!t.query)throw m(-32602,`query is required`);return b(await e.h(r,t))}case`load`:{let t=c||{};if(!t.query)throw m(-32602,`query is required`);return b(await e.p(r,await i(a,o),t))}default:throw m(-32601,`Unknown tool: ${s.name}`)}}function b(e){return{content:[{type:`text`,text:typeof e==`string`?e:JSON.stringify(e)}],isError:!1}}var x=t.a(),S=[{uri:`drizzle-cube://quickstart`,name:`Drizzle Cube MCP Quickstart`,description:`Minimal guide for using discover/suggest/validate/load`,mimeType:`text/markdown`,text:[`# Drizzle Cube MCP Quickstart`,``,`Tools:`,`- discover: { topic?, intent?, limit?, minScore? } → cubes list`,`- suggest: { naturalLanguage, cube? } → draft query`,`- validate: { query } → corrected query + issues`,`- load: { query } → data + annotation`,``,`Recommended flow:`,`1) tools/list`,`2) tools/call name=discover intent="<goal>"`,`3) tools/call name=suggest naturalLanguage="<goal>"`,`4) tools/call name=validate query=<from suggest>`,`5) tools/call name=load query=<validated>`,``,`Query shapes supported:`,`- regular Cube.js-style query { measures, dimensions, filters, timeDimensions, order, limit, offset }`,`- funnel { bindingKey, timeDimension, steps[], includeTimeMetrics? }`,`- flow { bindingKey, eventDimension, steps?, window? }`,`- retention { bindingKey, timeDimension, periods, granularity, retentionType, breakdownDimensions }`,``,`Filter rules: flat arrays of { member, operator, values }; do not nest arrays.`].join(`
|
|
57
|
-
`)},{uri:`drizzle-cube://query-shapes`,name:`Query Shapes Reference`,description:`Detailed schema examples for regular, funnel, flow, and retention queries`,mimeType:`text/markdown`,text:[`# Query Shapes`,``,`## Regular query`,"```json",`{`,` "measures": ["Sales.count"],`,` "dimensions": ["Sales.channel"],`,` "filters": [ { "member": "Sales.status", "operator": "equals", "values": ["paid"] } ],`,` "timeDimensions": [ { "dimension": "Sales.createdAt", "dateRange": "last 30 days", "granularity": "day" } ],`,` "order": { "Sales.createdAt": "asc" },`,` "limit": 500`,`}`,"```",``,`## Funnel`,"```json",`{`,` "funnel": {`,` "bindingKey": "Events.userId",`,` "timeDimension": "Events.timestamp",`,` "steps": [`,` { "name": "Signup", "filter": [{ "member": "Events.eventType", "operator": "equals", "values": ["signup"] }] },`,` { "name": "Purchase", "filter": [{ "member": "Events.eventType", "operator": "equals", "values": ["purchase"] }] }`,` ],`,` "includeTimeMetrics": true`,` }`,`}`,"```",``,`## Flow`,"```json",`{`,` "flow": {`,` "bindingKey": "Events.sessionId",`,` "eventDimension": "Events.eventType",`,` "steps": ["view", "add_to_cart", "checkout"],`,` "window": { "unit": "minute", "value": 30 }`,` }`,`}`,"```",``,`## Retention`,"```json",`{`,` "retention": {`,` "bindingKey": "Users.id",`,` "timeDimension": "Events.timestamp",`,` "periods": 8,`,` "granularity": "week",`,` "retentionType": "rolling",`,` "breakdownDimensions": ["Events.country"]`,` }`,`}`,"```",``,`### Filter rules`,`- Always a flat array of filter objects: [{ member, operator, values }]`,`- For funnels, put time filter (inDateRange) only on step 0`,`- Operators: equals, notEquals, inDateRange, gt, gte, lt, lte, contains, notContains, set, notSet`,``,`### Time handling`,`- Relative ranges ("last 3 months") -> add ONLY an inDateRange filter on the time dimension (do NOT add timeDimensions unless grouping is requested).`,`- Grouping ("by month/week/day") -> add timeDimensions entry with granularity.`,`- Both can be combined: inDateRange filter + timeDimensions granularity.`].join(`
|
|
58
|
-
`)}];function C(){return S}function w(){return x}Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return f}});
|