KS
Killer-Skills

eve-esi-api — Categories.community

v1.0.0
GitHub

About this Skill

Perfect for Gaming Agents needing advanced EVE Online data analysis and ESI API integration capabilities. zk-activity is a bot that integrates EVE Online's Zkillboard with Discord, providing real-time killmail updates with customizable filters. Track specific regions, ship categories, and player activities according to your preferences.

ocn ocn
[0]
[0]
Updated: 3/4/2026

Quality Score

Top 5%
54
Excellent
Based on code quality & docs
Installation
SYS Universal Install (Auto-Detect)
Cursor IDE Windsurf IDE VS Code IDE
> npx killer-skills add ocn/zk-activity/eve-esi-api

Agent Capability Analysis

The eve-esi-api MCP Server by ocn is an open-source Categories.community integration for Claude and other AI agents, enabling seamless task automation and capability expansion.

Ideal Agent Persona

Perfect for Gaming Agents needing advanced EVE Online data analysis and ESI API integration capabilities.

Core Value

Empowers agents to fetch character, system, and ship data from the EVE Online ESI API, process killmail data from zkillboard, and implement ESI authentication using SSO, all while working with EVE-specific IDs and data structures.

Capabilities Granted for eve-esi-api MCP Server

Fetching data from the ESI API for real-time killmail updates
Processing killmail data from zkillboard for customizable filters
Implementing ESI authentication using SSO for secure agent interactions

! Prerequisites & Limits

  • Requires ESI API access and authentication
  • Limited to EVE Online data and zkillboard feeds
  • Needs caching mechanisms for efficient EVE universe data handling
Project
SKILL.md
10.3 KB
.cursorrules
1.2 KB
package.json
240 B
Ready
UTF-8

# Tags

[No tags]
SKILL.md
Readonly

EVE Online ESI API Guidelines

Purpose

Patterns for interacting with the EVE Online ESI API and zkillboard data feeds in this project.

When to Use

  • Fetching data from ESI (characters, systems, ships, etc.)
  • Processing killmail data from zkillboard
  • Implementing ESI authentication (SSO)
  • Caching EVE universe data
  • Working with EVE-specific IDs and data structures

Key URLs and Endpoints

ServiceBase URLPurpose
ESIhttps://esi.evetech.net/latest/Official EVE API
zkillboard RedisQhttps://zkillredisq.stream/listen.phpReal-time killmail feed
zkillboardhttps://zkillboard.com/Killmail browser
Fuzzworkhttps://www.fuzzwork.co.uk/api/Third-party celestial data
EVE SSOhttps://login.eveonline.com/OAuth authentication
EVE Imageshttps://images.evetech.net/Character/ship/alliance icons

ESI Client Pattern

Basic Structure

rust
1pub struct EsiClient { 2 client: Client, // reqwest::Client 3} 4 5impl EsiClient { 6 pub fn new() -> Self { 7 EsiClient { 8 client: Client::new(), 9 } 10 } 11 12 async fn fetch<T: for<'de> Deserialize<'de>>( 13 &self, 14 path: &str, 15 ) -> Result<T, Box<dyn Error + Send + Sync>> { 16 let url = format!("{}{}", ESI_URL, path); 17 let response = self.client.get(&url).send().await?; 18 if !response.status().is_success() { 19 return Err(format!("ESI API returned status: {}", response.status()).into()); 20 } 21 let data: T = response.json().await?; 22 Ok(data) 23 } 24}

Common ESI Endpoints

rust
1// Get system info 2pub async fn get_system(&self, system_id: u32) -> Result<System, Error> { 3 self.fetch(&format!("universe/systems/{}/", system_id)).await 4} 5 6// Get ship/item group 7pub async fn get_ship_group_id(&self, type_id: u32) -> Result<u32, Error> { 8 #[derive(Deserialize)] 9 struct EsiType { group_id: u32 } 10 let type_info: EsiType = self.fetch(&format!("universe/types/{}/", type_id)).await?; 11 Ok(type_info.group_id) 12} 13 14// Get names (POST endpoint) 15pub async fn get_name(&self, id: u64) -> Result<String, Error> { 16 let names: Vec<EsiName> = self.client 17 .post(format!("{}universe/names/", ESI_URL)) 18 .json(&[id]) // Array of IDs 19 .send() 20 .await? 21 .json() 22 .await?; 23 Ok(names.into_iter().next()?.name) 24} 25 26// Get character affiliation (POST endpoint) 27pub async fn get_character_affiliation(&self, character_id: u64) 28 -> Result<(u64, Option<u64>), Error> // (corp_id, alliance_id) 29{ 30 let affiliations: Vec<Affiliation> = self.client 31 .post(format!("{}characters/affiliation/", ESI_URL)) 32 .json(&[character_id]) 33 .send() 34 .await? 35 .json() 36 .await?; 37 let a = affiliations.into_iter().next()?; 38 Ok((a.corporation_id, a.alliance_id)) 39}

zkillboard RedisQ

Listener Pattern

rust
1const REDISQ_URL: &str = "https://zkillredisq.stream/listen.php"; 2 3pub struct RedisQListener { 4 client: Client, 5 url: String, 6} 7 8impl RedisQListener { 9 pub fn new(queue_id: &str) -> Self { 10 // Each listener needs a unique queue ID 11 let url = format!("{}?queueID={}", REDISQ_URL, queue_id); 12 RedisQListener { 13 client: Client::new(), 14 url, 15 } 16 } 17 18 pub async fn listen(&self) -> Result<Option<ZkData>, Error> { 19 let response = self.client.get(&self.url) 20 .timeout(Duration::from_secs(60)) // Long-polling 21 .send() 22 .await?; 23 24 let wrapper: RedisQResponse = response.json().await?; 25 Ok(wrapper.package) // None if no new killmails 26 } 27}

Main Loop Pattern

rust
1loop { 2 match listener.listen().await { 3 Ok(Some(zk_data)) => { 4 info!("[Kill: {}] Received", zk_data.kill_id); 5 process_killmail(&zk_data).await; 6 sleep(Duration::from_secs(1)).await; 7 } 8 Ok(None) => { 9 // No new data, RedisQ timed out 10 sleep(Duration::from_secs(1)).await; 11 } 12 Err(e) => { 13 error!("Error: {}", e); 14 sleep(Duration::from_secs(5)).await; // Backoff on error 15 } 16 } 17}

Data Models

Killmail Structure

rust
1#[derive(Debug, Deserialize)] 2pub struct ZkData { 3 pub kill_id: u64, 4 pub killmail: KillmailData, 5 pub zkb: ZkbMeta, 6} 7 8#[derive(Debug, Deserialize)] 9pub struct KillmailData { 10 pub killmail_id: u64, 11 pub killmail_time: String, // RFC3339 format 12 pub solar_system_id: u32, 13 pub victim: Victim, 14 pub attackers: Vec<Attacker>, 15} 16 17#[derive(Debug, Deserialize)] 18pub struct Victim { 19 pub ship_type_id: u32, 20 pub character_id: Option<u64>, 21 pub corporation_id: Option<u64>, 22 pub alliance_id: Option<u64>, 23 pub position: Option<Position>, 24} 25 26#[derive(Debug, Deserialize)] 27pub struct Attacker { 28 pub ship_type_id: Option<u32>, 29 pub weapon_type_id: Option<u32>, 30 pub character_id: Option<u64>, 31 pub corporation_id: Option<u64>, 32 pub alliance_id: Option<u64>, 33 pub final_blow: bool, 34} 35 36#[derive(Debug, Deserialize)] 37pub struct ZkbMeta { 38 pub total_value: f64, 39 pub location_id: Option<u64>, 40 pub esi: String, // URL to full ESI killmail 41}

System Data

rust
1#[derive(Debug, Clone, Serialize, Deserialize)] 2pub struct System { 3 pub id: u32, 4 pub name: String, 5 pub security_status: f64, 6 pub region_id: u32, 7 pub region: String, 8 pub x: f64, 9 pub y: f64, 10 pub z: f64, 11}

Caching Strategy

Cache ESI Data Locally

rust
1// Check cache first 2{ 3 let systems = app_state.systems.read().unwrap(); 4 if let Some(system) = systems.get(&system_id) { 5 return Some(system.clone()); 6 } 7} 8 9// Fetch and cache 10match esi_client.get_system(system_id).await { 11 Ok(system) => { 12 let mut systems = app_state.systems.write().unwrap(); 13 systems.insert(system_id, system.clone()); 14 save_systems(&systems); // Persist to disk 15 Some(system) 16 } 17 Err(e) => { 18 warn!("Failed to fetch system {}: {}", system_id, e); 19 None 20 } 21}

Using Moka for In-Memory Cache

rust
1use moka::future::Cache; 2 3pub struct AppState { 4 // Time-based expiry cache 5 pub celestial_cache: Cache<u32, Arc<Celestial>>, 6} 7 8// Check cache 9if let Some(celestial) = app_state.celestial_cache.get(&system_id) { 10 return Some(celestial); 11} 12 13// Fetch and cache 14let celestial = Arc::new(fetch_celestial().await?); 15app_state.celestial_cache.insert(system_id, celestial.clone()).await;

EVE-Specific Knowledge

Important IDs

TypeExample IDsNotes
Ship Groups485 (Dread), 659 (Super), 30 (Titan)Used for filtering
Regions10000030 (Devoid), 10000012 (Curse)Universe IDs
Systems30000142 (Jita), 30002086 (Turnur)Solar system IDs

Ship Group Priorities

rust
1const SHIP_GROUP_PRIORITY: &[u32] = &[ 2 30, // Titan 3 659, // Supercarrier 4 4594, // Lancer 5 485, // Dreadnought 6 1538, // FAX 7 547, // Carrier 8 883, // Capital Industrial Ship 9 902, // Jump Freighter 10 513, // Freighter 11];

Image URLs

rust
1// Alliance logo 2fn alliance_icon(id: u64) -> String { 3 format!("https://images.evetech.net/alliances/{}/logo?size=64", id) 4} 5 6// Corporation logo 7fn corp_icon(id: u64) -> String { 8 format!("https://images.evetech.net/corporations/{}/logo?size=64", id) 9} 10 11// Ship/item icon 12fn ship_icon(id: u32) -> String { 13 format!("https://images.evetech.net/types/{}/icon?size=64", id) 14} 15 16// Character portrait 17fn character_portrait(id: u64) -> String { 18 format!("https://images.evetech.net/characters/{}/portrait?size=64", id) 19}

External Links

rust
1// zkillboard 2fn zkb_kill(id: u64) -> String { 3 format!("https://zkillboard.com/kill/{}/", id) 4} 5fn zkb_character(id: u64) -> String { 6 format!("https://zkillboard.com/character/{}/", id) 7} 8fn zkb_corp(id: u64) -> String { 9 format!("https://zkillboard.com/corporation/{}/", id) 10} 11 12// Dotlan 13fn dotlan_system(id: u32) -> String { 14 format!("http://evemaps.dotlan.net/system/{}", id) 15} 16fn dotlan_region(id: u32) -> String { 17 format!("http://evemaps.dotlan.net/region/{}", id) 18} 19 20// EVE Tools battle report 21fn br_link(system_id: u32, timestamp: &str) -> String { 22 format!("https://br.evetools.org/related/{}/{}", system_id, timestamp) 23}

SSO Authentication

OAuth2 Flow

rust
1const ESI_AUTH_URL: &str = "https://login.eveonline.com/v2/oauth/token"; 2const ESI_VERIFY_URL: &str = "https://login.eveonline.com/oauth/verify"; 3 4pub async fn exchange_code_for_token( 5 &self, 6 code: &str, 7 client_id: &str, 8 client_secret: &str, 9) -> Result<EveAuthToken, Error> { 10 // 1. Exchange authorization code for tokens 11 let params = [("grant_type", "authorization_code"), ("code", code)]; 12 let auth_response: Value = self.client 13 .post(ESI_AUTH_URL) 14 .basic_auth(client_id, Some(client_secret)) 15 .form(&params) 16 .send() 17 .await? 18 .json() 19 .await?; 20 21 let access_token = auth_response["access_token"].as_str()?.to_string(); 22 let refresh_token = auth_response["refresh_token"].as_str()?.to_string(); 23 24 // 2. Verify token and get character info 25 let verify_response: Value = self.client 26 .get(ESI_VERIFY_URL) 27 .bearer_auth(&access_token) 28 .send() 29 .await? 30 .json() 31 .await?; 32 33 let character_id = verify_response["CharacterID"].as_u64()?; 34 let character_name = verify_response["CharacterName"].as_str()?.to_string(); 35 36 Ok(EveAuthToken { character_id, character_name, access_token, refresh_token, ... }) 37}

Authenticated Requests

rust
1pub async fn get_contacts( 2 &self, 3 entity_id: u64, 4 token: &str, 5 endpoint: &str, // "characters", "corporations", or "alliances" 6) -> Result<Vec<StandingContact>, Error> { 7 let url = format!("{}{}/{}/contacts/", ESI_URL, endpoint, entity_id); 8 let contacts: Vec<StandingContact> = self.client 9 .get(&url) 10 .bearer_auth(token) // Include access token 11 .send() 12 .await? 13 .json() 14 .await?; 15 Ok(contacts) 16}

Reference Files

Related Skills

Looking for an alternative to eve-esi-api or building a Categories.community AI Agent? Explore these related open-source MCP Servers.

View All

widget-generator

Logo of f
f

widget-generator is an open-source AI agent skill for creating widget plugins that are injected into prompt feeds on prompts.chat. It supports two rendering modes: standard prompt widgets using default PromptCard styling and custom render widgets built as full React components.

149.6k
0
Design

chat-sdk

Logo of lobehub
lobehub

chat-sdk is a unified TypeScript SDK for building chat bots across multiple platforms, providing a single interface for deploying bot logic.

73.0k
0
Communication

zustand

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
Communication

data-fetching

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
Communication