$npx -y skills add AlexAI-MCP/hermes-CCC --skill arxivSearch and retrieve academic papers from arXiv using their free REST API. No API key needed.
| 1 | # arXiv |
| 2 | |
| 3 | ## Purpose |
| 4 | |
| 5 | - Use this skill to search, inspect, and download academic papers from arXiv. |
| 6 | - Prefer it for literature review, paper triage, and reproducible paper retrieval. |
| 7 | - arXiv access is free and does not require an API key. |
| 8 | - The primary API is Atom XML over HTTP. |
| 9 | |
| 10 | ## Base Endpoint |
| 11 | |
| 12 | - Base URL: `https://export.arxiv.org/api/query` |
| 13 | - Response format: Atom XML feed |
| 14 | - Transport: HTTP GET |
| 15 | - Authentication: none |
| 16 | |
| 17 | ## Core Record Shape |
| 18 | |
| 19 | - `id`: canonical entry URL for the paper |
| 20 | - `title`: paper title |
| 21 | - `summary`: abstract text |
| 22 | - `authors`: ordered author list |
| 23 | - `published`: original publication timestamp |
| 24 | - `categories`: arXiv subject tags |
| 25 | - `pdf_url`: direct PDF URL when present |
| 26 | |
| 27 | ## Useful Categories |
| 28 | |
| 29 | - `cs.AI` |
| 30 | - `cs.LG` |
| 31 | - `cs.CL` |
| 32 | - `stat.ML` |
| 33 | - `cs.CV` |
| 34 | |
| 35 | ## Search Syntax |
| 36 | |
| 37 | - Search terms are passed in `search_query=...` |
| 38 | - Field prefixes narrow the query: |
| 39 | - `ti:` title search |
| 40 | - `au:` author search |
| 41 | - `abs:` abstract search |
| 42 | - `all:` broad metadata search |
| 43 | - Combine terms with `AND`, `OR`, and `ANDNOT` |
| 44 | - URL-encode spaces as `+` or `%20` |
| 45 | |
| 46 | ## Common Query Patterns |
| 47 | |
| 48 | - `all:reasoning+AND+cat:cs.AI` |
| 49 | - `ti:transformer+AND+cat:cs.CL` |
| 50 | - `au:Goodfellow+AND+cat:cs.LG` |
| 51 | - `abs:diffusion+AND+cat:cs.CV` |
| 52 | - `all:reinforcement+learning+AND+cat:stat.ML` |
| 53 | |
| 54 | ## CLI Subcommands |
| 55 | |
| 56 | - `/arxiv search` |
| 57 | - `/arxiv get` |
| 58 | - `/arxiv recent` |
| 59 | - `/arxiv download` |
| 60 | |
| 61 | ## Subcommand Intent |
| 62 | |
| 63 | - `/arxiv search`: run a query and print matching entries |
| 64 | - `/arxiv get`: fetch one known arXiv identifier and display parsed metadata |
| 65 | - `/arxiv recent`: list recent submissions in a category or topic |
| 66 | - `/arxiv download`: save the PDF locally from a known identifier or PDF URL |
| 67 | |
| 68 | ## Search Example With curl |
| 69 | |
| 70 | ```bash |
| 71 | curl -s "https://export.arxiv.org/api/query?search_query=all:large+language+models+AND+cat:cs.CL&start=0&max_results=5&sortBy=relevance&sortOrder=descending" |
| 72 | ``` |
| 73 | |
| 74 | ## Recent Example With curl |
| 75 | |
| 76 | ```bash |
| 77 | curl -s "https://export.arxiv.org/api/query?search_query=cat:cs.LG&start=0&max_results=10&sortBy=submittedDate&sortOrder=descending" |
| 78 | ``` |
| 79 | |
| 80 | ## PDF Download Example With curl |
| 81 | |
| 82 | ```bash |
| 83 | curl -L "https://arxiv.org/pdf/2401.01234.pdf" -o 2401.01234.pdf |
| 84 | ``` |
| 85 | |
| 86 | ## Fetch A Single Entry By Identifier |
| 87 | |
| 88 | ```bash |
| 89 | curl -s "https://export.arxiv.org/api/query?id_list=2401.01234" |
| 90 | ``` |
| 91 | |
| 92 | ## Rate Limit Guidance |
| 93 | |
| 94 | - Keep requests at or below `3 req/sec` |
| 95 | - Sleep between loops when paginating large result sets |
| 96 | - Cache parsed results locally if you will revisit them |
| 97 | - Avoid hammering the endpoint with concurrent workers |
| 98 | |
| 99 | ## Python Parsing Pattern |
| 100 | |
| 101 | ```python |
| 102 | import xml.etree.ElementTree as ET |
| 103 | from urllib.request import urlopen |
| 104 | |
| 105 | API_URL = "https://export.arxiv.org/api/query?search_query=all:reasoning+AND+cat:cs.AI&start=0&max_results=3" |
| 106 | NS = {"atom": "http://www.w3.org/2005/Atom"} |
| 107 | |
| 108 | with urlopen(API_URL) as response: |
| 109 | xml_bytes = response.read() |
| 110 | |
| 111 | root = ET.fromstring(xml_bytes) |
| 112 | |
| 113 | for entry in root.findall("atom:entry", NS): |
| 114 | paper_id = entry.findtext("atom:id", default="", namespaces=NS) |
| 115 | title = entry.findtext("atom:title", default="", namespaces=NS).strip() |
| 116 | summary = entry.findtext("atom:summary", default="", namespaces=NS).strip() |
| 117 | published = entry.findtext("atom:published", default="", namespaces=NS) |
| 118 | authors = [ |
| 119 | author.findtext("atom:name", default="", namespaces=NS) |
| 120 | for author in entry.findall("atom:author", NS) |
| 121 | ] |
| 122 | categories = [node.attrib.get("term", "") for node in entry.findall("atom:category", NS)] |
| 123 | pdf_url = "" |
| 124 | for link in entry.findall("atom:link", NS): |
| 125 | if link.attrib.get("title") == "pdf": |
| 126 | pdf_url = link.attrib.get("href", "") |
| 127 | break |
| 128 | print("id:", paper_id) |
| 129 | print("title:", title) |
| 130 | print("published:", published) |
| 131 | print("authors:", ", ".join(authors)) |
| 132 | print("categories:", ", ".join(categories)) |
| 133 | print("pdf_url:", pdf_url) |
| 134 | print("summary:", summary[:240], "...") |
| 135 | print("-" * 60) |
| 136 | ``` |
| 137 | |
| 138 | ## Minimal Search Helper |
| 139 | |
| 140 | ```python |
| 141 | import xml.etree.ElementTree as ET |
| 142 | from urllib.parse import quote_plus |
| 143 | from urllib.request import urlopen |
| 144 | |
| 145 | def search_arxiv(query: str, max_results: int = 5) -> list[dict]: |
| 146 | encoded = quote_plus(query) |
| 147 | url = ( |
| 148 | "https://export.arxiv.org/api/query" |
| 149 | f"?search_query={encoded}&start=0&max_results={max_results}" |
| 150 | ) |
| 151 | ns = {"atom": "http://www.w3.org/2005/Atom"} |
| 152 | with urlopen(url) as response: |
| 153 | root = ET.fromstring(response.read()) |
| 154 | rows = [] |
| 155 | for entry in root.findall("atom:entry", ns): |
| 156 | authors = [ |
| 157 | node.findtext("atom:name", default="", namespaces=ns) |
| 158 | for node in entry.findall("atom:author", ns) |
| 159 | ] |
| 160 | categories = [node.attrib.get("term", "") for node |