@scavio/mcp-server 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/LICENSE +21 -0
- package/README.md +253 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/client.d.ts +8 -0
- package/dist/lib/client.js +40 -0
- package/dist/lib/client.js.map +1 -0
- package/dist/lib/env.d.ts +6 -0
- package/dist/lib/env.js +12 -0
- package/dist/lib/env.js.map +1 -0
- package/dist/lib/errors.d.ts +5 -0
- package/dist/lib/errors.js +11 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/tools/amazon.d.ts +3 -0
- package/dist/tools/amazon.js +52 -0
- package/dist/tools/amazon.js.map +1 -0
- package/dist/tools/google.d.ts +3 -0
- package/dist/tools/google.js +37 -0
- package/dist/tools/google.js.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.js +17 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/reddit.d.ts +3 -0
- package/dist/tools/reddit.js +44 -0
- package/dist/tools/reddit.js.map +1 -0
- package/dist/tools/tiktok.d.ts +3 -0
- package/dist/tools/tiktok.js +196 -0
- package/dist/tools/tiktok.js.map +1 -0
- package/dist/tools/usage.d.ts +3 -0
- package/dist/tools/usage.js +21 -0
- package/dist/tools/usage.js.map +1 -0
- package/dist/tools/walmart.d.ts +3 -0
- package/dist/tools/walmart.js +48 -0
- package/dist/tools/walmart.js.map +1 -0
- package/dist/tools/youtube.d.ts +3 -0
- package/dist/tools/youtube.js +48 -0
- package/dist/tools/youtube.js.map +1 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Scavio
|
|
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,253 @@
|
|
|
1
|
+
# Scavio MCP Server
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
An MCP server that connects AI agents to Google, YouTube, Amazon, Walmart, TikTok, and Reddit. 21 tools for web search, product lookup, video discovery, and social media analysis through a single HTTP endpoint.
|
|
7
|
+
|
|
8
|
+
## Remote MCP Server
|
|
9
|
+
|
|
10
|
+
Connect directly to Scavio's remote MCP server without any local installation:
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
https://mcp.scavio.dev/mcp
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Pass your API key via the `x-api-key` header. Get your key at [scavio.dev](https://scavio.dev).
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Run Locally (npx)
|
|
21
|
+
|
|
22
|
+
Prefer to run the server on your own machine? Use `npx` with no clone or build. The server runs over stdio and only needs your `SCAVIO_API_KEY`.
|
|
23
|
+
|
|
24
|
+
### Claude Code
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
claude mcp add scavio -e SCAVIO_API_KEY=YOUR_SCAVIO_API_KEY -- npx -y @scavio/mcp-server
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Any MCP-Compatible Client (Claude Desktop, Cursor, Windsurf, VS Code, etc.)
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"mcpServers": {
|
|
35
|
+
"scavio": {
|
|
36
|
+
"command": "npx",
|
|
37
|
+
"args": ["-y", "@scavio/mcp-server"],
|
|
38
|
+
"env": {
|
|
39
|
+
"SCAVIO_API_KEY": "YOUR_SCAVIO_API_KEY"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Requires Node.js 20+. Get your API key at [scavio.dev](https://scavio.dev).
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
### Claude Code
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
claude mcp add scavio --transport http --url https://mcp.scavio.dev/mcp --header "x-api-key: YOUR_SCAVIO_API_KEY"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Claude Desktop
|
|
59
|
+
|
|
60
|
+
Add to `claude_desktop_config.json` (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS, `%APPDATA%\Claude\claude_desktop_config.json` on Windows):
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"mcpServers": {
|
|
65
|
+
"scavio": {
|
|
66
|
+
"type": "http",
|
|
67
|
+
"url": "https://mcp.scavio.dev/mcp",
|
|
68
|
+
"headers": {
|
|
69
|
+
"x-api-key": "YOUR_SCAVIO_API_KEY"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Cursor
|
|
77
|
+
|
|
78
|
+
[](https://cursor.com/en/install-mcp?name=scavio&config=eyJ1cmwiOiJodHRwczovL21jcC5zY2F2aW8uZGV2L21jcCIsImhlYWRlcnMiOnsieC1hcGkta2V5IjoiWU9VUl9TQ0FWSU9fQVBJX0tFWSJ9fQ%3D%3D)
|
|
79
|
+
|
|
80
|
+
Or add to `.cursor/mcp.json` in your project root or `~/.cursor/mcp.json` for global:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"mcpServers": {
|
|
85
|
+
"scavio": {
|
|
86
|
+
"type": "http",
|
|
87
|
+
"url": "https://mcp.scavio.dev/mcp",
|
|
88
|
+
"headers": {
|
|
89
|
+
"x-api-key": "YOUR_SCAVIO_API_KEY"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Windsurf
|
|
97
|
+
|
|
98
|
+
Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"mcpServers": {
|
|
103
|
+
"scavio": {
|
|
104
|
+
"type": "http",
|
|
105
|
+
"url": "https://mcp.scavio.dev/mcp",
|
|
106
|
+
"headers": {
|
|
107
|
+
"x-api-key": "YOUR_SCAVIO_API_KEY"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### VS Code
|
|
115
|
+
|
|
116
|
+
Create `.vscode/mcp.json` in your project root:
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"servers": {
|
|
121
|
+
"scavio": {
|
|
122
|
+
"type": "http",
|
|
123
|
+
"url": "https://mcp.scavio.dev/mcp",
|
|
124
|
+
"headers": {
|
|
125
|
+
"x-api-key": "YOUR_SCAVIO_API_KEY"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### ChatGPT
|
|
133
|
+
|
|
134
|
+
1. Go to [ChatGPT](https://chatgpt.com) > **Settings** > **Apps & Connectors**
|
|
135
|
+
2. Click **Add custom connector**
|
|
136
|
+
3. Enter the MCP server URL: `https://mcp.scavio.dev/mcp`
|
|
137
|
+
4. Configure authentication with your API key
|
|
138
|
+
|
|
139
|
+
### Cline
|
|
140
|
+
|
|
141
|
+
Add to `cline_mcp_settings.json` (open via Cline sidebar > MCP Servers > Configure):
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"mcpServers": {
|
|
146
|
+
"scavio": {
|
|
147
|
+
"type": "http",
|
|
148
|
+
"url": "https://mcp.scavio.dev/mcp",
|
|
149
|
+
"headers": {
|
|
150
|
+
"x-api-key": "YOUR_SCAVIO_API_KEY"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Zed
|
|
158
|
+
|
|
159
|
+
Add to settings (`Cmd+,`):
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{
|
|
163
|
+
"assistant": {
|
|
164
|
+
"mcp_servers": {
|
|
165
|
+
"scavio": {
|
|
166
|
+
"type": "http",
|
|
167
|
+
"url": "https://mcp.scavio.dev/mcp",
|
|
168
|
+
"headers": {
|
|
169
|
+
"x-api-key": "YOUR_SCAVIO_API_KEY"
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Any MCP-Compatible Client
|
|
178
|
+
|
|
179
|
+
```json
|
|
180
|
+
{
|
|
181
|
+
"type": "http",
|
|
182
|
+
"url": "https://mcp.scavio.dev/mcp",
|
|
183
|
+
"headers": {
|
|
184
|
+
"x-api-key": "YOUR_SCAVIO_API_KEY"
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Available Tools
|
|
192
|
+
|
|
193
|
+
### Google
|
|
194
|
+
|
|
195
|
+
| Tool | Description |
|
|
196
|
+
|------|-------------|
|
|
197
|
+
| `search_google` | Web search with structured results, news, images, maps, and knowledge graph |
|
|
198
|
+
|
|
199
|
+
### YouTube
|
|
200
|
+
|
|
201
|
+
| Tool | Description |
|
|
202
|
+
|------|-------------|
|
|
203
|
+
| `search_youtube` | Search videos, channels, and playlists |
|
|
204
|
+
| `get_youtube_metadata` | Get video metadata including title, views, likes, and duration |
|
|
205
|
+
|
|
206
|
+
### Amazon
|
|
207
|
+
|
|
208
|
+
| Tool | Description |
|
|
209
|
+
|------|-------------|
|
|
210
|
+
| `search_amazon` | Search product listings with price and sort filters |
|
|
211
|
+
| `get_amazon_product` | Get full product details by ASIN |
|
|
212
|
+
|
|
213
|
+
### Walmart
|
|
214
|
+
|
|
215
|
+
| Tool | Description |
|
|
216
|
+
|------|-------------|
|
|
217
|
+
| `search_walmart` | Search product listings with price and delivery filters |
|
|
218
|
+
| `get_walmart_product` | Get full product details by product ID |
|
|
219
|
+
|
|
220
|
+
### TikTok
|
|
221
|
+
|
|
222
|
+
| Tool | Description |
|
|
223
|
+
|------|-------------|
|
|
224
|
+
| `get_tiktok_profile` | Get user profile (bio, follower/following counts, likes) |
|
|
225
|
+
| `get_tiktok_user_posts` | List a user's videos with stats |
|
|
226
|
+
| `get_tiktok_video` | Get detailed info for a single video |
|
|
227
|
+
| `get_tiktok_video_comments` | Get comments on a video |
|
|
228
|
+
| `get_tiktok_comment_replies` | Get replies to a specific comment |
|
|
229
|
+
| `search_tiktok_videos` | Search videos by keyword |
|
|
230
|
+
| `search_tiktok_users` | Search users by keyword |
|
|
231
|
+
| `get_tiktok_hashtag` | Get hashtag details and stats |
|
|
232
|
+
| `get_tiktok_hashtag_videos` | List videos for a hashtag |
|
|
233
|
+
| `get_tiktok_user_followers` | Get a user's follower list |
|
|
234
|
+
| `get_tiktok_user_followings` | Get a user's following list |
|
|
235
|
+
|
|
236
|
+
### Reddit
|
|
237
|
+
|
|
238
|
+
| Tool | Description |
|
|
239
|
+
|------|-------------|
|
|
240
|
+
| `search_reddit` | Search Reddit posts by query with sort and pagination |
|
|
241
|
+
| `get_reddit_post` | Get a full post with threaded comments by URL |
|
|
242
|
+
|
|
243
|
+
### Account
|
|
244
|
+
|
|
245
|
+
| Tool | Description |
|
|
246
|
+
|------|-------------|
|
|
247
|
+
| `get_usage` | Check credit balance, plan, and usage stats |
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## License
|
|
252
|
+
|
|
253
|
+
[MIT](LICENSE)
|
package/dist/index.d.ts
ADDED
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 { env } from "./lib/env.js";
|
|
4
|
+
import { ScavioClient } from "./lib/client.js";
|
|
5
|
+
import { registerAllTools } from "./tools/index.js";
|
|
6
|
+
const SERVER_NAME = "scavio-mcp";
|
|
7
|
+
const SERVER_VERSION = "0.1.0";
|
|
8
|
+
if (env.TRANSPORT === "stdio") {
|
|
9
|
+
await startStdio();
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
await startHttp();
|
|
13
|
+
}
|
|
14
|
+
async function startStdio() {
|
|
15
|
+
const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
|
|
16
|
+
const apiKey = env.SCAVIO_API_KEY;
|
|
17
|
+
if (!apiKey) {
|
|
18
|
+
console.error("SCAVIO_API_KEY is required for stdio transport");
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });
|
|
22
|
+
const client = new ScavioClient(apiKey);
|
|
23
|
+
registerAllTools(server, () => client);
|
|
24
|
+
const transport = new StdioServerTransport();
|
|
25
|
+
await server.connect(transport);
|
|
26
|
+
console.error(`${SERVER_NAME} started (stdio)`);
|
|
27
|
+
}
|
|
28
|
+
async function startHttp() {
|
|
29
|
+
const { Hono } = await import("hono");
|
|
30
|
+
const { serve } = await import("@hono/node-server");
|
|
31
|
+
const { WebStandardStreamableHTTPServerTransport } = await import("@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js");
|
|
32
|
+
const app = new Hono();
|
|
33
|
+
app.get("/", (c) => c.json({ status: "ok", server: SERVER_NAME }));
|
|
34
|
+
app.get("/health", (c) => c.json({ status: "ok" }));
|
|
35
|
+
app.post("/mcp", async (c) => {
|
|
36
|
+
const apiKey = c.req.header("x-api-key") ??
|
|
37
|
+
c.req.header("authorization")?.replace("Bearer ", "") ??
|
|
38
|
+
c.req.query("api_key");
|
|
39
|
+
if (!apiKey) {
|
|
40
|
+
return c.json({ error: "Missing SCAVIO_API_KEY. Provide x-api-key or Authorization: Bearer header." }, 401);
|
|
41
|
+
}
|
|
42
|
+
const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });
|
|
43
|
+
const client = new ScavioClient(apiKey);
|
|
44
|
+
registerAllTools(server, () => client);
|
|
45
|
+
const transport = new WebStandardStreamableHTTPServerTransport({ sessionIdGenerator: undefined });
|
|
46
|
+
await server.connect(transport);
|
|
47
|
+
return transport.handleRequest(c.req.raw);
|
|
48
|
+
});
|
|
49
|
+
serve({ fetch: app.fetch, port: env.PORT }, (info) => {
|
|
50
|
+
console.error(`${SERVER_NAME} started (http) on port ${info.port}`);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { env } from "./env.js";
|
|
2
|
+
import { ApiError } from "./errors.js";
|
|
3
|
+
export class ScavioClient {
|
|
4
|
+
baseUrl;
|
|
5
|
+
apiKey;
|
|
6
|
+
constructor(apiKey) {
|
|
7
|
+
this.baseUrl = env.SCAVIO_API_BASE_URL;
|
|
8
|
+
this.apiKey = apiKey;
|
|
9
|
+
}
|
|
10
|
+
async request(method, path, body) {
|
|
11
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
12
|
+
method,
|
|
13
|
+
headers: {
|
|
14
|
+
"Content-Type": "application/json",
|
|
15
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
16
|
+
},
|
|
17
|
+
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
|
|
18
|
+
});
|
|
19
|
+
if (!response.ok) {
|
|
20
|
+
const text = await response.text();
|
|
21
|
+
let message;
|
|
22
|
+
try {
|
|
23
|
+
const json = JSON.parse(text);
|
|
24
|
+
message = json.error ?? json.message ?? text;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
message = text;
|
|
28
|
+
}
|
|
29
|
+
throw new ApiError(response.status, message);
|
|
30
|
+
}
|
|
31
|
+
return response.json();
|
|
32
|
+
}
|
|
33
|
+
async get(path) {
|
|
34
|
+
return this.request("GET", path);
|
|
35
|
+
}
|
|
36
|
+
async post(path, body) {
|
|
37
|
+
return this.request("POST", path, body);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,MAAM,OAAO,YAAY;IACf,OAAO,CAAS;IAChB,MAAM,CAAS;IAEvB,YAAY,MAAc;QACxB,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,mBAAmB,CAAC;QACvC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAEO,KAAK,CAAC,OAAO,CAAI,MAAc,EAAE,IAAY,EAAE,IAAc;QACnE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;YACrD,MAAM;YACN,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,eAAe,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;aACzC;YACD,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9D,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,OAAe,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC9B,OAAO,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;YAC/C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,GAAG,IAAI,CAAC;YACjB,CAAC;YACD,MAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/C,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,EAAgB,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,GAAG,CAAI,IAAY;QACvB,OAAO,IAAI,CAAC,OAAO,CAAI,KAAK,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,IAAI,CAAI,IAAY,EAAE,IAAc;QACxC,OAAO,IAAI,CAAC,OAAO,CAAI,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;CACF"}
|
package/dist/lib/env.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const envSchema = z.object({
|
|
3
|
+
SCAVIO_API_BASE_URL: z.string().url()
|
|
4
|
+
.default("https://api.scavio.dev"),
|
|
5
|
+
SCAVIO_API_KEY: z.string().optional(),
|
|
6
|
+
PORT: z.coerce.number().int().min(1).max(65535)
|
|
7
|
+
.default(3000),
|
|
8
|
+
TRANSPORT: z.enum(["http", "stdio"])
|
|
9
|
+
.default("stdio"),
|
|
10
|
+
});
|
|
11
|
+
export const env = envSchema.parse(process.env);
|
|
12
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/lib/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;SAClC,OAAO,CAAC,wBAAwB,CAAC;IACpC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACrC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;SAC5C,OAAO,CAAC,IAAI,CAAC;IAChB,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SACjC,OAAO,CAAC,OAAO,CAAC;CACpB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,QAAS,SAAQ,KAAK;IAEf;IAEA;IAHlB,YACkB,MAAc,EAC9B,OAAe,EACC,IAAa;QAE7B,KAAK,CAAC,OAAO,CAAC,CAAC;QAJC,WAAM,GAAN,MAAM,CAAQ;QAEd,SAAI,GAAJ,IAAI,CAAS;QAG7B,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import { ApiError } from "../lib/errors.js";
|
|
4
|
+
function handleApiError(err) {
|
|
5
|
+
if (err instanceof ApiError) {
|
|
6
|
+
if (err.status === 429)
|
|
7
|
+
return { isError: true, content: [{ type: "text", text: "Rate limited. Wait and retry." }] };
|
|
8
|
+
if (err.status === 401)
|
|
9
|
+
throw new McpError(ErrorCode.InternalError, "Invalid SCAVIO_API_KEY. Check your configuration.");
|
|
10
|
+
return { isError: true, content: [{ type: "text", text: `Scavio API error (${err.status}): ${err.message}` }] };
|
|
11
|
+
}
|
|
12
|
+
throw new McpError(ErrorCode.InternalError, String(err));
|
|
13
|
+
}
|
|
14
|
+
export function registerAmazonTools(server, getClient) {
|
|
15
|
+
server.tool("search_amazon", `Search Amazon and return product listings as JSON. Each result includes title, ASIN, price, rating, review count, and image URL. Use when the user wants to find products on Amazon or compare prices.`, {
|
|
16
|
+
query: z.string().min(1).max(500)
|
|
17
|
+
.describe("Product search query, e.g. 'wireless noise cancelling headphones'."),
|
|
18
|
+
domain: z.string().default("com")
|
|
19
|
+
.describe("Amazon domain suffix, e.g. 'com' (US), 'co.uk' (UK), 'de' (Germany), 'co.jp' (Japan)."),
|
|
20
|
+
sort_by: z.enum(["most_recent", "price_low_to_high", "price_high_to_low", "featured", "average_review", "bestsellers"]).default("featured")
|
|
21
|
+
.describe("Sort order for results."),
|
|
22
|
+
start_page: z.number().int().min(1).default(1)
|
|
23
|
+
.describe("Starting page number."),
|
|
24
|
+
min_price: z.number().optional()
|
|
25
|
+
.describe("Minimum price filter in the domain's local currency."),
|
|
26
|
+
max_price: z.number().optional()
|
|
27
|
+
.describe("Maximum price filter in the domain's local currency."),
|
|
28
|
+
}, async (params) => {
|
|
29
|
+
try {
|
|
30
|
+
const data = await getClient().post("/api/v1/amazon/search", params);
|
|
31
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
return handleApiError(err);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
server.tool("get_amazon_product", `Get detailed information for an Amazon product by its ASIN. Returns title, full description, price, rating, review count, images, variants, and seller info. Use when the user has a specific Amazon product URL or ASIN and wants full details.`, {
|
|
38
|
+
query: z.string().length(10)
|
|
39
|
+
.describe("Amazon ASIN — the 10-character product ID, e.g. 'B09V3KXJPB'. Extract from the Amazon URL (/dp/ASIN)."),
|
|
40
|
+
domain: z.string().default("com")
|
|
41
|
+
.describe("Amazon domain suffix, e.g. 'com', 'co.uk', 'de'."),
|
|
42
|
+
}, async (params) => {
|
|
43
|
+
try {
|
|
44
|
+
const data = await getClient().post("/api/v1/amazon/product", params);
|
|
45
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
return handleApiError(err);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=amazon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amazon.js","sourceRoot":"","sources":["../../src/tools/amazon.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import { ApiError } from "../lib/errors.js";
|
|
4
|
+
export function registerGoogleTools(server, getClient) {
|
|
5
|
+
server.tool("search_google", `Search Google and return structured results as JSON. Each result includes title, URL, and snippet. Also returns top stories, knowledge graph, local results, news, images, and related searches depending on search type. Use when the user asks to search the web, find current information, or look something up online. Returns 1 credit (light) or 2 credits (full).`, {
|
|
6
|
+
query: z.string().min(1).max(500)
|
|
7
|
+
.describe("The search query."),
|
|
8
|
+
search_type: z.enum(["classic", "news", "maps", "images", "lens"]).default("classic")
|
|
9
|
+
.describe("Type of search. Use 'news' for recent articles, 'maps' for local results, 'images' for image results."),
|
|
10
|
+
country_code: z.string().length(2).default("us")
|
|
11
|
+
.describe("ISO 3166-1 alpha-2 country code, e.g. 'us', 'gb', 'fr'."),
|
|
12
|
+
language: z.string().default("en")
|
|
13
|
+
.describe("Language code, e.g. 'en', 'fr', 'de'."),
|
|
14
|
+
page: z.number().int().min(1).max(100).default(1)
|
|
15
|
+
.describe("Page number, 1-indexed."),
|
|
16
|
+
device: z.enum(["desktop", "mobile"]).default("desktop")
|
|
17
|
+
.describe("Device type for results."),
|
|
18
|
+
light_request: z.boolean().default(true)
|
|
19
|
+
.describe("true = 1 credit (fewer results). false = 2 credits (full results). Use false only when the user needs comprehensive results."),
|
|
20
|
+
}, async (params) => {
|
|
21
|
+
try {
|
|
22
|
+
const data = await getClient().post("/api/v1/google", params);
|
|
23
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
if (err instanceof ApiError) {
|
|
27
|
+
if (err.status === 429)
|
|
28
|
+
return { isError: true, content: [{ type: "text", text: "Rate limited. Wait and retry." }] };
|
|
29
|
+
if (err.status === 401)
|
|
30
|
+
throw new McpError(ErrorCode.InternalError, "Invalid SCAVIO_API_KEY. Check your configuration.");
|
|
31
|
+
return { isError: true, content: [{ type: "text", text: `Scavio API error (${err.status}): ${err.message}` }] };
|
|
32
|
+
}
|
|
33
|
+
throw new McpError(ErrorCode.InternalError, String(err));
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=google.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google.js","sourceRoot":"","sources":["../../src/tools/google.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,SAA6B;IAClF,MAAM,CAAC,IAAI,CACT,eAAe,EACf,0WAA0W,EAC1W;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;aAC9B,QAAQ,CAAC,mBAAmB,CAAC;QAChC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;aAClF,QAAQ,CAAC,uGAAuG,CAAC;QACpH,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;aAC7C,QAAQ,CAAC,yDAAyD,CAAC;QACtE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;aAC/B,QAAQ,CAAC,uCAAuC,CAAC;QACpD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;aAC9C,QAAQ,CAAC,yBAAyB,CAAC;QACtC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;aACrD,QAAQ,CAAC,0BAA0B,CAAC;QACvC,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;aACrC,QAAQ,CAAC,8HAA8H,CAAC;KAC5I,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;YAC9D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,QAAQ,EAAE,CAAC;gBAC5B,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;oBAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,+BAA+B,EAAE,CAAC,EAAE,CAAC;gBACrH,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;oBAAE,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,mDAAmD,CAAC,CAAC;gBACzH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,qBAAqB,GAAG,CAAC,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;YAClH,CAAC;YACD,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { registerGoogleTools } from "./google.js";
|
|
2
|
+
import { registerYoutubeTools } from "./youtube.js";
|
|
3
|
+
import { registerAmazonTools } from "./amazon.js";
|
|
4
|
+
import { registerWalmartTools } from "./walmart.js";
|
|
5
|
+
import { registerUsageTool } from "./usage.js";
|
|
6
|
+
import { registerTiktokTools } from "./tiktok.js";
|
|
7
|
+
import { registerRedditTools } from "./reddit.js";
|
|
8
|
+
export function registerAllTools(server, getClient) {
|
|
9
|
+
registerGoogleTools(server, getClient);
|
|
10
|
+
registerYoutubeTools(server, getClient);
|
|
11
|
+
registerAmazonTools(server, getClient);
|
|
12
|
+
registerWalmartTools(server, getClient);
|
|
13
|
+
registerTiktokTools(server, getClient);
|
|
14
|
+
registerRedditTools(server, getClient);
|
|
15
|
+
registerUsageTool(server, getClient);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,SAA6B;IAC/E,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACvC,oBAAoB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACxC,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACvC,oBAAoB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACxC,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACvC,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACvC,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import { ApiError } from "../lib/errors.js";
|
|
4
|
+
function handleApiError(err) {
|
|
5
|
+
if (err instanceof ApiError) {
|
|
6
|
+
if (err.status === 429)
|
|
7
|
+
return { isError: true, content: [{ type: "text", text: "Rate limited. Wait and retry." }] };
|
|
8
|
+
if (err.status === 401)
|
|
9
|
+
throw new McpError(ErrorCode.InternalError, "Invalid SCAVIO_API_KEY. Check your configuration.");
|
|
10
|
+
return { isError: true, content: [{ type: "text", text: `Scavio API error (${err.status}): ${err.message}` }] };
|
|
11
|
+
}
|
|
12
|
+
throw new McpError(ErrorCode.InternalError, String(err));
|
|
13
|
+
}
|
|
14
|
+
export function registerRedditTools(server, getClient) {
|
|
15
|
+
server.tool("search_reddit", `Search Reddit posts across all of Reddit as JSON. Each post includes title, URL, subreddit, author, timestamp, and NSFW flag. Use data.nextCursor as the cursor parameter for the next page; stop when nextCursor is null. Slower than other platforms (5-15 seconds).`, {
|
|
16
|
+
query: z.string().min(1).max(500)
|
|
17
|
+
.describe("Search query (1-500 chars)."),
|
|
18
|
+
sort: z.enum(["relevance", "hot", "top", "new", "comments"]).default("relevance")
|
|
19
|
+
.describe("Sort order. 'relevance' (default), 'hot', 'top', 'new', or 'comments'."),
|
|
20
|
+
cursor: z.string().optional()
|
|
21
|
+
.describe("Pagination token. Use data.nextCursor from previous response for next page."),
|
|
22
|
+
}, async (params) => {
|
|
23
|
+
try {
|
|
24
|
+
const data = await getClient().post("/api/v1/reddit/search", params);
|
|
25
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
return handleApiError(err);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
server.tool("get_reddit_post", `Get a full Reddit post by URL as JSON, including body, score, upvote ratio, flair, awards, and the full comment tree. Comments are a flat array in traversal order; use depth (0-indexed) or parentId to reconstruct the thread hierarchy. contentUrl is the external article for link posts. Slower than other platforms (5-15 seconds).`, {
|
|
32
|
+
url: z.string()
|
|
33
|
+
.describe("Full Reddit post URL, e.g. 'https://www.reddit.com/r/Python/comments/1smb9du/fastapi_vs_django/'."),
|
|
34
|
+
}, async (params) => {
|
|
35
|
+
try {
|
|
36
|
+
const data = await getClient().post("/api/v1/reddit/post", params);
|
|
37
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
return handleApiError(err);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=reddit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reddit.js","sourceRoot":"","sources":["../../src/tools/reddit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,SAAS,cAAc,CAAC,GAAY;IAClC,IAAI,GAAG,YAAY,QAAQ,EAAE,CAAC;QAC5B,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,+BAA+B,EAAE,CAAC,EAAE,CAAC;QACrH,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,mDAAmD,CAAC,CAAC;QACzH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,qBAAqB,GAAG,CAAC,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;IAClH,CAAC;IACD,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,SAA6B;IAClF,MAAM,CAAC,IAAI,CACT,eAAe,EACf,wQAAwQ,EACxQ;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;aAC9B,QAAQ,CAAC,6BAA6B,CAAC;QAC1C,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;aAC9E,QAAQ,CAAC,wEAAwE,CAAC;QACrF,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC1B,QAAQ,CAAC,6EAA6E,CAAC;KAC3F,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAC;YACrE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,2UAA2U,EAC3U;QACE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;aACZ,QAAQ,CAAC,mGAAmG,CAAC;KACjH,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;YACnE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import { ApiError } from "../lib/errors.js";
|
|
4
|
+
function handleApiError(err) {
|
|
5
|
+
if (err instanceof ApiError) {
|
|
6
|
+
if (err.status === 429)
|
|
7
|
+
return { isError: true, content: [{ type: "text", text: "Rate limited. Wait and retry." }] };
|
|
8
|
+
if (err.status === 401)
|
|
9
|
+
throw new McpError(ErrorCode.InternalError, "Invalid SCAVIO_API_KEY. Check your configuration.");
|
|
10
|
+
return { isError: true, content: [{ type: "text", text: `Scavio API error (${err.status}): ${err.message}` }] };
|
|
11
|
+
}
|
|
12
|
+
throw new McpError(ErrorCode.InternalError, String(err));
|
|
13
|
+
}
|
|
14
|
+
export function registerTiktokTools(server, getClient) {
|
|
15
|
+
server.tool("get_tiktok_profile", `Get a TikTok user's profile data as JSON. Returns username, display name, bio, follower/following counts, video count, total likes, and avatar URL. Use when the user wants info about a TikTok account. Provide either username or sec_user_id.`, {
|
|
16
|
+
username: z.string().optional()
|
|
17
|
+
.describe("TikTok handle without the @ symbol, e.g. 'charlidamelio'."),
|
|
18
|
+
sec_user_id: z.string().optional()
|
|
19
|
+
.describe("Secure user ID. Use this if you already have it from a previous request."),
|
|
20
|
+
}, async (params) => {
|
|
21
|
+
try {
|
|
22
|
+
const data = await getClient().post("/api/v1/tiktok/profile", params);
|
|
23
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
return handleApiError(err);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
server.tool("get_tiktok_user_posts", `List a TikTok user's videos with pagination as JSON. Each video includes ID, caption, timestamp, and stats (likes, comments, views, shares, bookmarks). Requires sec_user_id from the profile endpoint. Use data.max_cursor for next page; stop when data.has_more is 0.`, {
|
|
30
|
+
sec_user_id: z.string()
|
|
31
|
+
.describe("Secure user ID from the get_tiktok_profile response."),
|
|
32
|
+
cursor: z.string().default("0")
|
|
33
|
+
.describe("Pagination cursor. Use data.max_cursor from previous response for next page."),
|
|
34
|
+
count: z.number().int().min(1).max(30).default(20)
|
|
35
|
+
.describe("Number of results per page (1-30)."),
|
|
36
|
+
sort_type: z.enum(["0", "1"]).default("0")
|
|
37
|
+
.describe("Sort order. '0' = latest first, '1' = most popular first."),
|
|
38
|
+
}, async (params) => {
|
|
39
|
+
try {
|
|
40
|
+
const data = await getClient().post("/api/v1/tiktok/user/posts", params);
|
|
41
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
return handleApiError(err);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
server.tool("get_tiktok_video", `Get detailed info for a single TikTok video by ID as JSON. Returns caption, author, music, stats (likes, comments, views, shares, bookmarks), play/download URLs, cover image, duration, hashtags, and mentions. Use when the user has a specific TikTok video URL or ID.`, {
|
|
48
|
+
video_id: z.string()
|
|
49
|
+
.describe("TikTok video ID. Extract from a TikTok URL if the user provides one."),
|
|
50
|
+
}, async (params) => {
|
|
51
|
+
try {
|
|
52
|
+
const data = await getClient().post("/api/v1/tiktok/video", params);
|
|
53
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
return handleApiError(err);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
server.tool("get_tiktok_video_comments", `Get comments on a TikTok video as JSON. Each comment includes ID, text, timestamp, like count, reply count, commenter info, and whether the video creator liked it. Use data.cursor for next page; stop when data.has_more is 0.`, {
|
|
60
|
+
video_id: z.string()
|
|
61
|
+
.describe("TikTok video ID."),
|
|
62
|
+
cursor: z.string().default("0")
|
|
63
|
+
.describe("Pagination cursor. Use data.cursor from previous response for next page."),
|
|
64
|
+
count: z.number().int().min(1).max(50).default(20)
|
|
65
|
+
.describe("Number of comments per page (1-50)."),
|
|
66
|
+
}, async (params) => {
|
|
67
|
+
try {
|
|
68
|
+
const data = await getClient().post("/api/v1/tiktok/video/comments", params);
|
|
69
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
return handleApiError(err);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
server.tool("get_tiktok_comment_replies", `Get replies to a specific comment on a TikTok video as JSON. Each reply has the same structure as a comment. Requires both video_id and comment_id. Use data.cursor for next page; stop when data.has_more is 0.`, {
|
|
76
|
+
video_id: z.string()
|
|
77
|
+
.describe("TikTok video ID."),
|
|
78
|
+
comment_id: z.string()
|
|
79
|
+
.describe("Comment ID (cid) from the get_tiktok_video_comments response."),
|
|
80
|
+
cursor: z.string().default("0")
|
|
81
|
+
.describe("Pagination cursor. Use data.cursor from previous response for next page."),
|
|
82
|
+
count: z.number().int().min(1).max(50).default(20)
|
|
83
|
+
.describe("Number of replies per page (1-50)."),
|
|
84
|
+
}, async (params) => {
|
|
85
|
+
try {
|
|
86
|
+
const data = await getClient().post("/api/v1/tiktok/video/comments/replies", params);
|
|
87
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
return handleApiError(err);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
server.tool("search_tiktok_videos", `Search TikTok videos by keyword as JSON. Each result includes video ID, caption, author, music, stats, and video URLs. Supports sorting by relevance or likes, and filtering by publish time. Use data.cursor for next page; stop when data.has_more is 0.`, {
|
|
94
|
+
keyword: z.string().min(1).max(500)
|
|
95
|
+
.describe("Search query."),
|
|
96
|
+
cursor: z.string().default("0")
|
|
97
|
+
.describe("Pagination cursor. Use data.cursor from previous response for next page."),
|
|
98
|
+
count: z.number().int().min(1).max(30).default(20)
|
|
99
|
+
.describe("Number of results per page (1-30)."),
|
|
100
|
+
sort_type: z.enum(["0", "1"]).default("0")
|
|
101
|
+
.describe("Sort order. '0' = relevance, '1' = most likes."),
|
|
102
|
+
publish_time: z.enum(["0", "1", "7", "30", "90", "180"]).default("0")
|
|
103
|
+
.describe("Time filter. '0'=all time, '1'=last day, '7'=week, '30'=month, '90'=3 months, '180'=6 months."),
|
|
104
|
+
}, async (params) => {
|
|
105
|
+
try {
|
|
106
|
+
const data = await getClient().post("/api/v1/tiktok/search/videos", params);
|
|
107
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
return handleApiError(err);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
server.tool("search_tiktok_users", `Search TikTok users by keyword as JSON. Each result includes user ID, username, display name, sec_uid, follower count, and bio. Use data.cursor for next page; stop when data.has_more is 0.`, {
|
|
114
|
+
keyword: z.string().min(1).max(500)
|
|
115
|
+
.describe("Search query."),
|
|
116
|
+
cursor: z.string().default("0")
|
|
117
|
+
.describe("Pagination cursor. Use data.cursor from previous response for next page."),
|
|
118
|
+
count: z.number().int().min(1).max(30).default(20)
|
|
119
|
+
.describe("Number of results per page (1-30)."),
|
|
120
|
+
}, async (params) => {
|
|
121
|
+
try {
|
|
122
|
+
const data = await getClient().post("/api/v1/tiktok/search/users", params);
|
|
123
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
return handleApiError(err);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
server.tool("get_tiktok_hashtag", `Get TikTok hashtag details and stats as JSON. Returns hashtag ID, title, description, video count, and view count. Provide either hashtag_name or hashtag_id. Use the returned ID with get_tiktok_hashtag_videos.`, {
|
|
130
|
+
hashtag_name: z.string().optional()
|
|
131
|
+
.describe("Hashtag text without the # symbol, e.g. 'fyp'."),
|
|
132
|
+
hashtag_id: z.string().optional()
|
|
133
|
+
.describe("Numeric hashtag ID. Use if you already have it from a previous request."),
|
|
134
|
+
}, async (params) => {
|
|
135
|
+
try {
|
|
136
|
+
const data = await getClient().post("/api/v1/tiktok/hashtag", params);
|
|
137
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
return handleApiError(err);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
server.tool("get_tiktok_hashtag_videos", `List TikTok videos for a given hashtag as JSON. Each video includes ID, caption, author, stats, and video URLs. Requires hashtag_id from the get_tiktok_hashtag response. Use data.cursor for next page; stop when data.has_more is 0.`, {
|
|
144
|
+
hashtag_id: z.string()
|
|
145
|
+
.describe("Hashtag ID from the get_tiktok_hashtag response."),
|
|
146
|
+
cursor: z.string().default("0")
|
|
147
|
+
.describe("Pagination cursor. Use data.cursor from previous response for next page."),
|
|
148
|
+
count: z.number().int().min(1).max(30).default(20)
|
|
149
|
+
.describe("Number of results per page (1-30)."),
|
|
150
|
+
}, async (params) => {
|
|
151
|
+
try {
|
|
152
|
+
const data = await getClient().post("/api/v1/tiktok/hashtag/videos", params);
|
|
153
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
return handleApiError(err);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
server.tool("get_tiktok_user_followers", `Get a TikTok user's follower list as JSON. Each follower includes username, display name, sec_uid, follower count, video count, bio, and avatar. Pass both page_token and min_time from previous response for pagination; stop when data.has_more is false.`, {
|
|
160
|
+
sec_user_id: z.string()
|
|
161
|
+
.describe("Secure user ID from the get_tiktok_profile response."),
|
|
162
|
+
count: z.number().int().min(1).max(20).default(20)
|
|
163
|
+
.describe("Number of results per page (1-20)."),
|
|
164
|
+
page_token: z.string().optional()
|
|
165
|
+
.describe("Pagination token from previous response."),
|
|
166
|
+
min_time: z.number().optional()
|
|
167
|
+
.describe("Pagination timestamp from previous response. Must be passed together with page_token."),
|
|
168
|
+
}, async (params) => {
|
|
169
|
+
try {
|
|
170
|
+
const data = await getClient().post("/api/v1/tiktok/user/followers", params);
|
|
171
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
return handleApiError(err);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
server.tool("get_tiktok_user_followings", `Get the list of accounts a TikTok user follows as JSON. Each entry includes username, display name, sec_uid, follower count, video count, bio, and avatar. Pass both page_token and min_time from previous response for pagination; stop when data.has_more is false.`, {
|
|
178
|
+
sec_user_id: z.string()
|
|
179
|
+
.describe("Secure user ID from the get_tiktok_profile response."),
|
|
180
|
+
count: z.number().int().min(1).max(20).default(20)
|
|
181
|
+
.describe("Number of results per page (1-20)."),
|
|
182
|
+
page_token: z.string().optional()
|
|
183
|
+
.describe("Pagination token from previous response."),
|
|
184
|
+
min_time: z.number().optional()
|
|
185
|
+
.describe("Pagination timestamp from previous response. Must be passed together with page_token."),
|
|
186
|
+
}, async (params) => {
|
|
187
|
+
try {
|
|
188
|
+
const data = await getClient().post("/api/v1/tiktok/user/followings", params);
|
|
189
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
return handleApiError(err);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=tiktok.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tiktok.js","sourceRoot":"","sources":["../../src/tools/tiktok.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,SAAS,cAAc,CAAC,GAAY;IAClC,IAAI,GAAG,YAAY,QAAQ,EAAE,CAAC;QAC5B,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,+BAA+B,EAAE,CAAC,EAAE,CAAC;QACrH,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,mDAAmD,CAAC,CAAC;QACzH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,qBAAqB,GAAG,CAAC,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;IAClH,CAAC;IACD,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,SAA6B;IAClF,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,kPAAkP,EAClP;QACE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC5B,QAAQ,CAAC,2DAA2D,CAAC;QACxE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC/B,QAAQ,CAAC,0EAA0E,CAAC;KACxF,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC;YACtE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,uBAAuB,EACvB,0QAA0Q,EAC1Q;QACE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;aACpB,QAAQ,CAAC,sDAAsD,CAAC;QACnE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;aAC5B,QAAQ,CAAC,8EAA8E,CAAC;QAC3F,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;aAC/C,QAAQ,CAAC,oCAAoC,CAAC;QACjD,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;aACvC,QAAQ,CAAC,2DAA2D,CAAC;KACzE,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,2BAA2B,EAAE,MAAM,CAAC,CAAC;YACzE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,2QAA2Q,EAC3Q;QACE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;aACjB,QAAQ,CAAC,sEAAsE,CAAC;KACpF,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC;YACpE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,2BAA2B,EAC3B,kOAAkO,EAClO;QACE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;aACjB,QAAQ,CAAC,kBAAkB,CAAC;QAC/B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;aAC5B,QAAQ,CAAC,0EAA0E,CAAC;QACvF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;aAC/C,QAAQ,CAAC,qCAAqC,CAAC;KACnD,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,+BAA+B,EAAE,MAAM,CAAC,CAAC;YAC7E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,4BAA4B,EAC5B,kNAAkN,EAClN;QACE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;aACjB,QAAQ,CAAC,kBAAkB,CAAC;QAC/B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;aACnB,QAAQ,CAAC,+DAA+D,CAAC;QAC5E,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;aAC5B,QAAQ,CAAC,0EAA0E,CAAC;QACvF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;aAC/C,QAAQ,CAAC,oCAAoC,CAAC;KAClD,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,uCAAuC,EAAE,MAAM,CAAC,CAAC;YACrF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,sBAAsB,EACtB,4PAA4P,EAC5P;QACE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;aAChC,QAAQ,CAAC,eAAe,CAAC;QAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;aAC5B,QAAQ,CAAC,0EAA0E,CAAC;QACvF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;aAC/C,QAAQ,CAAC,oCAAoC,CAAC;QACjD,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;aACvC,QAAQ,CAAC,gDAAgD,CAAC;QAC7D,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;aAClE,QAAQ,CAAC,+FAA+F,CAAC;KAC7G,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,8BAA8B,EAAE,MAAM,CAAC,CAAC;YAC5E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,8LAA8L,EAC9L;QACE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;aAChC,QAAQ,CAAC,eAAe,CAAC;QAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;aAC5B,QAAQ,CAAC,0EAA0E,CAAC;QACvF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;aAC/C,QAAQ,CAAC,oCAAoC,CAAC;KAClD,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;YAC3E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,mNAAmN,EACnN;QACE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAChC,QAAQ,CAAC,gDAAgD,CAAC;QAC7D,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC9B,QAAQ,CAAC,yEAAyE,CAAC;KACvF,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC;YACtE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,2BAA2B,EAC3B,wOAAwO,EACxO;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;aACnB,QAAQ,CAAC,kDAAkD,CAAC;QAC/D,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;aAC5B,QAAQ,CAAC,0EAA0E,CAAC;QACvF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;aAC/C,QAAQ,CAAC,oCAAoC,CAAC;KAClD,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,+BAA+B,EAAE,MAAM,CAAC,CAAC;YAC7E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,2BAA2B,EAC3B,6PAA6P,EAC7P;QACE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;aACpB,QAAQ,CAAC,sDAAsD,CAAC;QACnE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;aAC/C,QAAQ,CAAC,oCAAoC,CAAC;QACjD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC9B,QAAQ,CAAC,0CAA0C,CAAC;QACvD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC5B,QAAQ,CAAC,uFAAuF,CAAC;KACrG,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,+BAA+B,EAAE,MAAM,CAAC,CAAC;YAC7E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,4BAA4B,EAC5B,uQAAuQ,EACvQ;QACE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;aACpB,QAAQ,CAAC,sDAAsD,CAAC;QACnE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;aAC/C,QAAQ,CAAC,oCAAoC,CAAC;QACjD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC9B,QAAQ,CAAC,0CAA0C,CAAC;QACvD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC5B,QAAQ,CAAC,uFAAuF,CAAC;KACrG,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,gCAAgC,EAAE,MAAM,CAAC,CAAC;YAC9E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
import { ApiError } from "../lib/errors.js";
|
|
3
|
+
export function registerUsageTool(server, getClient) {
|
|
4
|
+
server.tool("get_usage", `Get the current user's credit balance, plan, searches used this month, and auto-recharge settings. Use when the user asks how many credits they have left, what plan they're on, or about their usage.`, {}, async () => {
|
|
5
|
+
try {
|
|
6
|
+
const data = await getClient().get("/api/v1/usage");
|
|
7
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
8
|
+
}
|
|
9
|
+
catch (err) {
|
|
10
|
+
if (err instanceof ApiError) {
|
|
11
|
+
if (err.status === 429)
|
|
12
|
+
return { isError: true, content: [{ type: "text", text: "Rate limited. Wait and retry." }] };
|
|
13
|
+
if (err.status === 401)
|
|
14
|
+
throw new McpError(ErrorCode.InternalError, "Invalid SCAVIO_API_KEY. Check your configuration.");
|
|
15
|
+
return { isError: true, content: [{ type: "text", text: `Scavio API error (${err.status}): ${err.message}` }] };
|
|
16
|
+
}
|
|
17
|
+
throw new McpError(ErrorCode.InternalError, String(err));
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/tools/usage.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,SAA6B;IAChF,MAAM,CAAC,IAAI,CACT,WAAW,EACX,wMAAwM,EACxM,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YACpD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,QAAQ,EAAE,CAAC;gBAC5B,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;oBAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,+BAA+B,EAAE,CAAC,EAAE,CAAC;gBACrH,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;oBAAE,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,mDAAmD,CAAC,CAAC;gBACzH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,qBAAqB,GAAG,CAAC,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;YAClH,CAAC;YACD,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import { ApiError } from "../lib/errors.js";
|
|
4
|
+
function handleApiError(err) {
|
|
5
|
+
if (err instanceof ApiError) {
|
|
6
|
+
if (err.status === 429)
|
|
7
|
+
return { isError: true, content: [{ type: "text", text: "Rate limited. Wait and retry." }] };
|
|
8
|
+
if (err.status === 401)
|
|
9
|
+
throw new McpError(ErrorCode.InternalError, "Invalid SCAVIO_API_KEY. Check your configuration.");
|
|
10
|
+
return { isError: true, content: [{ type: "text", text: `Scavio API error (${err.status}): ${err.message}` }] };
|
|
11
|
+
}
|
|
12
|
+
throw new McpError(ErrorCode.InternalError, String(err));
|
|
13
|
+
}
|
|
14
|
+
export function registerWalmartTools(server, getClient) {
|
|
15
|
+
server.tool("search_walmart", `Search Walmart and return product listings as JSON. Each result includes title, product ID, price, rating, and image URL. Use when the user wants to find products on Walmart or compare prices with Amazon.`, {
|
|
16
|
+
query: z.string().min(1).max(500)
|
|
17
|
+
.describe("Product search query, e.g. 'air fryer 6 quart'."),
|
|
18
|
+
sort_by: z.enum(["best_match", "price_low", "price_high", "best_seller"]).default("best_match")
|
|
19
|
+
.describe("Sort order for results."),
|
|
20
|
+
min_price: z.number().optional()
|
|
21
|
+
.describe("Minimum price filter in USD."),
|
|
22
|
+
max_price: z.number().optional()
|
|
23
|
+
.describe("Maximum price filter in USD."),
|
|
24
|
+
fulfillment_speed: z.enum(["today", "tomorrow", "2_days", "anytime"]).default("anytime")
|
|
25
|
+
.describe("Delivery speed filter."),
|
|
26
|
+
}, async (params) => {
|
|
27
|
+
try {
|
|
28
|
+
const data = await getClient().post("/api/v1/walmart/search", params);
|
|
29
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
return handleApiError(err);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
server.tool("get_walmart_product", `Get detailed information for a Walmart product by its product ID. Returns title, full description, price, rating, images, and seller info. Use when the user has a specific Walmart product URL or product ID and wants full details.`, {
|
|
36
|
+
product_id: z.string()
|
|
37
|
+
.describe("Walmart product ID — numeric string from the product URL (/ip/name/PRODUCT_ID)."),
|
|
38
|
+
}, async (params) => {
|
|
39
|
+
try {
|
|
40
|
+
const data = await getClient().post("/api/v1/walmart/product", params);
|
|
41
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
return handleApiError(err);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=walmart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walmart.js","sourceRoot":"","sources":["../../src/tools/walmart.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import { ApiError } from "../lib/errors.js";
|
|
4
|
+
function handleApiError(err) {
|
|
5
|
+
if (err instanceof ApiError) {
|
|
6
|
+
if (err.status === 429)
|
|
7
|
+
return { isError: true, content: [{ type: "text", text: "Rate limited. Wait and retry." }] };
|
|
8
|
+
if (err.status === 401)
|
|
9
|
+
throw new McpError(ErrorCode.InternalError, "Invalid SCAVIO_API_KEY. Check your configuration.");
|
|
10
|
+
return { isError: true, content: [{ type: "text", text: `Scavio API error (${err.status}): ${err.message}` }] };
|
|
11
|
+
}
|
|
12
|
+
throw new McpError(ErrorCode.InternalError, String(err));
|
|
13
|
+
}
|
|
14
|
+
export function registerYoutubeTools(server, getClient) {
|
|
15
|
+
server.tool("search_youtube", `Search YouTube and return video results as JSON. Each result includes video ID, title, channel, duration, view count, and upload date. Use when the user asks to find YouTube videos on a topic.`, {
|
|
16
|
+
search: z.string().min(1).max(500)
|
|
17
|
+
.describe("YouTube search query."),
|
|
18
|
+
sort_by: z.enum(["relevance", "date", "view_count", "rating"]).default("relevance")
|
|
19
|
+
.describe("Sort order. Use 'date' for most recent, 'view_count' for most watched."),
|
|
20
|
+
type: z.enum(["video", "channel", "playlist"]).default("video")
|
|
21
|
+
.describe("Result type filter."),
|
|
22
|
+
upload_date: z.enum(["last_hour", "today", "this_week", "this_month", "this_year"]).optional()
|
|
23
|
+
.describe("Filter by upload date. Omit for all time."),
|
|
24
|
+
duration: z.enum(["short", "medium", "long"]).optional()
|
|
25
|
+
.describe("Filter by duration. short=<4min, medium=4-20min, long=>20min."),
|
|
26
|
+
}, async (params) => {
|
|
27
|
+
try {
|
|
28
|
+
const data = await getClient().post("/api/v1/youtube/search", params);
|
|
29
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
return handleApiError(err);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
server.tool("get_youtube_metadata", `Get metadata for a YouTube video by its video ID. Returns title, description, channel, duration, view count, like count, publish date, and thumbnail URLs. Use when the user has a specific video ID or URL and wants details about that video.`, {
|
|
36
|
+
video_id: z.string()
|
|
37
|
+
.describe("YouTube video ID, e.g. 'dQw4w9WgXcQ'. Extract from URL if the user provides a youtube.com link."),
|
|
38
|
+
}, async (params) => {
|
|
39
|
+
try {
|
|
40
|
+
const data = await getClient().post("/api/v1/youtube/metadata", params);
|
|
41
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
return handleApiError(err);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=youtube.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"youtube.js","sourceRoot":"","sources":["../../src/tools/youtube.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@scavio/mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server connecting AI agents to Google, YouTube, Amazon, Walmart, TikTok, and Reddit. 21 tools for web search, product lookup, video discovery, and social media analysis.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Scavio",
|
|
8
|
+
"homepage": "https://github.com/scavio-ai/scavio-mcp#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/scavio-ai/scavio-mcp.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/scavio-ai/scavio-mcp/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"mcp",
|
|
18
|
+
"model-context-protocol",
|
|
19
|
+
"scavio",
|
|
20
|
+
"google",
|
|
21
|
+
"youtube",
|
|
22
|
+
"amazon",
|
|
23
|
+
"walmart",
|
|
24
|
+
"tiktok",
|
|
25
|
+
"reddit",
|
|
26
|
+
"web-search"
|
|
27
|
+
],
|
|
28
|
+
"bin": {
|
|
29
|
+
"scavio-mcp": "./dist/index.js"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"dev": "tsx watch src/index.ts",
|
|
36
|
+
"dev:inspect": "npx @modelcontextprotocol/inspector tsx src/index.ts",
|
|
37
|
+
"build": "tsc",
|
|
38
|
+
"start": "node dist/index.js",
|
|
39
|
+
"typecheck": "tsc --noEmit",
|
|
40
|
+
"prepublishOnly": "npm run build"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=20.0.0"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@hono/node-server": "^1.19.12",
|
|
50
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
51
|
+
"hono": "^4.12.10",
|
|
52
|
+
"zod": "^4.3.6"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/node": "^25.5.2",
|
|
56
|
+
"tsx": "^4.21.0",
|
|
57
|
+
"typescript": "^6.0.2"
|
|
58
|
+
}
|
|
59
|
+
}
|