jujugrowth-mcp 1.0.7 → 1.0.9
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/README.md +3 -1
- package/package.json +1 -1
- package/server.mjs +34 -19
package/README.md
CHANGED
|
@@ -49,7 +49,9 @@ commands pre-filled.
|
|
|
49
49
|
- `get_recommendation` — the full brief for one (implement it in your repo)
|
|
50
50
|
- `mark_recommendation_handled` — mark it done (with a note of what you changed)
|
|
51
51
|
- `request_site_advice` — Pro: trigger a fresh website analysis
|
|
52
|
-
|
|
52
|
+
|
|
53
|
+
(Campaigns/ad briefs aren't here by design — those are owner budget
|
|
54
|
+
decisions, handled in the jujugrowth web UI, not dev-AI work.)
|
|
53
55
|
|
|
54
56
|
A token can be scoped to one business; the server then announces itself as
|
|
55
57
|
`jujugrowth (yoursite.com)` and only ever touches that site. Generate scoped
|
package/package.json
CHANGED
package/server.mjs
CHANGED
|
@@ -58,12 +58,18 @@ const TOOLS = [
|
|
|
58
58
|
inputSchema: {
|
|
59
59
|
type: "object",
|
|
60
60
|
properties: {
|
|
61
|
-
tenantId: {
|
|
61
|
+
tenantId: {
|
|
62
|
+
type: "string",
|
|
63
|
+
description: "the site to list (optional; required when more than one site is connected)",
|
|
64
|
+
},
|
|
62
65
|
},
|
|
63
66
|
additionalProperties: false,
|
|
64
67
|
},
|
|
65
68
|
run: async (a) =>
|
|
66
|
-
call(
|
|
69
|
+
call(
|
|
70
|
+
"GET",
|
|
71
|
+
`/recommendations${a.tenantId ? `?tenantId=${encodeURIComponent(a.tenantId)}` : ""}`,
|
|
72
|
+
),
|
|
67
73
|
},
|
|
68
74
|
{
|
|
69
75
|
name: "get_recommendation",
|
|
@@ -92,7 +98,11 @@ const TOOLS = [
|
|
|
92
98
|
additionalProperties: false,
|
|
93
99
|
},
|
|
94
100
|
run: async (a) =>
|
|
95
|
-
call(
|
|
101
|
+
call(
|
|
102
|
+
"POST",
|
|
103
|
+
`/recommendations/${a.tenantId}/${a.recId}/handled`,
|
|
104
|
+
a.note ? { note: a.note } : undefined,
|
|
105
|
+
),
|
|
96
106
|
},
|
|
97
107
|
{
|
|
98
108
|
name: "request_site_advice",
|
|
@@ -107,16 +117,11 @@ const TOOLS = [
|
|
|
107
117
|
run: async (a) => call("POST", `/site-advice/${a.tenantId}`),
|
|
108
118
|
},
|
|
109
119
|
{
|
|
110
|
-
name: "
|
|
120
|
+
name: "list_capability_gaps",
|
|
111
121
|
description:
|
|
112
|
-
"
|
|
113
|
-
inputSchema: {
|
|
114
|
-
|
|
115
|
-
properties: { tenantId: { type: "string" } },
|
|
116
|
-
required: ["tenantId"],
|
|
117
|
-
additionalProperties: false,
|
|
118
|
-
},
|
|
119
|
-
run: async (a) => call("POST", `/campaign-brief/${a.tenantId}`),
|
|
122
|
+
"ADMIN/OPERATOR TOKEN ONLY. The jujugrowth system's OWN dev backlog: platform rules it has LEARNED (from docs + real platform responses) but cannot yet check because no collector observes the property the rule needs. Each item names the generic tool to build — `subject.attribute` per platform — with an example rule. Build that collector in the jujugrowth repo (make it write the property as a flat dotted attribute key on the synced entity); the gap auto-resolves once the fact is observable. The list is generated from real learned rules, never a hardcoded checklist. Returns 403 for non-admin tokens.",
|
|
123
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
124
|
+
run: async () => call("GET", "/capability-gaps"),
|
|
120
125
|
},
|
|
121
126
|
];
|
|
122
127
|
|
|
@@ -147,7 +152,7 @@ async function handle(msg) {
|
|
|
147
152
|
"3) Before changing anything, VERIFY the brief's current-state claims against the actual code — they can be stale; skip what's already done.\n" +
|
|
148
153
|
"4) Implement in the user's repo, scoped to wording/structure/SEO. Never change checkout, auth, or analytics events. Show a diff / open a PR for the user to review.\n" +
|
|
149
154
|
"5) ALWAYS call mark_recommendation_handled with a short note of what you changed once it's shipped — don't wait to be told.\n" +
|
|
150
|
-
"Skip GA4-console toggles and business-judgment items — flag those for the user instead of editing code. This server is bound to ONE site; never act on another.",
|
|
155
|
+
"Skip GA4-console toggles and business-judgment items — flag those for the user instead of editing code. Campaigns and ad budgets are NOT here — those are owner decisions in the jujugrowth web UI. This server is bound to ONE site; never act on another.",
|
|
151
156
|
},
|
|
152
157
|
});
|
|
153
158
|
}
|
|
@@ -156,14 +161,22 @@ async function handle(msg) {
|
|
|
156
161
|
return send({
|
|
157
162
|
jsonrpc: "2.0",
|
|
158
163
|
id,
|
|
159
|
-
result: {
|
|
164
|
+
result: {
|
|
165
|
+
tools: TOOLS.map(({ name, description, inputSchema }) => ({
|
|
166
|
+
name,
|
|
167
|
+
description,
|
|
168
|
+
inputSchema,
|
|
169
|
+
})),
|
|
170
|
+
},
|
|
160
171
|
});
|
|
161
172
|
}
|
|
162
173
|
if (method === "tools/call") {
|
|
163
174
|
const tool = TOOLS.find((t) => t.name === params?.name);
|
|
164
|
-
if (!tool)
|
|
175
|
+
if (!tool)
|
|
176
|
+
return send({ jsonrpc: "2.0", id, error: { code: -32601, message: "unknown tool" } });
|
|
165
177
|
try {
|
|
166
|
-
if (!TOKEN)
|
|
178
|
+
if (!TOKEN)
|
|
179
|
+
throw new Error("JUJUGROWTH_TOKEN not set — generate one in Settings → Developer");
|
|
167
180
|
const result = await tool.run(params.arguments ?? {});
|
|
168
181
|
return send({
|
|
169
182
|
jsonrpc: "2.0",
|
|
@@ -180,17 +193,19 @@ async function handle(msg) {
|
|
|
180
193
|
});
|
|
181
194
|
}
|
|
182
195
|
}
|
|
183
|
-
if (id !== undefined)
|
|
196
|
+
if (id !== undefined)
|
|
197
|
+
send({ jsonrpc: "2.0", id, error: { code: -32601, message: "method not found" } });
|
|
184
198
|
}
|
|
185
199
|
|
|
186
200
|
let buf = "";
|
|
187
201
|
process.stdin.setEncoding("utf8");
|
|
188
202
|
process.stdin.on("data", (chunk) => {
|
|
189
203
|
buf += chunk;
|
|
190
|
-
let nl;
|
|
191
|
-
while (
|
|
204
|
+
let nl = buf.indexOf("\n");
|
|
205
|
+
while (nl >= 0) {
|
|
192
206
|
const line = buf.slice(0, nl).trim();
|
|
193
207
|
buf = buf.slice(nl + 1);
|
|
194
208
|
if (line) handle(JSON.parse(line)).catch((e) => process.stderr.write(`${e}\n`));
|
|
209
|
+
nl = buf.indexOf("\n");
|
|
195
210
|
}
|
|
196
211
|
});
|