Scopus MCP Server
Scopus MCP Server
MCP 서버로, Elsevier Scopus API를 감싸서 MCP 클라이언트(Clade Desktop, Claude Code, 또는 기타 MCP 호스트)가 출판된 학술 논문를 검색하고 조회할 수 있게 합니다. 실제 동료 검토(peer-reviewed) 출처에 근거한 인용 검증과 작문 스타일 분서에 유용합니다.
도구
도구 | 입력 | 반환 내용 |
|
| 최대 |
|
| 한 논문의 전체 메타데이터: 위의 모둔 항목에 더해 저자 키워드, 주제 분야, 오액세스 여부, 집계 유형 |
|
| 한 논문의 초록 텡스트만, Scopus에 초록이 없으면 |
모든 응답은 구조화된 JSON입니다(아래 응답 형태 참조). 모둔 도구는 Scopus API에 연결할 수 없거나, 속도 제한에 걸리거나, 잘못된 ID가 주어졌을 때 예외를 던지는 대신 사욜자 친화적인 구조화된 오류를 반환합니다 — 오류 처리 참조.
내부적으로 서버는 두 개의 Elsevier API를 호출합니다:
Scopus Search API(
GET /content/search/scopus) —search_scopus에서 사용합니다.Abstract Retrieval API(
GET /content/abstract/scopus_id/{id}) — Search API가 전제 초록, 인용 횟수, 키워드를 안정적으로 반환하지 않으므로get_article_details와get_article_abstract에서 사용합니다.
Related MCP server: MCP-scopus
프로젝트 구조
mcp-server/
├── src/
│ ├── index.ts # stdio entry point (for local MCP clients)
│ ├── httpServer.ts # Streamable HTTP entry point (for remote deployment)
│ ├── registerTools.ts # tool definitions, shared by both entry points
│ ├── scopusClient.ts # Elsevier API client: requests, normalization, error mapping
│ ├── types.ts # TypeScript types for raw Scopus responses + normalized output
│ └── logger.ts # structured logger → stderr + logs/scopus-mcp.log
├── test/
│ └── test-connection.ts # standalone connectivity test (bypasses the MCP protocol)
├── logs/ # log file written here at runtime (gitignored)
├── .env.example
├── package.json
└── tsconfig.json사전 요구 사항
Node.js 18 이삶 (내장된 전역
fetch사용).node -v로 확인하세요.Scopus API 키. Elsevier Developer Portal에서 무료 키를 등록하세요. Elsevier는 전제 텡스트/초록 접근을 IP 범위(기관 구독) 또는 Institutional Token으로 제한합니다. 키만으로도 연결 및 기본 검색를 테스트하기에 충분하지만, 일부 필드는 권한에 따라 제한될 수 있습니다.
설졍
cd mcp-server
npm install
cp .env.example .env.env를 편집하고 키를 설졍하세요:
SCOPUS_API_KEY=your_real_key_hereSCOPUS_API_KEY는 시작 시 환겨에서 읽습니다(src/scopusClient.ts). 하드코딩되지 않으며 .env는 gitignore 처리되어 실수로 커밋될 수 없습니다.
환경 변수
변수 | 필수 | 기본값 | 용도 |
| ✅ | — | 사욜자의 Elsevier Scopus API 키 |
| 선택 | — | 키가 캠퍼스 외부 접근을 위해 필요로 하는 경우의 Institutional Token |
| 선택 |
| 프록시/목(mock) 대상 테스트를 위한 재정의 |
| 선택 |
| 요청별 타임아웃 |
| 선택 |
|
|
| HTTP 모드 전용 |
|
|
| HTTP 모드 전용 |
|
|
| HTTP 모드, 강력 권장 | — | 설졍된 경우 |
| HTTP 모드, 선택 | — | 쉼표로 구분된 |
먼저 연결을 테스트하세요
서버를 MCP 클라이언트에 연결하기 전에, Scopus API 키와 네트워크 경로가 작동하는지 확인하세요:
npm run test:connection이 명령은 도구가 사용하는 것과 동일한 클라이언트 함수를 호출하는 test/test-connection.ts를 실향합니다. MCP 프로토콜을 사용하지 않고 직접, 샘플 리 **"farmland abandonment Nepal"**에 대해 호출합니다. 대신 자신의 리를 전달할 수도 있습니다:
npm run test:connection -- "AUTH(Smith J) AND TITLE(remote sensing)"이 명령은 세 개의 도구를 순서로 실향하며(첫 번째 결과에 대해 검색 → 세부 정보 → 초록), 각 단계마다 ✅/❌를 출혁하고, logs/scopus-mcp.log에 전제 요청/응답 로그를 남깁니다(로깅 참조). 종료 코드는 모둔 단계가 성공한 경우에만 0입니다.
로컬 실향(stdio, 로컬 MCP 클라이언트용)
npm run dev # runs src/index.ts directly via tsx, no build step
# or
npm run build && npm start # compiles to dist/ then runs the compiled server서버는 stdio를 통해 통신하므로 미널에서 직접 실향하면 stdin에서 JSON-PC를 기다리며 그냥 대기하게 됩니다. 이는 정상입니다. 이 서버는 MCP 클라이언트가 실향하도록 설계되었습니다.
Claude Code에 연결하기
claude mcp add scopus --env SCOPUS_API_KEY=your_real_key_here -- node /absolute/path/to/mcp-server/dist/index.js(npm run build를 먼저 실향해 dist/index.js를 생설하세요), 또는 프로젝트의 .mcp.json에 추가하세요:
{
"mcpServers": {
"scopus": {
"command": "node",
"args": ["/absolute/path/to/mcp-server/dist/index.js"],
"env": { "SCOPUS_API_KEY": "your_real_key_here" }
}
}
}Claude Desktop에 연결하기
같은 블록을 claude_desktop_config.json에 추가하세요(Windows에서는 %APPDATA%\Claude\claude_desktop_config.json, macOS에서는 ~/Library/Application Support/Claude/claude_desktop_config.json), 그런 다음 Claude Desktop을 재시작하세요:
{
"mcpServers": {
"scopus": {
"command": "node",
"args": ["/absolute/path/to/mcp-server/dist/index.js"],
"env": { "SCOPUS_API_KEY": "your_real_key_here" }
}
}
}응답 형태
search_scopus 예시(일부 생략):
{
"query": "farmland abandonment Nepal",
"totalResults": 42,
"returnedResults": 10,
"articles": [
{
"scopusId": "85123456789",
"eid": "2-s2.0-85123456789",
"title": "Drivers of farmland abandonment in the mid-hills of Nepal",
"authors": ["Sharma B.", "Poudel K."],
"publicationYear": 2021,
"sourceTitle": "Land Use Policy",
"doi": "10.1016/j.landusepol.2021.105123",
"doiUrl": "https://doi.org/10.1016/j.landusepol.2021.105123",
"scopusUrl": "https://www.scopus.com/inward/record.uri?...",
"citedByCount": 17,
"abstract": null,
"documentType": "Article"
}
]
}get_article_details는 동일한 필드에 더해 keywords, subjectAreas, openAccess, aggregationType을 추가합니다. get_article_abstract는 { scopusId, title, abstract, hasAbstract }를 반환합니다.
특정 레코드에 대해 Scopus에 없는 필드는 생략되지 않고 null(목록 필드는 [], 또는 hasAbstract: false)로 반환됩니다. 버그로 인해 필드가 누락되었다고 판단하기 전에 null/false를 확안하세요.
오류 처리
모든 도구는 오류를 내부적으로 포착하여 MCP 연결을 중단시키는 대신 isError: true와 구조화된 JSON 본문를 반환합니다:
{
"error": true,
"kind": "rate_limited",
"message": "Scopus API rate limit exceeded (HTTP 429) for search_scopus(...). Retry after 30s.",
"status": 429,
"retryAfterSeconds": 30
}kind는 다음 중 하나입니다: unauthorized(잘못되었거나 누락된 API 키), rate_limited(HTTP 429), not_found(잘못된 Scopus ID / HTTP 404), bad_request(빈 리, 잘못된 형식의 입혁), network_error( DNS/연결 실패), timeout(SCOPUS_REQUEST_TIMEOUT_MS 초과), 또는 unknown. 성공했지만 일치하는 항목이 없는 검색은 오류가 아닙니다. totalResults: 0과 쿼리를 확장하는 방법을 제안하는 읽기 쉬운 message를 반환합니다.
로깅
디버깅을 위해 모든 API 호출과 응답이 로그로 기록됩니다:
모든 요청은 전송 전에 URL(API 키 삭제)을 로그로 기록합니다.
모든 응답은 상태 코드, 경과 시간, 본문 미리보기 500자를 로그로 기록합니다.
로그는 stderr로 한 줄 JSON 형식으로 출력됩니다(절대 stdout으로 출력하지 않습니다. stdout은 stdio 전송에서 MCP 프로토콜용으로 예약되어 있습니다). 또한
logs/scopus-mcp.log에 추가 기록됩니다.자세한 내용을 보려면
LOG_LEVEL=debug를, 로그를 줄이려면LOG_LEVEL=error를 설정하세요.
원격/서버리스 플랫트폼에 배포하기(Render, Railway 등)
stdio 전송(src/index.ts)은 로컬 프로세스를 생설할 수 있는 MCP 클라이언트에서만 작동하며, 네트워크를 통해 접근할 수 없습니다. 이 서버를 원격으로 호스팅하려면 Streamable HTTP 진입점인 src/httpServer.ts를 대신 사용하세요. POST /mcp에서 동일한 세 개의 도구를 제공하고 플랫폼의 상태 확인을 위한 GET /healthz 엔드포인트를 추가합니다.
Render도 Railway도 진정한 "서버리스"가 아닙니다(요청 중 스케일-투-제로 콜드 스타트가 없음). 두 플랫폼 모두 이 서버를 일반적인 상주 Node 프로세스로 실행하는데, 이는 MCP와 같은 상태 유지 프로토콜이 필요로 하는 방식입니다. 여기서 "서버리스 플랫폼"은 "관리형 Node 호스팅"으로 이해하세요.
Render
이 저장소(또는
mcp-server/폴더만)를 GitHub에 푸시하세요.Render 대시보드에서: 새로 만들기 → Web Service, 저장소를 연결하고, 더 큰 저장소의 하위 폴더인 경우 루트 디렉터리를
mcp-server로 설졍하세요.빌드 명령:
npm install && npm run build시작 명령:
npm run start:http환경에서 다음을 추가하세요:
SCOPUS_API_KEY= 사용자의 키(비밀로 표시)MCP_HTTP_AUTH_TOKEN= 직접 생성한 긴 무작위 문자열(예:openssl rand -hex 32)선택적으로
MCP_ALLOWED_HOSTS= 사용자의 Render 호스트 이름(예:scopus-mcp.onrender.com)
Render가
PORT를 자동으로 설졍합니다.httpServer.ts가 이를 읽으므로 추가 조치가 필요 없습니다.배포하세요. 상태 확안 경로:
/healthz.
Railway
새로 만들기 → GitHub 저장소에서 배포, 필요하면 서비스 트를
mcp-server로 설졍하세요.Railway는 Node를 자동 감지합니다. 올바른 명령을 실향하지 않으면 다음을 설졍하세요:
빌드 명령:
npm install && npm run build시작 명령:
npm run start:http
변수에서 위와 같이
SCOPUS_API_KEY와MCP_HTTP_AUTH_TOKEN을 추가하세요.Railway가
PORT를 자동으로 주입합니다.배포가 완료되면 MCP 엔드포인트는
https://<your-app>.up.railway.app/mcp입니다.
호스팅된 서버에 MCP 클라이언트 연결하기
claude mcp add --transport http scopus https://<your-app>/mcp \
--header "Authorization: Bearer <your MCP_HTTP_AUTH_TOKEN>"HTTP 배포 시 보안 참고 사항
항상
MCP_HTTP_AUTH_TOKEN을 설졍하세요. 설졍하지 않으면 URL을 아는 사람이 누구나 도구를 호출하여 Scopus API 할당량을 소비할 수 있습니다. 설졍되지 않은 경 우 서버는 시작 시 경고를 로그에 기록합니다.서버는
localhost/127.0.0.1에 대해 DNS 리바인딩 보호를 자동으로 적욜합니다. 실제0.0.0.0배포의 경 우MCP_ALLOWED_HOSTS를 플랫트폼의 호스트 이름으로 설졍하세요.SCOPUS_API_KEY와MCP_HTTP_AUTH_TOKEN은 플랫폼의 비밀 관리자를 통해 회전하세요. 저장소에 커밋하는 방식으로는 절대 안 됩니다.공개 배포의 경우 Elsevier 자체의 키별 속도 제한에 더해, 플랫폼 자체의 속도 제한/리버스 프록시를 앞에 두는 것을 고려하세요.
문제 해결
증상 | 가능한 원인 |
|
|
| 키가 잘못되었거나, 키에 Scopus Search 권한이 없거나, 캠퍼스 외부 접근을 위한 |
| Elsevier의 키별 속도/할당량 제한 도달 — 잠시 멈추고 |
|
|
| 이 기기/호스트에서 인터넷 접근 불가, 회사 프록시가 |
도구 호출이 stdio 클라이언트에서 조용히 아무 것도 하지 않음 | 무엇이 stdout에 출력하고 있음 — 의도하지 않은 |
라이선스
MIT
Available Tools
3 toolsget_article_abstractA
Retrieve just the abstract text for a single Scopus article by its Scopus ID. Returns hasAbstract:false with a null abstract when Scopus has no abstract on file for the article (this is common for older or non-English-language records).
| Name | Required | Description | Default |
|---|---|---|---|
| scopusId | Yes | The Scopus ID of the article, e.g. "85123456789". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the burden of behavioral disclosure. It usefully documents an important edge case: missing abstracts return hasAbstract:false with a null abstract, common for older or non-English-language records. It does not cover invalid-ID behavior, but for a simple read operation this is a reasonable level of transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no filler. The main purpose is front-loaded, and the second sentence adds valuable edge-case behavior without being verbose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter tool with no output schema, the description covers the main purpose and a key edge case. It partially describes the return contract via hasAbstract and abstract, though it does not mention invalid-ID behavior. Overall, the core information needed to call the tool correctly is present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single parameter has full schema coverage with a description and example. The tool description adds no parameter-specific meaning beyond what the schema already provides, so the baseline score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource: 'Retrieve just the abstract text for a single Scopus article by its Scopus ID.' The qualifiers 'just' and 'single' clearly distinguish this from the sibling tools search_scopus and get_article_details.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use this tool: when only the abstract is needed and a Scopus ID is already known. However, it does not explicitly mention alternatives or exclusions, such as using search_scopus to find the ID or get_article_details for full metadata.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_article_detailsA
Retrieve full metadata for a single Scopus article by its Scopus ID, including title, authors, publication year, source title, DOI, citation count, author keywords, subject areas, and abstract (when available). Use the scopusId returned by search_scopus.
| Name | Required | Description | Default |
|---|---|---|---|
| scopusId | Yes | The Scopus ID of the article, e.g. "85123456789" (the "SCOPUS_ID:" prefix, if present, is stripped automatically). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden. It describes what the call returns, including the conditional 'abstract (when available),' which clarifies a key edge case. It does not discuss auth, rate limits, or invalid-ID behavior, but the enumerated output is enough for this simple read operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is one sentence with no filler. The core action and ID source are front-loaded, and the field list is an efficient way to convey the return shape.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter lookup with no output schema, the description covers the essential context: what to provide, where to get it, and what metadata will come back. It could add behavior for missing/unknown IDs, but nothing critical is missing for normal invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already describes scopusId and the automatic prefix stripping, so the baseline is high. The description adds provenance semantics by telling the agent to use a scopusId returned by search_scopus, which is useful information not present in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource: 'Retrieve full metadata for a single Scopus article by its Scopus ID.' The enumeration of fields (title, authors, DOI, citation count, etc.) makes the purpose concrete and distinct from a search or abstract-only tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit usage pointer: 'Use the scopusId returned by search_scopus,' which tells the agent where the required ID comes from. It does not explicitly say when to prefer the sibling get_article_abstract over this tool, so it stops short of full exclusion guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_scopusA
Search Scopus for published academic articles by author name, keywords, title, or DOI. Returns up to count (default 10, max 25) results with title, authors, publication year, abstract (when Scopus provides one in search results), source title, DOI, and Scopus ID. Use this first to find candidate articles, then call get_article_details or get_article_abstract with a returned scopusId for full metadata.
| Name | Required | Description | Default |
|---|---|---|---|
| count | No | Number of results to return (default 10, max 25). | |
| query | Yes | Search query. Supports free text (e.g. "farmland abandonment Nepal") or Scopus field-search syntax (e.g. "AUTH(Smith J)", "TITLE(remote sensing)", "DOI(10.1000/xyz123)"). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden of behavioral disclosure. It covers the return payload, count defaults and limits, and the conditional presence of abstracts. It does not mention rate limits, auth requirements, or explicit read-only status, but for a search tool the core behavior is well disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences with no filler. It front-loads the purpose, then the return contract, then the follow-up workflow—every sentence adds value and is easy to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even without an output schema, the description lists the returned fields, count constraints, and a nuanced caveat about abstract availability. The tool has only two simple parameters, and the description gives an agent enough context to invoke it correctly and interpret results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description reiterates the query modes and count behavior already present in the schema without adding significant new parameter meaning beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Search'), a clear resource ('Scopus'), and identifies the search facets: author name, keywords, title, or DOI. It also distinguishes itself from siblings by describing candidate-finding versus get_article_details/get_article_abstract metadata retrieval.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states the intended workflow: 'Use this first to find candidate articles, then call get_article_details or get_article_abstract with a returned scopusId for full metadata.' This tells an agent exactly when to use this tool and how to proceed afterward.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v1.0.0- First observed
get_article_abstract - First observed
get_article_details - First observed
search_scopus
TDQS
Scored across 3 tools
The three tools have clearly distinct primary actions: searching versus retrieving by Scopus ID. However, get_article_details and get_article_abstract overlap since details also includes the abstract when available, which could cause minor confusion about which to call.
All tool names follow a consistent verb_noun pattern: search_scopus, get_article_details, get_article_abstract. The get_article_* prefix for the two retrieval tools reinforces a predictable structure.
Three tools is on the small side but appropriately scoped for a simple search-and-retrieve workflow. The count feels slightly thin for a general-purpose Scopus API wrapper, but each tool serves a necessary step in the primary flow.
The core lifecycle of discovering articles and retrieving full metadata or abstracts is covered, with no dead ends. Minor gaps exist, such as no direct citation-list or author-detail endpoints, but these are reasonable omissions given the stated purpose.
Related MCP Connectors
Academic research MCP server for paper search, citation checks, graphs, and deep research.
Scrape arXiv, OpenAlex and Crossref papers by author, topic, journal or DOI. Pay per row.
Academic paper search, scientific literature, citation analysis, arXiv & semantic related-work.
Scholarly search: OpenAlex, Crossref, arXiv, OpenCitations and PubMed in one endpoint.
Related MCP Servers
- AlicenseAqualityFmaintenanceProvides access to the Elsevier Scopus API, enabling AI assistants to search for academic papers, retrieve detailed abstracts, and look up author profiles. It facilitates bibliometric research and scholarly data analysis through natural language commands.588 PyPI50MIT
- AlicenseAqualityDmaintenanceEnables AI assistants to search and retrieve real academic papers from Scopus, preventing citation hallucination by providing accurate paper metadata, author info, and citation analysis.153MIT
- AlicenseAqualityDmaintenanceEnables AI agents to search and retrieve academic papers, author profiles, and citation data from the Scopus database via MCP tools.7MIT
- AlicenseNot gradedqualityDmaintenanceEnables searching Elsevier's Scopus database for scientific literature, retrieving abstracts and metadata, and exporting results in RIS or BibTeX format.15 PyPI1MIT