mcp-server-indexforge 1.0.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 +92 -0
- package/index.js +321 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# mcp-server-indexforge
|
|
2
|
+
|
|
3
|
+
MCP server for [IndexForge](https://indexforge.metaltorque.dev) — gives AI agents the ability to submit URLs to Google and Bing for indexing.
|
|
4
|
+
|
|
5
|
+
Deploy a site, then immediately tell your AI agent to index it. Works with Claude Desktop, Claude Code, Cursor, and any MCP-compatible client.
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
### Claude Desktop
|
|
10
|
+
|
|
11
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"mcpServers": {
|
|
16
|
+
"indexforge": {
|
|
17
|
+
"command": "npx",
|
|
18
|
+
"args": ["-y", "mcp-server-indexforge"],
|
|
19
|
+
"env": {
|
|
20
|
+
"INDEXFORGE_API_KEY": "your-api-key-here"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Claude Code
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
claude mcp add indexforge -- npx -y mcp-server-indexforge
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Set the API key in your environment:
|
|
34
|
+
```bash
|
|
35
|
+
export INDEXFORGE_API_KEY=your-api-key-here
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Tools
|
|
39
|
+
|
|
40
|
+
| Tool | Description |
|
|
41
|
+
|------|-------------|
|
|
42
|
+
| `indexing_status` | Account overview — domains, URLs, indexed, submitted, dead |
|
|
43
|
+
| `list_domains` | List all managed domains with stats |
|
|
44
|
+
| `add_domain` | Add a new domain (optionally with custom sitemap URL) |
|
|
45
|
+
| `remove_domain` | Remove a domain |
|
|
46
|
+
| `scan_sitemap` | Discover new URLs from a domain's sitemap |
|
|
47
|
+
| `submit_urls` | Submit pending URLs to Google + IndexNow |
|
|
48
|
+
| `push_to_index` | Scan + submit in one shot (most common operation) |
|
|
49
|
+
| `check_404s` | Find broken links across all URLs |
|
|
50
|
+
| `check_index_status` | Check which URLs Google has actually indexed |
|
|
51
|
+
| `list_urls` | Paginated URL list with status details |
|
|
52
|
+
| `submission_history` | Recent submission activity |
|
|
53
|
+
|
|
54
|
+
## Usage Examples
|
|
55
|
+
|
|
56
|
+
Once configured, just ask your AI assistant:
|
|
57
|
+
|
|
58
|
+
- "Add example.com and submit all URLs to Google"
|
|
59
|
+
- "Scan my sitemap for new pages and submit them"
|
|
60
|
+
- "Which of my URLs are not indexed yet?"
|
|
61
|
+
- "Check my site for broken links"
|
|
62
|
+
- "Show me my indexing stats"
|
|
63
|
+
- "Push my site to Google" (scan + submit in one shot)
|
|
64
|
+
|
|
65
|
+
### The Deploy → Index Workflow
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
You: "Deploy my site to Vercel and index it"
|
|
69
|
+
|
|
70
|
+
Agent: *deploys to Vercel*
|
|
71
|
+
Agent: *calls add_domain with your domain*
|
|
72
|
+
Agent: *calls push_to_index*
|
|
73
|
+
Agent: "Done. Site deployed and 47 URLs submitted to Google and Bing."
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Environment Variables
|
|
77
|
+
|
|
78
|
+
| Variable | Description |
|
|
79
|
+
|----------|-------------|
|
|
80
|
+
| `INDEXFORGE_API_KEY` | API key (required — get one at indexforge.metaltorque.dev) |
|
|
81
|
+
| `INDEXFORGE_URL` | Server URL (default: `https://indexforge.metaltorque.dev`) |
|
|
82
|
+
|
|
83
|
+
## Pricing
|
|
84
|
+
|
|
85
|
+
| Plan | Price | Domains | URLs/Domain |
|
|
86
|
+
|------|-------|---------|-------------|
|
|
87
|
+
| Free | $0/yr | 1 | 50 |
|
|
88
|
+
| Starter | $99/yr | 5 | 500 |
|
|
89
|
+
| Pro | $199/yr | 25 | 5,000 |
|
|
90
|
+
| Business | $499/yr | 100 | 50,000 |
|
|
91
|
+
|
|
92
|
+
Sign up at [indexforge.metaltorque.dev](https://indexforge.metaltorque.dev)
|
package/index.js
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { McpServer } = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
4
|
+
const { StdioServerTransport } = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
5
|
+
const { z } = require("zod");
|
|
6
|
+
const https = require("https");
|
|
7
|
+
const http = require("http");
|
|
8
|
+
|
|
9
|
+
// ── Config ──────────────────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
const API_KEY = process.env.INDEXFORGE_API_KEY || "";
|
|
12
|
+
const BASE_URL = (process.env.INDEXFORGE_URL || "https://indexforge.metaltorque.dev").replace(/\/$/, "");
|
|
13
|
+
|
|
14
|
+
// ── HTTP helper ─────────────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
function request(method, urlPath, body, timeout = 120_000) {
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
if (!API_KEY) return reject(new Error("INDEXFORGE_API_KEY environment variable is required. Sign up at https://indexforge.metaltorque.dev"));
|
|
19
|
+
|
|
20
|
+
const sep = urlPath.includes("?") ? "&" : "?";
|
|
21
|
+
const fullPath = `${urlPath}${sep}apiKey=${API_KEY}`;
|
|
22
|
+
const fullUrl = `${BASE_URL}${fullPath}`;
|
|
23
|
+
const mod = fullUrl.startsWith("https") ? https : http;
|
|
24
|
+
const parsed = new URL(fullUrl);
|
|
25
|
+
|
|
26
|
+
const opts = {
|
|
27
|
+
hostname: parsed.hostname,
|
|
28
|
+
port: parsed.port || (parsed.protocol === "https:" ? 443 : 80),
|
|
29
|
+
path: parsed.pathname + parsed.search,
|
|
30
|
+
method,
|
|
31
|
+
headers: { "Content-Type": "application/json", "User-Agent": "mcp-server-indexforge/1.0.0" },
|
|
32
|
+
timeout,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const req = mod.request(opts, (res) => {
|
|
36
|
+
let data = "";
|
|
37
|
+
res.on("data", (c) => (data += c));
|
|
38
|
+
res.on("end", () => {
|
|
39
|
+
try {
|
|
40
|
+
const json = JSON.parse(data);
|
|
41
|
+
if (res.statusCode >= 400) return reject(new Error(json.error || `HTTP ${res.statusCode}`));
|
|
42
|
+
resolve(json);
|
|
43
|
+
} catch {
|
|
44
|
+
if (res.statusCode >= 400) return reject(new Error(`HTTP ${res.statusCode}: ${data.slice(0, 300)}`));
|
|
45
|
+
resolve(data);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
req.on("error", reject);
|
|
51
|
+
req.on("timeout", () => { req.destroy(); reject(new Error("Request timed out")); });
|
|
52
|
+
if (body) req.write(JSON.stringify(body));
|
|
53
|
+
req.end();
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function noKeyError() {
|
|
58
|
+
return {
|
|
59
|
+
content: [{ type: "text", text: "Error: INDEXFORGE_API_KEY environment variable is required.\n\nSign up at https://indexforge.metaltorque.dev to get an API key.\nFree plan: 1 domain, 50 URLs." }],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ── MCP Server ──────────────────────────────────────────────────────
|
|
64
|
+
|
|
65
|
+
const server = new McpServer({
|
|
66
|
+
name: "indexforge",
|
|
67
|
+
version: "1.0.0",
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// ── Tool: indexing_status ───────────────────────────────────────────
|
|
71
|
+
|
|
72
|
+
server.tool(
|
|
73
|
+
"indexing_status",
|
|
74
|
+
"Get an overview of your IndexForge account — total domains, URLs, how many are indexed, how many are submitted, and how many are dead (404). Also shows your current plan and limits.",
|
|
75
|
+
{},
|
|
76
|
+
async () => {
|
|
77
|
+
if (!API_KEY) return noKeyError();
|
|
78
|
+
try {
|
|
79
|
+
const result = await request("GET", "/api/stats");
|
|
80
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
81
|
+
} catch (e) {
|
|
82
|
+
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// ── Tool: list_domains ──────────────────────────────────────────────
|
|
88
|
+
|
|
89
|
+
server.tool(
|
|
90
|
+
"list_domains",
|
|
91
|
+
"List all domains managed in your IndexForge account with their URL counts, indexing stats, and last scan dates.",
|
|
92
|
+
{},
|
|
93
|
+
async () => {
|
|
94
|
+
if (!API_KEY) return noKeyError();
|
|
95
|
+
try {
|
|
96
|
+
const result = await request("GET", "/api/domains");
|
|
97
|
+
const summary = result.map((d) => ({
|
|
98
|
+
id: d.id,
|
|
99
|
+
domain: d.domain,
|
|
100
|
+
sitemapUrl: d.sitemapUrl,
|
|
101
|
+
totalUrls: d.urlCount || d.stats?.totalUrls || 0,
|
|
102
|
+
indexed: d.stats?.indexed || 0,
|
|
103
|
+
submitted: d.stats?.submitted || 0,
|
|
104
|
+
dead: d.stats?.dead || 0,
|
|
105
|
+
lastScan: d.lastScan,
|
|
106
|
+
lastSubmission: d.lastSubmission,
|
|
107
|
+
}));
|
|
108
|
+
return { content: [{ type: "text", text: JSON.stringify(summary, null, 2) }] };
|
|
109
|
+
} catch (e) {
|
|
110
|
+
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
// ── Tool: add_domain ────────────────────────────────────────────────
|
|
116
|
+
|
|
117
|
+
server.tool(
|
|
118
|
+
"add_domain",
|
|
119
|
+
"Add a new domain to IndexForge for indexing management. Optionally provide a custom sitemap URL (defaults to /sitemap.xml). Returns the domain ID needed for other operations.",
|
|
120
|
+
{
|
|
121
|
+
domain: z.string().describe("The domain to add (e.g. 'example.com')"),
|
|
122
|
+
sitemap_url: z.string().optional().describe("Custom sitemap URL (default: https://domain/sitemap.xml)"),
|
|
123
|
+
},
|
|
124
|
+
async ({ domain, sitemap_url }) => {
|
|
125
|
+
if (!API_KEY) return noKeyError();
|
|
126
|
+
try {
|
|
127
|
+
const result = await request("POST", "/api/domains", { domain, sitemapUrl: sitemap_url });
|
|
128
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
129
|
+
} catch (e) {
|
|
130
|
+
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// ── Tool: remove_domain ─────────────────────────────────────────────
|
|
136
|
+
|
|
137
|
+
server.tool(
|
|
138
|
+
"remove_domain",
|
|
139
|
+
"Remove a domain from IndexForge. Use list_domains first to get the domain ID.",
|
|
140
|
+
{
|
|
141
|
+
domain_id: z.string().describe("The domain ID to remove"),
|
|
142
|
+
},
|
|
143
|
+
async ({ domain_id }) => {
|
|
144
|
+
if (!API_KEY) return noKeyError();
|
|
145
|
+
try {
|
|
146
|
+
await request("DELETE", `/api/domains/${domain_id}`);
|
|
147
|
+
return { content: [{ type: "text", text: "Domain removed successfully." }] };
|
|
148
|
+
} catch (e) {
|
|
149
|
+
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
// ── Tool: scan_sitemap ──────────────────────────────────────────────
|
|
155
|
+
|
|
156
|
+
server.tool(
|
|
157
|
+
"scan_sitemap",
|
|
158
|
+
"Scan a domain's sitemap to discover new URLs. This fetches and parses the sitemap XML (including gzipped and sitemap index files) and adds any new URLs to the domain. Run this after deploying new content.",
|
|
159
|
+
{
|
|
160
|
+
domain_id: z.string().describe("The domain ID to scan (use list_domains to find it)"),
|
|
161
|
+
},
|
|
162
|
+
async ({ domain_id }) => {
|
|
163
|
+
if (!API_KEY) return noKeyError();
|
|
164
|
+
try {
|
|
165
|
+
const result = await request("POST", `/api/domains/${domain_id}/scan`);
|
|
166
|
+
return { content: [{ type: "text", text: `Scan complete. Found ${result.added} new URLs (${result.total} total).` }] };
|
|
167
|
+
} catch (e) {
|
|
168
|
+
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
// ── Tool: submit_urls ───────────────────────────────────────────────
|
|
174
|
+
|
|
175
|
+
server.tool(
|
|
176
|
+
"submit_urls",
|
|
177
|
+
"Submit pending URLs to Google (via Indexing API, 200/day limit) and to Bing/Yandex/10+ search engines (via IndexNow, unlimited). Only submits URLs that haven't been submitted yet or that need resubmission.",
|
|
178
|
+
{
|
|
179
|
+
domain_id: z.string().describe("The domain ID to submit URLs for"),
|
|
180
|
+
},
|
|
181
|
+
async ({ domain_id }) => {
|
|
182
|
+
if (!API_KEY) return noKeyError();
|
|
183
|
+
try {
|
|
184
|
+
const result = await request("POST", `/api/domains/${domain_id}/submit`);
|
|
185
|
+
const g = result.results?.google || [];
|
|
186
|
+
const n = result.results?.indexNow || [];
|
|
187
|
+
const gSuccess = g.reduce((s, b) => s + (b.success || 0), 0);
|
|
188
|
+
const gTotal = g.reduce((s, b) => s + (b.total || 0), 0);
|
|
189
|
+
const nTotal = n.reduce((s, b) => s + (b.total || 0), 0);
|
|
190
|
+
return { content: [{ type: "text", text: `Submission complete.\nGoogle: ${gSuccess}/${gTotal} URLs submitted\nIndexNow: ${nTotal} URLs submitted to Bing, Yandex, and 10+ engines` }] };
|
|
191
|
+
} catch (e) {
|
|
192
|
+
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
// ── Tool: check_404s ────────────────────────────────────────────────
|
|
198
|
+
|
|
199
|
+
server.tool(
|
|
200
|
+
"check_404s",
|
|
201
|
+
"Check all URLs in a domain for broken links (404s). Sends HEAD requests to every URL and categorizes them as live, redirect, dead, or error.",
|
|
202
|
+
{
|
|
203
|
+
domain_id: z.string().describe("The domain ID to check"),
|
|
204
|
+
},
|
|
205
|
+
async ({ domain_id }) => {
|
|
206
|
+
if (!API_KEY) return noKeyError();
|
|
207
|
+
try {
|
|
208
|
+
const result = await request("POST", `/api/domains/${domain_id}/check`);
|
|
209
|
+
const st = result.stats || result;
|
|
210
|
+
return { content: [{ type: "text", text: `404 check complete.\nLive: ${st.live || 0}\nRedirect: ${st.redirect || 0}\nDead (404): ${st.dead || 0}\nErrors: ${st.errors || 0}` }] };
|
|
211
|
+
} catch (e) {
|
|
212
|
+
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
// ── Tool: check_index_status ────────────────────────────────────────
|
|
218
|
+
|
|
219
|
+
server.tool(
|
|
220
|
+
"check_index_status",
|
|
221
|
+
"Check which URLs are actually indexed by Google using the URL Inspection API (requires Google service account credentials uploaded for this domain).",
|
|
222
|
+
{
|
|
223
|
+
domain_id: z.string().describe("The domain ID to inspect"),
|
|
224
|
+
},
|
|
225
|
+
async ({ domain_id }) => {
|
|
226
|
+
if (!API_KEY) return noKeyError();
|
|
227
|
+
try {
|
|
228
|
+
const result = await request("POST", `/api/domains/${domain_id}/inspect`);
|
|
229
|
+
return { content: [{ type: "text", text: `Index status check complete.\nChecked: ${result.checked}\nIndexed: ${result.indexed}\nNot indexed: ${result.notIndexed}${result.errors ? `\nErrors: ${result.errors}` : ""}` }] };
|
|
230
|
+
} catch (e) {
|
|
231
|
+
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
// ── Tool: list_urls ─────────────────────────────────────────────────
|
|
237
|
+
|
|
238
|
+
server.tool(
|
|
239
|
+
"list_urls",
|
|
240
|
+
"List URLs for a domain with their submission status, index status, and HTTP status. Paginated — use page and limit parameters for large domains.",
|
|
241
|
+
{
|
|
242
|
+
domain_id: z.string().describe("The domain ID"),
|
|
243
|
+
page: z.number().default(1).describe("Page number (default: 1)"),
|
|
244
|
+
limit: z.number().default(50).describe("URLs per page (default: 50, max: 500)"),
|
|
245
|
+
},
|
|
246
|
+
async ({ domain_id, page, limit }) => {
|
|
247
|
+
if (!API_KEY) return noKeyError();
|
|
248
|
+
try {
|
|
249
|
+
const result = await request("GET", `/api/domains/${domain_id}/urls?page=${page}&limit=${limit}`);
|
|
250
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
251
|
+
} catch (e) {
|
|
252
|
+
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
// ── Tool: push_to_index (scan + submit combo) ──────────────────────
|
|
258
|
+
|
|
259
|
+
server.tool(
|
|
260
|
+
"push_to_index",
|
|
261
|
+
"One-shot command: scan the sitemap for new URLs, then immediately submit everything to Google and IndexNow. Use this after deploying a website or publishing new content. This is the most common operation.",
|
|
262
|
+
{
|
|
263
|
+
domain_id: z.string().describe("The domain ID to push"),
|
|
264
|
+
},
|
|
265
|
+
async ({ domain_id }) => {
|
|
266
|
+
if (!API_KEY) return noKeyError();
|
|
267
|
+
try {
|
|
268
|
+
const scanResult = await request("POST", `/api/domains/${domain_id}/scan`);
|
|
269
|
+
|
|
270
|
+
const submitResult = await request("POST", `/api/domains/${domain_id}/submit`);
|
|
271
|
+
const g = submitResult.results?.google || [];
|
|
272
|
+
const n = submitResult.results?.indexNow || [];
|
|
273
|
+
const gSuccess = g.reduce((s, b) => s + (b.success || 0), 0);
|
|
274
|
+
const nTotal = n.reduce((s, b) => s + (b.total || 0), 0);
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
content: [{
|
|
278
|
+
type: "text",
|
|
279
|
+
text: `Push complete!\n\nSitemap scan: ${scanResult.added} new URLs found (${scanResult.total} total)\nGoogle: ${gSuccess} URLs submitted\nIndexNow: ${nTotal} URLs submitted to Bing, Yandex, and 10+ engines`,
|
|
280
|
+
}],
|
|
281
|
+
};
|
|
282
|
+
} catch (e) {
|
|
283
|
+
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
// ── Tool: submission_history ────────────────────────────────────────
|
|
289
|
+
|
|
290
|
+
server.tool(
|
|
291
|
+
"submission_history",
|
|
292
|
+
"View recent submission history — which domains were submitted, how many URLs went to Google vs IndexNow, and when.",
|
|
293
|
+
{},
|
|
294
|
+
async () => {
|
|
295
|
+
if (!API_KEY) return noKeyError();
|
|
296
|
+
try {
|
|
297
|
+
const result = await request("GET", "/api/submissions");
|
|
298
|
+
const summary = result.slice(0, 20).map((s) => ({
|
|
299
|
+
domain: s.domain,
|
|
300
|
+
googleSuccess: (s.google || []).reduce((a, b) => a + (b.success || 0), 0),
|
|
301
|
+
indexNowTotal: (s.indexNow || []).reduce((a, b) => a + (b.total || 0), 0),
|
|
302
|
+
timestamp: s.timestamp,
|
|
303
|
+
}));
|
|
304
|
+
return { content: [{ type: "text", text: JSON.stringify(summary, null, 2) }] };
|
|
305
|
+
} catch (e) {
|
|
306
|
+
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
// ── Start ───────────────────────────────────────────────────────────
|
|
312
|
+
|
|
313
|
+
async function main() {
|
|
314
|
+
const transport = new StdioServerTransport();
|
|
315
|
+
await server.connect(transport);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
main().catch((e) => {
|
|
319
|
+
console.error("MCP server error:", e);
|
|
320
|
+
process.exit(1);
|
|
321
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mcp-server-indexforge",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for IndexForge — gives AI agents the ability to submit URLs to Google and Bing for indexing, scan sitemaps, check index status, and detect 404s.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"mcp-server-indexforge": "index.js"
|
|
7
|
+
},
|
|
8
|
+
"keywords": [
|
|
9
|
+
"mcp",
|
|
10
|
+
"seo",
|
|
11
|
+
"indexing",
|
|
12
|
+
"google",
|
|
13
|
+
"indexnow",
|
|
14
|
+
"sitemap",
|
|
15
|
+
"ai",
|
|
16
|
+
"agent",
|
|
17
|
+
"claude",
|
|
18
|
+
"llm"
|
|
19
|
+
],
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"author": "MetalTorque",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/joepangallo/index-forge"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@modelcontextprotocol/sdk": "^1.27.0"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=18"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"index.js",
|
|
34
|
+
"README.md"
|
|
35
|
+
]
|
|
36
|
+
}
|