gadgethumans-mcp 1.0.16 → 1.2.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 +37 -11
- package/index.js +128 -245
- package/package.json +15 -7
package/README.md
CHANGED
|
@@ -1,21 +1,46 @@
|
|
|
1
1
|
# gadgethumans-mcp
|
|
2
2
|
|
|
3
|
-
MCP server for the **GadgetHumans API Hub**:
|
|
4
|
-
|
|
3
|
+
MCP server for the **GadgetHumans API Hub**: 224 tools — web search, page reads and scraping to markdown,
|
|
4
|
+
Base token safety verdicts, prediction markets, OCR, ENS, DNS/WHOIS, crypto prices, geocoding, text/LLM
|
|
5
|
+
utilities — plus a free cross-bazaar x402 search.
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
The tool list is fetched live from `https://api.gadgethumans.com/mcp` at startup, so it always matches what
|
|
8
|
+
the server actually sells: every tool arrives with its real parameter schema, price and description.
|
|
9
|
+
|
|
10
|
+
## Two ways to pay
|
|
11
|
+
|
|
12
|
+
**1. Prepaid credits — works in any MCP client, no wallet:**
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
https://api.gadgethumans.com/buy-credits?pack=500 # $5 = 500 calls
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The purchase returns an `api_key`. Set it and restart:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
export GADGETHUMANS_API_KEY=gh_...
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**2. x402 — USDC on Base, only if your client can sign the payment itself:**
|
|
25
|
+
|
|
26
|
+
An unpaid call returns `HTTP 402` with an x402 `accepts[]` challenge (also in the `Payment-Required`
|
|
27
|
+
header). Settle it and retry with an `X-PAYMENT` header. USDC on Base, chainId 8453.
|
|
28
|
+
|
|
29
|
+
This package never asks for a wallet private key — it is a proxy, and signing belongs in the client that
|
|
30
|
+
owns the key.
|
|
7
31
|
|
|
8
32
|
## Free: cross-bazaar x402 discovery
|
|
9
33
|
|
|
10
|
-
|
|
34
|
+
`x402_search` searches **both live x402 bazaars plus this catalogue** in one call, ranked by measured
|
|
35
|
+
30-day call volume:
|
|
11
36
|
|
|
12
37
|
```
|
|
13
38
|
GET https://api.gadgethumans.com/discovery/search?q=whois&limit=10
|
|
14
39
|
```
|
|
15
40
|
|
|
16
|
-
Merges `facilitator.payai.network` (14,841 listings), `api.cdp.coinbase.com` (73,178 listings) and
|
|
17
|
-
|
|
18
|
-
|
|
41
|
+
Merges `facilitator.payai.network` (14,841 listings), `api.cdp.coinbase.com` (73,178 listings) and this
|
|
42
|
+
catalogue. Returns `{ query, count, sources, results: [{ resource, source, price_usd, calls_30d, payTo,
|
|
43
|
+
description }] }`. No key, no payment, cached 900s, 120 queries/hour/IP.
|
|
19
44
|
|
|
20
45
|
Use it to compare providers and prices **before** paying any x402 endpoint.
|
|
21
46
|
|
|
@@ -26,13 +51,14 @@ npx -y gadgethumans-mcp
|
|
|
26
51
|
```
|
|
27
52
|
|
|
28
53
|
```json
|
|
29
|
-
{ "mcpServers": { "gadgethumans": { "command": "npx", "args": ["-y", "gadgethumans-mcp"]
|
|
54
|
+
{ "mcpServers": { "gadgethumans": { "command": "npx", "args": ["-y", "gadgethumans-mcp"],
|
|
55
|
+
"env": { "GADGETHUMANS_API_KEY": "gh_..." } } } }
|
|
30
56
|
```
|
|
31
57
|
|
|
32
|
-
##
|
|
58
|
+
## Free tier
|
|
33
59
|
|
|
34
|
-
|
|
35
|
-
|
|
60
|
+
The MCP door allows 5 calls/day per IP without payment; the REST door allows 100 requests/day per IP.
|
|
61
|
+
Prices per tool are in `tools/list` (`price_usd`) and in the OpenAPI document.
|
|
36
62
|
|
|
37
63
|
## Links
|
|
38
64
|
|
package/index.js
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
|
+
// Thin MCP client for the GadgetHumans API (https://api.gadgethumans.com/mcp).
|
|
5
|
+
//
|
|
6
|
+
// The remote server is the single source of truth for the tool list, so nothing
|
|
7
|
+
// here can drift from it: this package forwards tools/list and tools/call over
|
|
8
|
+
// JSON-RPC and adds an optional x-api-key (prepaid credits) header.
|
|
9
|
+
//
|
|
10
|
+
// It never touches a wallet private key. x402 signing belongs in the client that
|
|
11
|
+
// owns the key; a proxy must not be handed one.
|
|
12
|
+
|
|
4
13
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
14
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
15
|
import {
|
|
@@ -8,280 +17,154 @@ import {
|
|
|
8
17
|
ListToolsRequestSchema,
|
|
9
18
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
10
19
|
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
const
|
|
20
|
+
const ENDPOINT = process.env.MCP_ENDPOINT || "https://api.gadgethumans.com/mcp";
|
|
21
|
+
const API_KEY =
|
|
22
|
+
process.env.GADGETHUMANS_API_KEY || process.env.GADGETHUMANS_CREDITS_KEY || "";
|
|
23
|
+
const BUY_URL = "https://api.gadgethumans.com/buy-credits";
|
|
24
|
+
const REST_BASE = process.env.GADGETHUMANS_REST || "https://api.gadgethumans.com";
|
|
25
|
+
|
|
26
|
+
// A 402 is the moment a caller decides whether we are real. Give it a ready-to-run
|
|
27
|
+
// proof call instead of a pricing lecture: most tool names are the REST route's own
|
|
28
|
+
// slug, so the same tool can be answered free (3/day per IP) with ?trial=1.
|
|
29
|
+
function trialUrl(name, args) {
|
|
30
|
+
if (!/^[a-z0-9][a-z0-9._-]{0,60}$/i.test(name || "")) return "";
|
|
31
|
+
const qs = new URLSearchParams();
|
|
32
|
+
for (const [k, v] of Object.entries(args || {})) {
|
|
33
|
+
if (v === undefined || v === null || typeof v === "object") continue;
|
|
34
|
+
qs.set(k, String(v));
|
|
35
|
+
}
|
|
36
|
+
qs.set("trial", "1");
|
|
37
|
+
return `${REST_BASE}/${name}?${qs.toString()}`;
|
|
38
|
+
}
|
|
15
39
|
|
|
16
40
|
const server = new Server(
|
|
17
|
-
{ name: "gadgethumans-mcp", version: "1.0
|
|
41
|
+
{ name: "gadgethumans-mcp", version: "1.2.0" },
|
|
18
42
|
{ capabilities: { tools: {} } }
|
|
19
43
|
);
|
|
20
44
|
|
|
21
|
-
|
|
22
|
-
// Category groups for organization
|
|
23
|
-
const CATEGORIES = [
|
|
24
|
-
{ name: "Security & Network", count: 18, tools: [
|
|
25
|
-
"dns_lookup", "check_ssl_certificate", "port_check", "domain_age",
|
|
26
|
-
"dnssec_check", "reverse_dns_lookup", "cdn_detect", "email_domain_check",
|
|
27
|
-
"http_headers", "check_links", "check_page_size", "ipv4_subnet",
|
|
28
|
-
"ipv6_expand", "dns_whois_lookup", "whois", "ssl_chain_check",
|
|
29
|
-
"traceroute", "ping"
|
|
30
|
-
]},
|
|
31
|
-
{ name: "Data & Weather", count: 14, tools: [
|
|
32
|
-
"get_weather", "get_forecast", "get_air_quality", "get_crypto_prices",
|
|
33
|
-
"convert_currency", "currency_cross", "geocode", "reverse_geocode",
|
|
34
|
-
"geolocate_ip", "get_season", "get_week_number", "list_countries",
|
|
35
|
-
"list_currencies", "list_languages"
|
|
36
|
-
]},
|
|
37
|
-
{ name: "Text & Encoding", count: 28, tools: [
|
|
38
|
-
"hash_text", "encode_base64", "encode_base32", "encode_base85",
|
|
39
|
-
"binary_convert", "morse_code", "url_encode_decode", "html_escape",
|
|
40
|
-
"string_escape", "regex_escape", "normalize_text", "remove_accents",
|
|
41
|
-
"convert_case", "slugify_text", "title_case", "invert_case",
|
|
42
|
-
"swap_case", "reverse_text", "shuffle_text", "truncate_text",
|
|
43
|
-
"pad_text", "indent_text", "line_wrap", "clean_whitespace",
|
|
44
|
-
"wrap_text", "expand_text", "simplify_text", "casualize"
|
|
45
|
-
]},
|
|
46
|
-
{ name: "Colors & Design", count: 16, tools: [
|
|
47
|
-
"convert_color", "hex_to_hsl", "hex_to_hsv", "hex_to_cmyk",
|
|
48
|
-
"hsl_to_rgb", "hsv_to_hex", "cmyk_to_hex", "rgb_to_hsl",
|
|
49
|
-
"color_mix", "complementary_color", "color_harmony",
|
|
50
|
-
"generate_color_palette", "color_tint_shade", "color_temperature",
|
|
51
|
-
"color_blindness_sim", "check_color_contrast", "web_safe_color",
|
|
52
|
-
"color_named", "list_color_names", "random_color"
|
|
53
|
-
]},
|
|
54
|
-
{ name: "Finance & Math", count: 30, tools: [
|
|
55
|
-
"loan_calculator", "mortgage_calculator", "compound_interest",
|
|
56
|
-
"simple_interest_calc", "investment_calculator", "sip_calc",
|
|
57
|
-
"emi_calc", "amortization_calc", "auto_loan_calc",
|
|
58
|
-
"credit_card_payoff", "retirement_calc", "savings_goal_calc",
|
|
59
|
-
"roi_calc", "cagr_calc", "stock_return", "dividend_calc",
|
|
60
|
-
"bond_yield", "inflation_calc", "tax_bracket", "salary_breakdown",
|
|
61
|
-
"margin_calc", "markup_calc", "discount_calculator",
|
|
62
|
-
"percentage_calculator", "percentage_change_calc",
|
|
63
|
-
"descriptive_statistics", "calculate_correlation",
|
|
64
|
-
"matrix_operations", "quadratic_solver", "pythagorean_calc"
|
|
65
|
-
]},
|
|
66
|
-
{ name: "JSON & Data", count: 12, tools: [
|
|
67
|
-
"process_json", "validate_json", "json_path_query", "flatten_json",
|
|
68
|
-
"unflatten_json", "merge_json", "convert_json_to_csv",
|
|
69
|
-
"convert_csv_to_json", "json_to_yaml", "json_to_xml",
|
|
70
|
-
"toml_to_json", "ini_to_json", "xml_to_json", "yaml_to_json"
|
|
71
|
-
]},
|
|
72
|
-
{ name: "Content & AI", count: 16, tools: [
|
|
73
|
-
"summarize", "paraphrase", "translate", "grammar", "proofread",
|
|
74
|
-
"headline", "keywords", "sentiment", "classify", "explain",
|
|
75
|
-
"faq", "questions", "quiz", "social", "bullets", "tldr"
|
|
76
|
-
]},
|
|
77
|
-
{ name: "Health & Fitness", count: 14, tools: [
|
|
78
|
-
"calculate_bmi", "bmr_calc", "tdee_calc", "body_fat_calc",
|
|
79
|
-
"ideal_weight_calc", "lean_body_mass", "macro_calc",
|
|
80
|
-
"calorie_burn", "water_intake_calc", "heart_rate_zones",
|
|
81
|
-
"fitness_age_calc", "vo2max_calc", "sleep_calc", "body_surface_area"
|
|
82
|
-
]},
|
|
83
|
-
{ name: "Generators", count: 8, tools: [
|
|
84
|
-
"generate_password", "generate_uuid", "generate_nanoid",
|
|
85
|
-
"generate_ulids", "generate_qr_code", "generate_lorem_ipsum",
|
|
86
|
-
"generate_random_numbers", "generate_random_data"
|
|
87
|
-
]},
|
|
88
|
-
{ name: "Kronos Market Intel", count: 7, tools: [
|
|
89
|
-
"kronos_signals", "kronos_history", "kronos_preflight",
|
|
90
|
-
"kronos_decision", "kronos_audit", "kronos_forecast", "kronos_risk"
|
|
91
|
-
]},
|
|
92
|
-
{ name: "Converters", count: 12, tools: [
|
|
93
|
-
"convert_units", "temperature_all", "speed_convert",
|
|
94
|
-
"pressure_convert", "energy_convert", "volume_convert",
|
|
95
|
-
"area_convert", "data_rate_convert", "angle_convert",
|
|
96
|
-
"time_convert", "bytes_format", "convert_number_base"
|
|
97
|
-
]},
|
|
98
|
-
{ name: "Web & SEO", count: 10, tools: [
|
|
99
|
-
"read_url", "web_scrape", "parse_rss_feed", "crawl_website",
|
|
100
|
-
"get_og_metadata", "scrape_meta_tags", "generate_seo_metadata",
|
|
101
|
-
"research_topic", "extract_contacts", "readability_url"
|
|
102
|
-
]},
|
|
103
|
-
{ name: "x402 & Wallet", count: 5, tools: [
|
|
104
|
-
"x402_wallet_info", "x402_pricing", "x402_payment_request",
|
|
105
|
-
"x402_verify_payment", "wallet_info"
|
|
106
|
-
]},
|
|
107
|
-
{ name: "Other Utilities", count: 147, tools: [
|
|
108
|
-
"generate_password", "generate_uuid", "generate_nanoid",
|
|
109
|
-
"generate_ulids", "generate_qr_code", "generate_lorem_ipsum",
|
|
110
|
-
"generate_random_numbers", "generate_random_data",
|
|
111
|
-
"evaluate_math", "factorial_calculator", "fibonacci_sequence",
|
|
112
|
-
"prime_operations", "gcd_lcm", "fraction_calc", "ratio_calc",
|
|
113
|
-
"proportion_calc", "percentage_calculator", "percentage_change_calc",
|
|
114
|
-
"calculate_combinations", "calculate_entropy", "scientific_notation",
|
|
115
|
-
"significant_figures", "roman_numerals", "nato_phonetic",
|
|
116
|
-
"soundex_code", "levenshtein_distance", "word_similarity",
|
|
117
|
-
"anagram_check", "palindrome_check", "pangram_check",
|
|
118
|
-
"word_count", "char_count", "line_count", "sentence_length_analyze",
|
|
119
|
-
"paragraph_count", "punctuation_count", "unique_words",
|
|
120
|
-
"word_frequency", "word_length_distribution", "keyword_density",
|
|
121
|
-
"repeated_words", "find_long_words", "find_short_words",
|
|
122
|
-
"caps_analysis", "whitespace_analyze", "readability_analyze",
|
|
123
|
-
"reading_time", "speaking_time", "detect_language",
|
|
124
|
-
"detect_text_encoding", "gibberish_detect", "extract_entities",
|
|
125
|
-
"analyze_tone", "validate_email", "verify_email",
|
|
126
|
-
"validate_iban", "validate_vat", "parse_phone_number",
|
|
127
|
-
"mask_text", "text_stats", "text_diff", "deduplicate_data",
|
|
128
|
-
"filter_data", "sort_data", "code_stats", "code_complexity",
|
|
129
|
-
"code_indent_check", "comment_strip", "code_beautify",
|
|
130
|
-
"bracket_match", "todo_finder", "sql_format",
|
|
131
|
-
"regex_test", "convert_markdown", "extract_html_table",
|
|
132
|
-
"generate_color_palette", "color_tint_shade", "random_color",
|
|
133
|
-
"date_calc", "calculate_age", "calculate_business_days",
|
|
134
|
-
"due_date_calc", "ovulation_calc", "calculate_distance",
|
|
135
|
-
"distance_2d", "midpoint_calc", "slope_calc", "geometry_calc",
|
|
136
|
-
"electrical_calc", "force_calc", "pressure_calc",
|
|
137
|
-
"work_calc", "kinetic_energy_calc", "momentum_calc",
|
|
138
|
-
"density_calc", "gravitational_force_calc", "heart_rate_zones",
|
|
139
|
-
"metabolic_age_calc", "fitness_age_calc", "waist_hip_ratio",
|
|
140
|
-
"calorie_burn", "bmr_calc", "tdee_calc", "body_fat_calc",
|
|
141
|
-
"ideal_weight_calc", "lean_body_mass", "macro_calc",
|
|
142
|
-
"water_intake_calc", "sleep_calc", "body_surface_area",
|
|
143
|
-
"blood_alcohol_calc", "tip_calculator", "fuel_cost",
|
|
144
|
-
"pace_calc", "rent_vs_buy_calc", "vat_calc",
|
|
145
|
-
"temperature_all", "pressure_convert", "speed_convert",
|
|
146
|
-
"energy_convert", "volume_convert", "area_convert",
|
|
147
|
-
"time_convert", "data_rate_convert", "angle_convert",
|
|
148
|
-
"bytes_format", "convert_number_base", "pixel_convert",
|
|
149
|
-
"paper_size_reference", "keyboard_layout",
|
|
150
|
-
"list_color_names", "list_emojis", "lookup_html_entity",
|
|
151
|
-
"lookup_http_code", "lookup_mime_type", "chemical_elements",
|
|
152
|
-
"ascii_table", "caesar_cipher", "atbash_cipher",
|
|
153
|
-
"rot13_cipher", "vigenere_cipher", "flip_coin", "roll_dice"
|
|
154
|
-
]}
|
|
155
|
-
];
|
|
45
|
+
let TOOLS = [];
|
|
156
46
|
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
47
|
+
function rpcHeaders() {
|
|
48
|
+
const h = {
|
|
49
|
+
"Content-Type": "application/json",
|
|
50
|
+
Accept: "application/json, text/event-stream",
|
|
51
|
+
};
|
|
52
|
+
if (API_KEY) h["x-api-key"] = API_KEY;
|
|
53
|
+
return h;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// The remote door answers with plain JSON; tolerate an SSE frame in case a proxy
|
|
57
|
+
// in front of it flips the content type.
|
|
58
|
+
function parseBody(text, contentType) {
|
|
59
|
+
if ((contentType || "").includes("event-stream")) {
|
|
60
|
+
const line = text.split("\n").find((l) => l.trim().startsWith("data:"));
|
|
61
|
+
if (!line) throw new Error("empty event-stream response");
|
|
62
|
+
return JSON.parse(line.trim().slice(5).trim());
|
|
174
63
|
}
|
|
64
|
+
return JSON.parse(text);
|
|
175
65
|
}
|
|
176
66
|
|
|
177
|
-
|
|
67
|
+
async function rpc(method, params) {
|
|
68
|
+
const res = await fetch(ENDPOINT, {
|
|
69
|
+
method: "POST",
|
|
70
|
+
headers: rpcHeaders(),
|
|
71
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params: params || {} }),
|
|
72
|
+
});
|
|
73
|
+
const text = await res.text();
|
|
74
|
+
return { res, text };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function loadTools() {
|
|
78
|
+
try {
|
|
79
|
+
const { res, text } = await rpc("tools/list", {});
|
|
80
|
+
if (!res.ok) throw new Error("tools/list http " + res.status);
|
|
81
|
+
const d = parseBody(text, res.headers.get("content-type"));
|
|
82
|
+
if (d.error) throw new Error(d.error.message || "tools/list error");
|
|
83
|
+
TOOLS = (d.result && d.result.tools) || [];
|
|
84
|
+
} catch (e) {
|
|
85
|
+
console.error(`[gadgethumans-mcp] could not load tool list: ${e.message}`);
|
|
86
|
+
TOOLS = [];
|
|
87
|
+
}
|
|
88
|
+
return TOOLS;
|
|
89
|
+
}
|
|
178
90
|
|
|
179
|
-
server.setRequestHandler(ListToolsRequestSchema, async () =>
|
|
180
|
-
|
|
181
|
-
}
|
|
91
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
92
|
+
if (!TOOLS.length) await loadTools();
|
|
93
|
+
return { tools: TOOLS };
|
|
94
|
+
});
|
|
182
95
|
|
|
183
96
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
184
|
-
const { name, arguments: args } = request.params;
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
if (!tool) {
|
|
188
|
-
return {
|
|
189
|
-
content: [{ type: "text", text: `Unknown tool: ${name}` }],
|
|
190
|
-
isError: true,
|
|
191
|
-
};
|
|
97
|
+
const { name, arguments: args } = request.params || {};
|
|
98
|
+
if (!name) {
|
|
99
|
+
return { content: [{ type: "text", text: "Missing tool name." }], isError: true };
|
|
192
100
|
}
|
|
193
101
|
|
|
194
102
|
try {
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
103
|
+
const { res, text } = await rpc("tools/call", { name, arguments: args || {} });
|
|
104
|
+
|
|
105
|
+
if (res.status === 402) {
|
|
106
|
+
const free = trialUrl(name, args);
|
|
107
|
+
const hint = API_KEY
|
|
108
|
+
? [
|
|
109
|
+
`The credits key on this install has no balance left. Top up at ${BUY_URL}?pack=500 ($5 = 500 calls) and set GADGETHUMANS_API_KEY to the key it returns.`,
|
|
110
|
+
free ? `\nOr check the answer for free (3 calls/day per IP, no key, no wallet):\n curl "${free}"` : "",
|
|
111
|
+
].join("\n")
|
|
112
|
+
: [
|
|
113
|
+
"This tool is priced per call. Two ways to pay — and one way to check us for free:",
|
|
114
|
+
"",
|
|
115
|
+
free
|
|
116
|
+
? `0. Free proof call, right now — 3 answered calls/day per IP, no key, no wallet:\n curl "${free}"\n`
|
|
117
|
+
: "",
|
|
118
|
+
"1. Prepaid credits — works in any MCP client, no wallet needed:",
|
|
119
|
+
` buy at ${BUY_URL}?pack=500 ($5 = 500 calls; 1 credit = $0.01)`,
|
|
120
|
+
" the purchase returns an api_key; set it and restart:",
|
|
121
|
+
" export GADGETHUMANS_API_KEY=gh_...",
|
|
122
|
+
"",
|
|
123
|
+
"2. x402 — USDC on Base, only if your client can sign the payment itself:",
|
|
124
|
+
" an unpaid call returns accepts[] with amount and payTo; settle it and",
|
|
125
|
+
" retry with the X-PAYMENT header.",
|
|
126
|
+
" Catalogue: https://api.gadgethumans.com/.well-known/x402",
|
|
127
|
+
"",
|
|
128
|
+
`All packs and prices: ${BUY_URL}`,
|
|
129
|
+
].join("\n");
|
|
130
|
+
return {
|
|
131
|
+
content: [{ type: "text", text: `Payment required.\n\n${hint}` }],
|
|
132
|
+
isError: false,
|
|
133
|
+
};
|
|
208
134
|
}
|
|
209
135
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
136
|
+
if (!res.ok) {
|
|
137
|
+
return {
|
|
138
|
+
content: [{ type: "text", text: `HTTP ${res.status}: ${text.slice(0, 400)}` }],
|
|
139
|
+
isError: true,
|
|
140
|
+
};
|
|
213
141
|
}
|
|
214
142
|
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
headers,
|
|
218
|
-
body: JSON.stringify({
|
|
219
|
-
jsonrpc: "2.0",
|
|
220
|
-
method: "tools/call",
|
|
221
|
-
params: { name, arguments: args || {} },
|
|
222
|
-
id: 1,
|
|
223
|
-
}),
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
if (!response.ok) {
|
|
227
|
-
const text = await response.text();
|
|
228
|
-
|
|
229
|
-
// Handle 402 Payment Required
|
|
230
|
-
if (response.status === 402) {
|
|
231
|
-
const price = response.headers.get("X-402-Price") || "$0.001";
|
|
232
|
-
const merchant = response.headers.get("X-402-Merchant") || "";
|
|
233
|
-
return {
|
|
234
|
-
content: [{
|
|
235
|
-
type: "text",
|
|
236
|
-
text: [
|
|
237
|
-
`⚠️ Payment Required — ${price} USDC`,
|
|
238
|
-
``,
|
|
239
|
-
`This tool costs ${price} USDC on Base.`,
|
|
240
|
-
`Merchant: ${merchant}`,
|
|
241
|
-
``,
|
|
242
|
-
`PAY WITH A CARD — no wallet, no signup, credits applied instantly:`,
|
|
243
|
-
` https://api.gadgethumans.com/buy-credits?pack=500`,
|
|
244
|
-
``,
|
|
245
|
-
`OR let your agent pay automatically over x402:`,
|
|
246
|
-
` export WALLET_PRIVATE_KEY=0x...`,
|
|
247
|
-
`Your agent then signs USDC micropayments on Base with no manual steps.`,
|
|
248
|
-
``,
|
|
249
|
-
`All options and prices: https://api.gadgethumans.com/buy-credits`,
|
|
250
|
-
].join("\n"),
|
|
251
|
-
}],
|
|
252
|
-
isError: false,
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
|
|
143
|
+
const d = parseBody(text, res.headers.get("content-type"));
|
|
144
|
+
if (d.error) {
|
|
256
145
|
return {
|
|
257
|
-
content: [{ type: "text", text: `Error ${
|
|
146
|
+
content: [{ type: "text", text: `Error: ${d.error.message || JSON.stringify(d.error)}` }],
|
|
258
147
|
isError: true,
|
|
259
148
|
};
|
|
260
149
|
}
|
|
261
150
|
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
return {
|
|
266
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
267
|
-
};
|
|
151
|
+
const result = d.result !== undefined ? d.result : d;
|
|
152
|
+
if (result && Array.isArray(result.content)) return result;
|
|
153
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
268
154
|
} catch (error) {
|
|
269
|
-
return {
|
|
270
|
-
content: [{ type: "text", text: `Error: ${error.message}` }],
|
|
271
|
-
isError: true,
|
|
272
|
-
};
|
|
155
|
+
return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
|
|
273
156
|
}
|
|
274
157
|
});
|
|
275
158
|
|
|
276
|
-
// ── Startup ───────────────────────────────────────────────
|
|
277
|
-
|
|
278
159
|
async function main() {
|
|
279
|
-
|
|
280
|
-
await
|
|
281
|
-
console.error(`[gadgethumans-mcp]
|
|
282
|
-
console.error(
|
|
283
|
-
|
|
284
|
-
|
|
160
|
+
await server.connect(new StdioServerTransport());
|
|
161
|
+
await loadTools();
|
|
162
|
+
console.error(`[gadgethumans-mcp] ${TOOLS.length} tools from ${ENDPOINT}`);
|
|
163
|
+
console.error(
|
|
164
|
+
`[gadgethumans-mcp] credits key: ${
|
|
165
|
+
API_KEY ? "set" : "not set — paid tools answer 402 with instructions"
|
|
166
|
+
}`
|
|
167
|
+
);
|
|
285
168
|
}
|
|
286
169
|
|
|
287
170
|
main().catch((e) => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gadgethumans-mcp",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "MCP server for the GadgetHumans API: 226 tools in one install (ocr, ens, token safety, translate, sentiment, whois, hash, geocode, dns, weather, vat, timezone, ip, search, and a free x402 catalogue search ranked by measured 30-day call volume). Prepaid credits key or x402 USDC on Base.",
|
|
5
5
|
"mcpName": "com.gadgethumans/gadgethumans-mcp",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "index.js",
|
|
@@ -29,7 +29,18 @@
|
|
|
29
29
|
"crypto-payments",
|
|
30
30
|
"gadgethumans",
|
|
31
31
|
"claude",
|
|
32
|
-
"cursor"
|
|
32
|
+
"cursor",
|
|
33
|
+
"ocr",
|
|
34
|
+
"token-safety",
|
|
35
|
+
"honeypot-check",
|
|
36
|
+
"ens",
|
|
37
|
+
"translate",
|
|
38
|
+
"sentiment",
|
|
39
|
+
"whois",
|
|
40
|
+
"web-search",
|
|
41
|
+
"pay-per-call",
|
|
42
|
+
"agent-payments",
|
|
43
|
+
"discovery"
|
|
33
44
|
],
|
|
34
45
|
"author": "GadgetHumans",
|
|
35
46
|
"license": "MIT",
|
|
@@ -38,10 +49,7 @@
|
|
|
38
49
|
"url": "git+https://github.com/gadgethumans-dev/api-hub.git"
|
|
39
50
|
},
|
|
40
51
|
"dependencies": {
|
|
41
|
-
"@modelcontextprotocol/sdk": "^1.10.0"
|
|
42
|
-
"@x402/core": "^2.17.0",
|
|
43
|
-
"@x402/evm": "^2.17.0",
|
|
44
|
-
"viem": "^2.27.0"
|
|
52
|
+
"@modelcontextprotocol/sdk": "^1.10.0"
|
|
45
53
|
},
|
|
46
54
|
"engines": {
|
|
47
55
|
"node": ">=18.0.0"
|