@ace-grid/mcp 1.0.6
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/LICENSE +21 -0
- package/README.md +94 -0
- package/data/apiSpecCoverage.json +408 -0
- package/data/apiSpecQuality.json +15 -0
- package/data/docsIndex.json +4632 -0
- package/data/formulaFunctionSnapshot.json +1137 -0
- package/data/gridApiSnapshot.json +9162 -0
- package/dist/catalog.d.ts +229 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +518 -0
- package/dist/demoServer.d.ts +2 -0
- package/dist/demoServer.d.ts.map +1 -0
- package/dist/demoServer.js +324 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +79 -0
- package/dist/portalApi.d.ts +18 -0
- package/dist/portalApi.d.ts.map +1 -0
- package/dist/portalApi.js +34 -0
- package/dist/tools.d.ts +78 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +154 -0
- package/package.json +58 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { toolHandlers } from "./tools.js";
|
|
4
|
+
const port = Number(process.env.PORT ?? 4177);
|
|
5
|
+
const googleClient = process.env.GOOGLE_API_CLIENT ?? "gen-lang-client-0901195546";
|
|
6
|
+
const defaultApiKey = process.env.GOOGLE_API_KEY ?? "";
|
|
7
|
+
const models = [
|
|
8
|
+
{ id: "gemma-4-31b-it", label: "Gemma 4 31B" },
|
|
9
|
+
{ id: "gemini-3.1-flash-lite", label: "Gemini 3.1 Flash Lite" },
|
|
10
|
+
{ id: "gemini-3.5-flash", label: "Gemini 3.5 Flash" },
|
|
11
|
+
];
|
|
12
|
+
const testPrompts = [
|
|
13
|
+
"Search Ace Grid docs for license setup and explain whether users need to pass leaseSigningPublicKey.",
|
|
14
|
+
"Find the metadata for license.appId and license.domain.",
|
|
15
|
+
"Open the validation docs page and summarize when to use it.",
|
|
16
|
+
"Generate a Svelte Ace Grid example and explain the package imports.",
|
|
17
|
+
"Plan an Angular Enterprise grid with server row model, pivoting, and pagination.",
|
|
18
|
+
"Generate a Svelte Pro grid with validation, appId app_demo, and license key ag_key_demo.",
|
|
19
|
+
"Generate a Vue implementation for charts and master detail with domain app.example.com.",
|
|
20
|
+
"Generate a React Pro example using appId app_demo and license key ag_key_demo.",
|
|
21
|
+
"Validate this config and explain what is wrong: {\"data\":{\"rows\":[]},\"layout\":{\"height\":400},\"badFeature\":true}",
|
|
22
|
+
"Which Ace Grid feature groups are relevant for spreadsheet editing and validation?",
|
|
23
|
+
"Create an Enterprise React example with domain app.example.com.",
|
|
24
|
+
"Explain the difference between automatic browser domain detection and an explicit license domain.",
|
|
25
|
+
];
|
|
26
|
+
const localToolNames = [
|
|
27
|
+
"ace_grid_search_docs",
|
|
28
|
+
"ace_grid_search_api",
|
|
29
|
+
"ace_grid_search_doc_pages",
|
|
30
|
+
"ace_grid_list_doc_pages",
|
|
31
|
+
"ace_grid_get_doc_page",
|
|
32
|
+
"ace_grid_list_feature_groups",
|
|
33
|
+
"ace_grid_get_prop",
|
|
34
|
+
"ace_grid_validate_config",
|
|
35
|
+
"ace_grid_plan_implementation",
|
|
36
|
+
"ace_grid_generate_implementation",
|
|
37
|
+
"ace_grid_generate_react_example",
|
|
38
|
+
"ace_grid_list_examples",
|
|
39
|
+
"ace_grid_generate_framework_example",
|
|
40
|
+
"ace_grid_license_setup",
|
|
41
|
+
];
|
|
42
|
+
const localToolDescriptions = {
|
|
43
|
+
ace_grid_search_docs: "Search all bundled Ace Grid docs and API metadata. Arguments: { query: string, limit?: number }.",
|
|
44
|
+
ace_grid_search_api: "Search only generated API metadata. Arguments: { query: string, limit?: number }.",
|
|
45
|
+
ace_grid_search_doc_pages: "Search only written docs pages. Arguments: { query: string, limit?: number }.",
|
|
46
|
+
ace_grid_list_doc_pages: "List bundled docs pages. Arguments: {}.",
|
|
47
|
+
ace_grid_get_doc_page: "Get a docs page by slug or path. Arguments: { slugOrPath: string }.",
|
|
48
|
+
ace_grid_list_feature_groups: "List feature groups and generated metadata status. Arguments: {}.",
|
|
49
|
+
ace_grid_get_prop: "Get a property by path, for example license.appId. Arguments: { path: string }.",
|
|
50
|
+
ace_grid_validate_config: "Validate an Ace Grid config object. Arguments: { config: object }.",
|
|
51
|
+
ace_grid_plan_implementation: "Plan an implementation from a query. Arguments: { query: string, framework?: 'react'|'angular'|'vue'|'svelte'|'web-components', tier?: 'Community'|'Pro'|'Enterprise' }.",
|
|
52
|
+
ace_grid_generate_implementation: "Generate implementation code from a query. Arguments: { query: string, framework?: 'react'|'angular'|'vue'|'svelte'|'web-components', tier?: 'Community'|'Pro'|'Enterprise', appId?: string, licenseKey?: string, domain?: string }.",
|
|
53
|
+
ace_grid_generate_react_example: "Generate React example. Arguments: { plan?: 'Community'|'Pro'|'Enterprise', appId?: string, licenseKey?: string, domain?: string }.",
|
|
54
|
+
ace_grid_list_examples: "List framework examples. Arguments: {}.",
|
|
55
|
+
ace_grid_generate_framework_example: "Generate framework example. Arguments: { framework: 'react'|'angular'|'vue'|'svelte'|'web-components', includeActions?: boolean }.",
|
|
56
|
+
ace_grid_license_setup: "Explain license setup, public key auto-fetch, and domain behavior. Arguments: {}.",
|
|
57
|
+
};
|
|
58
|
+
function json(response, status, body) {
|
|
59
|
+
response.writeHead(status, {
|
|
60
|
+
"content-type": "application/json; charset=utf-8",
|
|
61
|
+
});
|
|
62
|
+
response.end(JSON.stringify(body));
|
|
63
|
+
}
|
|
64
|
+
function text(response, status, body, contentType) {
|
|
65
|
+
response.writeHead(status, {
|
|
66
|
+
"content-type": contentType,
|
|
67
|
+
});
|
|
68
|
+
response.end(body);
|
|
69
|
+
}
|
|
70
|
+
async function readJsonBody(request) {
|
|
71
|
+
const chunks = [];
|
|
72
|
+
for await (const chunk of request) {
|
|
73
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
74
|
+
}
|
|
75
|
+
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
76
|
+
}
|
|
77
|
+
function parseJsonBlock(value) {
|
|
78
|
+
const fenced = value.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
79
|
+
const text = fenced?.[1] ?? value;
|
|
80
|
+
const firstBrace = text.indexOf("{");
|
|
81
|
+
const lastBrace = text.lastIndexOf("}");
|
|
82
|
+
const candidate = firstBrace >= 0 && lastBrace > firstBrace ? text.slice(firstBrace, lastBrace + 1) : text;
|
|
83
|
+
return JSON.parse(candidate);
|
|
84
|
+
}
|
|
85
|
+
function googleEndpoint(model, apiKey) {
|
|
86
|
+
return `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(model)}:generateContent?key=${encodeURIComponent(apiKey)}`;
|
|
87
|
+
}
|
|
88
|
+
function isFramework(value) {
|
|
89
|
+
return (value === "react" ||
|
|
90
|
+
value === "angular" ||
|
|
91
|
+
value === "vue" ||
|
|
92
|
+
value === "svelte" ||
|
|
93
|
+
value === "web-components");
|
|
94
|
+
}
|
|
95
|
+
function isTier(value) {
|
|
96
|
+
return value === "Community" || value === "Pro" || value === "Enterprise";
|
|
97
|
+
}
|
|
98
|
+
async function callGoogle(options) {
|
|
99
|
+
const response = await fetch(googleEndpoint(options.model, options.apiKey), {
|
|
100
|
+
body: JSON.stringify({
|
|
101
|
+
contents: [
|
|
102
|
+
{
|
|
103
|
+
parts: [{ text: options.prompt }],
|
|
104
|
+
role: "user",
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
generationConfig: {
|
|
108
|
+
temperature: 0.2,
|
|
109
|
+
},
|
|
110
|
+
}),
|
|
111
|
+
headers: {
|
|
112
|
+
"content-type": "application/json",
|
|
113
|
+
"x-goog-api-client": googleClient,
|
|
114
|
+
},
|
|
115
|
+
method: "POST",
|
|
116
|
+
});
|
|
117
|
+
const body = await response.json().catch(() => ({}));
|
|
118
|
+
if (!response.ok) {
|
|
119
|
+
const message = typeof body === "object" && body && "error" in body
|
|
120
|
+
? JSON.stringify(body.error)
|
|
121
|
+
: "Google model request failed.";
|
|
122
|
+
throw new Error(message);
|
|
123
|
+
}
|
|
124
|
+
const text = body
|
|
125
|
+
.candidates?.[0]?.content?.parts?.map((part) => part.text ?? "")
|
|
126
|
+
.join("\n")
|
|
127
|
+
.trim();
|
|
128
|
+
return text || JSON.stringify(body, null, 2);
|
|
129
|
+
}
|
|
130
|
+
async function executeToolCall(call) {
|
|
131
|
+
if (!localToolNames.includes(call.name)) {
|
|
132
|
+
throw new Error(`Unsupported local demo tool: ${call.name}`);
|
|
133
|
+
}
|
|
134
|
+
const args = call.arguments ?? {};
|
|
135
|
+
switch (call.name) {
|
|
136
|
+
case "ace_grid_search_docs":
|
|
137
|
+
return toolHandlers.searchDocs({
|
|
138
|
+
limit: typeof args.limit === "number" ? args.limit : 8,
|
|
139
|
+
query: String(args.query ?? ""),
|
|
140
|
+
});
|
|
141
|
+
case "ace_grid_search_api":
|
|
142
|
+
return toolHandlers.searchApi({
|
|
143
|
+
limit: typeof args.limit === "number" ? args.limit : 8,
|
|
144
|
+
query: String(args.query ?? ""),
|
|
145
|
+
});
|
|
146
|
+
case "ace_grid_search_doc_pages":
|
|
147
|
+
return toolHandlers.searchDocsPages({
|
|
148
|
+
limit: typeof args.limit === "number" ? args.limit : 8,
|
|
149
|
+
query: String(args.query ?? ""),
|
|
150
|
+
});
|
|
151
|
+
case "ace_grid_list_doc_pages":
|
|
152
|
+
return toolHandlers.listDocsPages();
|
|
153
|
+
case "ace_grid_get_doc_page":
|
|
154
|
+
return toolHandlers.getDocsPage({ slugOrPath: String(args.slugOrPath ?? "") });
|
|
155
|
+
case "ace_grid_list_feature_groups":
|
|
156
|
+
return toolHandlers.listFeatureGroups();
|
|
157
|
+
case "ace_grid_get_prop":
|
|
158
|
+
return toolHandlers.getProp({ path: String(args.path ?? "") });
|
|
159
|
+
case "ace_grid_validate_config":
|
|
160
|
+
return toolHandlers.validateConfig({ config: args.config });
|
|
161
|
+
case "ace_grid_plan_implementation":
|
|
162
|
+
return toolHandlers.planImplementation({
|
|
163
|
+
framework: isFramework(args.framework) ? args.framework : undefined,
|
|
164
|
+
query: String(args.query ?? ""),
|
|
165
|
+
tier: isTier(args.tier) ? args.tier : undefined,
|
|
166
|
+
});
|
|
167
|
+
case "ace_grid_generate_implementation":
|
|
168
|
+
return toolHandlers.generateImplementation({
|
|
169
|
+
appId: typeof args.appId === "string" ? args.appId : undefined,
|
|
170
|
+
domain: typeof args.domain === "string" ? args.domain : undefined,
|
|
171
|
+
framework: isFramework(args.framework) ? args.framework : undefined,
|
|
172
|
+
licenseKey: typeof args.licenseKey === "string" ? args.licenseKey : undefined,
|
|
173
|
+
query: String(args.query ?? ""),
|
|
174
|
+
tier: isTier(args.tier) ? args.tier : undefined,
|
|
175
|
+
});
|
|
176
|
+
case "ace_grid_generate_react_example":
|
|
177
|
+
return toolHandlers.generateReactExample({
|
|
178
|
+
appId: typeof args.appId === "string" ? args.appId : undefined,
|
|
179
|
+
domain: typeof args.domain === "string" ? args.domain : undefined,
|
|
180
|
+
licenseKey: typeof args.licenseKey === "string" ? args.licenseKey : undefined,
|
|
181
|
+
plan: args.plan === "Community" || args.plan === "Pro" || args.plan === "Enterprise"
|
|
182
|
+
? args.plan
|
|
183
|
+
: undefined,
|
|
184
|
+
});
|
|
185
|
+
case "ace_grid_list_examples":
|
|
186
|
+
return toolHandlers.listExamples();
|
|
187
|
+
case "ace_grid_generate_framework_example":
|
|
188
|
+
return toolHandlers.generateFrameworkExample({
|
|
189
|
+
framework: String(args.framework ?? ""),
|
|
190
|
+
includeActions: Boolean(args.includeActions),
|
|
191
|
+
});
|
|
192
|
+
case "ace_grid_license_setup":
|
|
193
|
+
return toolHandlers.licenseSetup();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
async function runDemoAgent(input) {
|
|
197
|
+
const plannerPrompt = [
|
|
198
|
+
"You are testing the local Ace Grid MCP server.",
|
|
199
|
+
"Choose zero to three useful local tool calls before answering.",
|
|
200
|
+
"Return only JSON with this exact shape:",
|
|
201
|
+
'{"toolCalls":[{"name":"ace_grid_search_docs","arguments":{"query":"license"}}],"notes":"why these tools help"}',
|
|
202
|
+
"",
|
|
203
|
+
"Available tools:",
|
|
204
|
+
...Object.entries(localToolDescriptions).map(([name, description]) => `- ${name}: ${description}`),
|
|
205
|
+
"",
|
|
206
|
+
`User prompt: ${input.prompt}`,
|
|
207
|
+
].join("\n");
|
|
208
|
+
const plannerText = await callGoogle({
|
|
209
|
+
apiKey: input.apiKey,
|
|
210
|
+
model: input.model,
|
|
211
|
+
prompt: plannerPrompt,
|
|
212
|
+
});
|
|
213
|
+
const parsed = parseJsonBlock(plannerText);
|
|
214
|
+
const toolCalls = Array.isArray(parsed.toolCalls) ? parsed.toolCalls.slice(0, 3) : [];
|
|
215
|
+
const toolResults = [];
|
|
216
|
+
for (const call of toolCalls) {
|
|
217
|
+
const result = await executeToolCall(call);
|
|
218
|
+
toolResults.push({
|
|
219
|
+
call,
|
|
220
|
+
result: result.content.map((item) => item.text).join("\n"),
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
const finalPrompt = [
|
|
224
|
+
"Answer the user's Ace Grid question using the MCP tool results.",
|
|
225
|
+
"Be concrete. If code is useful, include code.",
|
|
226
|
+
"",
|
|
227
|
+
`User prompt: ${input.prompt}`,
|
|
228
|
+
"",
|
|
229
|
+
`Planner notes: ${parsed.notes ?? ""}`,
|
|
230
|
+
"",
|
|
231
|
+
"Tool results:",
|
|
232
|
+
JSON.stringify(toolResults, null, 2),
|
|
233
|
+
].join("\n");
|
|
234
|
+
const answer = await callGoogle({
|
|
235
|
+
apiKey: input.apiKey,
|
|
236
|
+
model: input.model,
|
|
237
|
+
prompt: finalPrompt,
|
|
238
|
+
});
|
|
239
|
+
return {
|
|
240
|
+
answer,
|
|
241
|
+
model: input.model,
|
|
242
|
+
planner: parsed,
|
|
243
|
+
toolResults,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
function serveStatic(pathname, response) {
|
|
247
|
+
const file = pathname === "/"
|
|
248
|
+
? "../demo/index.html"
|
|
249
|
+
: pathname === "/app.js"
|
|
250
|
+
? "../demo/app.js"
|
|
251
|
+
: pathname === "/styles.css"
|
|
252
|
+
? "../demo/styles.css"
|
|
253
|
+
: undefined;
|
|
254
|
+
if (!file) {
|
|
255
|
+
text(response, 404, "Not found", "text/plain; charset=utf-8");
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
const contentType = file.endsWith(".html")
|
|
259
|
+
? "text/html; charset=utf-8"
|
|
260
|
+
: file.endsWith(".css")
|
|
261
|
+
? "text/css; charset=utf-8"
|
|
262
|
+
: "text/javascript; charset=utf-8";
|
|
263
|
+
text(response, 200, readFileSync(new URL(file, import.meta.url), "utf8"), contentType);
|
|
264
|
+
}
|
|
265
|
+
const server = createServer(async (request, response) => {
|
|
266
|
+
try {
|
|
267
|
+
const url = new URL(request.url ?? "/", `http://${request.headers.host ?? "localhost"}`);
|
|
268
|
+
if (request.method === "GET" && url.pathname === "/api/config") {
|
|
269
|
+
json(response, 200, {
|
|
270
|
+
defaultApiKey,
|
|
271
|
+
googleClient,
|
|
272
|
+
models,
|
|
273
|
+
});
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
if (request.method === "GET" && url.pathname === "/api/prompts") {
|
|
277
|
+
json(response, 200, {
|
|
278
|
+
prompts: testPrompts,
|
|
279
|
+
});
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (request.method === "GET" && url.pathname === "/api/tools") {
|
|
283
|
+
json(response, 200, {
|
|
284
|
+
tools: localToolDescriptions,
|
|
285
|
+
});
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
if (request.method === "POST" && url.pathname === "/api/chat") {
|
|
289
|
+
const body = await readJsonBody(request);
|
|
290
|
+
if (!body.apiKey) {
|
|
291
|
+
json(response, 400, { error: "Google API key is required." });
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
if (!body.prompt) {
|
|
295
|
+
json(response, 400, { error: "Prompt is required." });
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
json(response, 200, await runDemoAgent({
|
|
299
|
+
apiKey: body.apiKey,
|
|
300
|
+
model: body.model || models[0].id,
|
|
301
|
+
prompt: body.prompt,
|
|
302
|
+
}));
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if (request.method === "POST" && url.pathname === "/api/tool") {
|
|
306
|
+
const body = await readJsonBody(request);
|
|
307
|
+
json(response, 200, await executeToolCall(body));
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (request.method === "GET") {
|
|
311
|
+
serveStatic(url.pathname, response);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
text(response, 405, "Method not allowed", "text/plain; charset=utf-8");
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
json(response, 500, {
|
|
318
|
+
error: error instanceof Error ? error.message : "Unknown error.",
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
server.listen(port, () => {
|
|
323
|
+
console.log(`Ace Grid MCP demo listening on http://localhost:${port}`);
|
|
324
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { toolHandlers } from "./tools.js";
|
|
6
|
+
const server = new McpServer({
|
|
7
|
+
name: "ace-grid-mcp",
|
|
8
|
+
version: "0.1.0",
|
|
9
|
+
});
|
|
10
|
+
server.tool("ace_grid_search_docs", "Search bundled Ace Grid docs pages, guide text, API metadata, and feature groups.", {
|
|
11
|
+
limit: z.number().int().min(1).max(50).optional(),
|
|
12
|
+
query: z.string().min(1),
|
|
13
|
+
}, async (input) => toolHandlers.searchDocs(input));
|
|
14
|
+
server.tool("ace_grid_search_api", "Search only generated Ace Grid API metadata and feature groups.", {
|
|
15
|
+
limit: z.number().int().min(1).max(50).optional(),
|
|
16
|
+
query: z.string().min(1),
|
|
17
|
+
}, async (input) => toolHandlers.searchApi(input));
|
|
18
|
+
server.tool("ace_grid_search_doc_pages", "Search only written Ace Grid docs page content and guide text.", {
|
|
19
|
+
limit: z.number().int().min(1).max(50).optional(),
|
|
20
|
+
query: z.string().min(1),
|
|
21
|
+
}, async (input) => toolHandlers.searchDocsPages(input));
|
|
22
|
+
server.tool("ace_grid_list_doc_pages", "List bundled Ace Grid docs pages available to the MCP server.", {}, async () => toolHandlers.listDocsPages());
|
|
23
|
+
server.tool("ace_grid_get_doc_page", "Return a bundled Ace Grid docs page by slug or path, including guide text and relevant props.", {
|
|
24
|
+
slugOrPath: z.string().min(1),
|
|
25
|
+
}, async (input) => toolHandlers.getDocsPage(input));
|
|
26
|
+
server.tool("ace_grid_list_feature_groups", "List Ace Grid feature groups, prop counts, and generated metadata status.", {}, async () => toolHandlers.listFeatureGroups());
|
|
27
|
+
server.tool("ace_grid_get_prop", "Inspect an Ace Grid prop by path, for example layout.height or license.appId.", {
|
|
28
|
+
path: z.string().min(1),
|
|
29
|
+
}, async (input) => toolHandlers.getProp(input));
|
|
30
|
+
server.tool("ace_grid_validate_config", "Validate a JSON Ace Grid config object against bundled generated API metadata.", {
|
|
31
|
+
config: z.unknown(),
|
|
32
|
+
}, async (input) => toolHandlers.validateConfig(input));
|
|
33
|
+
server.tool("ace_grid_plan_implementation", "Plan an Ace Grid implementation from a natural-language request. Returns matched features, tier, packages, docs, and relevant props.", {
|
|
34
|
+
framework: z.enum(["react", "angular", "vue", "svelte", "web-components"]).optional(),
|
|
35
|
+
query: z.string().min(1),
|
|
36
|
+
tier: z.enum(["Community", "Pro", "Enterprise"]).optional(),
|
|
37
|
+
}, async (input) => toolHandlers.planImplementation(input));
|
|
38
|
+
server.tool("ace_grid_generate_implementation", "Generate framework-specific Ace Grid starter code from a natural-language request, using bundled docs and API metadata.", {
|
|
39
|
+
appId: z.string().optional(),
|
|
40
|
+
domain: z.string().optional(),
|
|
41
|
+
framework: z.enum(["react", "angular", "vue", "svelte", "web-components"]).optional(),
|
|
42
|
+
licenseKey: z.string().optional(),
|
|
43
|
+
query: z.string().min(1),
|
|
44
|
+
tier: z.enum(["Community", "Pro", "Enterprise"]).optional(),
|
|
45
|
+
}, async (input) => toolHandlers.generateImplementation(input));
|
|
46
|
+
server.tool("ace_grid_generate_react_example", "Generate a small React Ace Grid example for Community, Pro, or Enterprise.", {
|
|
47
|
+
appId: z.string().optional(),
|
|
48
|
+
domain: z.string().optional(),
|
|
49
|
+
licenseKey: z.string().optional(),
|
|
50
|
+
plan: z.enum(["Community", "Pro", "Enterprise"]).optional(),
|
|
51
|
+
}, async (input) => toolHandlers.generateReactExample(input));
|
|
52
|
+
server.tool("ace_grid_list_examples", "List bundled framework examples available to the MCP server.", {}, async () => toolHandlers.listExamples());
|
|
53
|
+
server.tool("ace_grid_generate_framework_example", "Generate a bundled Ace Grid framework example for react, angular, vue, svelte, or web-components.", {
|
|
54
|
+
framework: z.enum(["react", "angular", "vue", "svelte", "web-components"]),
|
|
55
|
+
includeActions: z.boolean().optional(),
|
|
56
|
+
}, async (input) => toolHandlers.generateFrameworkExample(input));
|
|
57
|
+
server.tool("ace_grid_license_setup", "Explain Ace Grid license config, domain auto-detection, and public signing-key behavior.", {}, async () => toolHandlers.licenseSetup());
|
|
58
|
+
server.tool("ace_grid_account_status", "Fetch authenticated Ace Grid account, entitlement, and subscription status. Requires ACE_GRID_PORTAL_TOKEN or token input.", {
|
|
59
|
+
token: z.string().optional(),
|
|
60
|
+
}, async (input) => toolHandlers.accountStatus(input));
|
|
61
|
+
server.tool("ace_grid_list_apps", "List authenticated Ace Grid license apps. Requires ACE_GRID_PORTAL_TOKEN or token input.", {
|
|
62
|
+
token: z.string().optional(),
|
|
63
|
+
}, async (input) => toolHandlers.listApps(input));
|
|
64
|
+
server.tool("ace_grid_create_app", "Create an authenticated Ace Grid license app. Requires ACE_GRID_PORTAL_TOKEN or token input.", {
|
|
65
|
+
allowedDomains: z.array(z.string()).optional(),
|
|
66
|
+
name: z.string().min(1),
|
|
67
|
+
token: z.string().optional(),
|
|
68
|
+
}, async (input) => toolHandlers.createApp(input));
|
|
69
|
+
server.tool("ace_grid_list_license_keys", "List license keys for an authenticated Ace Grid app. Requires ACE_GRID_PORTAL_TOKEN or token input.", {
|
|
70
|
+
appId: z.string().min(1),
|
|
71
|
+
token: z.string().optional(),
|
|
72
|
+
}, async (input) => toolHandlers.listLicenseKeys(input));
|
|
73
|
+
server.tool("ace_grid_create_license_key", "Create a license key for an authenticated Ace Grid app. Requires ACE_GRID_PORTAL_TOKEN or token input.", {
|
|
74
|
+
appId: z.string().min(1),
|
|
75
|
+
label: z.string().optional(),
|
|
76
|
+
token: z.string().optional(),
|
|
77
|
+
}, async (input) => toolHandlers.createLicenseKey(input));
|
|
78
|
+
const transport = new StdioServerTransport();
|
|
79
|
+
await server.connect(transport);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type PortalClientOptions = {
|
|
2
|
+
apiBaseUrl?: string;
|
|
3
|
+
token?: string;
|
|
4
|
+
};
|
|
5
|
+
export type PortalRequestOptions = {
|
|
6
|
+
body?: unknown;
|
|
7
|
+
method?: "GET" | "POST" | "PATCH" | "DELETE";
|
|
8
|
+
};
|
|
9
|
+
export declare class PortalAuthError extends Error {
|
|
10
|
+
constructor();
|
|
11
|
+
}
|
|
12
|
+
export declare class PortalClient {
|
|
13
|
+
private readonly apiBaseUrl;
|
|
14
|
+
private readonly token?;
|
|
15
|
+
constructor(options?: PortalClientOptions);
|
|
16
|
+
request<T>(path: string, options?: PortalRequestOptions): Promise<T>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=portalApi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portalApi.d.ts","sourceRoot":"","sources":["../src/portalApi.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,mBAAmB,GAAG;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;CAC9C,CAAC;AAEF,qBAAa,eAAgB,SAAQ,KAAK;;CAIzC;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAS;gBAEpB,OAAO,GAAE,mBAAwB;IAKvC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,CAAC,CAAC;CAyB/E"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export class PortalAuthError extends Error {
|
|
2
|
+
constructor() {
|
|
3
|
+
super("Set ACE_GRID_PORTAL_TOKEN to use authenticated Ace Grid account tools.");
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
export class PortalClient {
|
|
7
|
+
apiBaseUrl;
|
|
8
|
+
token;
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
this.apiBaseUrl = options.apiBaseUrl ?? process.env.ACE_GRID_API_BASE_URL ?? "https://api.ace-grid.com";
|
|
11
|
+
this.token = options.token ?? process.env.ACE_GRID_PORTAL_TOKEN;
|
|
12
|
+
}
|
|
13
|
+
async request(path, options = {}) {
|
|
14
|
+
if (!this.token) {
|
|
15
|
+
throw new PortalAuthError();
|
|
16
|
+
}
|
|
17
|
+
const response = await fetch(`${this.apiBaseUrl}${path}`, {
|
|
18
|
+
body: options.body ? JSON.stringify(options.body) : undefined,
|
|
19
|
+
headers: {
|
|
20
|
+
authorization: `Bearer ${this.token}`,
|
|
21
|
+
...(options.body ? { "content-type": "application/json" } : {}),
|
|
22
|
+
},
|
|
23
|
+
method: options.method ?? "GET",
|
|
24
|
+
});
|
|
25
|
+
const body = await response.json().catch(() => ({}));
|
|
26
|
+
if (!response.ok) {
|
|
27
|
+
const message = typeof body === "object" && body && "message" in body
|
|
28
|
+
? String(body.message)
|
|
29
|
+
: "Ace Grid portal API request failed.";
|
|
30
|
+
throw new Error(message);
|
|
31
|
+
}
|
|
32
|
+
return body;
|
|
33
|
+
}
|
|
34
|
+
}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { type AceGridFramework, type AceGridTier } from "./catalog.js";
|
|
2
|
+
export type ToolResult = {
|
|
3
|
+
content: Array<{
|
|
4
|
+
text: string;
|
|
5
|
+
type: "text";
|
|
6
|
+
}>;
|
|
7
|
+
};
|
|
8
|
+
export declare const toolHandlers: {
|
|
9
|
+
searchDocs(input: {
|
|
10
|
+
limit?: number;
|
|
11
|
+
query: string;
|
|
12
|
+
}): ToolResult;
|
|
13
|
+
searchApi(input: {
|
|
14
|
+
limit?: number;
|
|
15
|
+
query: string;
|
|
16
|
+
}): ToolResult;
|
|
17
|
+
searchDocsPages(input: {
|
|
18
|
+
limit?: number;
|
|
19
|
+
query: string;
|
|
20
|
+
}): ToolResult;
|
|
21
|
+
listFeatureGroups(): ToolResult;
|
|
22
|
+
listDocsPages(): ToolResult;
|
|
23
|
+
getDocsPage(input: {
|
|
24
|
+
slugOrPath: string;
|
|
25
|
+
}): ToolResult;
|
|
26
|
+
getProp(input: {
|
|
27
|
+
path: string;
|
|
28
|
+
}): ToolResult;
|
|
29
|
+
validateConfig(input: {
|
|
30
|
+
config: unknown;
|
|
31
|
+
}): ToolResult;
|
|
32
|
+
planImplementation(input: {
|
|
33
|
+
framework?: AceGridFramework;
|
|
34
|
+
query: string;
|
|
35
|
+
tier?: AceGridTier;
|
|
36
|
+
}): ToolResult;
|
|
37
|
+
generateImplementation(input: {
|
|
38
|
+
appId?: string;
|
|
39
|
+
domain?: string;
|
|
40
|
+
framework?: AceGridFramework;
|
|
41
|
+
licenseKey?: string;
|
|
42
|
+
query: string;
|
|
43
|
+
tier?: AceGridTier;
|
|
44
|
+
}): ToolResult;
|
|
45
|
+
generateReactExample(input: {
|
|
46
|
+
appId?: string;
|
|
47
|
+
domain?: string;
|
|
48
|
+
licenseKey?: string;
|
|
49
|
+
plan?: "Community" | "Pro" | "Enterprise";
|
|
50
|
+
}): ToolResult;
|
|
51
|
+
listExamples(): ToolResult;
|
|
52
|
+
generateFrameworkExample(input: {
|
|
53
|
+
framework: string;
|
|
54
|
+
includeActions?: boolean;
|
|
55
|
+
}): ToolResult;
|
|
56
|
+
licenseSetup(): ToolResult;
|
|
57
|
+
accountStatus(input?: {
|
|
58
|
+
token?: string;
|
|
59
|
+
}): Promise<ToolResult>;
|
|
60
|
+
listApps(input?: {
|
|
61
|
+
token?: string;
|
|
62
|
+
}): Promise<ToolResult>;
|
|
63
|
+
createApp(input: {
|
|
64
|
+
allowedDomains?: string[];
|
|
65
|
+
name: string;
|
|
66
|
+
token?: string;
|
|
67
|
+
}): Promise<ToolResult>;
|
|
68
|
+
listLicenseKeys(input: {
|
|
69
|
+
appId: string;
|
|
70
|
+
token?: string;
|
|
71
|
+
}): Promise<ToolResult>;
|
|
72
|
+
createLicenseKey(input: {
|
|
73
|
+
appId: string;
|
|
74
|
+
label?: string;
|
|
75
|
+
token?: string;
|
|
76
|
+
}): Promise<ToolResult>;
|
|
77
|
+
};
|
|
78
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAiBL,KAAK,gBAAgB,EACrB,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AAGtB,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;CACJ,CAAC;AAwBF,eAAO,MAAM,YAAY;sBACL;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;qBAQlC;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;2BAO3B;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;;;uBAqBrC;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE;mBAgB1B;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;0BAgBT;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE;8BAIf;QACxB,SAAS,CAAC,EAAE,gBAAgB,CAAC;QAC7B,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,WAAW,CAAC;KACpB;kCAI6B;QAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,gBAAgB,CAAC;QAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,WAAW,CAAC;KACpB;gCAI2B;QAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,IAAI,CAAC,EAAE,WAAW,GAAG,KAAK,GAAG,YAAY,CAAC;KAC3C;;oCAU+B;QAC9B,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,CAAC,EAAE,OAAO,CAAC;KAC1B;;0BAiB0B;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;qBAevB;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;qBAKjB;QAAE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;2BAarD;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;4BAOhC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;CAWhF,CAAC"}
|