export_search_results
Export search results from ArxivSearcher MCP Server to formats like bibtex, csv, json, or markdown. Save results to a specified directory with a custom filename for easy access and organization.
Instructions
Export search results to various formats.
:param results: Results from search_papers or other search functions :param format: Export format ('bibtex', 'csv', 'json', 'markdown') :param filename: Output filename (without extension) :param save_path: Directory to save the file (default: current directory)
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| filename | No | ||
| format | No | bibtex | |
| results | Yes | ||
| save_path | No |
Implementation Reference
- arxiv_searcher/arxiv_mcp.py:597-738 (handler)Synchronous handler function for the 'export_search_results' MCP tool. Exports arXiv search results to specified formats (bibtex, csv, json, markdown), saves to file, and returns export details.def export_search_results( results: Dict[str, Any], format: str = "bibtex", filename: str | None = None, save_path: str | None = None, ) -> dict: """ Export search results to various formats. :param results: Results from search_papers or other search functions :param format: Export format ('bibtex', 'csv', 'json', 'markdown') :param filename: Output filename (without extension) :param save_path: Directory to save the file (default: current directory) """ try: if save_path is None: save_path = os.getcwd() os.makedirs(save_path, exist_ok=True) # Extract papers from results if isinstance(results, dict) and "results" in results: papers = results["results"] elif isinstance(results, list): papers = results else: return { "error": "Invalid results format. Expected a list of papers or a dict with a 'results' key." } if not papers: return {"error": "No papers to export."} # Generate default filename if not provided if filename is None: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"arxiv_search_{timestamp}" full_path = os.path.join(save_path, f"{filename}.{format}") if format == "bibtex": bibtex_entries = [] query_info = results.get("query_used", "N/A") export_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") header = f"""% Query: {query_info} % Exported: {export_time} """ bibtex_entries.append(header) bibtex_keys = set() for i, paper in enumerate(papers): authors = paper.get("authors", ["unknown"]) year = paper.get("published_date", "unknown").split("-")[0] first_author_lastname = "unknown" if authors and isinstance(authors, list) and authors[0] != "unknown": name_parts = authors[0].split(" ") if name_parts: first_author_lastname = name_parts[-1] first_author_lastname = re.sub( r"[^a-zA-Z0-9]", "", first_author_lastname ).lower() key = f"{first_author_lastname}{year}" # Handle duplicates original_key = key suffix = 1 while key in bibtex_keys: key = f"{original_key}_{suffix}" suffix += 1 bibtex_keys.add(key) title = paper.get("title", "No Title Provided") author_str = " and ".join(paper.get("authors", [])) pdf_url = paper.get("pdf_url", "") arxiv_id_match = ( re.search(r"/pdf/([^v]+)", pdf_url) if pdf_url else None ) if arxiv_id_match: arxiv_id = arxiv_id_match.group(1) journal = f"arXiv preprint arXiv:{arxiv_id}" else: journal = f"arXiv preprint arXiv:{key}" entry = f"""@article{{{key}, title = {{{title}}}, author = {{{author_str}}}, year = {{{year}}}, journal = {{{journal}}}, url = {{{pdf_url}}} }}""" bibtex_entries.append(entry) content = "\n\n".join(bibtex_entries) with open(full_path, "w", encoding="utf-8") as f: f.write(content) elif format == "csv": df = pd.DataFrame(papers) df.to_csv(full_path, index=False, encoding="utf-8-sig") content = df.to_string() elif format == "json": with open(full_path, "w", encoding="utf-8") as f: json.dump(papers, f, indent=4) content = json.dumps(papers, indent=4) elif format == "markdown": md_entries = [] for paper in papers: title = paper.get("title", "N/A") authors = ", ".join(paper.get("authors", ["N/A"])) date = paper.get("published_date", "N/A") url = paper.get("pdf_url", "#") summary = paper.get("summary", "N/A").replace("\n", " ") md_entries.append( f"""### {title}\n**Authors:** {authors}\n**Published:** {date}\n**[PDF Link]({url})**\n> {summary}\n""" ) content = "\n---\n".join(md_entries) with open(full_path, "w", encoding="utf-8") as f: f.write(content) else: return {"error": f"Unsupported format: {format}"} return { "success": True, "format": format, "saved_path": full_path, "papers_exported": len(papers), "content_preview": content[:500] + ("..." if len(content) > 500 else ""), } except Exception as e: return {"success": False, "error": f"Failed to export results: {str(e)}"}
- Asynchronous handler function for the 'export_search_results' MCP tool in remote/server mode. Identical logic to the synchronous version in arxiv_mcp.py.async def export_search_results( results: Dict[str, Any], format: str = "bibtex", filename: str | None = None, save_path: str | None = None, ) -> dict: """ Export search results to various formats. :param results: Results from search_papers or other search functions :param format: Export format ('bibtex', 'csv', 'json', 'markdown') :param filename: Output filename (without extension) :param save_path: Directory to save the file (default: current directory) """ try: if save_path is None: save_path = os.getcwd() os.makedirs(save_path, exist_ok=True) # Extract papers from results if isinstance(results, dict) and "results" in results: papers = results["results"] elif isinstance(results, list): papers = results else: return { "error": "Invalid results format. Expected a list of papers or a dict with a 'results' key." } if not papers: return {"error": "No papers to export."} # Generate default filename if not provided if filename is None: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"arxiv_search_{timestamp}" full_path = os.path.join(save_path, f"{filename}.{format}") if format == "bibtex": bibtex_entries = [] query_info = results.get("query_used", "N/A") export_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") header = f"""% Query: {query_info} % Exported: {export_time} """ bibtex_entries.append(header) bibtex_keys = set() for i, paper in enumerate(papers): authors = paper.get("authors", ["unknown"]) year = paper.get("published_date", "unknown").split("-")[0] first_author_lastname = "unknown" if authors and isinstance(authors, list) and authors[0] != "unknown": name_parts = authors[0].split(" ") if name_parts: first_author_lastname = name_parts[-1] first_author_lastname = re.sub( r"[^a-zA-Z0-9]", "", first_author_lastname ).lower() key = f"{first_author_lastname}{year}" # Handle duplicates original_key = key suffix = 1 while key in bibtex_keys: key = f"{original_key}_{suffix}" suffix += 1 bibtex_keys.add(key) title = paper.get("title", "No Title Provided") author_str = " and ".join(paper.get("authors", [])) pdf_url = paper.get("pdf_url", "") arxiv_id_match = ( re.search(r"/pdf/([^v]+)", pdf_url) if pdf_url else None ) if arxiv_id_match: arxiv_id = arxiv_id_match.group(1) journal = f"arXiv preprint arXiv:{arxiv_id}" else: journal = f"arXiv preprint arXiv:{key}" entry = f"""@article{{{key}, title = {{{title}}}, author = {{{author_str}}}, year = {{{year}}}, journal = {{{journal}}}, url = {{{pdf_url}}} }}""" bibtex_entries.append(entry) content = "\n\n".join(bibtex_entries) with open(full_path, "w", encoding="utf-8") as f: f.write(content) elif format == "csv": df = pd.DataFrame(papers) df.to_csv(full_path, index=False, encoding="utf-8-sig") content = df.to_string() elif format == "json": with open(full_path, "w", encoding="utf-8") as f: json.dump(papers, f, indent=4) content = json.dumps(papers, indent=4) elif format == "markdown": md_entries = [] for paper in papers: title = paper.get("title", "N/A") authors = ", ".join(paper.get("authors", ["N/A"])) date = paper.get("published_date", "N/A") url = paper.get("pdf_url", "#") summary = paper.get("summary", "N/A").replace("\n", " ") md_entries.append( f"""### {title}\n**Authors:** {authors}\n**Published:** {date}\n**[PDF Link]({url})**\n> {summary}\n""" ) content = "\n---\n".join(md_entries) with open(full_path, "w", encoding="utf-8") as f: f.write(content) else: return {"error": f"Unsupported format: {format}"} return { "success": True, "format": format, "saved_path": full_path, "papers_exported": len(papers), "content_preview": content[:500] + ("..." if len(content) > 500 else ""), } except Exception as e: return {"success": False, "error": f"Failed to export results: {str(e)}"}