UNPKG

@aimaginationlab/marvel-rivals-mcp

Version:
3 lines 8.72 kB
#!/usr/bin/env node import {Server}from'@modelcontextprotocol/sdk/server/index.js';import {StdioServerTransport}from'@modelcontextprotocol/sdk/server/stdio.js';import {ListToolsRequestSchema,CallToolRequestSchema}from'@modelcontextprotocol/sdk/types.js';import b from'pino';import M from'p-queue';var u=b({name:"fetch-wrapper"},b.destination({dest:2,sync:false})),m=class extends Error{constructor(i,s,r){super(i);this.status=s;this.response=r;this.name="FetchError";}};async function d(a){return new Promise(e=>{setTimeout(e,a);})}async function k(a,e={}){let{timeout:i=3e4,retries:s=3,retryDelay:r=1e3,...t}=e,o;for(let l=0;l<=s;l++)try{let p=new AbortController,y=setTimeout(()=>{p.abort();},i);u.debug(`Making request to: ${a}`),u.debug(`Request options: ${JSON.stringify(t)}`);let n;try{n=await fetch(a,{...t,signal:p.signal});}finally{clearTimeout(y);}if(!n.ok){if(n.status===429){let c=n.headers.get("Retry-After"),v=c?parseInt(c,10)*1e3:r*(l+1);u.warn(`Rate limited. Retrying after ${String(v)}ms`),await d(v);continue}if(n.status>=500&&l<s){let c=r*(l+1);u.warn(`Server error ${String(n.status)}. Retrying after ${String(c)}ms`),await d(c);continue}let g="";try{let c=await n.text();c&&(g=` - ${c}`);}catch{}throw new m(`HTTP ${String(n.status)}: ${n.statusText}${g}`,n.status,n)}return n}catch(p){if(o=p,p instanceof Error&&p.name==="AbortError")throw new m(`Request timeout after ${String(i)}ms`);if(l<s){let y=r*(l+1);u.warn(`Request failed: ${String(p)}. Retrying after ${String(y)}ms`),await d(y);continue}}throw o||new m("Unknown error")}async function P(a,e){let i={Accept:"application/json","User-Agent":"marvel-rivals-mcp/0.0.6 (https://github.com/AImaginationLab/marvel-rivals-mcp)"};let s={};s.headers=i;let r=await k(a,s);try{return await r.json()}catch{throw new m("Invalid JSON response")}}var h=class{baseUrl;queue;constructor(e="https://marvelsapi.com/api"){this.baseUrl=e.replace(/\/$/,""),this.queue=new M({concurrency:5,interval:1e3,intervalCap:30});}async request(e,i){return this.queue.add(async()=>{let s=new URL(`${this.baseUrl}${e}`);i&&Object.entries(i).forEach(([t,o])=>{s.searchParams.set(t,o);});let r=s.toString();return P(r)})}async listHeroes(){return this.request("/heroes")}async getHeroAbilities(e){return this.request("/heroes/abilities/identifier",{id:e})}async getHeroInfo(e){let[i,s]=await Promise.all([this.request(`/heroes/information/${encodeURIComponent(e)}`),this.getHeroAbilities(e)]);return {...i,abilities:s}}async getHeroSkins(e){return this.request("/heroes/skins/id",{id:e})}async listSkins(){return this.request("/skins")}async listAchievements(){return this.request("/achievements")}async searchAchievement(e){return this.request(`/achievements/${encodeURIComponent(e)}`)}async listItems(){return this.request("/items")}async getItemsByType(e){return this.request(`/items/${encodeURIComponent(e)}`,{item_type:e})}async listMaps(){return this.request("/maps")}async filterMaps(e){return this.request(`/maps/${encodeURIComponent(e)}`)}async getPlayerProfile(e){return this.request(`/player/profile/${encodeURIComponent(e)}`)}async searchPlayer(e){return this.request(`/search_player/${encodeURIComponent(e)}`)}async getPlayerMatchHistory(e){return this.request(`/player/${encodeURIComponent(e)}/match-history`)}};var f={logLevel:"info",marvelsApiUrl:"https://marvelsapi.com/api"};var S=b({name:"marvel-rivals-mcp",level:f.logLevel},b.destination({dest:2,sync:false}));function E(){let a=new Server({name:"mcp-marvel-rivals",version:"0.1.0"},{capabilities:{tools:{}}}),e=new h(f.marvelsApiUrl);return a.setRequestHandler(ListToolsRequestSchema,()=>({tools:[{name:"listHeroes",description:"Retrieve complete roster of playable Marvel heroes. Returns all available characters with their basic info, roles (Vanguard/Duelist/Strategist), and identifiers for further queries.",inputSchema:{type:"object",properties:{}}},{name:"getHeroAbilities",description:"Fetch detailed ability kit for a specific hero including primary fire, abilities, ultimate, and passives. Essential for understanding hero mechanics and cooldowns.",inputSchema:{type:"object",properties:{identifier:{type:"string",description:"Hero ID or slug"}},required:["identifier"]}},{name:"getHeroInfo",description:"Comprehensive hero data: stats, abilities, lore, difficulty rating, role details. Best for complete hero overview including gameplay tips and synergies.",inputSchema:{type:"object",properties:{identifier:{type:"string",description:"Hero ID or slug"}},required:["identifier"]}},{name:"getHeroSkins",description:"List all cosmetic skins/outfits available for a hero. Includes rarity tiers, unlock methods, and visual variants.",inputSchema:{type:"object",properties:{id:{type:"string",description:"Hero ID"}},required:["id"]}},{name:"listSkins",description:"Browse entire game skin catalog across all heroes. Useful for finding cosmetics by rarity, event, or collection.",inputSchema:{type:"object",properties:{}}},{name:"listAchievements",description:"Full achievement/trophy list with unlock conditions, points, and progression tracking. Covers hero-specific and general gameplay milestones.",inputSchema:{type:"object",properties:{}}},{name:"searchAchievement",description:"Find specific achievements by partial name match. Helpful for tracking progress on particular challenges or hero mastery.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Achievement name to search for"}},required:["name"]}},{name:"listItems",description:"Catalog of all cosmetic items: nameplates, MVP animations, emotes, sprays. Shows unlock methods and rarity distribution.",inputSchema:{type:"object",properties:{}}},{name:"getItemsByType",description:"Filter cosmetics by category (NAMEPLATE/MVP/EMOTE/SPRAY). Perfect for browsing specific customization options.",inputSchema:{type:"object",properties:{type:{type:"string",enum:["NAMEPLATE","MVP","EMOTE","SPRAY"],description:"Item type"}},required:["type"]}},{name:"listMaps",description:"All playable maps with layouts, objectives, and modes. Includes map-specific strategies and callout locations.",inputSchema:{type:"object",properties:{}}},{name:"filterMaps",description:"Filter maps by game mode (convoy/convergence) or queue type (competitive/casual). Essential for mode-specific strategies.",inputSchema:{type:"object",properties:{filter:{type:"string",enum:["convoy","convergence","competitive","casual"],description:"Filter type"}},required:["filter"]}},{name:"getPlayerProfile",description:"Comprehensive player stats: rank, main heroes, win rates, playtime, seasonal performance. Accepts player ID or battletag.",inputSchema:{type:"object",properties:{identifier:{type:"string",description:"Player ID or username"}},required:["identifier"]}},{name:"searchPlayer",description:"Find players by username/battletag. Returns matching profiles with basic stats for player lookup and comparison.",inputSchema:{type:"object",properties:{username:{type:"string",description:"Username to search for"}},required:["username"]}},{name:"getPlayerMatchHistory",description:"Recent match results with heroes played, performance metrics, map details, and outcome. Tracks improvement and hero performance trends.",inputSchema:{type:"object",properties:{identifier:{type:"string",description:"Player ID"}},required:["identifier"]}}]})),a.setRequestHandler(CallToolRequestSchema,async i=>{let{name:s,arguments:r={}}=i.params;try{let t;switch(s){case "listHeroes":t=await e.listHeroes();break;case "getHeroAbilities":t=await e.getHeroAbilities(r.identifier);break;case "getHeroInfo":t=await e.getHeroInfo(r.identifier);break;case "getHeroSkins":t=await e.getHeroSkins(r.id);break;case "listSkins":t=await e.listSkins();break;case "listAchievements":t=await e.listAchievements();break;case "searchAchievement":t=await e.searchAchievement(r.name);break;case "listItems":t=await e.listItems();break;case "getItemsByType":t=await e.getItemsByType(r.type);break;case "listMaps":t=await e.listMaps();break;case "filterMaps":t=await e.filterMaps(r.filter);break;case "getPlayerProfile":t=await e.getPlayerProfile(r.identifier);break;case "searchPlayer":t=await e.searchPlayer(r.username);break;case "getPlayerMatchHistory":t=await e.getPlayerMatchHistory(r.identifier);break;default:throw new Error(`Unknown tool: ${s}`)}return {content:[{type:"text",text:JSON.stringify(t,null,2)}]}}catch(t){return S.error({tool:s,args:r,error:t},"Tool execution failed"),{content:[{type:"text",text:`Error: ${t instanceof Error?t.message:"Unknown error"}`}],isError:true}}}),a}async function A(){let a=E(),e=new StdioServerTransport;await a.connect(e),S.info("Marvel Rivals MCP server started");}await A();//# sourceMappingURL=cli.js.map //# sourceMappingURL=cli.js.map