drizzle-cube 0.4.48 → 0.4.50

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.
@@ -1,3 +1,3 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../utils-CyBt-as9.cjs`),t=require(`../compiler-CdL3ksb3.cjs`),n=require(`../mcp-transport-DlFvZl2c.cjs`);let r=require(`hono`);var i=e=>{let t={origin:`*`,allowMethods:[`GET`,`HEAD`,`PUT`,`POST`,`DELETE`,`PATCH`],allowHeaders:[],exposeHeaders:[],...e},n=(e=>typeof e==`string`?e===`*`?t.credentials?e=>e||null:()=>e:t=>e===t?t:null:typeof e==`function`?e:t=>e.includes(t)?t:null)(t.origin),r=(e=>typeof e==`function`?e:Array.isArray(e)?()=>e:()=>[])(t.allowMethods);return async function(e,i){function a(t,n){e.res.headers.set(t,n)}let o=await n(e.req.header(`origin`)||``,e);if(o&&a(`Access-Control-Allow-Origin`,o),t.credentials&&a(`Access-Control-Allow-Credentials`,`true`),t.exposeHeaders?.length&&a(`Access-Control-Expose-Headers`,t.exposeHeaders.join(`,`)),e.req.method===`OPTIONS`){(t.origin!==`*`||t.credentials)&&a(`Vary`,`Origin`),t.maxAge!=null&&a(`Access-Control-Max-Age`,t.maxAge.toString());let n=await r(e.req.header(`origin`)||``,e);n.length&&a(`Access-Control-Allow-Methods`,n.join(`,`));let i=t.allowHeaders;if(!i?.length){let t=e.req.header(`Access-Control-Request-Headers`);t&&(i=t.split(/\s*,\s*/))}return i?.length&&(a(`Access-Control-Allow-Headers`,i.join(`,`)),e.res.headers.append(`Vary`,`Access-Control-Request-Headers`)),e.res.headers.delete(`Content-Length`),e.res.headers.delete(`Content-Type`),new Response(null,{headers:e.res.headers,status:204,statusText:`No Content`})}await i(),(t.origin!==`*`||t.credentials)&&e.header(`Vary`,`Origin`,{append:!0})}};function a(a){let{cubes:o,drizzle:s,schema:c,extractSecurityContext:l,engineType:u,cors:d,basePath:f=`/cubejs-api/v1`,cache:p,mcp:m={enabled:!0},agent:h}=a;if(!a.semanticLayer&&(!o||o.length===0))throw Error(`Either semanticLayer or a non-empty cubes array must be provided`);let g=new r.Hono;d&&g.use(`/*`,i(d));let _=a.semanticLayer??new t.t({drizzle:s,schema:c,engineType:u,cache:p,rlsSetup:a.rlsSetup});if(!a.semanticLayer&&o&&o.forEach(e=>{_.registerCube(e)}),g.post(`${f}/load`,async t=>{try{let n=await t.req.json(),r=n.query||n,i=await l(t),a=_.validateQuery(r);if(!a.isValid)return t.json({error:`Query validation failed: ${a.errors.join(`, `)}`},400);let o=t.req.header(`x-cache-control`)===`no-cache`,s=await _.executeMultiCubeQuery(r,i,{skipCache:o});return t.json(e.r(r,s,_))}catch(e){return console.error(`Query execution error:`,e),t.json({error:e instanceof Error?e.message:`Query execution failed`},500)}}),g.get(`${f}/load`,async t=>{try{let n=t.req.query(`query`);if(!n)return t.json({error:`Query parameter is required`},400);let r;try{r=JSON.parse(n)}catch{return t.json({error:`Invalid JSON in query parameter`},400)}let i=await l(t),a=_.validateQuery(r);if(!a.isValid)return t.json({error:`Query validation failed: ${a.errors.join(`, `)}`},400);let o=t.req.header(`x-cache-control`)===`no-cache`,s=await _.executeMultiCubeQuery(r,i,{skipCache:o});return t.json(e.r(r,s,_))}catch(e){return console.error(`Query execution error:`,e),t.json({error:e instanceof Error?e.message:`Query execution failed`},500)}}),g.post(`${f}/batch`,async t=>{try{let{queries:n}=await t.req.json();if(!n||!Array.isArray(n))return t.json({error:`Request body must contain a "queries" array`},400);if(n.length===0)return t.json({error:`Queries array cannot be empty`},400);let r=await e.u(n,await l(t),_,{skipCache:t.req.header(`x-cache-control`)===`no-cache`});return t.json(r)}catch(e){return console.error(`Batch execution error:`,e),t.json({error:e instanceof Error?e.message:`Batch execution failed`},500)}}),g.get(`${f}/meta`,t=>{try{let n=_.getMetadata();return t.json(e.a(n))}catch(e){return console.error(`Metadata error:`,e),t.json({error:e instanceof Error?e.message:`Failed to fetch metadata`},500)}}),g.post(`${f}/sql`,async t=>{try{let n=await t.req.json(),r=await l(t),i=_.validateQuery(n);if(!i.isValid)return t.json({error:`Query validation failed: ${i.errors.join(`, `)}`},400);let a=n.measures?.[0]||n.dimensions?.[0];if(!a)return t.json({error:`No measures or dimensions specified`},400);let o=a.split(`.`)[0],s=await _.generateSQL(o,n,r);return t.json(e.o(n,s))}catch(e){return console.error(`SQL generation error:`,e),t.json({error:e instanceof Error?e.message:`SQL generation failed`},500)}}),g.get(`${f}/sql`,async t=>{try{let n=t.req.query(`query`);if(!n)return t.json({error:`Query parameter is required`},400);let r=JSON.parse(n),i=await l(t),a=_.validateQuery(r);if(!a.isValid)return t.json({error:`Query validation failed: ${a.errors.join(`, `)}`},400);let o=r.measures?.[0]||r.dimensions?.[0];if(!o)return t.json({error:`No measures or dimensions specified`},400);let s=o.split(`.`)[0],c=await _.generateSQL(s,r,i);return t.json(e.o(r,c))}catch(e){return console.error(`SQL generation error:`,e),t.json({error:e instanceof Error?e.message:`SQL generation failed`},500)}}),g.post(`${f}/dry-run`,async t=>{try{let n=await t.req.json(),r=await e.f(n.query||n,await l(t),_);return t.json(r)}catch(e){return console.error(`Dry-run error:`,e),t.json({error:e instanceof Error?e.message:`Dry-run validation failed`,valid:!1},400)}}),g.get(`${f}/dry-run`,async t=>{try{let n=t.req.query(`query`);if(!n)return t.json({error:`Query parameter is required`,valid:!1},400);let r=await e.f(JSON.parse(n),await l(t),_);return t.json(r)}catch(e){return console.error(`Dry-run error:`,e),t.json({error:e instanceof Error?e.message:`Dry-run validation failed`,valid:!1},400)}}),g.post(`${f}/explain`,async e=>{try{let t=await e.req.json(),n=t.query||t,r=t.options||{},i=await l(e),a=_.validateQuery(n);if(!a.isValid)return e.json({error:`Query validation failed: ${a.errors.join(`, `)}`},400);let o=await _.explainQuery(n,i,r);return e.json(o)}catch(t){return console.error(`Explain error:`,t),e.json({error:t instanceof Error?t.message:`Explain query failed`},500)}}),h&&g.post(`${f}/agent/chat`,async e=>{try{let{handleAgentChat:t}=await Promise.resolve().then(()=>require(`../handler-DumFgnNM.cjs`)),{message:n,sessionId:r,history:i}=await e.req.json();if(!n||typeof n!=`string`)return e.json({error:`message is required and must be a string`},400);let a=(h.apiKey||``).trim();if(h.allowClientApiKey){let t=e.req.header(`x-agent-api-key`);t&&(a=t.trim())}if(!a)return e.json({error:`No API key configured. Set agent.apiKey in server config or send X-Agent-Api-Key header.`},401);let o=h.allowClientApiKey?e.req.header(`x-agent-provider`):void 0,s=h.allowClientApiKey?e.req.header(`x-agent-model`):void 0,c=h.allowClientApiKey?e.req.header(`x-agent-provider-endpoint`):void 0,u=await l(e),d=h.buildSystemContext?.(u),f=new TextEncoder,p=new ReadableStream({async start(e){try{let l=t({message:n,sessionId:r,history:i,semanticLayer:_,securityContext:u,agentConfig:h,apiKey:a,systemContext:d,providerOverride:o,modelOverride:s,baseURLOverride:c});for await(let t of l){let n=`data: ${JSON.stringify(t)}\n\n`;e.enqueue(f.encode(n))}}catch(t){let n={type:`error`,data:{message:t instanceof Error?t.message:`Stream failed`}};e.enqueue(f.encode(`data: ${JSON.stringify(n)}\n\n`))}finally{e.close()}}});return new Response(p,{status:200,headers:{"Content-Type":`text/event-stream`,"Cache-Control":`no-cache`,Connection:`keep-alive`}})}catch(t){return console.error(`Agent chat error:`,t),e.json({error:t instanceof Error?t.message:`Agent chat failed`},500)}}),m.enabled!==!1){let e={uri:`drizzle-cube://schema`,name:`Cube Schema`,description:`Current cube metadata as JSON`,mimeType:`application/json`,text:JSON.stringify(_.getMetadata(),null,2)},t=[...n.l(),e],r=n.c(),i=m.basePath??`/mcp`;g.post(`${i}`,async e=>{let i=n._(e.req.header(`origin`),m.allowedOrigins?{allowedOrigins:m.allowedOrigins}:{});if(!i.valid)return e.json(n.i(null,-32600,i.reason),403);let a=e.req.header(`accept`);if(!n.g(a))return e.json(n.i(null,-32600,`Accept header must include both application/json and text/event-stream`),400);let o=n.f(e.req.header());if(!o.ok)return e.json({error:`Unsupported MCP protocol version`,supported:o.supported},426);let s=n.p(await e.req.json().catch(()=>null));if(!s)return e.json(n.i(null,-32600,`Invalid JSON-RPC 2.0 request`),400);let c=n.v(a),u=s.method===`initialize`;try{let i=await n.s(s.method,s.params,{semanticLayer:_,extractSecurityContext:l,rawRequest:e,rawResponse:null,negotiatedProtocol:o.negotiated,resources:t,prompts:r,appEnabled:!!m.app});if(n.d(s))return e.body(null,202);let a=n.a(s.id??null,i),d=u&&i&&typeof i==`object`&&`sessionId`in i?i.sessionId:void 0,f={};if(d&&(f[n.r]=d),c){let e=new TextEncoder,t=n.m(),r=new ReadableStream({start(r){r.enqueue(e.encode(`id: ${t}\n\n`)),r.enqueue(e.encode(n.h(a,t))),r.close()}});return new Response(r,{status:200,headers:{"Content-Type":`text/event-stream`,"Cache-Control":`no-cache`,Connection:`keep-alive`,...f}})}return e.json(a,200,f)}catch(t){if(n.d(s))return console.error(`MCP notification processing error:`,t),e.body(null,202);console.error(`MCP RPC error:`,t);let r=t?.code??-32603,i=t?.data,a=t.message||`MCP request failed`,o=n.i(s.id??null,r,a,i);if(c){let e=new TextEncoder,t=n.m(),r=new ReadableStream({start(r){r.enqueue(e.encode(`id: ${t}\n\n`)),r.enqueue(e.encode(n.h(o,t))),r.close()}});return new Response(r,{status:200,headers:{"Content-Type":`text/event-stream`,"Cache-Control":`no-cache`,Connection:`keep-alive`}})}return e.json(o,200)}}),g.delete(`${i}`,e=>e.json({error:`Session termination not supported`},405)),g.get(`${i}`,e=>{let t=new TextEncoder,r=n.m(),i,a=new ReadableStream({start(e){e.enqueue(t.encode(n.h({jsonrpc:`2.0`,method:`mcp/ready`,params:{protocol:`streamable-http`}},r,15e3))),i=setInterval(()=>{e.enqueue(t.encode(`: keep-alive
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../utils-CyBt-as9.cjs`),t=require(`../compiler-CPE-YZfe.cjs`),n=require(`../mcp-transport-B43Mcqo4.cjs`);let r=require(`hono`);var i=e=>{let t={origin:`*`,allowMethods:[`GET`,`HEAD`,`PUT`,`POST`,`DELETE`,`PATCH`],allowHeaders:[],exposeHeaders:[],...e},n=(e=>typeof e==`string`?e===`*`?t.credentials?e=>e||null:()=>e:t=>e===t?t:null:typeof e==`function`?e:t=>e.includes(t)?t:null)(t.origin),r=(e=>typeof e==`function`?e:Array.isArray(e)?()=>e:()=>[])(t.allowMethods);return async function(e,i){function a(t,n){e.res.headers.set(t,n)}let o=await n(e.req.header(`origin`)||``,e);if(o&&a(`Access-Control-Allow-Origin`,o),t.credentials&&a(`Access-Control-Allow-Credentials`,`true`),t.exposeHeaders?.length&&a(`Access-Control-Expose-Headers`,t.exposeHeaders.join(`,`)),e.req.method===`OPTIONS`){(t.origin!==`*`||t.credentials)&&a(`Vary`,`Origin`),t.maxAge!=null&&a(`Access-Control-Max-Age`,t.maxAge.toString());let n=await r(e.req.header(`origin`)||``,e);n.length&&a(`Access-Control-Allow-Methods`,n.join(`,`));let i=t.allowHeaders;if(!i?.length){let t=e.req.header(`Access-Control-Request-Headers`);t&&(i=t.split(/\s*,\s*/))}return i?.length&&(a(`Access-Control-Allow-Headers`,i.join(`,`)),e.res.headers.append(`Vary`,`Access-Control-Request-Headers`)),e.res.headers.delete(`Content-Length`),e.res.headers.delete(`Content-Type`),new Response(null,{headers:e.res.headers,status:204,statusText:`No Content`})}await i(),(t.origin!==`*`||t.credentials)&&e.header(`Vary`,`Origin`,{append:!0})}};function a(a){let{cubes:o,drizzle:s,schema:c,extractSecurityContext:l,engineType:u,cors:d,basePath:f=`/cubejs-api/v1`,cache:p,mcp:m={enabled:!0},agent:h}=a;if(!a.semanticLayer&&(!o||o.length===0))throw Error(`Either semanticLayer or a non-empty cubes array must be provided`);let g=new r.Hono;d&&g.use(`/*`,i(d));let _=a.semanticLayer??new t.t({drizzle:s,schema:c,engineType:u,cache:p,rlsSetup:a.rlsSetup});if(!a.semanticLayer&&o&&o.forEach(e=>{_.registerCube(e)}),g.post(`${f}/load`,async t=>{try{let n=await t.req.json(),r=n.query||n,i=await l(t),a=_.validateQuery(r);if(!a.isValid)return t.json({error:`Query validation failed: ${a.errors.join(`, `)}`},400);let o=t.req.header(`x-cache-control`)===`no-cache`,s=await _.executeMultiCubeQuery(r,i,{skipCache:o});return t.json(e.r(r,s,_))}catch(e){return console.error(`Query execution error:`,e),t.json({error:e instanceof Error?e.message:`Query execution failed`},500)}}),g.get(`${f}/load`,async t=>{try{let n=t.req.query(`query`);if(!n)return t.json({error:`Query parameter is required`},400);let r;try{r=JSON.parse(n)}catch{return t.json({error:`Invalid JSON in query parameter`},400)}let i=await l(t),a=_.validateQuery(r);if(!a.isValid)return t.json({error:`Query validation failed: ${a.errors.join(`, `)}`},400);let o=t.req.header(`x-cache-control`)===`no-cache`,s=await _.executeMultiCubeQuery(r,i,{skipCache:o});return t.json(e.r(r,s,_))}catch(e){return console.error(`Query execution error:`,e),t.json({error:e instanceof Error?e.message:`Query execution failed`},500)}}),g.post(`${f}/batch`,async t=>{try{let{queries:n}=await t.req.json();if(!n||!Array.isArray(n))return t.json({error:`Request body must contain a "queries" array`},400);if(n.length===0)return t.json({error:`Queries array cannot be empty`},400);let r=await e.u(n,await l(t),_,{skipCache:t.req.header(`x-cache-control`)===`no-cache`});return t.json(r)}catch(e){return console.error(`Batch execution error:`,e),t.json({error:e instanceof Error?e.message:`Batch execution failed`},500)}}),g.get(`${f}/meta`,t=>{try{let n=_.getMetadata();return t.json(e.a(n))}catch(e){return console.error(`Metadata error:`,e),t.json({error:e instanceof Error?e.message:`Failed to fetch metadata`},500)}}),g.post(`${f}/sql`,async t=>{try{let n=await t.req.json(),r=await l(t),i=_.validateQuery(n);if(!i.isValid)return t.json({error:`Query validation failed: ${i.errors.join(`, `)}`},400);let a=n.measures?.[0]||n.dimensions?.[0];if(!a)return t.json({error:`No measures or dimensions specified`},400);let o=a.split(`.`)[0],s=await _.generateSQL(o,n,r);return t.json(e.o(n,s))}catch(e){return console.error(`SQL generation error:`,e),t.json({error:e instanceof Error?e.message:`SQL generation failed`},500)}}),g.get(`${f}/sql`,async t=>{try{let n=t.req.query(`query`);if(!n)return t.json({error:`Query parameter is required`},400);let r=JSON.parse(n),i=await l(t),a=_.validateQuery(r);if(!a.isValid)return t.json({error:`Query validation failed: ${a.errors.join(`, `)}`},400);let o=r.measures?.[0]||r.dimensions?.[0];if(!o)return t.json({error:`No measures or dimensions specified`},400);let s=o.split(`.`)[0],c=await _.generateSQL(s,r,i);return t.json(e.o(r,c))}catch(e){return console.error(`SQL generation error:`,e),t.json({error:e instanceof Error?e.message:`SQL generation failed`},500)}}),g.post(`${f}/dry-run`,async t=>{try{let n=await t.req.json(),r=await e.f(n.query||n,await l(t),_);return t.json(r)}catch(e){return console.error(`Dry-run error:`,e),t.json({error:e instanceof Error?e.message:`Dry-run validation failed`,valid:!1},400)}}),g.get(`${f}/dry-run`,async t=>{try{let n=t.req.query(`query`);if(!n)return t.json({error:`Query parameter is required`,valid:!1},400);let r=await e.f(JSON.parse(n),await l(t),_);return t.json(r)}catch(e){return console.error(`Dry-run error:`,e),t.json({error:e instanceof Error?e.message:`Dry-run validation failed`,valid:!1},400)}}),g.post(`${f}/explain`,async e=>{try{let t=await e.req.json(),n=t.query||t,r=t.options||{},i=await l(e),a=_.validateQuery(n);if(!a.isValid)return e.json({error:`Query validation failed: ${a.errors.join(`, `)}`},400);let o=await _.explainQuery(n,i,r);return e.json(o)}catch(t){return console.error(`Explain error:`,t),e.json({error:t instanceof Error?t.message:`Explain query failed`},500)}}),h&&g.post(`${f}/agent/chat`,async e=>{try{let{handleAgentChat:t}=await Promise.resolve().then(()=>require(`../handler-DumFgnNM.cjs`)),{message:n,sessionId:r,history:i}=await e.req.json();if(!n||typeof n!=`string`)return e.json({error:`message is required and must be a string`},400);let a=(h.apiKey||``).trim();if(h.allowClientApiKey){let t=e.req.header(`x-agent-api-key`);t&&(a=t.trim())}if(!a)return e.json({error:`No API key configured. Set agent.apiKey in server config or send X-Agent-Api-Key header.`},401);let o=h.allowClientApiKey?e.req.header(`x-agent-provider`):void 0,s=h.allowClientApiKey?e.req.header(`x-agent-model`):void 0,c=h.allowClientApiKey?e.req.header(`x-agent-provider-endpoint`):void 0,u=await l(e),d=h.buildSystemContext?.(u),f=new TextEncoder,p=new ReadableStream({async start(e){try{let l=t({message:n,sessionId:r,history:i,semanticLayer:_,securityContext:u,agentConfig:h,apiKey:a,systemContext:d,providerOverride:o,modelOverride:s,baseURLOverride:c});for await(let t of l){let n=`data: ${JSON.stringify(t)}\n\n`;e.enqueue(f.encode(n))}}catch(t){let n={type:`error`,data:{message:t instanceof Error?t.message:`Stream failed`}};e.enqueue(f.encode(`data: ${JSON.stringify(n)}\n\n`))}finally{e.close()}}});return new Response(p,{status:200,headers:{"Content-Type":`text/event-stream`,"Cache-Control":`no-cache`,Connection:`keep-alive`}})}catch(t){return console.error(`Agent chat error:`,t),e.json({error:t instanceof Error?t.message:`Agent chat failed`},500)}}),m.enabled!==!1){let e={uri:`drizzle-cube://schema`,name:`Cube Schema`,description:`Current cube metadata as JSON`,mimeType:`application/json`,text:JSON.stringify(_.getMetadata(),null,2)},t=[...n.l(),e],r=n.c(),i=m.basePath??`/mcp`;g.post(`${i}`,async e=>{let i=n._(e.req.header(`origin`),m.allowedOrigins?{allowedOrigins:m.allowedOrigins}:{});if(!i.valid)return e.json(n.i(null,-32600,i.reason),403);let a=e.req.header(`accept`);if(!n.g(a))return e.json(n.i(null,-32600,`Accept header must include both application/json and text/event-stream`),400);let o=n.f(e.req.header());if(!o.ok)return e.json({error:`Unsupported MCP protocol version`,supported:o.supported},426);let s=n.p(await e.req.json().catch(()=>null));if(!s)return e.json(n.i(null,-32600,`Invalid JSON-RPC 2.0 request`),400);let c=n.v(a),u=s.method===`initialize`;try{let i=await n.s(s.method,s.params,{semanticLayer:_,extractSecurityContext:l,rawRequest:e,rawResponse:null,negotiatedProtocol:o.negotiated,resources:t,prompts:r,appEnabled:!!m.app});if(n.d(s))return e.body(null,202);let a=n.a(s.id??null,i),d=u&&i&&typeof i==`object`&&`sessionId`in i?i.sessionId:void 0,f={};if(d&&(f[n.r]=d),c){let e=new TextEncoder,t=n.m(),r=new ReadableStream({start(r){r.enqueue(e.encode(`id: ${t}\n\n`)),r.enqueue(e.encode(n.h(a,t))),r.close()}});return new Response(r,{status:200,headers:{"Content-Type":`text/event-stream`,"Cache-Control":`no-cache`,Connection:`keep-alive`,...f}})}return e.json(a,200,f)}catch(t){if(n.d(s))return console.error(`MCP notification processing error:`,t),e.body(null,202);console.error(`MCP RPC error:`,t);let r=t?.code??-32603,i=t?.data,a=t.message||`MCP request failed`,o=n.i(s.id??null,r,a,i);if(c){let e=new TextEncoder,t=n.m(),r=new ReadableStream({start(r){r.enqueue(e.encode(`id: ${t}\n\n`)),r.enqueue(e.encode(n.h(o,t))),r.close()}});return new Response(r,{status:200,headers:{"Content-Type":`text/event-stream`,"Cache-Control":`no-cache`,Connection:`keep-alive`}})}return e.json(o,200)}}),g.delete(`${i}`,e=>e.json({error:`Session termination not supported`},405)),g.get(`${i}`,e=>{let t=new TextEncoder,r=n.m(),i,a=new ReadableStream({start(e){e.enqueue(t.encode(n.h({jsonrpc:`2.0`,method:`mcp/ready`,params:{protocol:`streamable-http`}},r,15e3))),i=setInterval(()=>{e.enqueue(t.encode(`: keep-alive
2
2
 
3
3
  `))},15e3)},cancel(){clearInterval(i)}});return new Response(a,{status:200,headers:{"Content-Type":`text/event-stream`,"Cache-Control":`no-cache`,Connection:`keep-alive`}})})}return g}function o(e,t){let n=a(t);return e.route(`/`,n),e}function s(e){return o(new r.Hono,e)}exports.createCubeApp=s,exports.createCubeRoutes=a,exports.mountCubeRoutes=o;
@@ -1,6 +1,6 @@
1
1
  import { a as e, f as t, o as n, r, u as i } from "../utils-IH1ePsBd.js";
2
- import { t as a } from "../compiler-B_Nl7ZZb.js";
3
- import { _ as o, a as s, c, d as l, f as u, g as d, h as f, i as p, l as m, m as h, p as g, r as _, s as v, v as y } from "../mcp-transport-CG5Aw2cs.js";
2
+ import { t as a } from "../compiler-BXfrvebp.js";
3
+ import { _ as o, a as s, c, d as l, f as u, g as d, h as f, i as p, l as m, m as h, p as g, r as _, s as v, v as y } from "../mcp-transport-CgX_c5Sj.js";
4
4
  import { Hono as b } from "hono";
5
5
  //#region node_modules/hono/dist/middleware/cors/index.js
6
6
  var x = (e) => {
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./utils-CyBt-as9.cjs`),t=require(`./mcp-transport-DlFvZl2c.cjs`);function n(e){return{content:[{type:`text`,text:typeof e==`string`?e:JSON.stringify(e)}],isError:!1}}function r(e){return{content:[{type:`text`,text:e instanceof Error?e.message:String(e)}],isError:!0}}function i(i){let{semanticLayer:o,getSecurityContext:s,toolPrefix:c=`drizzle_cube_`,tools:l=[`discover`,`validate`,`load`],prompts:u=t.c(),resources:d,app:f=!1}=i,p=d??t.l(),m=f?[...p,...a()]:p,h=t.o({appEnabled:f}),g=new Map(h.map(e=>[e.name,e])),_=l.filter(e=>g.has(e)).map(e=>{let t=g.get(e),n={name:`${c}${e}`,description:t.description,inputSchema:t.inputSchema},r=t._meta;return r&&(n._meta=r),n}),v=_.map(e=>e.name),y=new Set;for(let e of l)y.add(e),y.add(`${c}${e}`);function b(e){return y.has(e)}async function x(t,i,a){let u=t.startsWith(c)?t.slice(c.length):t;if(!l.includes(u))return r(`Unknown tool: ${t}`);try{switch(u){case`discover`:return n(await e.d(o,i||{}));case`validate`:{let t=i||{};return t.query?n(await e.h(o,t)):r(`query is required`)}case`load`:{let t=i||{};return t.query?n(await e.p(o,await s(a),t)):r(`query is required`)}default:return r(`Unknown tool: ${t}`)}}catch(e){return r(e)}}return{definitions:_,handle:x,handles:b,prompts:u,resources:m,toolNames:v}}function a(){let e=t.u();return e?[{uri:t.n,name:`Drizzle Cube Visualization`,description:`Interactive chart visualization for query results`,mimeType:t.t,text:e}]:[]}exports.getCubeTools=i;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./utils-CyBt-as9.cjs`),t=require(`./mcp-transport-B43Mcqo4.cjs`);function n(e){return{content:[{type:`text`,text:typeof e==`string`?e:JSON.stringify(e)}],isError:!1}}function r(e){return{content:[{type:`text`,text:e instanceof Error?e.message:String(e)}],isError:!0}}function i(i){let{semanticLayer:o,getSecurityContext:s,toolPrefix:c=`drizzle_cube_`,tools:l=[`discover`,`validate`,`load`,`chart`],prompts:u=t.c(),resources:d,app:f=!1}=i,p=d??t.l(),m=f?[...p,...a()]:p,h=t.o({appEnabled:f}),g=new Map(h.map(e=>[e.name,e])),_=l.filter(e=>g.has(e)).map(e=>{let t=g.get(e),n={name:`${c}${e}`,description:t.description,inputSchema:t.inputSchema},r=t._meta;return r&&(n._meta=r),n}),v=_.map(e=>e.name),y=new Set;for(let e of l)y.add(e),y.add(`${c}${e}`);function b(e){return y.has(e)}async function x(t,i,a){let u=t.startsWith(c)?t.slice(c.length):t;if(!l.includes(u))return r(`Unknown tool: ${t}`);try{switch(u){case`discover`:return n(await e.d(o,i||{}));case`validate`:{let t=i||{};return t.query?n(await e.h(o,t)):r(`query is required`)}case`load`:{let t=i||{};return t.query?n(await e.p(o,await s(a),t)):r(`query is required`)}case`chart`:{let t=i||{};return t.query?n(await e.p(o,await s(a),t)):r(`query is required`)}default:return r(`Unknown tool: ${t}`)}}catch(e){return r(e)}}return{definitions:_,handle:x,handles:b,prompts:u,resources:m,toolNames:v}}function a(){let e=t.u();return e?[{uri:t.n,name:`Drizzle Cube Visualization`,description:`Interactive chart visualization for query results`,mimeType:t.t,text:e}]:[]}exports.getCubeTools=i;
@@ -1,5 +1,5 @@
1
1
  import { d as e, h as t, p as n } from "./utils-IH1ePsBd.js";
2
- import { c as r, l as i, n as a, o, t as s, u as c } from "./mcp-transport-CG5Aw2cs.js";
2
+ import { c as r, l as i, n as a, o, t as s, u as c } from "./mcp-transport-CgX_c5Sj.js";
3
3
  //#region src/adapters/mcp-tools.ts
4
4
  function l(e) {
5
5
  return {
@@ -23,7 +23,8 @@ function d(a) {
23
23
  let { semanticLayer: s, getSecurityContext: c, toolPrefix: d = "drizzle_cube_", tools: p = [
24
24
  "discover",
25
25
  "validate",
26
- "load"
26
+ "load",
27
+ "chart"
27
28
  ], prompts: m = r(), resources: h, app: g = !1 } = a, _ = h ?? i(), v = g ? [..._, ...f()] : _, y = o({ appEnabled: g }), b = new Map(y.map((e) => [e.name, e])), x = p.filter((e) => b.has(e)).map((e) => {
28
29
  let t = b.get(e), n = {
29
30
  name: `${d}${e}`,
@@ -50,6 +51,10 @@ function d(a) {
50
51
  let e = i || {};
51
52
  return e.query ? l(await n(s, await c(a), e)) : u("query is required");
52
53
  }
54
+ case "chart": {
55
+ let e = i || {};
56
+ return e.query ? l(await n(s, await c(a), e)) : u("query is required");
57
+ }
53
58
  default: return u(`Unknown tool: ${r}`);
54
59
  }
55
60
  } catch (e) {
@@ -28,8 +28,12 @@ Key rules:
28
28
  - Time series: use timeDimensions WITH granularity
29
29
  - Top N pattern: filters + order + limit
30
30
 
31
- CHART HINTS: Include a "chart" object to control the MCP App UI visualization.
32
- Chart types: bar, line, area, pie, scatter, bubble, radar, treemap, kpiNumber, kpiDelta, table, heatmap, funnel, sankey, sunburst, retentionHeatmap
33
- Guidelines: single number -> kpiNumber, trend -> line/area, categories -> bar, part-of-whole -> pie, correlation -> scatter/bubble, distribution -> boxPlot`,inputSchema:{type:`object`,required:[`query`],properties:{query:{type:`object`,description:`Semantic query object. Regular: { measures, dimensions, filters, timeDimensions, order, limit }. Funnel: { funnel: {...} }. Flow: { flow: {...} }. Retention: { retention: {...} }.`,properties:t.a},chart:{type:`object`,description:`Optional chart configuration for the MCP App UI. Uses the same chartConfig/displayConfig as the agent portlet system. If omitted, chart type is auto-detected.`,properties:{type:{type:`string`,enum:[`bar`,`line`,`area`,`pie`,`scatter`,`bubble`,`radar`,`radialBar`,`treemap`,`table`,`kpiNumber`,`kpiDelta`,`heatmap`,`boxPlot`,`funnel`,`sankey`,`sunburst`,`retentionHeatmap`,`retentionCombined`,`waterfall`,`activityGrid`],description:`Chart type to render`},title:{type:`string`,description:`Chart title`},chartConfig:{type:`object`,description:`Axis configuration — same schema as agent add_portlet chartConfig.`,properties:{xAxis:{type:`array`,items:{type:`string`},description:`Dimension fields for X axis`},yAxis:{type:`array`,items:{type:`string`},description:`Measure fields for Y axis`},series:{type:`array`,items:{type:`string`},description:`Dimension for series splitting (grouped/stacked)`},yAxisAssignment:{type:`object`,description:`Dual Y-axis: map measure fields to "left" or "right". Only bar/line/area with 2+ measures of different scales.`},sizeField:{type:`string`,description:`Bubble chart size field`},colorField:{type:`string`,description:`Bubble chart color field`}}},displayConfig:{type:`object`,description:`Display options.`,properties:{showLegend:{type:`boolean`},showGrid:{type:`boolean`},showTooltip:{type:`boolean`},stacked:{type:`boolean`},stackType:{type:`string`,enum:[`none`,`normal`,`percent`]},orientation:{type:`string`,enum:[`horizontal`,`vertical`]}}},xAxis:{type:`string`,description:`Deprecated: use chartConfig.xAxis`},yAxis:{type:`array`,items:{type:`string`},description:`Deprecated: use chartConfig.yAxis`}}}}}}];if(e?.appEnabled){let e=n.find(e=>e.name===`load`);e&&(e._meta={ui:{resourceUri:r}})}return n}async function C(t,n){let{semanticLayer:r,extractSecurityContext:i,rawRequest:a,rawResponse:o}=n,s=t||{};if(!s.name)throw v(-32602,`name is required for tools/call`);let c=s.arguments;switch(s.name){case`discover`:return w(await e.d(r,c||{}));case`validate`:{let t=c||{};if(!t.query)throw v(-32602,`query is required`);return w(await e.h(r,t))}case`load`:{let t=c||{};if(!t.query)throw v(-32602,`query is required`);return w(await e.p(r,await i(a,o),t))}default:throw v(-32601,`Unknown tool: ${s.name}`)}}function w(e){return{content:[{type:`text`,text:typeof e==`string`?e:JSON.stringify(e)}],isError:!1}}function T(){let e=a();return e?[{uri:r,name:`Drizzle Cube Visualization`,description:`Interactive chart visualization for query results`,mimeType:i,text:e}]:[]}var E=t.i(),D=[{uri:`drizzle-cube://quickstart`,name:`Drizzle Cube MCP Quickstart`,description:`Minimal guide for using discover/validate/load`,mimeType:`text/markdown`,text:[`# Drizzle Cube MCP Quickstart`,``,`Tools:`,`- discover: { topic?, intent?, limit?, minScore? } -> cubes list`,`- 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=validate query=<draft> (optional)`,`4) tools/call name=load query=<validated>`,``,`Query shapes supported:`,`- regular: { measures, dimensions, filters, timeDimensions, order, limit, offset, ungrouped }`,`- funnel: { funnel: { bindingKey, timeDimension, steps[], includeTimeMetrics?, globalTimeWindow? } }`,`- flow: { flow: { bindingKey, timeDimension, eventDimension, startingStep: { name, filter }, stepsBefore, stepsAfter } }`,`- retention: { retention: { timeDimension, bindingKey, dateRange: { start, end }, granularity, periods, retentionType } }`,``,`Filter rules: flat arrays of { member, operator, values }. Use { and: [...] } or { or: [...] } for logical grouping.`].join(`
31
+ Use "load" for data retrieval. Use "chart" to visualise results with an interactive chart.`,inputSchema:{type:`object`,required:[`query`],properties:{query:{type:`object`,description:`Semantic query object. Regular: { measures, dimensions, filters, timeDimensions, order, limit }. Funnel: { funnel: {...} }. Flow: { flow: {...} }. Retention: { retention: {...} }.`,properties:t.a}}}}];if(e?.appEnabled){n.push({name:`chart`,description:`Execute a semantic query and render an interactive chart visualization.
32
+
33
+ Same query format as "load", but renders results in the MCP App chart UI.
34
+ Include a "chart" object to control the visualization.
35
+
36
+ Chart types: bar, line, area, pie, scatter, bubble, radar, treemap, kpiNumber, kpiDelta, table, heatmap, funnel, sankey, sunburst, waterfall, activityGrid, boxPlot
37
+ Guidelines: single number -> kpiNumber, trend -> line/area, categories -> bar, part-of-whole -> pie, correlation -> scatter/bubble, distribution -> boxPlot`,inputSchema:{type:`object`,required:[`query`],properties:{query:{type:`object`,description:`Semantic query object. Same format as the load tool.`,properties:t.a},chart:{type:`object`,description:`Chart configuration for the visualization. If omitted, chart type is auto-detected from query shape.`,properties:{type:{type:`string`,enum:[`bar`,`line`,`area`,`pie`,`scatter`,`bubble`,`radar`,`radialBar`,`treemap`,`table`,`kpiNumber`,`kpiDelta`,`heatmap`,`boxPlot`,`funnel`,`sankey`,`sunburst`,`retentionHeatmap`,`retentionCombined`,`waterfall`,`activityGrid`],description:`Chart type to render`},title:{type:`string`,description:`Chart title`},chartConfig:{type:`object`,description:`Axis configuration — same schema as agent add_portlet chartConfig.`,properties:{xAxis:{type:`array`,items:{type:`string`},description:`Dimension fields for X axis`},yAxis:{type:`array`,items:{type:`string`},description:`Measure fields for Y axis`},series:{type:`array`,items:{type:`string`},description:`Dimension for series splitting (grouped/stacked)`},yAxisAssignment:{type:`object`,description:`Dual Y-axis: map measure fields to "left" or "right". Only bar/line/area with 2+ measures of different scales.`},sizeField:{type:`string`,description:`Bubble chart size field`},colorField:{type:`string`,description:`Bubble chart color field`}}},displayConfig:{type:`object`,description:`Display options.`,properties:{showLegend:{type:`boolean`},showGrid:{type:`boolean`},showTooltip:{type:`boolean`},stacked:{type:`boolean`},stackType:{type:`string`,enum:[`none`,`normal`,`percent`]},orientation:{type:`string`,enum:[`horizontal`,`vertical`]}}},xAxis:{type:`string`,description:`Deprecated: use chartConfig.xAxis`},yAxis:{type:`array`,items:{type:`string`},description:`Deprecated: use chartConfig.yAxis`}}}}}});let e=n.find(e=>e.name===`chart`);e&&(e._meta={ui:{resourceUri:r}})}return n}async function C(t,n){let{semanticLayer:r,extractSecurityContext:i,rawRequest:a,rawResponse:o}=n,s=t||{};if(!s.name)throw v(-32602,`name is required for tools/call`);let c=s.arguments;try{switch(s.name){case`discover`:return w(await e.d(r,c||{}));case`validate`:{let t=c||{};if(!t.query)throw v(-32602,`query is required`);return w(await e.h(r,t))}case`load`:{let t=c||{};if(!t.query)throw v(-32602,`query is required`);return w(await e.p(r,await i(a,o),t))}case`chart`:{let t=c||{};if(!t.query)throw v(-32602,`query is required`);return w(await e.p(r,await i(a,o),t))}default:throw v(-32601,`Unknown tool: ${s.name}`)}}catch(e){if(e?.code===-32602||e?.code===-32601)throw e;let t=e instanceof Error?e.message:String(e);return{content:[{type:`text`,text:JSON.stringify({error:t})}],isError:!0}}}function w(e){return{content:[{type:`text`,text:typeof e==`string`?e:JSON.stringify(e)}],isError:!1}}function T(){let e=a();return e?[{uri:r,name:`Drizzle Cube Visualization`,description:`Interactive chart visualization for query results`,mimeType:i,text:e}]:[]}var E=t.i(),D=[{uri:`drizzle-cube://quickstart`,name:`Drizzle Cube MCP Quickstart`,description:`Minimal guide for using discover/validate/load`,mimeType:`text/markdown`,text:[`# Drizzle Cube MCP Quickstart`,``,`Tools:`,`- discover: { topic?, intent?, limit?, minScore? } -> cubes list`,`- validate: { query } -> corrected query + issues`,`- load: { query } -> data + annotation (text only)`,`- chart: { query, chart? } -> data + interactive chart visualization`,``,`Recommended flow:`,`1) tools/call name=discover intent="<goal>"`,`2) tools/call name=validate query=<draft> (optional)`,`3) tools/call name=load query=<validated> (data only) OR name=chart query=<validated> chart={type, ...} (with visualization)`,``,`Query shapes supported:`,`- regular: { measures, dimensions, filters, timeDimensions, order, limit, offset, ungrouped }`,`- funnel: { funnel: { bindingKey, timeDimension, steps[], includeTimeMetrics?, globalTimeWindow? } }`,`- flow: { flow: { bindingKey, timeDimension, eventDimension, startingStep: { name, filter }, stepsBefore, stepsAfter } }`,`- retention: { retention: { timeDimension, bindingKey, dateRange: { start, end }, granularity, periods, retentionType } }`,``,`Filter rules: flat arrays of { member, operator, values }. Use { and: [...] } or { or: [...] } for logical grouping.`].join(`
34
38
  `)},{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"] },`,` { "or": [`,` { "member": "Sales.region", "operator": "equals", "values": ["US"] },`,` { "member": "Sales.region", "operator": "equals", "values": ["EU"] }`,` ]}`,` ],`,` "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"] },`,` { "member": "Events.timestamp", "operator": "inDateRange", "values": ["last 6 months"] }`,` ]`,` },`,` {`,` "name": "Purchase",`,` "filter": [{ "member": "Events.eventType", "operator": "equals", "values": ["purchase"] }],`,` "timeToConvert": "P7D"`,` }`,` ],`,` "includeTimeMetrics": true`,` }`,`}`,"```",``,`## Flow`,"```json",`{`,` "flow": {`,` "bindingKey": "Events.userId",`,` "timeDimension": "Events.timestamp",`,` "eventDimension": "Events.eventType",`,` "startingStep": {`,` "name": "Checkout",`,` "filter": { "member": "Events.eventType", "operator": "equals", "values": ["checkout"] }`,` },`,` "stepsBefore": 2,`,` "stepsAfter": 3`,` }`,`}`,"```",``,`## Retention`,"```json",`{`,` "retention": {`,` "timeDimension": "Events.timestamp",`,` "bindingKey": "Events.userId",`,` "dateRange": { "start": "2024-01-01", "end": "2024-03-31" },`,` "granularity": "week",`,` "periods": 8,`,` "retentionType": "classic",`,` "breakdownDimensions": ["Events.country"]`,` }`,`}`,"```",``,`### Filter operators`,`String: equals, notEquals, contains, notContains, startsWith, endsWith, like, ilike, regex`,`Numeric: gt, gte, lt, lte, between, notBetween`,`Set: in, notIn, set, notSet, isEmpty, isNotEmpty`,`Date: inDateRange, beforeDate, afterDate`,``,`### Time handling`,`- Aggregated totals: use filters with inDateRange (NOT timeDimensions)`,`- Time series grouping: use timeDimensions with granularity`,`- Both can be combined: inDateRange filter + timeDimensions with granularity`,`- Period comparison: use compareDateRange in timeDimensions`].join(`
35
39
  `)}];function O(){return D}function k(){return E}Object.defineProperty(exports,`_`,{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,`g`,{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,`v`,{enumerable:!0,get:function(){return l}});
@@ -223,19 +223,34 @@ function E(e) {
223
223
  },
224
224
  {
225
225
  name: "load",
226
- description: "Execute a semantic query and return aggregated results.\n\nSupports regular queries (measures/dimensions), funnel, flow, and retention analysis modes.\nSee the query language prompt for the full DSL reference.\n\nKey rules:\n- Fields are always \"CubeName.fieldName\" format\n- Cross-cube joins: include dimensions from related cubes (system auto-joins)\n- Aggregated totals: use filters with inDateRange (NOT timeDimensions)\n- Time series: use timeDimensions WITH granularity\n- Top N pattern: filters + order + limit\n\nCHART HINTS: Include a \"chart\" object to control the MCP App UI visualization.\nChart types: bar, line, area, pie, scatter, bubble, radar, treemap, kpiNumber, kpiDelta, table, heatmap, funnel, sankey, sunburst, retentionHeatmap\nGuidelines: single number -> kpiNumber, trend -> line/area, categories -> bar, part-of-whole -> pie, correlation -> scatter/bubble, distribution -> boxPlot",
226
+ description: "Execute a semantic query and return aggregated results.\n\nSupports regular queries (measures/dimensions), funnel, flow, and retention analysis modes.\nSee the query language prompt for the full DSL reference.\n\nKey rules:\n- Fields are always \"CubeName.fieldName\" format\n- Cross-cube joins: include dimensions from related cubes (system auto-joins)\n- Aggregated totals: use filters with inDateRange (NOT timeDimensions)\n- Time series: use timeDimensions WITH granularity\n- Top N pattern: filters + order + limit\n\nUse \"load\" for data retrieval. Use \"chart\" to visualise results with an interactive chart.",
227
+ inputSchema: {
228
+ type: "object",
229
+ required: ["query"],
230
+ properties: { query: {
231
+ type: "object",
232
+ description: "Semantic query object. Regular: { measures, dimensions, filters, timeDimensions, order, limit }. Funnel: { funnel: {...} }. Flow: { flow: {...} }. Retention: { retention: {...} }.",
233
+ properties: i
234
+ } }
235
+ }
236
+ }
237
+ ];
238
+ if (e?.appEnabled) {
239
+ t.push({
240
+ name: "chart",
241
+ description: "Execute a semantic query and render an interactive chart visualization.\n\nSame query format as \"load\", but renders results in the MCP App chart UI.\nInclude a \"chart\" object to control the visualization.\n\nChart types: bar, line, area, pie, scatter, bubble, radar, treemap, kpiNumber, kpiDelta, table, heatmap, funnel, sankey, sunburst, waterfall, activityGrid, boxPlot\nGuidelines: single number -> kpiNumber, trend -> line/area, categories -> bar, part-of-whole -> pie, correlation -> scatter/bubble, distribution -> boxPlot",
227
242
  inputSchema: {
228
243
  type: "object",
229
244
  required: ["query"],
230
245
  properties: {
231
246
  query: {
232
247
  type: "object",
233
- description: "Semantic query object. Regular: { measures, dimensions, filters, timeDimensions, order, limit }. Funnel: { funnel: {...} }. Flow: { flow: {...} }. Retention: { retention: {...} }.",
248
+ description: "Semantic query object. Same format as the load tool.",
234
249
  properties: i
235
250
  },
236
251
  chart: {
237
252
  type: "object",
238
- description: "Optional chart configuration for the MCP App UI. Uses the same chartConfig/displayConfig as the agent portlet system. If omitted, chart type is auto-detected.",
253
+ description: "Chart configuration for the visualization. If omitted, chart type is auto-detected from query shape.",
239
254
  properties: {
240
255
  type: {
241
256
  type: "string",
@@ -336,10 +351,8 @@ function E(e) {
336
351
  }
337
352
  }
338
353
  }
339
- }
340
- ];
341
- if (e?.appEnabled) {
342
- let e = t.find((e) => e.name === "load");
354
+ });
355
+ let e = t.find((e) => e.name === "chart");
343
356
  e && (e._meta = { ui: { resourceUri: s } });
344
357
  }
345
358
  return t;
@@ -348,19 +361,36 @@ async function D(e, i) {
348
361
  let { semanticLayer: a, extractSecurityContext: o, rawRequest: s, rawResponse: c } = i, l = e || {};
349
362
  if (!l.name) throw S(-32602, "name is required for tools/call");
350
363
  let u = l.arguments;
351
- switch (l.name) {
352
- case "discover": return O(await t(a, u || {}));
353
- case "validate": {
354
- let e = u || {};
355
- if (!e.query) throw S(-32602, "query is required");
356
- return O(await n(a, e));
357
- }
358
- case "load": {
359
- let e = u || {};
360
- if (!e.query) throw S(-32602, "query is required");
361
- return O(await r(a, await o(s, c), e));
364
+ try {
365
+ switch (l.name) {
366
+ case "discover": return O(await t(a, u || {}));
367
+ case "validate": {
368
+ let e = u || {};
369
+ if (!e.query) throw S(-32602, "query is required");
370
+ return O(await n(a, e));
371
+ }
372
+ case "load": {
373
+ let e = u || {};
374
+ if (!e.query) throw S(-32602, "query is required");
375
+ return O(await r(a, await o(s, c), e));
376
+ }
377
+ case "chart": {
378
+ let e = u || {};
379
+ if (!e.query) throw S(-32602, "query is required");
380
+ return O(await r(a, await o(s, c), e));
381
+ }
382
+ default: throw S(-32601, `Unknown tool: ${l.name}`);
362
383
  }
363
- default: throw S(-32601, `Unknown tool: ${l.name}`);
384
+ } catch (e) {
385
+ if (e?.code === -32602 || e?.code === -32601) throw e;
386
+ let t = e instanceof Error ? e.message : String(e);
387
+ return {
388
+ content: [{
389
+ type: "text",
390
+ text: JSON.stringify({ error: t })
391
+ }],
392
+ isError: !0
393
+ };
364
394
  }
365
395
  }
366
396
  function O(e) {
@@ -393,13 +423,13 @@ var A = a(), j = [{
393
423
  "Tools:",
394
424
  "- discover: { topic?, intent?, limit?, minScore? } -> cubes list",
395
425
  "- validate: { query } -> corrected query + issues",
396
- "- load: { query } -> data + annotation",
426
+ "- load: { query } -> data + annotation (text only)",
427
+ "- chart: { query, chart? } -> data + interactive chart visualization",
397
428
  "",
398
429
  "Recommended flow:",
399
- "1) tools/list",
400
- "2) tools/call name=discover intent=\"<goal>\"",
401
- "3) tools/call name=validate query=<draft> (optional)",
402
- "4) tools/call name=load query=<validated>",
430
+ "1) tools/call name=discover intent=\"<goal>\"",
431
+ "2) tools/call name=validate query=<draft> (optional)",
432
+ "3) tools/call name=load query=<validated> (data only) OR name=chart query=<validated> chart={type, ...} (with visualization)",
403
433
  "",
404
434
  "Query shapes supported:",
405
435
  "- regular: { measures, dimensions, filters, timeDimensions, order, limit, offset, ungrouped }",