@agentwonderland/mcp 0.1.1
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/core/api-client.d.ts +14 -0
- package/dist/core/api-client.js +98 -0
- package/dist/core/config.d.ts +77 -0
- package/dist/core/config.js +297 -0
- package/dist/core/formatters.d.ts +70 -0
- package/dist/core/formatters.js +193 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.js +6 -0
- package/dist/core/ows-adapter.d.ts +43 -0
- package/dist/core/ows-adapter.js +100 -0
- package/dist/core/payments.d.ts +41 -0
- package/dist/core/payments.js +254 -0
- package/dist/core/types.d.ts +27 -0
- package/dist/core/types.js +4 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +53 -0
- package/dist/prompts/index.d.ts +2 -0
- package/dist/prompts/index.js +89 -0
- package/dist/resources/agents.d.ts +2 -0
- package/dist/resources/agents.js +34 -0
- package/dist/resources/jobs.d.ts +2 -0
- package/dist/resources/jobs.js +15 -0
- package/dist/resources/wallet.d.ts +2 -0
- package/dist/resources/wallet.js +26 -0
- package/dist/tools/_token-cache.d.ts +5 -0
- package/dist/tools/_token-cache.js +9 -0
- package/dist/tools/agent-info.d.ts +2 -0
- package/dist/tools/agent-info.js +97 -0
- package/dist/tools/favorites.d.ts +2 -0
- package/dist/tools/favorites.js +51 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.js +9 -0
- package/dist/tools/jobs.d.ts +2 -0
- package/dist/tools/jobs.js +49 -0
- package/dist/tools/rate.d.ts +2 -0
- package/dist/tools/rate.js +44 -0
- package/dist/tools/run.d.ts +2 -0
- package/dist/tools/run.js +80 -0
- package/dist/tools/search.d.ts +2 -0
- package/dist/tools/search.js +81 -0
- package/dist/tools/solve.d.ts +2 -0
- package/dist/tools/solve.js +124 -0
- package/dist/tools/tip.d.ts +2 -0
- package/dist/tools/tip.js +40 -0
- package/dist/tools/wallet.d.ts +2 -0
- package/dist/tools/wallet.js +197 -0
- package/package.json +49 -0
- package/src/core/api-client.ts +114 -0
- package/src/core/config.ts +384 -0
- package/src/core/formatters.ts +256 -0
- package/src/core/index.ts +6 -0
- package/src/core/ows-adapter.ts +214 -0
- package/src/core/payments.ts +278 -0
- package/src/core/types.ts +28 -0
- package/src/index.ts +65 -0
- package/src/prompts/index.ts +120 -0
- package/src/resources/agents.ts +37 -0
- package/src/resources/jobs.ts +17 -0
- package/src/resources/wallet.ts +30 -0
- package/src/tools/_token-cache.ts +18 -0
- package/src/tools/agent-info.ts +120 -0
- package/src/tools/favorites.ts +74 -0
- package/src/tools/index.ts +9 -0
- package/src/tools/jobs.ts +69 -0
- package/src/tools/rate.ts +62 -0
- package/src/tools/run.ts +97 -0
- package/src/tools/search.ts +96 -0
- package/src/tools/solve.ts +162 -0
- package/src/tools/tip.ts +59 -0
- package/src/tools/wallet.ts +268 -0
- package/tsconfig.json +15 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
// ── Tools ────────────────────────────────────────────────────────
|
|
5
|
+
import { registerSearchTools } from "./tools/search.js";
|
|
6
|
+
import { registerRunTools } from "./tools/run.js";
|
|
7
|
+
import { registerSolveTools } from "./tools/solve.js";
|
|
8
|
+
import { registerAgentInfoTools } from "./tools/agent-info.js";
|
|
9
|
+
import { registerJobTools } from "./tools/jobs.js";
|
|
10
|
+
import { registerRateTools } from "./tools/rate.js";
|
|
11
|
+
import { registerWalletTools } from "./tools/wallet.js";
|
|
12
|
+
import { registerFavoriteTools } from "./tools/favorites.js";
|
|
13
|
+
import { registerTipTools } from "./tools/tip.js";
|
|
14
|
+
// ── Resources ────────────────────────────────────────────────────
|
|
15
|
+
import { registerAgentResources } from "./resources/agents.js";
|
|
16
|
+
import { registerWalletResources } from "./resources/wallet.js";
|
|
17
|
+
import { registerJobResources } from "./resources/jobs.js";
|
|
18
|
+
// ── Prompts ──────────────────────────────────────────────────────
|
|
19
|
+
import { registerPrompts } from "./prompts/index.js";
|
|
20
|
+
export async function startMcpServer() {
|
|
21
|
+
const server = new McpServer({
|
|
22
|
+
name: "agentwonderland",
|
|
23
|
+
version: "0.2.0",
|
|
24
|
+
});
|
|
25
|
+
// Register tools
|
|
26
|
+
registerSearchTools(server);
|
|
27
|
+
registerRunTools(server);
|
|
28
|
+
registerSolveTools(server);
|
|
29
|
+
registerAgentInfoTools(server);
|
|
30
|
+
registerJobTools(server);
|
|
31
|
+
registerRateTools(server);
|
|
32
|
+
registerWalletTools(server);
|
|
33
|
+
registerFavoriteTools(server);
|
|
34
|
+
registerTipTools(server);
|
|
35
|
+
// Register resources
|
|
36
|
+
registerAgentResources(server);
|
|
37
|
+
registerWalletResources(server);
|
|
38
|
+
registerJobResources(server);
|
|
39
|
+
// Register prompts
|
|
40
|
+
registerPrompts(server);
|
|
41
|
+
const transport = new StdioServerTransport();
|
|
42
|
+
await server.connect(transport);
|
|
43
|
+
}
|
|
44
|
+
// ── Direct execution ─────────────────────────────────────────────
|
|
45
|
+
// When run as a binary (agentwonderland-mcp), start the server immediately.
|
|
46
|
+
const isCli = process.argv[1]?.endsWith("agentwonderland-mcp") ||
|
|
47
|
+
process.argv[1]?.includes("packages/mcp");
|
|
48
|
+
if (isCli) {
|
|
49
|
+
startMcpServer().catch((err) => {
|
|
50
|
+
console.error("MCP server error:", err);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerPrompts(server) {
|
|
3
|
+
server.prompt("get-started", "Get started with Agent Wonderland — check wallet, discover agents, learn the tools", {}, async () => ({
|
|
4
|
+
messages: [{
|
|
5
|
+
role: "user",
|
|
6
|
+
content: {
|
|
7
|
+
type: "text",
|
|
8
|
+
text: [
|
|
9
|
+
"Help me get started with Agent Wonderland.",
|
|
10
|
+
"",
|
|
11
|
+
"Please:",
|
|
12
|
+
"1. Check my wallet status with wallet_status",
|
|
13
|
+
"2. If no wallet is configured, help me create one with wallet_setup",
|
|
14
|
+
"3. Show me some popular agents with search_agents",
|
|
15
|
+
"4. Briefly explain how solve, run_agent, rating, and tipping work",
|
|
16
|
+
].join("\n"),
|
|
17
|
+
},
|
|
18
|
+
}],
|
|
19
|
+
}));
|
|
20
|
+
server.prompt("wallet-setup", "Create and fund a wallet for paying agents", {}, async () => ({
|
|
21
|
+
messages: [{
|
|
22
|
+
role: "user",
|
|
23
|
+
content: {
|
|
24
|
+
type: "text",
|
|
25
|
+
text: [
|
|
26
|
+
"Help me set up a payment wallet for Agent Wonderland.",
|
|
27
|
+
"",
|
|
28
|
+
"Please:",
|
|
29
|
+
"1. Check if I already have a wallet with wallet_status",
|
|
30
|
+
"2. If not, create one with wallet_setup",
|
|
31
|
+
"3. Show me the address I need to fund",
|
|
32
|
+
"4. Explain what USDC I need and on which network (Tempo, Base, or Solana)",
|
|
33
|
+
].join("\n"),
|
|
34
|
+
},
|
|
35
|
+
}],
|
|
36
|
+
}));
|
|
37
|
+
server.prompt("find-agent", "Find the best agent for a task", { task: z.string().describe("What you need done") }, async ({ task }) => ({
|
|
38
|
+
messages: [{
|
|
39
|
+
role: "user",
|
|
40
|
+
content: {
|
|
41
|
+
type: "text",
|
|
42
|
+
text: [
|
|
43
|
+
`Find the best agent on Agent Wonderland for this task: "${task}"`,
|
|
44
|
+
"",
|
|
45
|
+
"Steps:",
|
|
46
|
+
"1. Use search_agents to find relevant agents",
|
|
47
|
+
"2. Use compare_agents on the top 2-3 candidates",
|
|
48
|
+
"3. Recommend the best one based on price, rating, and success rate",
|
|
49
|
+
"4. Ask if I want to run it",
|
|
50
|
+
].join("\n"),
|
|
51
|
+
},
|
|
52
|
+
}],
|
|
53
|
+
}));
|
|
54
|
+
server.prompt("budget-run", "Complete a task within a budget", {
|
|
55
|
+
task: z.string().describe("What you need done"),
|
|
56
|
+
budget: z.string().optional().describe("Max spend in USD (default: $1)"),
|
|
57
|
+
}, async ({ task, budget }) => ({
|
|
58
|
+
messages: [{
|
|
59
|
+
role: "user",
|
|
60
|
+
content: {
|
|
61
|
+
type: "text",
|
|
62
|
+
text: [
|
|
63
|
+
`Complete this task on Agent Wonderland within $${budget || "1.00"}: "${task}"`,
|
|
64
|
+
"",
|
|
65
|
+
"Use the solve tool with the budget parameter. Show me what agent was selected and why.",
|
|
66
|
+
].join("\n"),
|
|
67
|
+
},
|
|
68
|
+
}],
|
|
69
|
+
}));
|
|
70
|
+
server.prompt("run-with-review", "Run an agent and review the output", {
|
|
71
|
+
agent_id: z.string().describe("Agent ID to run"),
|
|
72
|
+
input: z.string().describe("JSON input for the agent"),
|
|
73
|
+
}, async ({ agent_id, input }) => ({
|
|
74
|
+
messages: [{
|
|
75
|
+
role: "user",
|
|
76
|
+
content: {
|
|
77
|
+
type: "text",
|
|
78
|
+
text: [
|
|
79
|
+
`Run agent ${agent_id} with this input: ${input}`,
|
|
80
|
+
"",
|
|
81
|
+
"After getting the result:",
|
|
82
|
+
"1. Summarize the output",
|
|
83
|
+
"2. Assess the quality",
|
|
84
|
+
"3. Ask if I want to rate the agent",
|
|
85
|
+
].join("\n"),
|
|
86
|
+
},
|
|
87
|
+
}],
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { apiGet } from "../core/api-client.js";
|
|
2
|
+
import { formatPrice, stars, compactNumber } from "../core/formatters.js";
|
|
3
|
+
export function registerAgentResources(server) {
|
|
4
|
+
// Agent directory — browsable list of all agents
|
|
5
|
+
server.resource("agent-directory", "aw://agents", async () => {
|
|
6
|
+
const agents = await apiGet("/agents?limit=50");
|
|
7
|
+
const lines = agents.map(a => {
|
|
8
|
+
const rating = stars(a.reputationScore);
|
|
9
|
+
const jobs = compactNumber(a.totalExecutions);
|
|
10
|
+
const price = formatPrice(a.pricePer1kTokens);
|
|
11
|
+
return `${a.name} ${rating} ${jobs} jobs | ${price}/req — ${a.description || ""}`;
|
|
12
|
+
});
|
|
13
|
+
return {
|
|
14
|
+
contents: [{
|
|
15
|
+
uri: "aw://agents",
|
|
16
|
+
mimeType: "text/plain",
|
|
17
|
+
text: `Agent Wonderland Marketplace (${agents.length} agents)\n\n${lines.join("\n")}`,
|
|
18
|
+
}],
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
// Agent schema — input schema for a specific agent
|
|
22
|
+
server.resource("agent-schema", "aw://agents/{id}/schema", async (uri) => {
|
|
23
|
+
const id = uri.pathname?.split("/").pop() || uri.href.split("/").pop()?.split("?")[0];
|
|
24
|
+
const agent = await apiGet(`/agents/${id}`);
|
|
25
|
+
const schema = agent.mcpSchema ? JSON.stringify(agent.mcpSchema, null, 2) : "No schema defined";
|
|
26
|
+
return {
|
|
27
|
+
contents: [{
|
|
28
|
+
uri: uri.href,
|
|
29
|
+
mimeType: "application/json",
|
|
30
|
+
text: schema,
|
|
31
|
+
}],
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { apiGet } from "../core/api-client.js";
|
|
2
|
+
import { formatRunResult } from "../core/formatters.js";
|
|
3
|
+
export function registerJobResources(server) {
|
|
4
|
+
server.resource("job-result", "aw://jobs/{id}", async (uri) => {
|
|
5
|
+
const id = uri.pathname?.split("/").pop() || uri.href.split("/").pop()?.split("?")[0];
|
|
6
|
+
const job = await apiGet(`/jobs/${id}`);
|
|
7
|
+
return {
|
|
8
|
+
contents: [{
|
|
9
|
+
uri: uri.href,
|
|
10
|
+
mimeType: "text/plain",
|
|
11
|
+
text: formatRunResult(job),
|
|
12
|
+
}],
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { getWallets, getCardConfig } from "../core/config.js";
|
|
2
|
+
import { getWalletAddress, getConfiguredMethods } from "../core/payments.js";
|
|
3
|
+
export function registerWalletResources(server) {
|
|
4
|
+
server.resource("wallet-config", "aw://wallet", async () => {
|
|
5
|
+
const wallets = getWallets();
|
|
6
|
+
const card = getCardConfig();
|
|
7
|
+
const methods = getConfiguredMethods();
|
|
8
|
+
const lines = ["Wallet Configuration", ""];
|
|
9
|
+
for (const w of wallets) {
|
|
10
|
+
const addr = await getWalletAddress(w.id);
|
|
11
|
+
const storage = w.keyType === "ows" ? "[encrypted]" : "[plaintext]";
|
|
12
|
+
lines.push(`${w.id} ${storage}: ${w.chains.join(", ")} — ${addr}`);
|
|
13
|
+
}
|
|
14
|
+
if (card) {
|
|
15
|
+
lines.push(`Card: ${card.brand} ****${card.last4}`);
|
|
16
|
+
}
|
|
17
|
+
lines.push("", `Configured methods: ${methods.join(", ") || "none"}`);
|
|
18
|
+
return {
|
|
19
|
+
contents: [{
|
|
20
|
+
uri: "aw://wallet",
|
|
21
|
+
mimeType: "text/plain",
|
|
22
|
+
text: lines.join("\n"),
|
|
23
|
+
}],
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Feedback token cache — stores tokens from recent run/solve results
|
|
2
|
+
// Tokens expire after 1 hour on the server, so no need for client-side cleanup
|
|
3
|
+
const cache = new Map();
|
|
4
|
+
export function storeFeedbackToken(jobId, token, agentId) {
|
|
5
|
+
cache.set(jobId, { token, agent_id: agentId });
|
|
6
|
+
}
|
|
7
|
+
export function getFeedbackToken(jobId) {
|
|
8
|
+
return cache.get(jobId);
|
|
9
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { apiGet } from "../core/api-client.js";
|
|
3
|
+
import { formatPrice, stars, compactNumber, outputTypeHint, agentWebUrl, formatFeedbackSummary, formatLastActive } from "../core/formatters.js";
|
|
4
|
+
function text(t) {
|
|
5
|
+
return { content: [{ type: "text", text: t }] };
|
|
6
|
+
}
|
|
7
|
+
export function registerAgentInfoTools(server) {
|
|
8
|
+
// ── get_agent (renamed from agent_profile) ──────────────────────
|
|
9
|
+
server.tool("get_agent", "Get detailed information about a specific agent including description, pricing, success rate, latency, and tags.", {
|
|
10
|
+
agent_id: z.string().describe("Agent ID (UUID) or slug"),
|
|
11
|
+
}, async ({ agent_id }) => {
|
|
12
|
+
const a = await apiGet(`/agents/${agent_id}`);
|
|
13
|
+
const s = (a.stats ?? {});
|
|
14
|
+
const payment = (a.payment ?? {});
|
|
15
|
+
const _pricing = (payment.pricing ?? {});
|
|
16
|
+
const lines = [
|
|
17
|
+
`${a.name}`,
|
|
18
|
+
`${stars(a.avgRating ?? s.avgRating)} (${s.ratingCount ?? 0} reviews) • ${compactNumber((s.completedJobs ?? a.totalExecutions ?? 0))} jobs`,
|
|
19
|
+
"",
|
|
20
|
+
a.description ?? "",
|
|
21
|
+
"",
|
|
22
|
+
`Pricing: ${formatPrice(a.pricePer1kTokens, a.pricingModel)}`,
|
|
23
|
+
`Reliability: ${a.successRate != null ? (Number(a.successRate) * 100).toFixed(0) + "%" : "N/A"}`,
|
|
24
|
+
`Avg latency: ${a.avgResponseTimeMs != null ? a.avgResponseTimeMs + "ms" : "N/A"}`,
|
|
25
|
+
...(() => {
|
|
26
|
+
const lastActive = formatLastActive(a.lastActiveAt);
|
|
27
|
+
return lastActive ? [lastActive] : [];
|
|
28
|
+
})(),
|
|
29
|
+
"",
|
|
30
|
+
`Tags: ${a.tags?.join(", ") ?? "none"}`,
|
|
31
|
+
...(() => {
|
|
32
|
+
const hint = outputTypeHint(a.tags);
|
|
33
|
+
return hint ? [`Output: ${hint}`] : [];
|
|
34
|
+
})(),
|
|
35
|
+
];
|
|
36
|
+
// Feedback summary (rating + tips)
|
|
37
|
+
const feedbackSummary = formatFeedbackSummary(s);
|
|
38
|
+
if (feedbackSummary) {
|
|
39
|
+
lines.push("", feedbackSummary);
|
|
40
|
+
}
|
|
41
|
+
// Fetch recent reviews with comments
|
|
42
|
+
try {
|
|
43
|
+
const reviews = await apiGet(`/agents/${a.id}/reviews?limit=3&sort=recent`);
|
|
44
|
+
const withComments = reviews.reviews?.filter((r) => r.comment);
|
|
45
|
+
if (withComments?.length) {
|
|
46
|
+
lines.push("", "Recent reviews:");
|
|
47
|
+
for (const r of withComments) {
|
|
48
|
+
lines.push(` ${stars(r.rating)} "${r.comment}"`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Reviews endpoint may not be available
|
|
54
|
+
}
|
|
55
|
+
// Input schema — show what fields the agent accepts
|
|
56
|
+
const schema = a.schema?.input;
|
|
57
|
+
const inputSchema = (schema?.inputSchema ?? a.mcpSchema?.inputSchema);
|
|
58
|
+
if (inputSchema?.properties) {
|
|
59
|
+
const props = inputSchema.properties;
|
|
60
|
+
const required = new Set(inputSchema.required ?? []);
|
|
61
|
+
lines.push("", "Input fields:");
|
|
62
|
+
for (const [name, def] of Object.entries(props)) {
|
|
63
|
+
const req = required.has(name) ? " (required)" : "";
|
|
64
|
+
const desc = def.description ? ` — ${def.description}` : "";
|
|
65
|
+
lines.push(` ${name}: ${def.type ?? "string"}${req}${desc}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
lines.push("", `ID: ${a.id}`, `View: ${agentWebUrl(a.id)}`);
|
|
69
|
+
return text(lines.join("\n"));
|
|
70
|
+
});
|
|
71
|
+
// ── compare_agents ──────────────────────────────────────────────
|
|
72
|
+
server.tool("compare_agents", "Compare multiple agents side-by-side on rating, price, success rate, and job count.", {
|
|
73
|
+
agent_ids: z
|
|
74
|
+
.array(z.string())
|
|
75
|
+
.min(2)
|
|
76
|
+
.max(5)
|
|
77
|
+
.describe("Agent IDs to compare (2-5)"),
|
|
78
|
+
}, async ({ agent_ids }) => {
|
|
79
|
+
const agents = await Promise.all(agent_ids.map((id) => apiGet(`/agents/${id}`)));
|
|
80
|
+
const header = "Agent Comparison:\n";
|
|
81
|
+
const lines = agents.map((a) => {
|
|
82
|
+
const s = (a.stats ?? {});
|
|
83
|
+
const rating = a.avgRating ?? s.avgRating;
|
|
84
|
+
const jobs = (s.completedJobs ?? a.totalExecutions ?? 0);
|
|
85
|
+
const tipCount = (s.tipCount ?? 0);
|
|
86
|
+
return [
|
|
87
|
+
` ${a.name}`,
|
|
88
|
+
` ${stars(rating)} (${s.ratingCount ?? 0} reviews)${tipCount > 0 ? ` • ${tipCount} tips` : ""}`,
|
|
89
|
+
` ${compactNumber(jobs)} jobs • ${formatPrice(a.pricePer1kTokens, a.pricingModel)}`,
|
|
90
|
+
` Success: ${a.successRate != null ? (Number(a.successRate) * 100).toFixed(0) + "%" : "N/A"}`,
|
|
91
|
+
` ${agentWebUrl(a.id)}`,
|
|
92
|
+
"",
|
|
93
|
+
].join("\n");
|
|
94
|
+
});
|
|
95
|
+
return text(header + lines.join("\n"));
|
|
96
|
+
});
|
|
97
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getFavorites, addFavorite, removeFavorite } from "../core/config.js";
|
|
3
|
+
import { apiGet } from "../core/api-client.js";
|
|
4
|
+
import { formatPrice, stars, compactNumber } from "../core/formatters.js";
|
|
5
|
+
function text(t) {
|
|
6
|
+
return { content: [{ type: "text", text: t }] };
|
|
7
|
+
}
|
|
8
|
+
export function registerFavoriteTools(server) {
|
|
9
|
+
// favorite_agent — add an agent to favorites
|
|
10
|
+
server.tool("favorite_agent", "Save an agent to your favorites for quick access", {
|
|
11
|
+
agent_id: z.string().describe("Agent ID to favorite"),
|
|
12
|
+
}, async ({ agent_id }) => {
|
|
13
|
+
// Verify agent exists
|
|
14
|
+
const agent = await apiGet(`/agents/${agent_id}`);
|
|
15
|
+
addFavorite(agent_id);
|
|
16
|
+
return text(`★ Added ${agent.name} to favorites`);
|
|
17
|
+
});
|
|
18
|
+
// unfavorite_agent — remove from favorites
|
|
19
|
+
server.tool("unfavorite_agent", "Remove an agent from your favorites", {
|
|
20
|
+
agent_id: z.string().describe("Agent ID to remove"),
|
|
21
|
+
}, async ({ agent_id }) => {
|
|
22
|
+
removeFavorite(agent_id);
|
|
23
|
+
return text("Removed from favorites");
|
|
24
|
+
});
|
|
25
|
+
// list_favorites — show all favorited agents with details
|
|
26
|
+
server.tool("list_favorites", "List your favorite agents", {}, async () => {
|
|
27
|
+
const ids = getFavorites();
|
|
28
|
+
if (ids.length === 0) {
|
|
29
|
+
return text("No favorites yet. Use favorite_agent to save agents you like.");
|
|
30
|
+
}
|
|
31
|
+
const lines = ["Your favorite agents:", ""];
|
|
32
|
+
for (const id of ids) {
|
|
33
|
+
try {
|
|
34
|
+
const agent = await apiGet(`/agents/${id}`);
|
|
35
|
+
const rating = stars(agent.avgRating);
|
|
36
|
+
const jobs = compactNumber(agent.totalExecutions);
|
|
37
|
+
const price = formatPrice(agent.pricePer1kTokens, agent.pricingModel);
|
|
38
|
+
lines.push(`${agent.name} ${rating} ${jobs} jobs | ${price}`);
|
|
39
|
+
lines.push(` ID: ${id}`);
|
|
40
|
+
if (agent.description)
|
|
41
|
+
lines.push(` ${agent.description}`);
|
|
42
|
+
lines.push("");
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
lines.push(`${id} (not found — may have been removed)`);
|
|
46
|
+
lines.push("");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return text(lines.join("\n"));
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { registerSearchTools } from "./search.js";
|
|
2
|
+
export { registerRunTools } from "./run.js";
|
|
3
|
+
export { registerSolveTools } from "./solve.js";
|
|
4
|
+
export { registerAgentInfoTools } from "./agent-info.js";
|
|
5
|
+
export { registerJobTools } from "./jobs.js";
|
|
6
|
+
export { registerRateTools } from "./rate.js";
|
|
7
|
+
export { registerWalletTools } from "./wallet.js";
|
|
8
|
+
export { registerFavoriteTools } from "./favorites.js";
|
|
9
|
+
export { registerTipTools } from "./tip.js";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { registerSearchTools } from "./search.js";
|
|
2
|
+
export { registerRunTools } from "./run.js";
|
|
3
|
+
export { registerSolveTools } from "./solve.js";
|
|
4
|
+
export { registerAgentInfoTools } from "./agent-info.js";
|
|
5
|
+
export { registerJobTools } from "./jobs.js";
|
|
6
|
+
export { registerRateTools } from "./rate.js";
|
|
7
|
+
export { registerWalletTools } from "./wallet.js";
|
|
8
|
+
export { registerFavoriteTools } from "./favorites.js";
|
|
9
|
+
export { registerTipTools } from "./tip.js";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { apiGet } from "../core/api-client.js";
|
|
3
|
+
import { isAuthenticated } from "../core/config.js";
|
|
4
|
+
import { hasWalletConfigured, getWalletAddress } from "../core/payments.js";
|
|
5
|
+
import { formatRunResult } from "../core/formatters.js";
|
|
6
|
+
function text(t) {
|
|
7
|
+
return { content: [{ type: "text", text: t }] };
|
|
8
|
+
}
|
|
9
|
+
export function registerJobTools(server) {
|
|
10
|
+
// ── get_job ─────────────────────────────────────────────────────
|
|
11
|
+
server.tool("get_job", "Get the status and output of a job by ID. Use to poll async jobs until they complete.", {
|
|
12
|
+
job_id: z.string().describe("Job ID (UUID)"),
|
|
13
|
+
}, async ({ job_id }) => {
|
|
14
|
+
const result = await apiGet(`/jobs/${job_id}`);
|
|
15
|
+
if (result.status === "processing") {
|
|
16
|
+
return text(`Job ${job_id} is still processing...`);
|
|
17
|
+
}
|
|
18
|
+
return text(formatRunResult(result));
|
|
19
|
+
});
|
|
20
|
+
// ── list_jobs (renamed from list_my_jobs) ───────────────────────
|
|
21
|
+
server.tool("list_jobs", "List your recent jobs with status, cost, and agent info.", {
|
|
22
|
+
limit: z.coerce.number().optional().default(10).describe("Max results (1-50)"),
|
|
23
|
+
}, async ({ limit }) => {
|
|
24
|
+
let url = `/jobs?limit=${limit ?? 10}`;
|
|
25
|
+
// If not authenticated via API key, use wallet address for lookup
|
|
26
|
+
if (!isAuthenticated() && hasWalletConfigured()) {
|
|
27
|
+
const address = await getWalletAddress();
|
|
28
|
+
if (address) {
|
|
29
|
+
url += `&wallet=${encodeURIComponent(address)}`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const jobs = await apiGet(url);
|
|
33
|
+
if (jobs.length === 0)
|
|
34
|
+
return text("No jobs found.");
|
|
35
|
+
const lines = [`Recent jobs (${jobs.length}):`];
|
|
36
|
+
for (const j of jobs) {
|
|
37
|
+
const status = j.status === "completed"
|
|
38
|
+
? "\u2713"
|
|
39
|
+
: j.status === "processing"
|
|
40
|
+
? "\u2026"
|
|
41
|
+
: "\u2717";
|
|
42
|
+
const cost = j.estimated_cost != null
|
|
43
|
+
? `$${Number(j.estimated_cost).toFixed(4)}`
|
|
44
|
+
: "";
|
|
45
|
+
lines.push(` ${status} ${j.job_id?.slice(0, 8)}\u2026 ${j.agent_id ? String(j.agent_id).slice(0, 8) + "\u2026" : ""} ${cost}`);
|
|
46
|
+
}
|
|
47
|
+
return text(lines.join("\n"));
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { apiPost } from "../core/api-client.js";
|
|
3
|
+
import { stars } from "../core/formatters.js";
|
|
4
|
+
import { getFeedbackToken } from "./_token-cache.js";
|
|
5
|
+
function text(t) {
|
|
6
|
+
return { content: [{ type: "text", text: t }] };
|
|
7
|
+
}
|
|
8
|
+
export function registerRateTools(server) {
|
|
9
|
+
server.tool("rate_agent", "Rate an agent after running it. Provide the job ID from the run result. Must be used within 1 hour of running the agent.", {
|
|
10
|
+
job_id: z.string().describe("Job ID from the run result"),
|
|
11
|
+
rating: z.number().min(1).max(5).describe("Rating 1-5 stars"),
|
|
12
|
+
comment: z.string().optional().describe("Optional feedback comment"),
|
|
13
|
+
}, async ({ job_id, rating, comment }) => {
|
|
14
|
+
const tokenData = getFeedbackToken(job_id);
|
|
15
|
+
if (!tokenData) {
|
|
16
|
+
return text("No feedback token found for this job. You can only rate agents immediately after running them.");
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
await apiPost("/feedback", {
|
|
20
|
+
job_id,
|
|
21
|
+
feedback_token: tokenData.token,
|
|
22
|
+
rating,
|
|
23
|
+
thumb: rating >= 3 ? "up" : "down",
|
|
24
|
+
...(comment ? { comment } : {}),
|
|
25
|
+
});
|
|
26
|
+
const starStr = stars(rating);
|
|
27
|
+
return text(`${starStr} Rating submitted for job ${job_id}${comment ? ` \u2014 "${comment}"` : ""}`);
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
const apiErr = err;
|
|
31
|
+
if (apiErr?.status === 401) {
|
|
32
|
+
return text("Feedback token expired. Ratings must be submitted within 1 hour of running the agent.");
|
|
33
|
+
}
|
|
34
|
+
if (apiErr?.status === 409) {
|
|
35
|
+
return text("You've already rated this job.");
|
|
36
|
+
}
|
|
37
|
+
if (apiErr?.status === 429) {
|
|
38
|
+
return text("You can only rate this agent once every 30 days.");
|
|
39
|
+
}
|
|
40
|
+
const msg = apiErr?.body?.error || apiErr?.message || "Rating failed";
|
|
41
|
+
return text(`Could not submit rating: ${msg}`);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { apiGet, apiPostWithPayment } from "../core/api-client.js";
|
|
3
|
+
import { getConfiguredMethods, hasWalletConfigured } from "../core/payments.js";
|
|
4
|
+
import { formatRunResult } from "../core/formatters.js";
|
|
5
|
+
import { storeFeedbackToken } from "./_token-cache.js";
|
|
6
|
+
function text(t) {
|
|
7
|
+
return { content: [{ type: "text", text: t }] };
|
|
8
|
+
}
|
|
9
|
+
export function registerRunTools(server) {
|
|
10
|
+
server.tool("run_agent", "Run an AI agent from the marketplace. Pays automatically via configured wallet. Returns the agent's output, cost, and job ID for tracking.", {
|
|
11
|
+
agent_id: z.string().describe("Agent ID (UUID or slug)"),
|
|
12
|
+
input: z.record(z.unknown()).describe("Input payload for the agent"),
|
|
13
|
+
pay_with: z.string().optional().describe("Payment method — wallet ID, chain name (tempo, base, etc.), or 'card'. Auto-detected if omitted."),
|
|
14
|
+
}, async ({ agent_id, input, pay_with }) => {
|
|
15
|
+
if (!hasWalletConfigured()) {
|
|
16
|
+
return text("No wallet configured. Set one up first:\n\n" +
|
|
17
|
+
' wallet_setup({ action: "create", name: "my-wallet" })\n\n' +
|
|
18
|
+
"Then fund it with USDC on Tempo and try again.");
|
|
19
|
+
}
|
|
20
|
+
// Resolve slug to UUID if needed (slugs don't contain hyphens in UUID positions)
|
|
21
|
+
let resolvedId = agent_id;
|
|
22
|
+
const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(agent_id);
|
|
23
|
+
if (!isUuid) {
|
|
24
|
+
try {
|
|
25
|
+
const agent = await apiGet(`/agents/${agent_id}`);
|
|
26
|
+
resolvedId = agent.id;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return text(`Agent "${agent_id}" not found. Use search_agents to find available agents.`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const method = pay_with;
|
|
33
|
+
let result;
|
|
34
|
+
try {
|
|
35
|
+
result = await apiPostWithPayment(`/agents/${resolvedId}/run`, { input }, method);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
const apiErr = err;
|
|
39
|
+
if (apiErr?.status === 402) {
|
|
40
|
+
return text("Payment failed — your wallet may not have enough USDC.\n\n" +
|
|
41
|
+
"Check your balance and fund your wallet, then try again.\n" +
|
|
42
|
+
"Use wallet_status to check your current payment methods.");
|
|
43
|
+
}
|
|
44
|
+
const msg = apiErr?.message ?? "Failed to run agent";
|
|
45
|
+
if (msg.includes("Missing required field") || msg.includes("validation failed")) {
|
|
46
|
+
return text(`Error: ${msg}\n\nUse get_agent("${agent_id}") to see the required input fields.`);
|
|
47
|
+
}
|
|
48
|
+
return text(`Error: ${msg}`);
|
|
49
|
+
}
|
|
50
|
+
const formatted = formatRunResult(result, {
|
|
51
|
+
paymentMethod: method ?? getConfiguredMethods()[0],
|
|
52
|
+
});
|
|
53
|
+
const jobId = result.job_id ?? "";
|
|
54
|
+
const agentId = result.agent_id ?? agent_id;
|
|
55
|
+
if (result.feedback_token) {
|
|
56
|
+
storeFeedbackToken(jobId, result.feedback_token, agentId);
|
|
57
|
+
}
|
|
58
|
+
const status = result.status;
|
|
59
|
+
let prompt;
|
|
60
|
+
if (status === "success") {
|
|
61
|
+
prompt = [
|
|
62
|
+
"",
|
|
63
|
+
"---",
|
|
64
|
+
"How was this result? You can:",
|
|
65
|
+
` • rate_agent with job_id "${jobId}" and a score (1-5) — within 1 hour`,
|
|
66
|
+
" • tip_agent to show appreciation — within 1 hour",
|
|
67
|
+
" • favorite_agent to save this agent for later",
|
|
68
|
+
].join("\n");
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
prompt = [
|
|
72
|
+
"",
|
|
73
|
+
"---",
|
|
74
|
+
"The agent execution failed. A refund has been initiated automatically",
|
|
75
|
+
"and will be returned to your wallet.",
|
|
76
|
+
].join("\n");
|
|
77
|
+
}
|
|
78
|
+
return text(formatted + prompt);
|
|
79
|
+
});
|
|
80
|
+
}
|