kaax-mcp 0.1.0

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/i18n.js ADDED
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Tiny i18n — user-facing strings that the agent passes through verbatim.
3
+ *
4
+ * The agent (Claude) translates fluently on its own, but messages that
5
+ * users tend to copy/paste (URLs, codes, file paths, "your account is
6
+ * locked" stubs) we localize directly so they read native instead of
7
+ * machine-translated.
8
+ *
9
+ * Selection:
10
+ * 1. `KAAX_LOCALE` env var ("es" | "en"). Defaults to "es" because the
11
+ * Kaax user base is overwhelmingly Spanish-speaking.
12
+ * 2. Falls back to "es" for unknown locales rather than English so we
13
+ * never accidentally surface English to a Spanish-speaking user.
14
+ */
15
+ export function getLocale() {
16
+ const raw = (process.env.KAAX_LOCALE || "es").toLowerCase().trim();
17
+ if (raw === "en")
18
+ return "en";
19
+ return "es";
20
+ }
21
+ // Centralised dictionary. Add new keys here rather than scattering literal
22
+ // strings across tools.ts.
23
+ const dict = {
24
+ proRequired_title: {
25
+ es: "Esta acción requiere suscripción Pro",
26
+ en: "This action requires a Pro subscription",
27
+ },
28
+ proRequired_body: {
29
+ es: "Tu plan actual es Free y no incluye acceso al API de Kaax. Para listar campos, modelos, análisis o configuraciones tenés que activar Pro.",
30
+ en: "Your current plan is Free and does not include Kaax API access. To list fields, models, analyses or configurations you need to activate Pro.",
31
+ },
32
+ proRequired_cta: {
33
+ es: "Llama a `kaax_open_billing` para abrir la página de planes, o ve a {url}.",
34
+ en: "Call `kaax_open_billing` to open the plans page, or visit {url}.",
35
+ },
36
+ freeAvailable_header: {
37
+ es: "Mientras tanto, en el plan Free podés:",
38
+ en: "In the meantime, on the Free plan you can:",
39
+ },
40
+ freeAvailable_items: {
41
+ es: [
42
+ "Crear cuenta y activarla (kaax_start_onboarding)",
43
+ "Solicitar y descargar las apps de escritorio (kaax_request_download, kaax_download_kaax)",
44
+ "Convertir shapefiles a KML localmente (kaax_convert_shapefile_to_kml)",
45
+ "Recibir sugerencias de tags y configuraciones (kaax_suggest_tags_for_field, kaax_suggest_configuration)",
46
+ "Leer la documentación (kaax://docs/*)",
47
+ ],
48
+ en: [
49
+ "Create an account and activate it (kaax_start_onboarding)",
50
+ "Request and download the desktop apps (kaax_request_download, kaax_download_kaax)",
51
+ "Convert shapefiles to KML locally (kaax_convert_shapefile_to_kml)",
52
+ "Get tag and configuration suggestions (kaax_suggest_tags_for_field, kaax_suggest_configuration)",
53
+ "Read the documentation (kaax://docs/*)",
54
+ ],
55
+ },
56
+ needsActivation: {
57
+ es: "Activá tu cuenta haciendo clic en el enlace del correo que te enviamos antes de continuar.",
58
+ en: "Activate your account by clicking the link in the email we sent you before continuing.",
59
+ },
60
+ missingApiKey: {
61
+ es: "No hay KAAX_API_KEY configurado. Si no tenés cuenta, llamá a `kaax_start_onboarding`. Si ya tenés, configurá la variable en el cliente MCP y reiniciá.",
62
+ en: "KAAX_API_KEY is not configured. If you have no account, call `kaax_start_onboarding`. Otherwise, set the env var in your MCP client config and restart.",
63
+ },
64
+ invalidApiKey: {
65
+ es: "El apiKey configurado no es válido. Revisá tu config del MCP o emití uno nuevo en /dashboard/api-manage.",
66
+ en: "The configured apiKey is invalid. Check your MCP config or issue a new key at /dashboard/api-manage.",
67
+ },
68
+ rateLimited: {
69
+ es: "Demasiadas solicitudes en poco tiempo. Esperá un momento y volvé a intentar.",
70
+ en: "Too many requests in a short time. Wait a moment and try again.",
71
+ },
72
+ network: {
73
+ es: "Error de red al hablar con Kaax. Verificá tu conexión y volvé a intentar.",
74
+ en: "Network error talking to Kaax. Check your connection and retry.",
75
+ },
76
+ };
77
+ /** Look up a translated phrase, optionally with `{placeholder}` substitution. */
78
+ export function t(key, vars) {
79
+ const locale = getLocale();
80
+ const entry = dict[key];
81
+ let value = entry[locale] ?? entry.es;
82
+ if (vars) {
83
+ for (const [k, v] of Object.entries(vars)) {
84
+ value = value.replace(new RegExp(`\\{${k}\\}`, "g"), v);
85
+ }
86
+ }
87
+ return value;
88
+ }
89
+ /** Array variant — for bullet lists. */
90
+ export function tList(key) {
91
+ const locale = getLocale();
92
+ const entry = dict[key];
93
+ if (Array.isArray(entry.es)) {
94
+ return (entry[locale] ?? entry.es);
95
+ }
96
+ return [];
97
+ }
98
+ //# sourceMappingURL=i18n.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.js","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,MAAM,UAAU,SAAS;IACvB,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IACnE,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC9B,OAAO,IAAI,CAAC;AACd,CAAC;AAOD,2EAA2E;AAC3E,2BAA2B;AAC3B,MAAM,IAAI,GAAG;IACX,iBAAiB,EAAE;QACjB,EAAE,EAAE,sCAAsC;QAC1C,EAAE,EAAE,yCAAyC;KAC9C;IACD,gBAAgB,EAAE;QAChB,EAAE,EAAE,2IAA2I;QAC/I,EAAE,EAAE,8IAA8I;KACnJ;IACD,eAAe,EAAE;QACf,EAAE,EAAE,2EAA2E;QAC/E,EAAE,EAAE,kEAAkE;KACvE;IACD,oBAAoB,EAAE;QACpB,EAAE,EAAE,wCAAwC;QAC5C,EAAE,EAAE,4CAA4C;KACjD;IACD,mBAAmB,EAAE;QACnB,EAAE,EAAE;YACF,kDAAkD;YAClD,0FAA0F;YAC1F,uEAAuE;YACvE,yGAAyG;YACzG,uCAAuC;SACxC;QACD,EAAE,EAAE;YACF,2DAA2D;YAC3D,mFAAmF;YACnF,mEAAmE;YACnE,iGAAiG;YACjG,wCAAwC;SACzC;KACF;IACD,eAAe,EAAE;QACf,EAAE,EAAE,4FAA4F;QAChG,EAAE,EAAE,wFAAwF;KAC7F;IACD,aAAa,EAAE;QACb,EAAE,EAAE,wJAAwJ;QAC5J,EAAE,EAAE,yJAAyJ;KAC9J;IACD,aAAa,EAAE;QACb,EAAE,EAAE,0GAA0G;QAC9G,EAAE,EAAE,sGAAsG;KAC3G;IACD,WAAW,EAAE;QACX,EAAE,EAAE,8EAA8E;QAClF,EAAE,EAAE,iEAAiE;KACtE;IACD,OAAO,EAAE;QACP,EAAE,EAAE,2EAA2E;QAC/E,EAAE,EAAE,iEAAiE;KACtE;CACgE,CAAC;AAIpE,iFAAiF;AACjF,MAAM,UAAU,CAAC,CAAC,GAAY,EAAE,IAA6B;IAC3D,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAW,CAAC;IAClC,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;IACtC,IAAI,IAAI,EAAE,CAAC;QACT,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1C,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,wCAAwC;AACxC,MAAM,UAAU,KAAK,CAAC,GAAY;IAChC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAmC,CAAC;IAC1D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAa,CAAC;IACjD,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Kaax MCP server entry point.
4
+ *
5
+ * Starts a stdio-transport MCP server that exposes the Kaax API plus a
6
+ * handful of agent-friendly heuristics (tag suggestions, configuration
7
+ * presets, peer-averaged configs, similarity search, shapefile conversion).
8
+ *
9
+ * Configuration:
10
+ * • KAAX_API_KEY (required) — issued at /dashboard/api-manage.
11
+ * • KAAX_BASE_URL (optional) — defaults to https://www.kaax-agritech.com.
12
+ *
13
+ * The server logs to stderr only — the LLM never sees logs, only tool
14
+ * outputs.
15
+ */
16
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Kaax MCP server entry point.
4
+ *
5
+ * Starts a stdio-transport MCP server that exposes the Kaax API plus a
6
+ * handful of agent-friendly heuristics (tag suggestions, configuration
7
+ * presets, peer-averaged configs, similarity search, shapefile conversion).
8
+ *
9
+ * Configuration:
10
+ * • KAAX_API_KEY (required) — issued at /dashboard/api-manage.
11
+ * • KAAX_BASE_URL (optional) — defaults to https://www.kaax-agritech.com.
12
+ *
13
+ * The server logs to stderr only — the LLM never sees logs, only tool
14
+ * outputs.
15
+ */
16
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
17
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
18
+ import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
19
+ import { KaaxClient } from "./client.js";
20
+ import { buildTools } from "./tools.js";
21
+ import { buildResources } from "./resources.js";
22
+ import { buildPrompts } from "./prompts.js";
23
+ const SERVER_NAME = "kaax-mcp";
24
+ const SERVER_VERSION = "0.1.0";
25
+ function bail(msg) {
26
+ // stderr only — MCP clients pipe stdout for protocol traffic.
27
+ process.stderr.write(`[${SERVER_NAME}] ${msg}\n`);
28
+ process.exit(1);
29
+ }
30
+ async function main() {
31
+ // KAAX_API_KEY is OPTIONAL. The MCP must be able to boot without it so a
32
+ // brand-new user can run `kaax_start_onboarding` to provision an account
33
+ // and acquire a key from inside the agent conversation. Once acquired,
34
+ // the client late-binds via `setApiKey`.
35
+ const apiKey = process.env.KAAX_API_KEY?.trim() || undefined;
36
+ const baseUrl = process.env.KAAX_BASE_URL?.trim() || undefined;
37
+ const client = new KaaxClient({ apiKey, baseUrl });
38
+ const tools = buildTools();
39
+ const resources = buildResources();
40
+ const prompts = buildPrompts();
41
+ const server = new Server({ name: SERVER_NAME, version: SERVER_VERSION }, {
42
+ capabilities: {
43
+ tools: {},
44
+ resources: {},
45
+ prompts: {},
46
+ },
47
+ });
48
+ // ── Tools ───────────────────────────────────────────────────────────────
49
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
50
+ tools: tools.map((t) => ({
51
+ name: t.name,
52
+ description: t.description,
53
+ inputSchema: t.inputSchema,
54
+ })),
55
+ }));
56
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
57
+ const tool = tools.find((t) => t.name === req.params.name);
58
+ if (!tool) {
59
+ return {
60
+ content: [
61
+ { type: "text", text: `Unknown tool: ${req.params.name}` },
62
+ ],
63
+ isError: true,
64
+ };
65
+ }
66
+ return tool.handler(req.params.arguments ?? {}, { client });
67
+ });
68
+ // ── Resources ──────────────────────────────────────────────────────────
69
+ server.setRequestHandler(ListResourcesRequestSchema, async () => ({
70
+ resources: resources.map((r) => r.resource),
71
+ }));
72
+ server.setRequestHandler(ReadResourceRequestSchema, async (req) => {
73
+ const match = resources.find((r) => r.resource.uri === req.params.uri);
74
+ if (!match) {
75
+ throw new Error(`Unknown resource: ${req.params.uri}`);
76
+ }
77
+ return {
78
+ contents: [
79
+ {
80
+ uri: match.resource.uri,
81
+ mimeType: match.resource.mimeType ?? "text/plain",
82
+ text: match.text,
83
+ },
84
+ ],
85
+ };
86
+ });
87
+ // ── Prompts ────────────────────────────────────────────────────────────
88
+ server.setRequestHandler(ListPromptsRequestSchema, async () => ({
89
+ prompts: prompts.map((p) => p.prompt),
90
+ }));
91
+ server.setRequestHandler(GetPromptRequestSchema, async (req) => {
92
+ const match = prompts.find((p) => p.prompt.name === req.params.name);
93
+ if (!match) {
94
+ throw new Error(`Unknown prompt: ${req.params.name}`);
95
+ }
96
+ return match.build((req.params.arguments ?? {}));
97
+ });
98
+ const transport = new StdioServerTransport();
99
+ await server.connect(transport);
100
+ const keyState = client.hasApiKey() ? "configured" : "missing (onboarding mode)";
101
+ process.stderr.write(`[${SERVER_NAME}] v${SERVER_VERSION} ready · tools=${tools.length} resources=${resources.length} prompts=${prompts.length} · apiKey=${keyState}\n`);
102
+ }
103
+ main().catch((err) => {
104
+ bail(`fatal: ${err instanceof Error ? err.stack ?? err.message : String(err)}`);
105
+ });
106
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Cross-platform helpers — kept tiny and dependency-free so the MCP server
3
+ * stays slim. We deliberately avoid the `open` npm package to keep the
4
+ * dependency tree auditable.
5
+ */
6
+ /**
7
+ * Open a URL in the user's default browser. Fire-and-forget — never throws.
8
+ *
9
+ * - Windows: spawns `cmd /c start "" <url>`. The empty title arg is required
10
+ * because `start` treats the first quoted arg as the window title.
11
+ * - macOS: spawns `open <url>`.
12
+ * - Linux: spawns `xdg-open <url>`.
13
+ *
14
+ * Child processes are detached and unref'd so the MCP process exits cleanly
15
+ * even if the browser is still running.
16
+ */
17
+ export declare function openBrowser(url: string): {
18
+ spawned: boolean;
19
+ platform: string;
20
+ };
21
+ /**
22
+ * Download a remote file to disk with bounded resource use:
23
+ * - Connect timeout enforced via AbortController.
24
+ * - Streams the response body directly to disk (no full-buffer in memory).
25
+ * - Refuses to write outside the user's intended directory tree (the
26
+ * parent must already exist OR we create it via mkdir -p first).
27
+ * - Caller controls the destination path — we never derive a path from
28
+ * a server-supplied Content-Disposition.
29
+ */
30
+ export interface DownloadResult {
31
+ bytesWritten: number;
32
+ outputPath: string;
33
+ contentType?: string;
34
+ }
35
+ export declare function downloadFile(url: string, outputPath: string, opts?: {
36
+ timeoutMs?: number;
37
+ }): Promise<DownloadResult>;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Cross-platform helpers — kept tiny and dependency-free so the MCP server
3
+ * stays slim. We deliberately avoid the `open` npm package to keep the
4
+ * dependency tree auditable.
5
+ */
6
+ import { spawn } from "child_process";
7
+ import { createWriteStream } from "fs";
8
+ import { mkdir, stat } from "fs/promises";
9
+ import { dirname } from "path";
10
+ import { pipeline } from "stream/promises";
11
+ import { fetch } from "undici";
12
+ /**
13
+ * Open a URL in the user's default browser. Fire-and-forget — never throws.
14
+ *
15
+ * - Windows: spawns `cmd /c start "" <url>`. The empty title arg is required
16
+ * because `start` treats the first quoted arg as the window title.
17
+ * - macOS: spawns `open <url>`.
18
+ * - Linux: spawns `xdg-open <url>`.
19
+ *
20
+ * Child processes are detached and unref'd so the MCP process exits cleanly
21
+ * even if the browser is still running.
22
+ */
23
+ export function openBrowser(url) {
24
+ const platform = process.platform;
25
+ try {
26
+ let child;
27
+ if (platform === "win32") {
28
+ child = spawn("cmd", ["/c", "start", "", url], {
29
+ detached: true,
30
+ stdio: "ignore",
31
+ windowsHide: true,
32
+ });
33
+ }
34
+ else if (platform === "darwin") {
35
+ child = spawn("open", [url], { detached: true, stdio: "ignore" });
36
+ }
37
+ else {
38
+ child = spawn("xdg-open", [url], { detached: true, stdio: "ignore" });
39
+ }
40
+ child.unref();
41
+ return { spawned: true, platform };
42
+ }
43
+ catch (err) {
44
+ process.stderr.write(`[kaax-mcp] openBrowser failed on ${platform}: ${err.message}\n`);
45
+ return { spawned: false, platform };
46
+ }
47
+ }
48
+ export async function downloadFile(url, outputPath, opts = {}) {
49
+ const timeoutMs = opts.timeoutMs ?? 5 * 60_000; // 5 min
50
+ const ctrl = new AbortController();
51
+ const timer = setTimeout(() => ctrl.abort(), timeoutMs);
52
+ try {
53
+ // Make sure the destination directory exists.
54
+ await mkdir(dirname(outputPath), { recursive: true });
55
+ const res = await fetch(url, { signal: ctrl.signal });
56
+ if (!res.ok || !res.body) {
57
+ throw new Error(`Download failed: ${res.status} ${res.statusText}`);
58
+ }
59
+ const sink = createWriteStream(outputPath);
60
+ await pipeline(res.body, sink);
61
+ const st = await stat(outputPath);
62
+ return {
63
+ bytesWritten: st.size,
64
+ outputPath,
65
+ contentType: res.headers.get("content-type") ?? undefined,
66
+ };
67
+ }
68
+ finally {
69
+ clearTimeout(timer);
70
+ }
71
+ }
72
+ //# sourceMappingURL=platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Guided prompts — pre-canned conversation starters the agent can offer the
3
+ * user. Each prompt expands to a short instruction block that nudges the
4
+ * agent through a known-good Kaax flow without re-deriving it from scratch.
5
+ */
6
+ import type { Prompt, GetPromptResult } from "@modelcontextprotocol/sdk/types.js";
7
+ interface PromptDef {
8
+ prompt: Prompt;
9
+ build: (args: Record<string, string>) => GetPromptResult;
10
+ }
11
+ export declare function buildPrompts(): PromptDef[];
12
+ export {};
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Guided prompts — pre-canned conversation starters the agent can offer the
3
+ * user. Each prompt expands to a short instruction block that nudges the
4
+ * agent through a known-good Kaax flow without re-deriving it from scratch.
5
+ */
6
+ export function buildPrompts() {
7
+ return [
8
+ {
9
+ prompt: {
10
+ name: "kaax_quickstart",
11
+ description: "Walk a new user through setting up Kaax from zero to first analysis.",
12
+ arguments: [
13
+ {
14
+ name: "crop",
15
+ description: "Crop type (sugarcane, pineapple, banana, oil palm…)",
16
+ required: false,
17
+ },
18
+ {
19
+ name: "region",
20
+ description: "Region or country — used to seed regional tags.",
21
+ required: false,
22
+ },
23
+ ],
24
+ },
25
+ build: (args) => ({
26
+ messages: [
27
+ {
28
+ role: "user",
29
+ content: {
30
+ type: "text",
31
+ text: [
32
+ "I'm new to Kaax. Walk me through getting from zero to my first analysis.",
33
+ args.crop ? `Crop: ${args.crop}.` : "",
34
+ args.region ? `Region: ${args.region}.` : "",
35
+ "",
36
+ "Please:",
37
+ "1. Call kaax_check_setup_status first so we know what's missing.",
38
+ "2. Read kaax://docs/quickstart for the canonical walkthrough.",
39
+ "3. If I have no model, point me at kaax://docs/models.",
40
+ "4. Propose 3–4 tags via kaax_suggest_tags_for_field for my first parcel.",
41
+ "5. Suggest the right configuration with kaax_suggest_configuration once I pick an analysis type.",
42
+ "Be concise — list the next concrete action at the end.",
43
+ ]
44
+ .filter(Boolean)
45
+ .join("\n"),
46
+ },
47
+ },
48
+ ],
49
+ }),
50
+ },
51
+ {
52
+ prompt: {
53
+ name: "kaax_analyze_field",
54
+ description: "Given a field name, queue the right analysis with a sensible config.",
55
+ arguments: [
56
+ { name: "field", description: "Field / parcel name", required: true },
57
+ {
58
+ name: "analysisType",
59
+ description: "replanting / counting / path",
60
+ required: true,
61
+ },
62
+ {
63
+ name: "goal",
64
+ description: "balanced | high_recall | high_precision",
65
+ required: false,
66
+ },
67
+ ],
68
+ },
69
+ build: (args) => ({
70
+ messages: [
71
+ {
72
+ role: "user",
73
+ content: {
74
+ type: "text",
75
+ text: [
76
+ `I want to run a ${args.analysisType} analysis on the parcel "${args.field}".`,
77
+ args.goal ? `Goal: ${args.goal}.` : "",
78
+ "",
79
+ "Please:",
80
+ `1. Call kaax_list_fields with q="${args.field}" so we know the field id.`,
81
+ "2. Verify a detection model exists via kaax_list_models (skip for path analyses).",
82
+ `3. Call kaax_suggest_configuration with analysisType="${args.analysisType}"${args.goal ? `, goal="${args.goal}"` : ""}.`,
83
+ `4. Call kaax_peer_config_suggestions with type="${args.analysisType}" and reconcile the two.`,
84
+ "5. Return a short summary: field id, model id, final config JSON, and the URL the user should open to actually trigger the run.",
85
+ ]
86
+ .filter(Boolean)
87
+ .join("\n"),
88
+ },
89
+ },
90
+ ],
91
+ }),
92
+ },
93
+ {
94
+ prompt: {
95
+ name: "kaax_organize_data",
96
+ description: "Audit the user's tagging hygiene and propose a clean taxonomy.",
97
+ arguments: [],
98
+ },
99
+ build: () => ({
100
+ messages: [
101
+ {
102
+ role: "user",
103
+ content: {
104
+ type: "text",
105
+ text: [
106
+ "Help me clean up my tag taxonomy.",
107
+ "",
108
+ "Please:",
109
+ "1. Read kaax://docs/tags for the recommended 4-axis taxonomy.",
110
+ "2. Call kaax_list_tags to see what I already use.",
111
+ "3. Spot collisions (same meaning, different spelling) and singletons that should be merged.",
112
+ "4. Propose a final shortlist organised by axis (zafra / region / cultivo / estado).",
113
+ "5. For any field I name, call kaax_suggest_tags_for_field then kaax_attach_field_tags to persist.",
114
+ ].join("\n"),
115
+ },
116
+ },
117
+ ],
118
+ }),
119
+ },
120
+ {
121
+ prompt: {
122
+ name: "kaax_onboard_from_zero",
123
+ description: "Full onboarding flow for someone who has never used Kaax: signup → activate → request download → grab the binary.",
124
+ arguments: [],
125
+ },
126
+ build: () => ({
127
+ messages: [
128
+ {
129
+ role: "user",
130
+ content: {
131
+ type: "text",
132
+ text: [
133
+ "I have never used Kaax. Walk me through everything end-to-end.",
134
+ "",
135
+ "Please:",
136
+ "1. Call kaax_start_onboarding — this opens the signup page in my browser. Tell me to fill it in and click submit.",
137
+ "2. Call kaax_complete_onboarding with the token from step 1. Show me the apiKey when it returns and remind me to save it to KAAX_API_KEY.",
138
+ "3. Remind me to click the activation link in the welcome email before continuing.",
139
+ "4. Once activated, call kaax_request_download with a short useCase so I get the desktop / labeling apps.",
140
+ "5. Poll kaax_check_download_status until approved. Show me what's happening.",
141
+ "6. When approved, call kaax_download_kaax for the product I ask for and save it to my Downloads folder.",
142
+ "7. Finally call kaax_check_setup_status so I know what to do next inside the dashboard.",
143
+ "Be concise — one paragraph per step, not a wall of text.",
144
+ ].join("\n"),
145
+ },
146
+ },
147
+ ],
148
+ }),
149
+ },
150
+ {
151
+ prompt: {
152
+ name: "kaax_import_shapefile",
153
+ description: "Convert a local shapefile to KML and upload it into Kaax.",
154
+ arguments: [
155
+ {
156
+ name: "shpPath",
157
+ description: "Absolute path to the .shp file",
158
+ required: true,
159
+ },
160
+ ],
161
+ },
162
+ build: (args) => ({
163
+ messages: [
164
+ {
165
+ role: "user",
166
+ content: {
167
+ type: "text",
168
+ text: [
169
+ `I have a shapefile at ${args.shpPath}.`,
170
+ "",
171
+ "Please:",
172
+ "1. Read kaax://docs/shapefile-import so you know the constraints (EPSG:4326, .dbf must be present).",
173
+ `2. Call kaax_convert_shapefile_to_kml with shpPath="${args.shpPath}".`,
174
+ "3. Tell me the output .kml path and any per-feature warnings.",
175
+ "4. Walk me through uploading it at /dashboard/manage → Tus Campos → Nuevo campo.",
176
+ "5. Suggest tags for the new field via kaax_suggest_tags_for_field.",
177
+ ].join("\n"),
178
+ },
179
+ },
180
+ ],
181
+ }),
182
+ },
183
+ ];
184
+ }
185
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Static documentation resources exposed to the agent.
3
+ *
4
+ * MCP resources are read-only blobs the agent can fetch by URI. We keep them
5
+ * embedded in the binary instead of fetching the live web pages so the MCP
6
+ * server stays usable offline and snappy. The URIs map 1:1 to the references
7
+ * that the tools above emit (kaax://docs/quickstart, kaax://docs/tags, …) —
8
+ * if an agent says "see kaax://docs/X" the agent can then call
9
+ * `resources/read` on that URI to actually consume the doc.
10
+ */
11
+ import type { Resource } from "@modelcontextprotocol/sdk/types.js";
12
+ interface ResourceDef {
13
+ resource: Resource;
14
+ text: string;
15
+ }
16
+ export declare function buildResources(): ResourceDef[];
17
+ export {};