mcp-server-auction 0.2.0 → 0.2.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/README.md +106 -0
- package/build/providers/hetzner.js +7 -7
- package/build/providers/ovh.js +7 -7
- package/package.json +5 -3
package/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# MCP Server Auction
|
|
2
|
+
|
|
3
|
+
MCP server for dedicated server auctions and listings. Enables LLMs to search, filter, and analyze real-time dedicated server listings from multiple providers through a unified interface.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/mcp-server-auction)
|
|
6
|
+
[](https://github.com/raws-labs/mcp-server-auction/actions/workflows/ci.yml)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Multi-provider** — Hetzner Server Auction + OVH ECO in a single interface
|
|
12
|
+
- **14+ filter parameters** — price, RAM, disk type/size/count, CPU vendor/model/cores, ECC, GPU, datacenter, bandwidth, and more
|
|
13
|
+
- **Real-time data** — fetches live listings directly from provider APIs
|
|
14
|
+
- **No auth required** — all upstream APIs are public
|
|
15
|
+
- **Stdio transport** — works with any MCP-compatible client
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g mcp-server-auction
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or run directly with npx:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx mcp-server-auction
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Configuration
|
|
30
|
+
|
|
31
|
+
The server communicates over stdio using the Model Context Protocol. Point your MCP client at the binary:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
mcp-server-auction
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Tools
|
|
38
|
+
|
|
39
|
+
### `search_auctions`
|
|
40
|
+
|
|
41
|
+
Search and filter dedicated server auction listings by price, RAM, disk, CPU, datacenter, GPU, bandwidth, and more.
|
|
42
|
+
|
|
43
|
+
| Parameter | Type | Description |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| `provider` | `"hetzner" \| "ovh" \| "all"` | Provider filter (default: `"all"`) |
|
|
46
|
+
| `max_price` | `number` | Maximum monthly price in EUR |
|
|
47
|
+
| `min_ram` | `number` | Minimum RAM in GB |
|
|
48
|
+
| `min_disk_size` | `number` | Minimum total disk capacity in GB |
|
|
49
|
+
| `min_disk_count` | `number` | Minimum number of disks |
|
|
50
|
+
| `disk_type` | `"ssd" \| "nvme" \| "hdd" \| "any"` | Filter by disk type (`ssd` matches both SATA SSD and NVMe) |
|
|
51
|
+
| `cpu_vendor` | `"intel" \| "amd" \| "any"` | CPU vendor filter |
|
|
52
|
+
| `cpu_search` | `string` | Free-text search within CPU model name (e.g. `"EPYC 7502"`, `"Xeon E5"`) |
|
|
53
|
+
| `min_cpu_count` | `number` | Minimum CPU/socket count |
|
|
54
|
+
| `min_cores` | `number` | Minimum total CPU cores (accounts for multi-socket) |
|
|
55
|
+
| `ecc` | `boolean` | Require ECC RAM |
|
|
56
|
+
| `datacenter` | `string` | Datacenter filter (e.g. `FSN`, `NBG`, `HEL`, `FRA`, `GRA`) |
|
|
57
|
+
| `gpu` | `boolean` | Require GPU |
|
|
58
|
+
| `min_bandwidth` | `number` | Minimum bandwidth in Mbit (e.g. `1000` = 1 Gbit) |
|
|
59
|
+
| `fixed_price` | `boolean` | `true` = fixed price only, `false` = auction only |
|
|
60
|
+
| `max_setup_price` | `number` | Maximum setup price in EUR (use `0` for no setup fee) |
|
|
61
|
+
| `highio` | `boolean` | Require high I/O hardware |
|
|
62
|
+
| `sort_by` | `"price" \| "ram" \| "disk_size" \| "cpu" \| "cores"` | Sort field (default: `"price"`) |
|
|
63
|
+
| `limit` | `number` | Max results, 1–50 (default: `10`) |
|
|
64
|
+
|
|
65
|
+
### `get_auction_stats`
|
|
66
|
+
|
|
67
|
+
Get aggregate statistics about current server auction listings: provider breakdown, price range, CPU vendor split, datacenter distribution, RAM tiers, GPU/ECC counts.
|
|
68
|
+
|
|
69
|
+
| Parameter | Type | Description |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| `provider` | `"hetzner" \| "ovh" \| "all"` | Provider filter (default: `"all"`) |
|
|
72
|
+
|
|
73
|
+
### `get_auction_server`
|
|
74
|
+
|
|
75
|
+
Get full details of a specific auction server by its ID.
|
|
76
|
+
|
|
77
|
+
| Parameter | Type | Description |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| `server_id` | `string` | The server ID (numeric for Hetzner, FQN for OVH) |
|
|
80
|
+
| `provider` | `"hetzner" \| "ovh" \| "all"` | Provider filter (default: `"all"`) |
|
|
81
|
+
|
|
82
|
+
## Providers
|
|
83
|
+
|
|
84
|
+
| Provider | Regions | Pricing | Auth |
|
|
85
|
+
|---|---|---|---|
|
|
86
|
+
| **Hetzner** | FSN, NBG (Germany), HEL (Finland) | Auction + fixed | None |
|
|
87
|
+
| **OVH ECO** | FRA (Germany), GRA, RBX, SBG (France), LON (UK), WAW (Poland), BHS (Canada) | Fixed | None |
|
|
88
|
+
|
|
89
|
+
## Development
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npm install # install dependencies
|
|
93
|
+
npm run build # compile TypeScript → build/
|
|
94
|
+
npm start # run the server (stdio)
|
|
95
|
+
npm test # run tests
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Inspect interactively with the MCP Inspector:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npx @modelcontextprotocol/inspector build/index.js
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
[MIT](LICENSE)
|
|
@@ -39,7 +39,7 @@ function getCountry(dc) {
|
|
|
39
39
|
return "FI";
|
|
40
40
|
return "DE";
|
|
41
41
|
}
|
|
42
|
-
function buildDisks(d) {
|
|
42
|
+
export function buildDisks(d) {
|
|
43
43
|
const disks = [];
|
|
44
44
|
const addGroup = (sizes, type) => {
|
|
45
45
|
const groups = new Map();
|
|
@@ -56,7 +56,7 @@ function buildDisks(d) {
|
|
|
56
56
|
addGroup(d.general, "unknown");
|
|
57
57
|
return disks;
|
|
58
58
|
}
|
|
59
|
-
function normalizeServer(server, cores) {
|
|
59
|
+
export function normalizeServer(server, cores) {
|
|
60
60
|
const disks = buildDisks(server.serverDiskData);
|
|
61
61
|
return {
|
|
62
62
|
id: String(server.id),
|
|
@@ -93,7 +93,7 @@ function normalizeServer(server, cores) {
|
|
|
93
93
|
// ---------- CPU core resolution ----------
|
|
94
94
|
// Hetzner doesn't include core counts in its API, so we resolve them
|
|
95
95
|
// via a static lookup table + GitHub CSV fallback.
|
|
96
|
-
const KNOWN_CORES = {
|
|
96
|
+
export const KNOWN_CORES = {
|
|
97
97
|
"AMD EPYC 7401P": 24,
|
|
98
98
|
"AMD EPYC 7502": 32,
|
|
99
99
|
"AMD EPYC 7502P": 32,
|
|
@@ -124,19 +124,19 @@ const KNOWN_CORES = {
|
|
|
124
124
|
"Intel Xeon W-2295": 18,
|
|
125
125
|
"Intel Xeon Gold 5412U": 24,
|
|
126
126
|
};
|
|
127
|
-
function normaliseCpuName(name) {
|
|
127
|
+
export function normaliseCpuName(name) {
|
|
128
128
|
return name
|
|
129
129
|
.replace(/[®™]/g, "")
|
|
130
130
|
.replace(/\s+/g, " ")
|
|
131
131
|
.trim()
|
|
132
132
|
.toLowerCase();
|
|
133
133
|
}
|
|
134
|
-
function extractModelToken(name) {
|
|
134
|
+
export function extractModelToken(name) {
|
|
135
135
|
const cleaned = normaliseCpuName(name);
|
|
136
136
|
const m = cleaned.match(/(?:i[3579]-\d{4,5}[a-z]*|e[35]-\d{4}\s*v?\d*|e-\d{4}[a-z]*|w-\d{4,5}[a-z]*|gold \d{4}[a-z]*|epyc \d{4}[a-z]*|ryzen \d+ (?:pro )?\d{4}[a-z]*|threadripper \d{4,5}[a-z]*)/);
|
|
137
137
|
return m ? m[0] : null;
|
|
138
138
|
}
|
|
139
|
-
function parseCsvRow(line) {
|
|
139
|
+
export function parseCsvRow(line) {
|
|
140
140
|
const fields = [];
|
|
141
141
|
let current = "";
|
|
142
142
|
let inQuotes = false;
|
|
@@ -216,7 +216,7 @@ async function fetchCsvCoreMap() {
|
|
|
216
216
|
csvCache = { map, timestamp: Date.now() };
|
|
217
217
|
return map;
|
|
218
218
|
}
|
|
219
|
-
async function resolveCpuCores(cpuName) {
|
|
219
|
+
export async function resolveCpuCores(cpuName) {
|
|
220
220
|
if (cpuName in KNOWN_CORES)
|
|
221
221
|
return KNOWN_CORES[cpuName];
|
|
222
222
|
const norm = normaliseCpuName(cpuName);
|
package/build/providers/ovh.js
CHANGED
|
@@ -40,14 +40,14 @@ const DC_COUNTRY = {
|
|
|
40
40
|
waw: "PL",
|
|
41
41
|
bhs: "CA",
|
|
42
42
|
};
|
|
43
|
-
function dcToCountry(dc) {
|
|
43
|
+
export function dcToCountry(dc) {
|
|
44
44
|
const prefix = dc.replace(/\d+$/, "").toLowerCase();
|
|
45
45
|
return DC_COUNTRY[prefix] ?? "FR";
|
|
46
46
|
}
|
|
47
|
-
function dcToRegion(dc) {
|
|
47
|
+
export function dcToRegion(dc) {
|
|
48
48
|
return dc.replace(/\d+$/, "").toUpperCase();
|
|
49
49
|
}
|
|
50
|
-
function parseMemoryCode(code) {
|
|
50
|
+
export function parseMemoryCode(code) {
|
|
51
51
|
// e.g. "ram-32g-ecc-3200", "ram-64g-noecc-2400"
|
|
52
52
|
const match = code.match(/ram-(\d+)g/i);
|
|
53
53
|
if (!match)
|
|
@@ -57,7 +57,7 @@ function parseMemoryCode(code) {
|
|
|
57
57
|
is_ecc: code.toLowerCase().includes("ecc") && !code.toLowerCase().includes("noecc"),
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
|
-
function parseStorageCode(code) {
|
|
60
|
+
export function parseStorageCode(code) {
|
|
61
61
|
// e.g. "softraid-2x512nvme", "softraid-2x2000sa", "softraid-4x960ssd"
|
|
62
62
|
// Also handle "raid" variants: "raid1-2x512nvme"
|
|
63
63
|
const match = code.match(/(\d+)x(\d+)(nvme|ssd|sa|hdd)/i);
|
|
@@ -74,7 +74,7 @@ function parseStorageCode(code) {
|
|
|
74
74
|
return [{ count, size_gb: size, type }];
|
|
75
75
|
}
|
|
76
76
|
// ---------- Price normalization ----------
|
|
77
|
-
function extractMonthlyPrice(plan) {
|
|
77
|
+
export function extractMonthlyPrice(plan) {
|
|
78
78
|
// Look for monthly renew pricing
|
|
79
79
|
const renew = plan.pricings.find((p) => p.capacities.includes("renew") && (p.interval === 1 || p.interval === undefined));
|
|
80
80
|
if (!renew)
|
|
@@ -86,7 +86,7 @@ function extractMonthlyPrice(plan) {
|
|
|
86
86
|
return renew.price / 100;
|
|
87
87
|
return priceEur;
|
|
88
88
|
}
|
|
89
|
-
function extractSetupPrice(plan) {
|
|
89
|
+
export function extractSetupPrice(plan) {
|
|
90
90
|
const install = plan.pricings.find((p) => p.capacities.includes("installation"));
|
|
91
91
|
if (!install)
|
|
92
92
|
return 0;
|
|
@@ -96,7 +96,7 @@ function extractSetupPrice(plan) {
|
|
|
96
96
|
return priceEur;
|
|
97
97
|
}
|
|
98
98
|
// ---------- Normalization ----------
|
|
99
|
-
function buildListing(entry, cpuInfo, pricing, planName, availableDcs) {
|
|
99
|
+
export function buildListing(entry, cpuInfo, pricing, planName, availableDcs) {
|
|
100
100
|
const mem = parseMemoryCode(entry.memory);
|
|
101
101
|
const disks = parseStorageCode(entry.storage);
|
|
102
102
|
const cpuName = cpuInfo
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-server-auction",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "MCP server for
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "MCP server for dedicated server auctions and listings",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/index.js",
|
|
7
7
|
"bin": {
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"scripts": {
|
|
14
14
|
"build": "tsc",
|
|
15
15
|
"start": "node build/index.js",
|
|
16
|
+
"test": "vitest run",
|
|
16
17
|
"prepublishOnly": "npm run build"
|
|
17
18
|
},
|
|
18
19
|
"keywords": [
|
|
@@ -37,7 +38,8 @@
|
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
39
40
|
"typescript": "^5.8.3",
|
|
40
|
-
"@types/node": "^22.15.3"
|
|
41
|
+
"@types/node": "^22.15.3",
|
|
42
|
+
"vitest": "^3.1.0"
|
|
41
43
|
},
|
|
42
44
|
"license": "MIT"
|
|
43
45
|
}
|