Skip to main content
Glama
index.ts9.65 kB
#!/usr/bin/env node /** * AMiner MCP Server * Model Context Protocol server providing academic paper and journal search functionality */ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import { AminerClient } from "./aminer-client.js"; import { AminerConfig } from "./types.js"; // Get configuration from environment variables const config: AminerConfig = { apiKey: process.env.AMINER_API_KEY || '', baseUrl: process.env.AMINER_BASE_URL || 'https://datacenter.aminer.cn/gateway/open_platform/api/paper/list/by/search/venue' }; if (!config.apiKey) { console.error('Error: Please set AMINER_API_KEY environment variable'); process.exit(1); } // Create AMiner client const aminerClient = new AminerClient(config); // Create MCP server const server = new McpServer({ name: "aminer-mcp-server", version: "1.0.0" }); // Register tool: Search papers by keyword server.registerTool( "search_papers_by_keyword", { title: "Search Papers by Keyword", description: "Search academic papers by keyword", inputSchema: { keyword: z.string().describe("Search keyword"), page: z.number().min(0).default(0).describe("Page number, starting from 0"), size: z.number().min(1).max(10).default(10).describe("Number of papers per page, maximum 10"), order: z.enum(["year", "n_citation"]).optional().describe("Sort order: year (by publication year) or n_citation (by citation count)") } }, async ({ keyword, page, size, order }) => { try { const result = await aminerClient.searchByKeyword(keyword, page, size, order); const formattedResult = aminerClient.formatSearchResults(result); return { content: [{ type: "text", text: JSON.stringify(formattedResult, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: JSON.stringify({ error: "Search failed", message: error instanceof Error ? error.message : 'Unknown error' }, null, 2) }], isError: true }; } } ); // Register tool: Search papers by venue server.registerTool( "search_papers_by_venue", { title: "Search Papers by Venue", description: "Search papers published in a specific venue/journal", inputSchema: { venue: z.string().describe("Venue/journal name"), page: z.number().min(0).default(0).describe("Page number, starting from 0"), size: z.number().min(1).max(10).default(10).describe("Number of papers per page, maximum 10"), order: z.enum(["year", "n_citation"]).optional().describe("Sort order: year (by publication year) or n_citation (by citation count)") } }, async ({ venue, page, size, order }) => { try { const result = await aminerClient.searchByVenue(venue, page, size, order); const formattedResult = aminerClient.formatSearchResults(result); return { content: [{ type: "text", text: JSON.stringify(formattedResult, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: JSON.stringify({ error: "Search failed", message: error instanceof Error ? error.message : 'Unknown error' }, null, 2) }], isError: true }; } } ); // Register tool: Search papers by author server.registerTool( "search_papers_by_author", { title: "Search Papers by Author", description: "Search papers published by a specific author", inputSchema: { author: z.string().describe("Author name"), page: z.number().min(0).default(0).describe("Page number, starting from 0"), size: z.number().min(1).max(10).default(10).describe("Number of papers per page, maximum 10"), order: z.enum(["year", "n_citation"]).optional().describe("Sort order: year (by publication year) or n_citation (by citation count)") } }, async ({ author, page, size, order }) => { try { const result = await aminerClient.searchByAuthor(author, page, size, order); const formattedResult = aminerClient.formatSearchResults(result); return { content: [{ type: "text", text: JSON.stringify(formattedResult, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: JSON.stringify({ error: "Search failed", message: error instanceof Error ? error.message : 'Unknown error' }, null, 2) }], isError: true }; } } ); // Register tool: Advanced search (supports multiple parameters) server.registerTool( "search_papers_advanced", { title: "Advanced Paper Search", description: "Advanced paper search functionality supporting multiple search criteria", inputSchema: { keyword: z.string().optional().describe("Search keyword"), venue: z.string().optional().describe("Venue/journal name"), author: z.string().optional().describe("Author name"), page: z.number().min(0).default(0).describe("Page number, starting from 0"), size: z.number().min(1).max(10).default(10).describe("Number of papers per page, maximum 10"), order: z.enum(["year", "n_citation"]).optional().describe("Sort order: year (by publication year) or n_citation (by citation count)") } }, async ({ keyword, venue, author, page, size, order }) => { try { // Validate at least one search condition is provided if (!keyword && !venue && !author) { return { content: [{ type: "text", text: JSON.stringify({ error: "Validation Error", message: "At least one of keyword, venue, or author must be provided" }, null, 2) }], isError: true }; } const result = await aminerClient.searchPapers({ keyword, venue, author, page, size, order }); const formattedResult = aminerClient.formatSearchResults(result); return { content: [{ type: "text", text: JSON.stringify(formattedResult, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: JSON.stringify({ error: "Search failed", message: error instanceof Error ? error.message : 'Unknown error' }, null, 2) }], isError: true }; } } ); // Register prompt template: Paper search assistant server.registerPrompt( "paper_search_assistant", { title: "Paper Search Assistant", description: "AI assistant prompt template to help users search and analyze academic papers", argsSchema: { research_topic: z.string().describe("Research topic or field"), search_focus: z.enum(["recent", "highly_cited", "comprehensive"]).optional().describe("Search focus: recent (latest papers), highly_cited (high citation papers), comprehensive (balanced)") } }, ({ research_topic, search_focus }) => { let searchStrategy = ""; let orderParam = ""; const focus = search_focus || "comprehensive"; switch (focus) { case "recent": searchStrategy = "Focus on recently published papers to understand the latest developments in the field"; orderParam = "year"; break; case "highly_cited": searchStrategy = "Focus on highly cited papers to understand important contributions and classic works in the field"; orderParam = "n_citation"; break; case "comprehensive": searchStrategy = "Conduct comprehensive search, balancing novelty and impact of papers"; orderParam = ""; break; } return { messages: [{ role: "user", content: { type: "text", text: `You are a professional academic research assistant. The user wants to learn about the research topic "${research_topic}". Please help the user: 1. ${searchStrategy} 2. Use AMiner search tools to find relevant papers 3. Analyze search results and provide valuable insights 4. Recommend important papers and authors 5. Summarize the current research status and development trends in this field Search suggestions: - Use keyword search: search_papers_by_keyword - If you know important venues, use: search_papers_by_venue - If you know important authors, use: search_papers_by_author - Sorting parameter suggestion: ${orderParam ? `order="${orderParam}"` : "use default comprehensive sorting"} Please start searching and analyzing relevant papers.` } }] }; } ); // Start server async function main() { console.error("AMiner MCP Server is starting..."); console.error(`API Key: ${config.apiKey ? 'Configured' : 'Not configured'}`); console.error(`Base URL: ${config.baseUrl}`); const transport = new StdioServerTransport(); await server.connect(transport); console.error("AMiner MCP Server started, waiting for connections..."); } // Error handling process.on('uncaughtException', (error) => { console.error('Uncaught exception:', error); process.exit(1); }); process.on('unhandledRejection', (reason, promise) => { console.error('Unhandled promise rejection:', reason); process.exit(1); }); // Start server main().catch((error) => { console.error("Failed to start server:", error); process.exit(1); });

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/scipenai/aminer-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server