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 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
+ [![npm version](https://img.shields.io/npm/v/mcp-server-auction)](https://www.npmjs.com/package/mcp-server-auction)
6
+ [![CI](https://github.com/raws-labs/mcp-server-auction/actions/workflows/ci.yml/badge.svg)](https://github.com/raws-labs/mcp-server-auction/actions/workflows/ci.yml)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](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);
@@ -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.0",
4
- "description": "MCP server for European dedicated server auctions and listings",
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
  }