taskfleet-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/README.md +70 -0
- package/index.mjs +100 -0
- package/package.json +17 -0
- package/toolname.mjs +4 -0
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# taskfleet-mcp
|
|
2
|
+
|
|
3
|
+
An [MCP](https://modelcontextprotocol.io) server that exposes **TaskFleet**'s
|
|
4
|
+
pay-per-call AI task APIs as tools any MCP-capable agent can discover and call:
|
|
5
|
+
web search, web scraping, structured extraction, translation, code review,
|
|
6
|
+
summarization, and on-chain wallet intelligence.
|
|
7
|
+
|
|
8
|
+
Payment is handled by the **x402** protocol (USDC on Base) — the caller brings
|
|
9
|
+
the wallet; there are no accounts or API keys.
|
|
10
|
+
|
|
11
|
+
## Why this exists
|
|
12
|
+
|
|
13
|
+
It's a discovery channel. Agents that browse MCP registries or load MCP
|
|
14
|
+
servers can find and use TaskFleet directly, in addition to the x402
|
|
15
|
+
directories. The tool list is loaded live from the fleet's manifest, so new
|
|
16
|
+
services appear automatically.
|
|
17
|
+
|
|
18
|
+
## Use it (as an agent operator)
|
|
19
|
+
|
|
20
|
+
Add to your MCP client config (e.g. Claude Desktop, or any MCP host):
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"mcpServers": {
|
|
25
|
+
"taskfleet": {
|
|
26
|
+
"command": "npx",
|
|
27
|
+
"args": ["-y", "taskfleet-mcp"],
|
|
28
|
+
"env": {
|
|
29
|
+
"BUYER_WALLET_PRIVATE_KEY": "0xYOUR_WALLET_KEY"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- **With** `BUYER_WALLET_PRIVATE_KEY` (an EVM key holding a little USDC on Base):
|
|
37
|
+
tool calls auto-pay via x402 and return results.
|
|
38
|
+
- **Without** it: tools still list (discovery works) and a call returns the
|
|
39
|
+
x402 payment instructions, so an x402-capable client can pay itself.
|
|
40
|
+
- `TASKFLEET_URL` overrides the target (defaults to `https://taskfleet.net`).
|
|
41
|
+
|
|
42
|
+
The wallet key stays on the operator's machine — it never reaches TaskFleet,
|
|
43
|
+
which only ever sees the on-chain payment.
|
|
44
|
+
|
|
45
|
+
## Tools
|
|
46
|
+
|
|
47
|
+
One tool per TaskFleet service, named `taskfleet_<service>` (e.g.
|
|
48
|
+
`taskfleet_search`, `taskfleet_scrape`, `taskfleet_wallet_intel`). Each tool's
|
|
49
|
+
input schema and price come straight from the fleet manifest.
|
|
50
|
+
|
|
51
|
+
## Publish it (as the fleet operator — discovery)
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
cd mcp
|
|
55
|
+
npm install
|
|
56
|
+
npm publish # publishes taskfleet-mcp to npm
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Once on npm it's installable via `npx taskfleet-mcp` and can be listed in MCP
|
|
60
|
+
registries (the public MCP Registry, Smithery, PulseMCP, etc.) — each listing
|
|
61
|
+
is another place agents discover TaskFleet. Submitting to those registries is
|
|
62
|
+
free and generally just points at the npm package or this repo.
|
|
63
|
+
|
|
64
|
+
## Local test
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npm install
|
|
68
|
+
TASKFLEET_URL=https://taskfleet.net node index.mjs
|
|
69
|
+
# should print: taskfleet-mcp v0.1.0: 14 tools from https://taskfleet.net (payment: caller-pays)
|
|
70
|
+
```
|
package/index.mjs
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// taskfleet-mcp — expose TaskFleet's paid services to any MCP-capable agent.
|
|
3
|
+
//
|
|
4
|
+
// Discovery: an agent that adds this server sees all TaskFleet services as
|
|
5
|
+
// native MCP tools (names, descriptions, input schemas) — a discovery channel
|
|
6
|
+
// entirely separate from the x402 directories.
|
|
7
|
+
//
|
|
8
|
+
// Payment: the *caller* brings the wallet. If BUYER_WALLET_PRIVATE_KEY is set,
|
|
9
|
+
// calls auto-pay via x402 (USDC on Base) and return results. If not, tools
|
|
10
|
+
// still list (discovery works) and a call returns the x402 payment
|
|
11
|
+
// instructions so an x402-capable client can pay itself.
|
|
12
|
+
//
|
|
13
|
+
// The tool list is loaded LIVE from the fleet's own manifest, so new services
|
|
14
|
+
// appear automatically — publish this once, it never goes stale.
|
|
15
|
+
|
|
16
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
17
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
18
|
+
import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
19
|
+
import { toolName } from "./toolname.mjs";
|
|
20
|
+
|
|
21
|
+
const BASE = (process.env.TASKFLEET_URL || "https://taskfleet.net").replace(/\/$/, "");
|
|
22
|
+
const PK = process.env.BUYER_WALLET_PRIVATE_KEY || "";
|
|
23
|
+
const VERSION = "0.1.0";
|
|
24
|
+
|
|
25
|
+
async function loadServices() {
|
|
26
|
+
const res = await fetch(`${BASE}/.well-known/x402.json`);
|
|
27
|
+
if (!res.ok) throw new Error(`Cannot load TaskFleet manifest (${res.status}) from ${BASE}`);
|
|
28
|
+
const data = await res.json();
|
|
29
|
+
if (!Array.isArray(data.services)) throw new Error("Manifest missing services[]");
|
|
30
|
+
return data.services;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Build a payment-capable fetch when a wallet is configured; else plain fetch.
|
|
34
|
+
async function makeFetch() {
|
|
35
|
+
if (!PK) return { fetchImpl: fetch, paid: false };
|
|
36
|
+
const { privateKeyToAccount } = await import("viem/accounts");
|
|
37
|
+
const { createWalletClient, http } = await import("viem");
|
|
38
|
+
const { base } = await import("viem/chains");
|
|
39
|
+
const { wrapFetchWithPayment } = await import("x402-fetch");
|
|
40
|
+
const account = privateKeyToAccount(PK.startsWith("0x") ? PK : `0x${PK}`);
|
|
41
|
+
const wallet = createWalletClient({ account, chain: base, transport: http() });
|
|
42
|
+
return { fetchImpl: wrapFetchWithPayment(fetch, wallet), paid: true };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const server = new Server({ name: "taskfleet", version: VERSION }, { capabilities: { tools: {} } });
|
|
46
|
+
|
|
47
|
+
let SERVICES = [];
|
|
48
|
+
let FETCH = { fetchImpl: fetch, paid: false };
|
|
49
|
+
|
|
50
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
51
|
+
tools: SERVICES.map((s) => ({
|
|
52
|
+
name: toolName(s.route),
|
|
53
|
+
description: `${s.description} Price: ${s.price} (USDC on Base via x402).`,
|
|
54
|
+
inputSchema: { type: "object", ...(s.input || {}) },
|
|
55
|
+
})),
|
|
56
|
+
}));
|
|
57
|
+
|
|
58
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
59
|
+
const svc = SERVICES.find((s) => toolName(s.route) === req.params.name);
|
|
60
|
+
if (!svc) return { isError: true, content: [{ type: "text", text: `Unknown tool: ${req.params.name}` }] };
|
|
61
|
+
const path = svc.route.split(" ")[1];
|
|
62
|
+
try {
|
|
63
|
+
const res = await FETCH.fetchImpl(`${BASE}${path}`, {
|
|
64
|
+
method: "POST",
|
|
65
|
+
headers: { "content-type": "application/json" },
|
|
66
|
+
body: JSON.stringify(req.params.arguments || {}),
|
|
67
|
+
});
|
|
68
|
+
const text = await res.text();
|
|
69
|
+
|
|
70
|
+
if (res.status === 402 && !FETCH.paid) {
|
|
71
|
+
const payHeader = res.headers.get("payment-required") || res.headers.get("PAYMENT-REQUIRED") || "";
|
|
72
|
+
return {
|
|
73
|
+
isError: true,
|
|
74
|
+
content: [{
|
|
75
|
+
type: "text",
|
|
76
|
+
text:
|
|
77
|
+
`Payment required (${svc.price}, USDC on Base). Set BUYER_WALLET_PRIVATE_KEY to auto-pay, ` +
|
|
78
|
+
`or handle x402 yourself with these instructions:\n${payHeader || text.slice(0, 600)}`,
|
|
79
|
+
}],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (!res.ok) return { isError: true, content: [{ type: "text", text: `TaskFleet ${res.status}: ${text.slice(0, 600)}` }] };
|
|
83
|
+
return { content: [{ type: "text", text }] };
|
|
84
|
+
} catch (e) {
|
|
85
|
+
return { isError: true, content: [{ type: "text", text: `Call failed: ${e.message}` }] };
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
async function main() {
|
|
90
|
+
SERVICES = await loadServices();
|
|
91
|
+
FETCH = await makeFetch();
|
|
92
|
+
await server.connect(new StdioServerTransport());
|
|
93
|
+
// logs go to stderr so they don't corrupt the stdio protocol on stdout
|
|
94
|
+
console.error(`taskfleet-mcp v${VERSION}: ${SERVICES.length} tools from ${BASE} (payment: ${FETCH.paid ? "auto-pay" : "caller-pays"})`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Only run when executed directly (allows importing toolName for tests).
|
|
98
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
99
|
+
main().catch((e) => { console.error(e.message); process.exit(1); });
|
|
100
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "taskfleet-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server exposing TaskFleet's pay-per-call AI task APIs (web search, scrape, extract, translate, code review, on-chain wallet intel) as tools. Payment via x402 (USDC on Base).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": { "taskfleet-mcp": "index.mjs" },
|
|
7
|
+
"main": "index.mjs",
|
|
8
|
+
"files": ["index.mjs", "toolname.mjs", "README.md"],
|
|
9
|
+
"engines": { "node": ">=20" },
|
|
10
|
+
"keywords": ["mcp", "model-context-protocol", "x402", "ai-agents", "web-search", "scraping", "web-scraper", "data-extraction", "translation", "code-review", "onchain", "base", "usdc", "agent-tools", "api"],
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
13
|
+
"viem": "^2.21.0",
|
|
14
|
+
"x402-fetch": "^0.6.0"
|
|
15
|
+
},
|
|
16
|
+
"license": "MIT"
|
|
17
|
+
}
|
package/toolname.mjs
ADDED