@tenpo/mcp 0.2.2 → 0.2.3
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 -0
- package/dist/index.js +46 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -237,6 +237,9 @@ That's the first line. **First run auto-issues a free API key** (500 calls/month
|
|
|
237
237
|
|
|
238
238
|
The second line goes into your AI host's config:
|
|
239
239
|
|
|
240
|
+
> ⚠️ **After editing the config, fully restart your AI host.**
|
|
241
|
+
> MCP servers are loaded at host startup — `claude mcp add`, saving Claude Desktop's config, or editing Cursor's MCP settings will register Tenpo, but the new tools won't appear in your running session until you **quit and relaunch the app** (Cmd+Q on Mac, fully close on Windows). This is a host-side limitation, not a Tenpo one.
|
|
242
|
+
|
|
240
243
|
<details>
|
|
241
244
|
<summary><b>Claude Desktop</b> · <code>claude_desktop_config.json</code></summary>
|
|
242
245
|
|
package/dist/index.js
CHANGED
|
@@ -370,6 +370,43 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
370
370
|
}));
|
|
371
371
|
return { tools: [...TOOLS, ...dynamicEntries] };
|
|
372
372
|
});
|
|
373
|
+
/**
|
|
374
|
+
* Format a backend tool result as MCP CallTool content.
|
|
375
|
+
*
|
|
376
|
+
* Many Tenpo tools return `data.chat_message` — a pre-formatted, chat-ready
|
|
377
|
+
* string the host AI should display verbatim. Surface that as the PRIMARY
|
|
378
|
+
* text block; append the structured JSON afterward so the host AI can still
|
|
379
|
+
* introspect (e.g. for follow-up tool calls or to read `instruction_for_host_ai`).
|
|
380
|
+
*
|
|
381
|
+
* This stops the old "double-encoded JSON inside JSON" UX where the host AI
|
|
382
|
+
* saw nothing but a stringified blob.
|
|
383
|
+
*/
|
|
384
|
+
function formatToolResult(result) {
|
|
385
|
+
// Type guard: try to pull data.chat_message safely
|
|
386
|
+
const r = result;
|
|
387
|
+
// Error path: backend returned ok:false. Show it cleanly.
|
|
388
|
+
if (r && r.ok === false) {
|
|
389
|
+
return {
|
|
390
|
+
content: [
|
|
391
|
+
{ type: "text", text: `Error: ${r.error ?? "Tool execution failed"}` },
|
|
392
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
393
|
+
],
|
|
394
|
+
isError: true,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
const chatMessage = r?.data?.chat_message;
|
|
398
|
+
if (typeof chatMessage === "string" && chatMessage.length > 0) {
|
|
399
|
+
// Primary: the chat-ready message. Secondary: structured JSON for introspection.
|
|
400
|
+
return {
|
|
401
|
+
content: [
|
|
402
|
+
{ type: "text", text: chatMessage },
|
|
403
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
404
|
+
],
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
// No chat_message — fall back to pretty-printed JSON.
|
|
408
|
+
return formatToolResult(result);
|
|
409
|
+
}
|
|
373
410
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
374
411
|
await ensureApiKey();
|
|
375
412
|
const { name, arguments: args = {} } = request.params;
|
|
@@ -380,7 +417,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
380
417
|
method: "POST",
|
|
381
418
|
body: args,
|
|
382
419
|
});
|
|
383
|
-
return
|
|
420
|
+
return formatToolResult(result);
|
|
384
421
|
}
|
|
385
422
|
case "tenpo_run_tool": {
|
|
386
423
|
const a = args;
|
|
@@ -390,7 +427,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
390
427
|
method: "POST",
|
|
391
428
|
body: a.args ?? {},
|
|
392
429
|
});
|
|
393
|
-
return
|
|
430
|
+
return formatToolResult(result);
|
|
394
431
|
}
|
|
395
432
|
case "tenpo_classify_intent": {
|
|
396
433
|
const a = args;
|
|
@@ -449,7 +486,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
449
486
|
if (!a.resource)
|
|
450
487
|
throw new Error("resource name required");
|
|
451
488
|
const result = await tenpoFetch(`/api/v1/resources/${encodeURIComponent(a.resource)}`);
|
|
452
|
-
return
|
|
489
|
+
return formatToolResult(result);
|
|
453
490
|
}
|
|
454
491
|
case "tenpo_get_prompt": {
|
|
455
492
|
const a = args;
|
|
@@ -464,7 +501,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
464
501
|
path += `?${params.toString()}`;
|
|
465
502
|
}
|
|
466
503
|
const result = await tenpoFetch(path);
|
|
467
|
-
return
|
|
504
|
+
return formatToolResult(result);
|
|
468
505
|
}
|
|
469
506
|
case "tenpo_list_prompts": {
|
|
470
507
|
const a = args;
|
|
@@ -472,7 +509,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
472
509
|
? `/api/v1/prompts?q=${encodeURIComponent(a.q)}`
|
|
473
510
|
: `/api/v1/prompts`;
|
|
474
511
|
const result = await tenpoFetch(path);
|
|
475
|
-
return
|
|
512
|
+
return formatToolResult(result);
|
|
476
513
|
}
|
|
477
514
|
case "tenpo_connect_integration": {
|
|
478
515
|
const a = args;
|
|
@@ -483,13 +520,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
483
520
|
method: "POST",
|
|
484
521
|
body: { integration_id: a.integration_id, credentials: a.credentials },
|
|
485
522
|
});
|
|
486
|
-
return
|
|
523
|
+
return formatToolResult(result);
|
|
487
524
|
}
|
|
488
525
|
const result = await tenpoFetch("/api/v1/connect/start", {
|
|
489
526
|
method: "POST",
|
|
490
527
|
body: { integration_id: a.integration_id },
|
|
491
528
|
});
|
|
492
|
-
return
|
|
529
|
+
return formatToolResult(result);
|
|
493
530
|
}
|
|
494
531
|
case "tenpo_remember": {
|
|
495
532
|
const a = args;
|
|
@@ -500,7 +537,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
500
537
|
method: "POST",
|
|
501
538
|
body: { content, scope: a.scope ?? a.memory_type ?? "fact", mode: a.mode ?? "append" },
|
|
502
539
|
});
|
|
503
|
-
return
|
|
540
|
+
return formatToolResult(result);
|
|
504
541
|
}
|
|
505
542
|
// tenpo_pattern_detect, tenpo_fetch_url, tenpo_write_md, tenpo_route_skills,
|
|
506
543
|
// tenpo_overview cases DROPPED — host AI's native capabilities cover them.
|
|
@@ -515,7 +552,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
515
552
|
throw new Error(`Unknown tool: ${name}. Use tenpo_route to discover available tools.`);
|
|
516
553
|
}
|
|
517
554
|
const result = await tenpoFetch(`/api/v1/tools/${encodeURIComponent(name)}`, { method: "POST", body: args });
|
|
518
|
-
return
|
|
555
|
+
return formatToolResult(result);
|
|
519
556
|
}
|
|
520
557
|
}
|
|
521
558
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tenpo/mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Tenpo — the operator that runs alongside your store. Connects to 45+ commerce platforms (Shopify, Klaviyo, Meta Ads, GA4, Stripe…) and gives any AI host (Claude Desktop, Cursor, Claude Code, ChatGPT) deterministic answers about your sales, ads, email, inventory, suppliers, customers, finance, and competitors. Free tier, no card required.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://tenpo.ai",
|