apiguru-mcp 1.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/LICENSE +21 -0
- package/README.md +123 -0
- package/bin/apiguru-mcp.mjs +183 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Apiguru
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# apiguru-mcp (npm)
|
|
2
|
+
|
|
3
|
+
Live Amazon marketplace data for AI agents as MCP tools: product details,
|
|
4
|
+
reviews, keyword search, best-sellers, deals, live offers and stock, and seller
|
|
5
|
+
profiles across 20 country marketplaces. Eleven read-only tools with prices and
|
|
6
|
+
retry rules in their descriptions.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npx -y apiguru-mcp
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
That is the whole install. Node 18+ is the only requirement: no Python, no
|
|
13
|
+
`uv`, no account, no API key.
|
|
14
|
+
|
|
15
|
+
<!-- mcp-name: app.apiguru/amazon-data -->
|
|
16
|
+
|
|
17
|
+
## What it runs
|
|
18
|
+
|
|
19
|
+
`npx apiguru-mcp` is a stdio bridge to the hosted server at
|
|
20
|
+
`https://mcp.apiguru.app/mcp`: your MCP client talks stdio to the bridge, the
|
|
21
|
+
bridge talks streamable HTTP to the server, and every JSON-RPC message passes
|
|
22
|
+
through untouched. You get exactly the tools `uvx apiguru-mcp` (the Python
|
|
23
|
+
package) serves locally, because that package is itself a thin HTTP client over
|
|
24
|
+
the same gateway.
|
|
25
|
+
|
|
26
|
+
Free probes are counted per caller, since the connection to the gateway comes
|
|
27
|
+
from your machine rather than from a shared vendor address.
|
|
28
|
+
|
|
29
|
+
Prefer to run the server itself? `npx apiguru-mcp --local` runs the Python
|
|
30
|
+
package through `uvx` (needs [uv](https://docs.astral.sh/uv/)).
|
|
31
|
+
|
|
32
|
+
## Client setup
|
|
33
|
+
|
|
34
|
+
**Claude Code**
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
claude mcp add apiguru -- npx -y apiguru-mcp
|
|
38
|
+
# or remote, nothing to run locally:
|
|
39
|
+
claude mcp add --transport http apiguru https://mcp.apiguru.app/mcp
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Codex CLI**
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
codex mcp add apiguru -- npx -y apiguru-mcp
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Cursor, Windsurf, Claude Desktop, Hermes, OpenClaw, any stdio client**
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"mcpServers": {
|
|
53
|
+
"apiguru": {
|
|
54
|
+
"command": "npx",
|
|
55
|
+
"args": ["-y", "apiguru-mcp"],
|
|
56
|
+
"env": { "APIGURU_API_KEY": "optional-key-here" }
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Drop the `env` block to run keyless.
|
|
63
|
+
|
|
64
|
+
**VS Code** (`.vscode/mcp.json`)
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"servers": {
|
|
69
|
+
"apiguru": { "type": "stdio", "command": "npx", "args": ["-y", "apiguru-mcp"] }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**claude.ai, Claude Desktop connectors, ChatGPT**: no bridge needed. Add
|
|
75
|
+
`https://mcp.apiguru.app/account` as a connector and sign in; calls bill your
|
|
76
|
+
Apiguru account.
|
|
77
|
+
|
|
78
|
+
## Paying for calls
|
|
79
|
+
|
|
80
|
+
Without a key you get 3 free calls per 24 hours per machine. After that a tool
|
|
81
|
+
call returns a structured error carrying an HTTP 402 payment challenge (x402,
|
|
82
|
+
USDC on Base mainnet). Either:
|
|
83
|
+
|
|
84
|
+
- set `APIGURU_API_KEY` from https://dash.apiguru.app so calls bill your
|
|
85
|
+
account at your plan's rates, or
|
|
86
|
+
- have an x402-capable HTTP client pay the challenge against the REST gateway
|
|
87
|
+
at `https://agent.apiguru.app/agent/v1/...` directly. The full guide is in
|
|
88
|
+
`https://agent.apiguru.app/llms.txt`.
|
|
89
|
+
|
|
90
|
+
## Options
|
|
91
|
+
|
|
92
|
+
| Flag / variable | Meaning |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `--url <url>` / `APIGURU_MCP_URL` | Bridge to another streamable-HTTP MCP server (default `https://mcp.apiguru.app/mcp`) |
|
|
95
|
+
| `--local [args...]` | Run the Python server via `uvx apiguru-mcp` instead; remaining arguments are passed through |
|
|
96
|
+
| `APIGURU_API_KEY` | Sent as `X-API-KEY`; bills that Apiguru account instead of using the keyless path |
|
|
97
|
+
| `APIGURU_MCP_DEBUG` | Log transport noise to stderr |
|
|
98
|
+
| `--version`, `--help` | |
|
|
99
|
+
|
|
100
|
+
## Tools
|
|
101
|
+
|
|
102
|
+
| Tool | Does | Price |
|
|
103
|
+
|---|---|---|
|
|
104
|
+
| `list_capabilities` | Endpoints, prices, marketplaces, your access mode | **free**, offline |
|
|
105
|
+
| `product_details` | Full record for one ASIN | $0.01 |
|
|
106
|
+
| `product_details_batch` | Up to 20 ASINs at once | $0.008/item |
|
|
107
|
+
| `product_reviews` | Reviews, rating, "customers say" | $0.01 |
|
|
108
|
+
| `search` | Keyword search with filters and sorting | $0.01 |
|
|
109
|
+
| `offers_stock` | Offers, buy box, live stock (≤10 ASINs) | $0.015/item |
|
|
110
|
+
| `best_sellers` | Category rankings | $0.01 |
|
|
111
|
+
| `deals` | Current discounts with filters | $0.01 |
|
|
112
|
+
| `seller_profile_batch` | Seller profiles (≤10 IDs) | $0.012/item |
|
|
113
|
+
| `seller_products` | A seller's catalogue | $0.01 |
|
|
114
|
+
| `seller_reviews` | Seller feedback | $0.01 |
|
|
115
|
+
|
|
116
|
+
Every tool is annotated `readOnlyHint: true`; nothing here writes anywhere.
|
|
117
|
+
|
|
118
|
+
## Links
|
|
119
|
+
|
|
120
|
+
- Source, skill and plugin: https://github.com/apiguru-app/agent-kit
|
|
121
|
+
- Python package: https://pypi.org/project/apiguru-mcp/
|
|
122
|
+
- API docs: https://dash.apiguru.app/docs
|
|
123
|
+
- Support: support@apiguru.app
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* apiguru-mcp: the Apiguru Amazon Data MCP server from npx, with nothing but
|
|
4
|
+
* Node installed.
|
|
5
|
+
*
|
|
6
|
+
* npx apiguru-mcp # stdio <-> https://mcp.apiguru.app/mcp
|
|
7
|
+
* npx apiguru-mcp --url <mcp url> # bridge to another streamable-HTTP server
|
|
8
|
+
* npx apiguru-mcp --local # run the Python server via uvx (needs uv)
|
|
9
|
+
*
|
|
10
|
+
* The default mode is a transparent stdio-to-streamable-HTTP bridge. Every
|
|
11
|
+
* JSON-RPC message from the local client is POSTed to the hosted server and
|
|
12
|
+
* every reply is written back, so the client sees exactly the 11 tools that
|
|
13
|
+
* `uvx apiguru-mcp` would serve locally. The Python package is a thin HTTP
|
|
14
|
+
* client over the same gateway anyway, so nothing is lost by running it on
|
|
15
|
+
* our side instead of yours.
|
|
16
|
+
*
|
|
17
|
+
* Free probes are counted per caller, because the connection to the gateway
|
|
18
|
+
* originates from THIS machine, not from a shared vendor address.
|
|
19
|
+
*
|
|
20
|
+
* Environment:
|
|
21
|
+
* APIGURU_API_KEY optional; sent as X-API-KEY so calls bill that account
|
|
22
|
+
* instead of using the free-probe-then-402 path
|
|
23
|
+
* APIGURU_MCP_URL optional; same as --url
|
|
24
|
+
* APIGURU_MCP_DEBUG set to anything to log transport noise to stderr
|
|
25
|
+
*/
|
|
26
|
+
import { spawn } from "node:child_process";
|
|
27
|
+
import { createRequire } from "node:module";
|
|
28
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
29
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
30
|
+
|
|
31
|
+
const { version } = createRequire(import.meta.url)("../package.json");
|
|
32
|
+
const DEFAULT_URL = "https://mcp.apiguru.app/mcp";
|
|
33
|
+
const ACCOUNT_URL = "https://mcp.apiguru.app/account";
|
|
34
|
+
|
|
35
|
+
const argv = process.argv.slice(2);
|
|
36
|
+
const has = (flag) => argv.includes(flag);
|
|
37
|
+
const valueOf = (flag) => {
|
|
38
|
+
const i = argv.indexOf(flag);
|
|
39
|
+
if (i === -1) return undefined;
|
|
40
|
+
const v = argv[i + 1];
|
|
41
|
+
if (v === undefined || v.startsWith("--")) fail(`${flag} needs a value`);
|
|
42
|
+
return v;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
function fail(message, code = 2) {
|
|
46
|
+
process.stderr.write(`apiguru-mcp: ${message}\n`);
|
|
47
|
+
process.exit(code);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (has("--help") || has("-h")) {
|
|
51
|
+
process.stdout.write(
|
|
52
|
+
[
|
|
53
|
+
`apiguru-mcp ${version}`,
|
|
54
|
+
"",
|
|
55
|
+
"Usage:",
|
|
56
|
+
` apiguru-mcp bridge stdio to ${DEFAULT_URL}`,
|
|
57
|
+
" apiguru-mcp --url <url> bridge stdio to another MCP streamable-HTTP URL",
|
|
58
|
+
" apiguru-mcp --local [...] run the Python server with uvx instead (needs uv;",
|
|
59
|
+
" extra arguments are passed through to it)",
|
|
60
|
+
"",
|
|
61
|
+
"Environment:",
|
|
62
|
+
" APIGURU_API_KEY bill an Apiguru account (sent as X-API-KEY); omit to stay keyless",
|
|
63
|
+
" APIGURU_MCP_URL default for --url",
|
|
64
|
+
"",
|
|
65
|
+
"Docs: https://github.com/apiguru-app/agent-kit",
|
|
66
|
+
"",
|
|
67
|
+
].join("\n"),
|
|
68
|
+
);
|
|
69
|
+
process.exit(0);
|
|
70
|
+
}
|
|
71
|
+
if (has("--version") || has("-V")) {
|
|
72
|
+
process.stdout.write(`${version}\n`);
|
|
73
|
+
process.exit(0);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (has("--local")) {
|
|
77
|
+
runLocal(argv.filter((a) => a !== "--local"));
|
|
78
|
+
} else {
|
|
79
|
+
await runBridge();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
|
|
84
|
+
function runLocal(args) {
|
|
85
|
+
const child = spawn("uvx", ["apiguru-mcp", ...args], { stdio: "inherit" });
|
|
86
|
+
child.on("error", (err) => {
|
|
87
|
+
if (err.code === "ENOENT") {
|
|
88
|
+
fail(
|
|
89
|
+
"`uvx` was not found. Install uv (https://docs.astral.sh/uv/) or drop " +
|
|
90
|
+
"--local to use the hosted server, which needs nothing else.",
|
|
91
|
+
127,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
fail(err.message, 1);
|
|
95
|
+
});
|
|
96
|
+
child.on("exit", (code, signal) => process.exit(code ?? (signal ? 1 : 0)));
|
|
97
|
+
for (const sig of ["SIGINT", "SIGTERM"]) {
|
|
98
|
+
process.on(sig, () => child.kill(sig));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function runBridge() {
|
|
103
|
+
let url;
|
|
104
|
+
try {
|
|
105
|
+
url = new URL(valueOf("--url") || process.env.APIGURU_MCP_URL || DEFAULT_URL);
|
|
106
|
+
} catch {
|
|
107
|
+
fail("--url must be an absolute http(s) URL");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const headers = {
|
|
111
|
+
"User-Agent": `apiguru-mcp-npm/${version} node/${process.versions.node}`,
|
|
112
|
+
};
|
|
113
|
+
const apiKey = (process.env.APIGURU_API_KEY || "").trim();
|
|
114
|
+
if (apiKey) headers["X-API-KEY"] = apiKey;
|
|
115
|
+
|
|
116
|
+
const remote = new StreamableHTTPClientTransport(url, { requestInit: { headers } });
|
|
117
|
+
const local = new StdioServerTransport();
|
|
118
|
+
|
|
119
|
+
let closing = false;
|
|
120
|
+
const shutdown = async (code = 0) => {
|
|
121
|
+
if (closing) return;
|
|
122
|
+
closing = true;
|
|
123
|
+
await Promise.allSettled([remote.close(), local.close()]);
|
|
124
|
+
process.exit(code);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// Server -> client: responses and server notifications pass straight through.
|
|
128
|
+
remote.onmessage = (message) => {
|
|
129
|
+
local.send(message).catch((err) => {
|
|
130
|
+
process.stderr.write(`apiguru-mcp: cannot write to client: ${err.message}\n`);
|
|
131
|
+
shutdown(1);
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
remote.onerror = (err) => {
|
|
135
|
+
// Transport noise that is not tied to a request, e.g. the optional GET
|
|
136
|
+
// stream that a stateless server answers with 405. Failing requests are
|
|
137
|
+
// answered individually below, so this is only logged on demand.
|
|
138
|
+
if (process.env.APIGURU_MCP_DEBUG) {
|
|
139
|
+
process.stderr.write(`apiguru-mcp: remote: ${err.message}\n`);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
remote.onclose = () => shutdown(0);
|
|
143
|
+
|
|
144
|
+
// Client -> server: a request that cannot reach the server gets a JSON-RPC
|
|
145
|
+
// error back instead of leaving the client waiting forever.
|
|
146
|
+
local.onmessage = async (message) => {
|
|
147
|
+
try {
|
|
148
|
+
await remote.send(message);
|
|
149
|
+
} catch (err) {
|
|
150
|
+
const isRequest =
|
|
151
|
+
message && typeof message === "object" && "method" in message && "id" in message;
|
|
152
|
+
const detail = describe(err, url);
|
|
153
|
+
if (isRequest) {
|
|
154
|
+
await local
|
|
155
|
+
.send({ jsonrpc: "2.0", id: message.id, error: { code: -32000, message: detail } })
|
|
156
|
+
.catch(() => {});
|
|
157
|
+
} else {
|
|
158
|
+
process.stderr.write(`apiguru-mcp: ${detail}\n`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
local.onerror = (err) => process.stderr.write(`apiguru-mcp: stdio: ${err.message}\n`);
|
|
163
|
+
local.onclose = () => shutdown(0);
|
|
164
|
+
|
|
165
|
+
for (const sig of ["SIGINT", "SIGTERM"]) process.on(sig, () => shutdown(0));
|
|
166
|
+
|
|
167
|
+
await remote.start();
|
|
168
|
+
await local.start();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function describe(err, url) {
|
|
172
|
+
const msg = err && err.message ? err.message : String(err);
|
|
173
|
+
if (err && err.name === "UnauthorizedError") {
|
|
174
|
+
return (
|
|
175
|
+
`${url.host} requires a sign-in this bridge cannot perform. Use the keyless ` +
|
|
176
|
+
`${DEFAULT_URL}, or add ${ACCOUNT_URL} as a connector in a client that supports OAuth.`
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
if (/ENOTFOUND|ECONNREFUSED|EAI_AGAIN|fetch failed/i.test(msg)) {
|
|
180
|
+
return `cannot reach ${url.host}: ${msg}. Check the network, or run with --local to use the Python server via uvx.`;
|
|
181
|
+
}
|
|
182
|
+
return `bridge to ${url.host} failed: ${msg}`;
|
|
183
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "apiguru-mcp",
|
|
3
|
+
"version": "1.1.1",
|
|
4
|
+
"description": "Live Amazon marketplace data for AI agents as MCP tools: product details, reviews, keyword search, best-sellers, deals, live offers and stock, and seller profiles across 20 countries. `npx apiguru-mcp` needs only Node 18+ - no Python, no uv, no API key.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"model-context-protocol",
|
|
8
|
+
"modelcontextprotocol",
|
|
9
|
+
"mcp-server",
|
|
10
|
+
"amazon",
|
|
11
|
+
"ecommerce",
|
|
12
|
+
"product-data",
|
|
13
|
+
"scraping",
|
|
14
|
+
"x402",
|
|
15
|
+
"agent",
|
|
16
|
+
"claude",
|
|
17
|
+
"cursor",
|
|
18
|
+
"codex"
|
|
19
|
+
],
|
|
20
|
+
"homepage": "https://apiguru.app",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/apiguru-app/agent-kit/issues",
|
|
23
|
+
"email": "support@apiguru.app"
|
|
24
|
+
},
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/apiguru-app/agent-kit.git",
|
|
28
|
+
"directory": "npm"
|
|
29
|
+
},
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"author": "Apiguru <support@apiguru.app> (https://apiguru.app)",
|
|
32
|
+
"type": "module",
|
|
33
|
+
"bin": {
|
|
34
|
+
"apiguru-mcp": "bin/apiguru-mcp.mjs"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"bin/",
|
|
38
|
+
"README.md",
|
|
39
|
+
"LICENSE"
|
|
40
|
+
],
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=18"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"test": "node test/smoke.mjs"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@modelcontextprotocol/sdk": "^1.30.0"
|
|
49
|
+
},
|
|
50
|
+
"mcpName": "app.apiguru/amazon-data"
|
|
51
|
+
}
|