@svgrid/mcp 3.0.21 → 3.0.23

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/index.js CHANGED
@@ -21,26 +21,70 @@ import { createRequire } from 'node:module';
21
21
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
22
22
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
23
23
  import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
24
- import { apiSurface } from './data.js';
25
- import { CORE_TOOLS, handleCoreTool } from './core-tools.js';
26
- import { handleProjectTool } from './project-tools.js';
27
- import { STUDIO_TOOLS, handleStudioTool, studioEnabled } from './studio-tools.js';
28
- import { listResources, readResource } from './resources.js';
29
- import { PREVIEW_TOOL, handlePreview, readPreviewResource } from './preview.js';
24
+ import { CORE_TOOLS, PREVIEW_TOOL } from './tool-defs.js';
30
25
  import { PROMPTS, getPrompt } from './prompts.js';
31
26
  import { installedGrid, versionNote } from './installed.js';
32
27
  import { applyFixes, checkSvGridCode } from './validate.js';
33
28
  import { compileWithSvelte } from './compile-svelte.js';
34
29
  import { ENTERPRISE_LINE, checkNeedsEnterprise } from './enterprise.js';
35
- import { checkLicenseKey, introspectDrizzle, introspectJson, scaffold, summarizeVerify, verifyScaffold, } from '@svgrid/enterprise/studio';
30
+ let corpusLoad;
31
+ function corpus() {
32
+ if (!corpusLoad) {
33
+ corpusLoad = Promise.all([
34
+ import('./data.js'),
35
+ import('./core-tools.js'),
36
+ import('./resources.js'),
37
+ import('./preview.js'),
38
+ ]).then(([data, core, resources, preview]) => ({ apiSurface: data.apiSurface, core, resources, preview }));
39
+ void corpusLoad.then(banner).catch(() => { });
40
+ }
41
+ return corpusLoad;
42
+ }
43
+ let studioApi = null;
44
+ let studioTools = null;
45
+ let projectTools = null;
46
+ const NEEDS_ENTERPRISE = 'This tool runs on @svgrid/enterprise, which is not installed beside the MCP server. ' +
47
+ 'Install both in the project, `npm i -D @svgrid/mcp @svgrid/enterprise`, and run the local server ' +
48
+ '(Claude Code: `claude mcp add svgrid -- npx svgrid-mcp`). ' +
49
+ 'It runs without a license key and watermarks generated apps until one is set. https://svgrid.com/pricing';
50
+ let studioLoad;
51
+ function loadStudio() {
52
+ studioLoad ??= (async () => {
53
+ try {
54
+ studioApi = await import('@svgrid/enterprise/studio');
55
+ studioTools = await import('./studio-tools.js');
56
+ projectTools = await import('./project-tools.js');
57
+ }
58
+ catch (err) {
59
+ studioApi = studioTools = projectTools = null;
60
+ // Enterprise not installed is the expected case. Anything else, a module
61
+ // missing INSIDE enterprise included, is a real failure to load it, and
62
+ // saying so beats a Studio that silently never turns on.
63
+ const code = err?.code;
64
+ const message = String(err?.message ?? err);
65
+ const absent = (code === 'ERR_MODULE_NOT_FOUND' || code === 'MODULE_NOT_FOUND') &&
66
+ /Cannot find (package|module) '@svgrid\/enterprise/.test(message);
67
+ if (!absent)
68
+ process.stderr.write(`@svgrid/mcp: could not load @svgrid/enterprise/studio: ${message}\n`);
69
+ }
70
+ })();
71
+ return studioLoad;
72
+ }
73
+ function studioEnabled() {
74
+ return studioTools?.studioEnabled() ?? false;
75
+ }
76
+ /** The names that run on enterprise, for a useful answer when it is missing. */
77
+ function needsEnterprise(name) {
78
+ return name === 'svgrid_scaffold' || name === 'introspect_source' || name === 'scaffold_entity' || name.startsWith('studio');
79
+ }
36
80
  /**
37
81
  * Soft commercial gate. Uses the SAME classifier as the browser
38
82
  * (checkLicenseKey), reading the key from the SVGRID_LICENSE_KEY env var. Never
39
83
  * blocks - unlicensed generation still runs, it just prepends a nudge (and the
40
84
  * generated app itself watermarks until a key is set).
41
85
  */
42
- function studioNote() {
43
- return checkLicenseKey(process.env.SVGRID_LICENSE_KEY ?? null).valid
86
+ function studioNoteFor(api) {
87
+ return api.checkLicenseKey(process.env.SVGRID_LICENSE_KEY ?? null).valid
44
88
  ? ''
45
89
  : '// SvGrid Studio is a commercial feature. Set SVGRID_LICENSE_KEY (in your MCP\n' +
46
90
  '// server config env) for licensed use. https://svgrid.com/pricing\n\n';
@@ -100,17 +144,26 @@ const SCAFFOLD_TOOL = {
100
144
  required: ['from'],
101
145
  },
102
146
  };
103
- function listedTools() {
147
+ async function listedTools() {
148
+ // The definitions, not the corpus: listing must not wait for data.js.
149
+ await loadStudio();
104
150
  const tools = [...CORE_TOOLS, CHECK_TOOL, PREVIEW_TOOL, SCAFFOLD_TOOL];
105
- if (studioEnabled())
106
- tools.push(...STUDIO_TOOLS);
151
+ if (studioTools && studioEnabled())
152
+ tools.push(...studioTools.STUDIO_TOOLS);
107
153
  return tools;
108
154
  }
109
- server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: listedTools() }));
155
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
156
+ const tools = await listedTools();
157
+ // Warm the corpus once this reply is on the wire, so its first load overlaps
158
+ // the model choosing a tool rather than the first call.
159
+ setTimeout(() => void corpus().catch(() => { }), 50);
160
+ return { tools };
161
+ });
110
162
  // ---- resources ------------------------------------------------------------
111
- server.setRequestHandler(ListResourcesRequestSchema, async (req) => listResources(req.params?.cursor));
163
+ server.setRequestHandler(ListResourcesRequestSchema, async (req) => (await corpus()).resources.listResources(req.params?.cursor));
112
164
  server.setRequestHandler(ReadResourceRequestSchema, async (req) => {
113
- const found = readPreviewResource(req.params.uri) ?? readResource(req.params.uri);
165
+ const { preview, resources } = await corpus();
166
+ const found = preview.readPreviewResource(req.params.uri) ?? resources.readResource(req.params.uri);
114
167
  if (!found)
115
168
  throw new Error(`No SvGrid resource at "${req.params.uri}".`);
116
169
  return found;
@@ -129,6 +182,7 @@ async function runCheck(args) {
129
182
  if (typeof source !== 'string' || !source.trim()) {
130
183
  return errText('source (the file contents to check) is required');
131
184
  }
185
+ const { apiSurface } = await corpus();
132
186
  const result = await checkSvGridCode(source, apiSurface, {
133
187
  filename: typeof args.filename === 'string' ? args.filename : undefined,
134
188
  compile: compileWithSvelte,
@@ -157,6 +211,11 @@ async function runCheck(args) {
157
211
  return { content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }] };
158
212
  }
159
213
  async function runScaffold(args) {
214
+ const api = studioApi;
215
+ if (!api)
216
+ return errText(NEEDS_ENTERPRISE);
217
+ const { introspectDrizzle, introspectJson, scaffold, verifyScaffold, summarizeVerify } = api;
218
+ const studioNote = () => studioNoteFor(api);
160
219
  const from = String(args.from ?? '');
161
220
  try {
162
221
  let schema;
@@ -228,18 +287,19 @@ const LEGACY_TARGET = {
228
287
  server.setRequestHandler(CallToolRequestSchema, async (req) => {
229
288
  const { name, arguments: rawArgs } = req.params;
230
289
  const args = (rawArgs ?? {});
290
+ const [{ core: coreTools, preview }] = await Promise.all([corpus(), loadStudio()]);
231
291
  // Retrieval tools, old names mapped onto the new ones.
232
292
  const legacy = LEGACY[name];
233
293
  if (legacy) {
234
- const mapped = handleCoreTool(LEGACY_TARGET[name], legacy(args));
294
+ const mapped = coreTools.handleCoreTool(LEGACY_TARGET[name], legacy(args));
235
295
  if (mapped)
236
296
  return mapped;
237
297
  }
238
- const core = handleCoreTool(name, args);
298
+ const core = coreTools.handleCoreTool(name, args);
239
299
  if (core)
240
300
  return core;
241
301
  if (name === 'svgrid_preview')
242
- return handlePreview(args);
302
+ return preview.handlePreview(args);
243
303
  if (name === 'svgrid_check_code' || name === 'check_svgrid_code')
244
304
  return runCheck(args);
245
305
  if (name === 'svgrid_scaffold')
@@ -259,18 +319,23 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
259
319
  }
260
320
  // Consolidated Studio tools, then the 27 individual pre-3.0 ones, which the
261
321
  // project dispatcher still understands.
262
- const studio = handleStudioTool(name, args);
263
- if (studio)
264
- return studio;
265
- const project = handleProjectTool(name, args);
266
- if (project)
267
- return project;
322
+ if (studioTools && projectTools) {
323
+ const studio = studioTools.handleStudioTool(name, args);
324
+ if (studio)
325
+ return studio;
326
+ const project = projectTools.handleProjectTool(name, args);
327
+ if (project)
328
+ return project;
329
+ }
330
+ else if (needsEnterprise(name)) {
331
+ return errText(NEEDS_ENTERPRISE);
332
+ }
268
333
  return {
269
334
  isError: true,
270
335
  content: [
271
336
  {
272
337
  type: 'text',
273
- text: `Unknown tool: ${name}. Available: ${listedTools()
338
+ text: `Unknown tool: ${name}. Available: ${(await listedTools())
274
339
  .map((t) => t.name)
275
340
  .join(', ')}` +
276
341
  (studioEnabled()
@@ -281,20 +346,28 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
281
346
  };
282
347
  });
283
348
  async function main() {
349
+ // Connect and nothing else: `initialize` is answered by the SDK and needs
350
+ // neither the corpus nor enterprise. They load on the first request that
351
+ // does (normally tools/list). Loading them eagerly after connect did not
352
+ // help: the first read of the 12 MB corpus held the event loop for seconds,
353
+ // and the initialize reply waited behind it.
284
354
  const transport = new StdioServerTransport();
285
355
  await server.connect(transport);
286
- // The MCP SDK keeps the process alive on the stdio transport, so we just log
287
- // a startup banner to stderr (stdout is reserved for the JSON-RPC protocol)
288
- // and let the SDK take over.
289
- // Name both versions up front. A corpus that describes a different grid than
290
- // the one installed is the quietest way for this server to be confidently
291
- // wrong, and the banner is where someone would actually notice.
356
+ process.stderr.write(`@svgrid/mcp ${pkgVersion} on stdio\n`);
357
+ }
358
+ /** The fuller banner, once the corpus is in, naming both grid versions. */
359
+ async function banner() {
360
+ const [{ apiSurface }] = await Promise.all([corpus(), loadStudio()]);
361
+ // stderr: stdout is reserved for the JSON-RPC protocol.
362
+ // Name both versions. A corpus that describes a different grid than the one
363
+ // installed is the quietest way for this server to be confidently wrong, and
364
+ // the banner is where someone would actually notice.
292
365
  const found = installedGrid();
293
366
  const versions = found && found.version !== apiSurface.gridVersion
294
367
  ? ` - describes grid ${apiSurface.gridVersion}, but ${found.version} is installed here`
295
368
  : ` - grid ${apiSurface.gridVersion}${found ? ' (matches installed)' : ''}`;
296
- process.stderr.write(`@svgrid/mcp ${pkgVersion} on stdio - ${listedTools().length} tools` +
297
- (studioEnabled() ? ' (Studio on)' : '') +
369
+ process.stderr.write(`@svgrid/mcp ${pkgVersion} ready - ${(await listedTools()).length} tools` +
370
+ (studioEnabled() ? ' (Studio on)' : studioApi ? '' : ' (Studio off: @svgrid/enterprise not installed)') +
298
371
  versions +
299
372
  '\n');
300
373
  }
package/dist/preview.d.ts CHANGED
@@ -1,6 +1,6 @@
1
+ export { UI_RESOURCE_URI, PREVIEW_TOOL } from './tool-defs.js';
1
2
  /** MCP Apps constants, inlined rather than depending on the extension SDK server-side. */
2
3
  export declare const UI_MIME_TYPE = "text/html;profile=mcp-app";
3
- export declare const UI_RESOURCE_URI = "ui://svgrid/preview.html";
4
4
  /**
5
5
  * The published versions the preview loads from the CDN.
6
6
  *
@@ -8,7 +8,7 @@ export declare const UI_RESOURCE_URI = "ui://svgrid/preview.html";
8
8
  * start failing in a way nobody is watching for. `tools/mcp-tools.test.ts` checks these
9
9
  * against the workspace so they cannot quietly rot either.
10
10
  */
11
- export declare const PREVIEW_GRID_WC_VERSION = "3.0.20";
11
+ export declare const PREVIEW_GRID_WC_VERSION = "3.0.24";
12
12
  export declare function previewResource(): {
13
13
  uri: string;
14
14
  name: string;
@@ -29,52 +29,6 @@ export declare function readPreviewResource(uri: string): {
29
29
  text: string;
30
30
  }[];
31
31
  } | undefined;
32
- export declare const PREVIEW_TOOL: {
33
- name: string;
34
- title: string;
35
- description: string;
36
- inputSchema: {
37
- type: string;
38
- properties: {
39
- columns: {
40
- type: string;
41
- description: string;
42
- };
43
- data: {
44
- type: string;
45
- description: string;
46
- };
47
- demo: {
48
- type: string;
49
- description: string;
50
- };
51
- title: {
52
- type: string;
53
- description: string;
54
- };
55
- sortable: {
56
- type: string;
57
- description: string;
58
- };
59
- filterable: {
60
- type: string;
61
- description: string;
62
- };
63
- pageable: {
64
- type: string;
65
- description: string;
66
- };
67
- groupBy: {
68
- type: string;
69
- description: string;
70
- };
71
- };
72
- required: never[];
73
- };
74
- _meta: {
75
- "ui/resourceUri": string;
76
- };
77
- };
78
32
  type ToolResult = {
79
33
  isError?: boolean;
80
34
  content: {
@@ -85,4 +39,3 @@ type ToolResult = {
85
39
  _meta?: Record<string, unknown>;
86
40
  };
87
41
  export declare function handlePreview(args: Record<string, unknown>): ToolResult;
88
- export {};
package/dist/preview.js CHANGED
@@ -16,10 +16,10 @@
16
16
  * why the text half has to stand on its own rather than say "see the preview".
17
17
  */
18
18
  import { examples } from './data.js';
19
+ import { UI_RESOURCE_URI, UI_RESOURCE_META_KEY } from './tool-defs.js';
20
+ export { UI_RESOURCE_URI, PREVIEW_TOOL } from './tool-defs.js';
19
21
  /** MCP Apps constants, inlined rather than depending on the extension SDK server-side. */
20
22
  export const UI_MIME_TYPE = 'text/html;profile=mcp-app';
21
- export const UI_RESOURCE_URI = 'ui://svgrid/preview.html';
22
- const UI_RESOURCE_META_KEY = 'ui/resourceUri';
23
23
  /**
24
24
  * The published versions the preview loads from the CDN.
25
25
  *
@@ -27,7 +27,7 @@ const UI_RESOURCE_META_KEY = 'ui/resourceUri';
27
27
  * start failing in a way nobody is watching for. `tools/mcp-tools.test.ts` checks these
28
28
  * against the workspace so they cannot quietly rot either.
29
29
  */
30
- export const PREVIEW_GRID_WC_VERSION = '3.0.20';
30
+ export const PREVIEW_GRID_WC_VERSION = '3.0.24';
31
31
  const EXT_APPS_VERSION = '1.7.5';
32
32
  const CDN = 'https://cdn.jsdelivr.net/npm';
33
33
  /**
@@ -116,35 +116,6 @@ export function readPreviewResource(uri) {
116
116
  return undefined;
117
117
  return { contents: [{ uri, mimeType: UI_MIME_TYPE, text: PREVIEW_HTML }] };
118
118
  }
119
- export const PREVIEW_TOOL = {
120
- name: 'svgrid_preview',
121
- title: 'Preview a grid',
122
- description: 'Render a REAL, interactive SvGrid in the conversation - sortable, filterable, scrollable - from columns and rows you pass, or from a demo id. Use it to show the user what a grid will look like before they build it, and after svgrid_check_code to demonstrate the result. In clients without UI support it returns a text summary instead, so it is always safe to call.',
123
- inputSchema: {
124
- type: 'object',
125
- properties: {
126
- columns: {
127
- type: 'array',
128
- description: 'Column definitions, e.g. [{ "field": "name", "header": "Name", "width": 160 }]. Required unless `demo` is set.',
129
- },
130
- data: {
131
- type: 'array',
132
- description: 'Rows to display. Required unless `demo` is set. Keep it under a few hundred for a preview.',
133
- },
134
- demo: {
135
- type: 'string',
136
- description: 'Preview a shipped demo instead, by id (e.g. "11-stock-market"). Its source is returned as text; find ids with svgrid_search.',
137
- },
138
- title: { type: 'string', description: 'Caption shown above the grid.' },
139
- sortable: { type: 'boolean', description: 'Sortable headers. Default true.' },
140
- filterable: { type: 'boolean', description: 'Filtering. Default true.' },
141
- pageable: { type: 'boolean', description: 'Pagination footer.' },
142
- groupBy: { type: 'array', description: 'Group by these column ids.' },
143
- },
144
- required: [],
145
- },
146
- _meta: { [UI_RESOURCE_META_KEY]: UI_RESOURCE_URI },
147
- };
148
119
  const fail = (message) => ({
149
120
  isError: true,
150
121
  content: [{ type: 'text', text: message }],
@@ -0,0 +1,122 @@
1
+ /**
2
+ * The tool definitions `tools/list` returns, kept free of the corpus.
3
+ *
4
+ * `core-tools.ts` and `preview.ts` read `data.js` (about 12 MB), whose first
5
+ * load after install took seconds. Defining the tools here lets the server
6
+ * list them without loading it; the handlers stay in those modules, which
7
+ * re-export these for existing imports.
8
+ */
9
+ export declare const UI_RESOURCE_URI = "ui://svgrid/preview.html";
10
+ export declare const UI_RESOURCE_META_KEY = "ui/resourceUri";
11
+ export declare const CORE_TOOLS: readonly [{
12
+ readonly name: "svgrid_search";
13
+ readonly title: "Search SvGrid";
14
+ readonly description: "Search SvGrid docs, example demos and the API surface in ONE call. Start here for any \"how do I ...\" question - it covers all three, so you do not have to guess which one holds the answer. Call with no arguments for an index of doc sections, demo categories and API groups. Returns ids/slugs you can pass to svgrid_get.";
15
+ readonly inputSchema: {
16
+ readonly type: "object";
17
+ readonly properties: {
18
+ readonly query: {
19
+ readonly type: "string";
20
+ readonly description: "What you are trying to do, e.g. \"pin a column\", \"server side pagination\", \"kanban swimlanes\". Omit for the index.";
21
+ };
22
+ readonly kind: {
23
+ readonly type: "string";
24
+ readonly enum: readonly ["all", "docs", "examples", "api"];
25
+ readonly description: "Restrict the search. Default \"all\".";
26
+ readonly default: "all";
27
+ };
28
+ readonly detail: {
29
+ readonly type: "string";
30
+ readonly enum: readonly ["concise", "full"];
31
+ readonly description: "\"concise\" (default) returns titles plus a short excerpt. \"full\" returns the matching doc excerpts at length - more tokens, fewer follow-up calls.";
32
+ readonly default: "concise";
33
+ };
34
+ readonly section: {
35
+ readonly type: "string";
36
+ readonly description: "Restrict docs to one section, exactly, e.g. \"Help\". Call with no arguments to see the sections.";
37
+ };
38
+ readonly category: {
39
+ readonly type: "string";
40
+ readonly description: "Restrict demos to one category, exactly, e.g. \"Kanban\". Call with no arguments to see the categories.";
41
+ };
42
+ readonly limit: {
43
+ readonly type: "number";
44
+ readonly description: "Max results per corpus. Default 10, max 50.";
45
+ readonly default: 10;
46
+ };
47
+ };
48
+ readonly required: readonly [];
49
+ };
50
+ }, {
51
+ readonly name: "svgrid_get";
52
+ readonly title: "Read a doc or demo";
53
+ readonly description: "Fetch one thing in full by reference: a doc slug (\"help/columns/column-definitions\"), a demo id (\"11-stock-market\"), or \"api\" for the curated API reference. Use svgrid_search first to find the reference.";
54
+ readonly inputSchema: {
55
+ readonly type: "object";
56
+ readonly properties: {
57
+ readonly ref: {
58
+ readonly type: "string";
59
+ readonly description: "A doc slug, a demo id, \"api\", or a schema id such as \"chart-spec\" (or \"chart spec schema\"). The kind is inferred; pass `kind` to force it.";
60
+ };
61
+ readonly kind: {
62
+ readonly type: "string";
63
+ readonly enum: readonly ["auto", "doc", "example", "api", "schema"];
64
+ readonly description: "Override the inferred kind. Default \"auto\".";
65
+ readonly default: "auto";
66
+ };
67
+ readonly detail: {
68
+ readonly type: "string";
69
+ readonly enum: readonly ["concise", "full"];
70
+ readonly description: "\"full\" (default) returns the whole thing; \"concise\" truncates long content.";
71
+ readonly default: "full";
72
+ };
73
+ };
74
+ readonly required: readonly ["ref"];
75
+ };
76
+ }];
77
+ export declare const PREVIEW_TOOL: {
78
+ name: string;
79
+ title: string;
80
+ description: string;
81
+ inputSchema: {
82
+ type: string;
83
+ properties: {
84
+ columns: {
85
+ type: string;
86
+ description: string;
87
+ };
88
+ data: {
89
+ type: string;
90
+ description: string;
91
+ };
92
+ demo: {
93
+ type: string;
94
+ description: string;
95
+ };
96
+ title: {
97
+ type: string;
98
+ description: string;
99
+ };
100
+ sortable: {
101
+ type: string;
102
+ description: string;
103
+ };
104
+ filterable: {
105
+ type: string;
106
+ description: string;
107
+ };
108
+ pageable: {
109
+ type: string;
110
+ description: string;
111
+ };
112
+ groupBy: {
113
+ type: string;
114
+ description: string;
115
+ };
116
+ };
117
+ required: never[];
118
+ };
119
+ _meta: {
120
+ "ui/resourceUri": string;
121
+ };
122
+ };
@@ -0,0 +1,104 @@
1
+ /**
2
+ * The tool definitions `tools/list` returns, kept free of the corpus.
3
+ *
4
+ * `core-tools.ts` and `preview.ts` read `data.js` (about 12 MB), whose first
5
+ * load after install took seconds. Defining the tools here lets the server
6
+ * list them without loading it; the handlers stay in those modules, which
7
+ * re-export these for existing imports.
8
+ */
9
+ export const UI_RESOURCE_URI = 'ui://svgrid/preview.html';
10
+ export const UI_RESOURCE_META_KEY = 'ui/resourceUri';
11
+ export const CORE_TOOLS = [
12
+ {
13
+ name: 'svgrid_search',
14
+ title: 'Search SvGrid',
15
+ description: 'Search SvGrid docs, example demos and the API surface in ONE call. Start here for any "how do I ..." question - it covers all three, so you do not have to guess which one holds the answer. Call with no arguments for an index of doc sections, demo categories and API groups. Returns ids/slugs you can pass to svgrid_get.',
16
+ inputSchema: {
17
+ type: 'object',
18
+ properties: {
19
+ query: {
20
+ type: 'string',
21
+ description: 'What you are trying to do, e.g. "pin a column", "server side pagination", "kanban swimlanes". Omit for the index.',
22
+ },
23
+ kind: {
24
+ type: 'string',
25
+ enum: ['all', 'docs', 'examples', 'api'],
26
+ description: 'Restrict the search. Default "all".',
27
+ default: 'all',
28
+ },
29
+ detail: {
30
+ type: 'string',
31
+ enum: ['concise', 'full'],
32
+ description: '"concise" (default) returns titles plus a short excerpt. "full" returns the matching doc excerpts at length - more tokens, fewer follow-up calls.',
33
+ default: 'concise',
34
+ },
35
+ section: {
36
+ type: 'string',
37
+ description: 'Restrict docs to one section, exactly, e.g. "Help". Call with no arguments to see the sections.',
38
+ },
39
+ category: {
40
+ type: 'string',
41
+ description: 'Restrict demos to one category, exactly, e.g. "Kanban". Call with no arguments to see the categories.',
42
+ },
43
+ limit: { type: 'number', description: 'Max results per corpus. Default 10, max 50.', default: 10 },
44
+ },
45
+ required: [],
46
+ },
47
+ },
48
+ {
49
+ name: 'svgrid_get',
50
+ title: 'Read a doc or demo',
51
+ description: 'Fetch one thing in full by reference: a doc slug ("help/columns/column-definitions"), a demo id ("11-stock-market"), or "api" for the curated API reference. Use svgrid_search first to find the reference.',
52
+ inputSchema: {
53
+ type: 'object',
54
+ properties: {
55
+ ref: {
56
+ type: 'string',
57
+ description: 'A doc slug, a demo id, "api", or a schema id such as "chart-spec" (or "chart spec schema"). The kind is inferred; pass `kind` to force it.',
58
+ },
59
+ kind: {
60
+ type: 'string',
61
+ enum: ['auto', 'doc', 'example', 'api', 'schema'],
62
+ description: 'Override the inferred kind. Default "auto".',
63
+ default: 'auto',
64
+ },
65
+ detail: {
66
+ type: 'string',
67
+ enum: ['concise', 'full'],
68
+ description: '"full" (default) returns the whole thing; "concise" truncates long content.',
69
+ default: 'full',
70
+ },
71
+ },
72
+ required: ['ref'],
73
+ },
74
+ },
75
+ ];
76
+ export const PREVIEW_TOOL = {
77
+ name: 'svgrid_preview',
78
+ title: 'Preview a grid',
79
+ description: 'Render a REAL, interactive SvGrid in the conversation - sortable, filterable, scrollable - from columns and rows you pass, or from a demo id. Use it to show the user what a grid will look like before they build it, and after svgrid_check_code to demonstrate the result. In clients without UI support it returns a text summary instead, so it is always safe to call.',
80
+ inputSchema: {
81
+ type: 'object',
82
+ properties: {
83
+ columns: {
84
+ type: 'array',
85
+ description: 'Column definitions, e.g. [{ "field": "name", "header": "Name", "width": 160 }]. Required unless `demo` is set.',
86
+ },
87
+ data: {
88
+ type: 'array',
89
+ description: 'Rows to display. Required unless `demo` is set. Keep it under a few hundred for a preview.',
90
+ },
91
+ demo: {
92
+ type: 'string',
93
+ description: 'Preview a shipped demo instead, by id (e.g. "11-stock-market"). Its source is returned as text; find ids with svgrid_search.',
94
+ },
95
+ title: { type: 'string', description: 'Caption shown above the grid.' },
96
+ sortable: { type: 'boolean', description: 'Sortable headers. Default true.' },
97
+ filterable: { type: 'boolean', description: 'Filtering. Default true.' },
98
+ pageable: { type: 'boolean', description: 'Pagination footer.' },
99
+ groupBy: { type: 'array', description: 'Group by these column ids.' },
100
+ },
101
+ required: [],
102
+ },
103
+ _meta: { [UI_RESOURCE_META_KEY]: UI_RESOURCE_URI },
104
+ };
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "type": "commercial",
6
6
  "url": "https://svgrid.com/pricing"
7
7
  },
8
- "version": "3.0.21",
8
+ "version": "3.0.23",
9
9
  "description": "Model Context Protocol server for SvGrid, the Svelte 5 data grid: checks the code your AI writes against the real API surface, plus version-pinned docs, API reference and 373 demo sources.",
10
10
  "license": "MIT",
11
11
  "author": "jQWidgets <sales@jqwidgets.com>",
@@ -32,12 +32,20 @@
32
32
  "dependencies": {
33
33
  "@modelcontextprotocol/sdk": "^1.0.4",
34
34
  "svelte": "^5.55.5",
35
- "zod": "^3.23.8",
36
- "@svgrid/enterprise": "^3.1.15"
35
+ "zod": "^3.23.8"
36
+ },
37
+ "peerDependencies": {
38
+ "@svgrid/enterprise": "^3.1.18"
39
+ },
40
+ "peerDependenciesMeta": {
41
+ "@svgrid/enterprise": {
42
+ "optional": true
43
+ }
37
44
  },
38
45
  "devDependencies": {
39
46
  "@types/node": "^22.10.7",
40
- "typescript": "6.0.3"
47
+ "typescript": "6.0.3",
48
+ "@svgrid/enterprise": "^3.1.18"
41
49
  },
42
50
  "engines": {
43
51
  "node": ">=18"
package/server.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "name": "com.svgrid/svgrid",
4
4
  "title": "SvGrid",
5
5
  "description": "Checks AI-written SvGrid code against the real API, plus version-pinned Svelte 5 grid docs.",
6
- "version": "3.0.21",
6
+ "version": "3.0.23",
7
7
  "websiteUrl": "https://svgrid.com/docs/help/mcp-server/",
8
8
  "repository": {
9
9
  "url": "https://github.com/sv-grid/sv-grid",
@@ -15,7 +15,7 @@
15
15
  "registryType": "npm",
16
16
  "registryBaseUrl": "https://registry.npmjs.org",
17
17
  "identifier": "@svgrid/mcp",
18
- "version": "3.0.21",
18
+ "version": "3.0.23",
19
19
  "runtimeHint": "npx",
20
20
  "transport": {
21
21
  "type": "stdio"