akemon 0.1.15 → 0.1.17
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/connect.js +47 -0
- package/dist/list.js +0 -10
- package/dist/server.js +95 -0
- package/package.json +1 -1
package/dist/connect.js
CHANGED
|
@@ -86,6 +86,53 @@ export async function connect(options) {
|
|
|
86
86
|
return { content: [{ type: "text", text: `[error] ${err.message}` }], isError: true };
|
|
87
87
|
}
|
|
88
88
|
});
|
|
89
|
+
// list_products — browse marketplace
|
|
90
|
+
server.tool("list_products", "Browse products and services available on the akemon marketplace.", {
|
|
91
|
+
search: z.string().optional().describe("Search by product name or description"),
|
|
92
|
+
agent: z.string().optional().describe("Filter by agent name"),
|
|
93
|
+
}, async ({ search, agent }) => {
|
|
94
|
+
try {
|
|
95
|
+
const params = new URLSearchParams();
|
|
96
|
+
if (search)
|
|
97
|
+
params.set("search", search);
|
|
98
|
+
if (agent)
|
|
99
|
+
params.set("agent", agent);
|
|
100
|
+
const res = await fetch(`${relayHttp}/v1/products?${params}`);
|
|
101
|
+
if (!res.ok) {
|
|
102
|
+
return { content: [{ type: "text", text: `[error] ${res.status}` }], isError: true };
|
|
103
|
+
}
|
|
104
|
+
const products = await res.json();
|
|
105
|
+
const list = products
|
|
106
|
+
.map((p) => `- "${p.name}" by ${p.agent_name} — price=${p.price} purchases=${p.purchase_count} — ${p.description || "no description"}`)
|
|
107
|
+
.join("\n");
|
|
108
|
+
return { content: [{ type: "text", text: list || "No products found." }] };
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
return { content: [{ type: "text", text: `[error] ${err.message}` }], isError: true };
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
// buy_product — purchase a product
|
|
115
|
+
server.tool("buy_product", "Purchase a product from the akemon marketplace. The seller agent will fulfill your request.", {
|
|
116
|
+
id: z.string().describe("Product ID to purchase"),
|
|
117
|
+
task: z.string().describe("Your specific request or requirements for this purchase"),
|
|
118
|
+
}, async ({ id, task }) => {
|
|
119
|
+
try {
|
|
120
|
+
const res = await fetch(`${relayHttp}/v1/products/${encodeURIComponent(id)}/buy`, {
|
|
121
|
+
method: "POST",
|
|
122
|
+
headers: authHeaders(),
|
|
123
|
+
body: JSON.stringify({ task }),
|
|
124
|
+
});
|
|
125
|
+
if (!res.ok) {
|
|
126
|
+
const err = await res.text();
|
|
127
|
+
return { content: [{ type: "text", text: `[error] ${res.status}: ${err}` }], isError: true };
|
|
128
|
+
}
|
|
129
|
+
const data = await res.json();
|
|
130
|
+
return { content: [{ type: "text", text: data.result || JSON.stringify(data) }] };
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
return { content: [{ type: "text", text: `[error] ${err.message}` }], isError: true };
|
|
134
|
+
}
|
|
135
|
+
});
|
|
89
136
|
const transport = new StdioServerTransport();
|
|
90
137
|
await server.connect(transport);
|
|
91
138
|
}
|
package/dist/list.js
CHANGED
|
@@ -16,12 +16,6 @@ function spdStars(avgMs) {
|
|
|
16
16
|
return "★★☆☆☆";
|
|
17
17
|
return "★☆☆☆☆";
|
|
18
18
|
}
|
|
19
|
-
function ppDisplay(totalTasks, maxTasks) {
|
|
20
|
-
if (!maxTasks || maxTasks <= 0)
|
|
21
|
-
return "∞";
|
|
22
|
-
const remaining = Math.max(0, maxTasks - totalTasks);
|
|
23
|
-
return `${remaining}/${maxTasks}`;
|
|
24
|
-
}
|
|
25
19
|
export async function listAgents(relayUrl, search) {
|
|
26
20
|
const url = `${relayUrl}/v1/agents`;
|
|
27
21
|
try {
|
|
@@ -49,7 +43,6 @@ export async function listAgents(relayUrl, search) {
|
|
|
49
43
|
lvl: String(a.level),
|
|
50
44
|
spd: spdStars(a.avg_response_ms),
|
|
51
45
|
rel: stars(a.success_rate),
|
|
52
|
-
pp: ppDisplay(a.total_tasks, a.max_tasks),
|
|
53
46
|
desc: (a.description || "-") + (a.public ? "" : " 🔒"),
|
|
54
47
|
}));
|
|
55
48
|
// Dynamic column widths based on actual data
|
|
@@ -59,14 +52,12 @@ export async function listAgents(relayUrl, search) {
|
|
|
59
52
|
const lvlW = Math.max(3, ...rows.map((r) => r.lvl.length)) + 2;
|
|
60
53
|
const spdW = 7;
|
|
61
54
|
const relW = 7;
|
|
62
|
-
const ppW = Math.max(2, ...rows.map((r) => r.pp.length)) + 2;
|
|
63
55
|
console.log(pad("", avatarW) +
|
|
64
56
|
pad("NAME", nameW) +
|
|
65
57
|
pad("ENGINE", engineW) +
|
|
66
58
|
pad("LVL", lvlW) +
|
|
67
59
|
pad("SPD", spdW) +
|
|
68
60
|
pad("REL", relW) +
|
|
69
|
-
pad("PP", ppW) +
|
|
70
61
|
"DESCRIPTION");
|
|
71
62
|
for (const r of rows) {
|
|
72
63
|
console.log(pad(r.avatar, avatarW) +
|
|
@@ -75,7 +66,6 @@ export async function listAgents(relayUrl, search) {
|
|
|
75
66
|
pad(r.lvl, lvlW) +
|
|
76
67
|
pad(r.spd, spdW) +
|
|
77
68
|
pad(r.rel, relW) +
|
|
78
|
-
pad(r.pp, ppW) +
|
|
79
69
|
r.desc);
|
|
80
70
|
}
|
|
81
71
|
}
|
package/dist/server.js
CHANGED
|
@@ -343,6 +343,101 @@ function createMcpServer(opts) {
|
|
|
343
343
|
return { content: [{ type: "text", text: `[error] ${err.message}` }], isError: true };
|
|
344
344
|
}
|
|
345
345
|
});
|
|
346
|
+
// --- Product management tools ---
|
|
347
|
+
server.tool("create_product", "List a new product or service for sale on the akemon marketplace. Other agents and humans can browse and buy it.", {
|
|
348
|
+
name: z.string().describe("Product name (e.g. 'Code Review', 'Resume Writing')"),
|
|
349
|
+
description: z.string().describe("What this product/service provides, what the buyer gets"),
|
|
350
|
+
price: z.number().optional().describe("Price in credits (default: 1)"),
|
|
351
|
+
}, async ({ name: prodName, description: prodDesc, price }) => {
|
|
352
|
+
if (!relayHttp || !secretKey) {
|
|
353
|
+
return { content: [{ type: "text", text: "[error] No relay configured" }], isError: true };
|
|
354
|
+
}
|
|
355
|
+
try {
|
|
356
|
+
const res = await fetch(`${relayHttp}/v1/agent/${encodeURIComponent(agentName)}/products`, {
|
|
357
|
+
method: "POST",
|
|
358
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${secretKey}` },
|
|
359
|
+
body: JSON.stringify({ name: prodName, description: prodDesc, price: price || 1 }),
|
|
360
|
+
});
|
|
361
|
+
if (!res.ok) {
|
|
362
|
+
const err = await res.text();
|
|
363
|
+
return { content: [{ type: "text", text: `[error] ${res.status}: ${err}` }], isError: true };
|
|
364
|
+
}
|
|
365
|
+
const product = await res.json();
|
|
366
|
+
return { content: [{ type: "text", text: `Product created: "${product.name}" (id=${product.id}, price=${product.price})` }] };
|
|
367
|
+
}
|
|
368
|
+
catch (err) {
|
|
369
|
+
return { content: [{ type: "text", text: `[error] ${err.message}` }], isError: true };
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
server.tool("list_my_products", "List your own products currently on sale.", {}, async () => {
|
|
373
|
+
if (!relayHttp) {
|
|
374
|
+
return { content: [{ type: "text", text: "[error] No relay configured" }], isError: true };
|
|
375
|
+
}
|
|
376
|
+
try {
|
|
377
|
+
const res = await fetch(`${relayHttp}/v1/agent/${encodeURIComponent(agentName)}/products`);
|
|
378
|
+
const products = await res.json();
|
|
379
|
+
if (!products.length)
|
|
380
|
+
return { content: [{ type: "text", text: "No products listed." }] };
|
|
381
|
+
const list = products.map((p) => `- [${p.id}] "${p.name}" price=${p.price} purchases=${p.purchase_count} — ${p.description || "no description"}`).join("\n");
|
|
382
|
+
return { content: [{ type: "text", text: list }] };
|
|
383
|
+
}
|
|
384
|
+
catch (err) {
|
|
385
|
+
return { content: [{ type: "text", text: `[error] ${err.message}` }], isError: true };
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
server.tool("update_product", "Update one of your products (name, description, or price).", {
|
|
389
|
+
id: z.string().describe("Product ID to update"),
|
|
390
|
+
name: z.string().optional().describe("New product name"),
|
|
391
|
+
description: z.string().optional().describe("New description"),
|
|
392
|
+
price: z.number().optional().describe("New price in credits"),
|
|
393
|
+
}, async ({ id, name: prodName, description: prodDesc, price }) => {
|
|
394
|
+
if (!relayHttp || !secretKey) {
|
|
395
|
+
return { content: [{ type: "text", text: "[error] No relay configured" }], isError: true };
|
|
396
|
+
}
|
|
397
|
+
try {
|
|
398
|
+
const body = {};
|
|
399
|
+
if (prodName)
|
|
400
|
+
body.name = prodName;
|
|
401
|
+
if (prodDesc)
|
|
402
|
+
body.description = prodDesc;
|
|
403
|
+
if (price)
|
|
404
|
+
body.price = price;
|
|
405
|
+
const res = await fetch(`${relayHttp}/v1/products/${encodeURIComponent(id)}`, {
|
|
406
|
+
method: "PUT",
|
|
407
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${secretKey}` },
|
|
408
|
+
body: JSON.stringify(body),
|
|
409
|
+
});
|
|
410
|
+
if (!res.ok) {
|
|
411
|
+
const err = await res.text();
|
|
412
|
+
return { content: [{ type: "text", text: `[error] ${res.status}: ${err}` }], isError: true };
|
|
413
|
+
}
|
|
414
|
+
return { content: [{ type: "text", text: `Product ${id} updated.` }] };
|
|
415
|
+
}
|
|
416
|
+
catch (err) {
|
|
417
|
+
return { content: [{ type: "text", text: `[error] ${err.message}` }], isError: true };
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
server.tool("delete_product", "Remove one of your products from the marketplace.", {
|
|
421
|
+
id: z.string().describe("Product ID to delete"),
|
|
422
|
+
}, async ({ id }) => {
|
|
423
|
+
if (!relayHttp || !secretKey) {
|
|
424
|
+
return { content: [{ type: "text", text: "[error] No relay configured" }], isError: true };
|
|
425
|
+
}
|
|
426
|
+
try {
|
|
427
|
+
const res = await fetch(`${relayHttp}/v1/products/${encodeURIComponent(id)}`, {
|
|
428
|
+
method: "DELETE",
|
|
429
|
+
headers: { Authorization: `Bearer ${secretKey}` },
|
|
430
|
+
});
|
|
431
|
+
if (!res.ok) {
|
|
432
|
+
const err = await res.text();
|
|
433
|
+
return { content: [{ type: "text", text: `[error] ${res.status}: ${err}` }], isError: true };
|
|
434
|
+
}
|
|
435
|
+
return { content: [{ type: "text", text: `Product ${id} deleted.` }] };
|
|
436
|
+
}
|
|
437
|
+
catch (err) {
|
|
438
|
+
return { content: [{ type: "text", text: `[error] ${err.message}` }], isError: true };
|
|
439
|
+
}
|
|
440
|
+
});
|
|
346
441
|
return server;
|
|
347
442
|
}
|
|
348
443
|
async function initMcpProxy(mcpServerCmd, workdir) {
|