
Security News
Happy Birthday, Shai-Hulud
It has been one year since Shai-Hulud made its first appearance on npm.
helldivers2-mcp
Advanced tools
A stateless Model Context Protocol (MCP) server that exposes live Helldivers 2 galactic war data to LLMs.
Data is sourced from the community API at api.helldivers2.dev.
| Tool | Description |
|---|---|
get_war_status | Galaxy-wide war statistics (kills by faction, missions won/lost, accuracy, deaths, impact multiplier) and active planets with owner, player count, active events, attack vectors, and region health |
get_assignments | Active Major Orders with title, briefing, decoded task list (faction, difficulty, target planet), current progress numbers, reward type and amount, and time until expiry |
get_all_planets | Full planet list with IDs, names, and sectors |
get_planet_details | Detailed per-planet info: biome, hazards, initial/current owner, health, waypoints, active events, full combat statistics, attacking planets, and regions (up to 5 planets per call) |
get_dispatches | In-game dispatch feed — High Command broadcasts with published date (relative time) and message text; optional limit parameter (default 20, max 50) |
get_steam_news | Steam news for Helldivers 2 with title, URL, publish date (relative time), and full article content; optional limit parameter (default 10, max 30) |
get_space_station_details | DSS details: current host planet (full planet info), time until next election, and active tactical actions with name, description, status, planet effects, and resource costs |
X-Super-Contact header (required by the upstream API)cp .env.example .env # set X_SUPER_CONTACT=your@email.com
npm install
npm run dev # hot-reload via tsx watch on :3000
npm run build # tsc → dist/
npm run start
Image is available on Docker Hub.
docker pull xerno42/helldivers2-mcp # pull from Docker Hub
# or
docker build -t helldivers2-mcp . # build locally
#then run with:
docker run -p 3000:3000 -e X_SUPER_CONTACT=your@email.com helldivers2-mcp
All configuration is via environment variables.
| Variable | Default | Description |
|---|---|---|
X_SUPER_CONTACT | (required) | Forwarded as X-Super-Contact to the upstream API per their usage guidelines |
PORT | 3000 | HTTP port to listen on |
BIND_HOST | 127.0.0.1 | Interface to bind (0.0.0.0 for Docker/containers) |
MCP_ALLOWED_ORIGINS | (unset) | Comma-separated list of allowed browser Origin headers. Unset means browser-originated requests are blocked; server-to-server calls (no Origin header) are always allowed |
MCP_RATE_LIMIT_PER_MIN | 60 | Sustained request rate limit (requests per minute) |
MCP_RATE_LIMIT_BURST | = MCP_RATE_LIMIT_PER_MIN | Burst capacity for the token-bucket rate limiter |
| Method | Path | Description |
|---|---|---|
POST | /mcp | MCP Streamable HTTP transport endpoint |
GET | /health | Liveness check — returns { "ok": true } |
The server uses the stateless Streamable HTTP transport. Each POST /mcp request creates a fresh McpServer + transport pair, handles the request, then tears them down. There is no session state.
Call the MCP server directly over HTTP using the Streamable HTTP transport. Each request is a JSON-RPC tools/call message sent to POST /mcp.
Using the official MCP TypeScript SDK:
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const client = new Client({ name: "my-app", version: "1.0.0" });
const transport = new StreamableHTTPClientTransport(
new URL("https://mcp.avengersofsuperearth.com/mcp")
);
await client.connect(transport);
// List available tools
const { tools } = await client.listTools();
console.log(tools.map((t) => t.name));
// Get current war status
const warStatus = await client.callTool({
name: "get_war_status",
arguments: {},
});
console.log(warStatus.content[0].text);
// Get details for specific planets by index (up to 5)
const planets = await client.callTool({
name: "get_planet_details",
arguments: { planetindices: [57, 153] },
});
console.log(planets.content[0].text);
await client.close();
Without the SDK — raw JSON-RPC over fetch:
async function callTool(name: string, args: Record<string, unknown> = {}) {
const res = await fetch("https://mcp.avengersofsuperearth.com/mcp", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "tools/call",
params: { name, arguments: args },
}),
});
const text = await res.text();
// The response is an SSE frame ("event: message\ndata: {json}\n\n");
// concatenate its data line(s) to recover the JSON-RPC payload.
const json = text
.split("\n")
.filter((line) => line.startsWith("data:"))
.map((line) => line.slice(5).trim())
.join("");
const data = JSON.parse(json);
return data.result.content[0].text;
}
const status = await callTool("get_war_status");
const assignments = await callTool("get_assignments");
const dispatches = await callTool("get_dispatches", { limit: 5 });
const planets = await callTool("get_planet_details", { planetindices: [57, 153] });
Using the official MCP Python SDK:
import asyncio
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
async def main():
async with streamablehttp_client("https://mcp.avengersofsuperearth.com/mcp") as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
# List available tools
tools = await session.list_tools()
print([t.name for t in tools.tools])
# Get current war status
result = await session.call_tool("get_war_status", {})
print(result.content[0].text)
# Get details for specific planets by index (up to 5)
result = await session.call_tool(
"get_planet_details",
{"planetindices": [57, 153]},
)
print(result.content[0].text)
asyncio.run(main())
Without the SDK — raw JSON-RPC over httpx:
import httpx
MCP_URL = "https://mcp.avengersofsuperearth.com/mcp"
def call_tool(name: str, arguments: dict = {}) -> str:
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {"name": name, "arguments": arguments},
}
headers = {
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
}
response = httpx.post(MCP_URL, json=payload, headers=headers)
response.raise_for_status()
import json
# The response is an SSE frame ("event: message\ndata: {json}\n\n");
# concatenate its data line(s) to recover the JSON-RPC payload.
text = "".join(
line[5:].strip()
for line in response.text.splitlines()
if line.startswith("data:")
)
return json.loads(text)["result"]["content"][0]["text"]
status = call_tool("get_war_status")
assignments = call_tool("get_assignments")
planets = call_tool("get_planet_details", {"planetindices": [57, 153]})
A public instance is available at https://mcp.avengersofsuperearth.com/mcp. No setup required — just add it to your claude_desktop_config.json:
{
"mcpServers": {
"helldivers2": {
"url": "https://mcp.avengersofsuperearth.com/mcp"
}
}
}
{
"mcpServers": {
"helldivers2": {
"command": "node",
"args": ["/path/to/helldivers2-mcp/dist/index.js"],
"env": {
"X_SUPER_CONTACT": "your@email.com"
}
}
}
}
{
"mcpServers": {
"helldivers2": {
"url": "http://localhost:3000/mcp"
}
}
}
npm run test # Jest (ESM mode)
npm run test:watch
npm run test:coverage
npm run lint # ESLint
Run a single test file:
npm run test src/__tests__/tools.war.test.ts
src/tools/your-tool.ts and export a Tool object with .definition and .handler.TOOLS array in src/index.ts.textResponse(...) on success or errorResponse(...) on failure — never throw from a handler.hd2Fetch (in-memory 2-minute cache + rate-limit-aware queue).FAQs
MCP server exposing live Helldivers 2 galactic war data.
The npm package helldivers2-mcp receives a total of 11 weekly downloads. As such, helldivers2-mcp popularity was classified as not popular.
We found that helldivers2-mcp demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
It has been one year since Shai-Hulud made its first appearance on npm.

Research
/Security News
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.

Security News
GitHub Actions now supports cache-mode, a least-privilege control on the Actions cache aimed at the cache poisoning technique behind recent compromises.