From gs-search
Search Google Scholar for academic papers by keywords. Returns results with title, authors, journal, year, citation count, and full-text links. Use when the user wants to search Google Scholar.
How this skill is triggered — by the user, by Claude, or both
Slash command
/gs-search:gs-search [search keywords][search keywords]The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Search Google Scholar for papers using keyword(s). Returns structured result list via DOM scraping.
Search Google Scholar for papers using keyword(s). Returns structured result list via DOM scraping.
$ARGUMENTS contains the search keyword(s).
Use mcp__chrome-devtools__navigate_page:
https://scholar.google.com/scholar?q={URL_ENCODED_KEYWORDS}&hl=en&num=10Wait for results to load, check for CAPTCHA, then scrape the DOM:
async () => {
// Wait for results or CAPTCHA
for (let i = 0; i < 20; i++) {
if (document.querySelector('#gs_res_ccl') || document.querySelector('#gs_captcha_ccl')) break;
await new Promise(r => setTimeout(r, 500));
}
// CAPTCHA check
if (document.querySelector('#gs_captcha_ccl') || document.body.innerText.includes('unusual traffic')) {
return { error: 'captcha', message: 'Google Scholar requires CAPTCHA verification. Please complete it in your browser, then tell me to continue.' };
}
const items = document.querySelectorAll('#gs_res_ccl .gs_r.gs_or.gs_scl');
const results = Array.from(items).map((item, i) => {
const titleEl = item.querySelector('.gs_rt a');
const meta = item.querySelector('.gs_a')?.textContent || '';
// Parse "Author1, Author2 - Journal, Year - publisher"
const parts = meta.split(' - ');
const authors = parts[0]?.trim() || '';
const journalYear = parts[1]?.trim() || '';
const citedByEl = item.querySelector('.gs_fl a[href*="cites"]');
const relatedEl = item.querySelector('.gs_fl a[href*="related"]');
const versionsEl = item.querySelector('.gs_fl a[href*="cluster"]');
return {
n: i + 1,
title: titleEl?.textContent?.trim() || item.querySelector('.gs_rt')?.textContent?.trim() || '',
href: titleEl?.href || '',
authors,
journalYear,
citedBy: citedByEl?.textContent?.match(/\d+/)?.[0] || '0',
citedByUrl: citedByEl?.href || '',
dataCid: item.getAttribute('data-cid') || '',
fullTextUrl: (item.querySelector('.gs_ggs a') || item.querySelector('.gs_or_ggsm a'))?.href || '',
snippet: item.querySelector('.gs_rs')?.textContent?.trim()?.substring(0, 200) || '',
relatedUrl: relatedEl?.href || '',
versionsUrl: versionsEl?.href || '',
versions: versionsEl?.textContent?.match(/\d+/)?.[0] || ''
};
});
const totalText = document.querySelector('#gs_ab_md')?.textContent?.trim() || '';
const currentUrl = window.location.href;
return { total: totalText, resultCount: results.length, currentUrl, results };
}
Present results as a numbered list:
Searched Google Scholar for "$ARGUMENTS": {total}
1. {title}
Authors: {authors} | {journalYear}
Cited by: {citedBy} | [Full text]({fullTextUrl})
Data-CID: {dataCid}
2. ...
Always show the dataCid — it's the unique identifier used for citation export and "cited by" tracking.
If fullTextUrl is available, highlight it (means open-access PDF/HTML).
When the user wants to:
gs-navigate-pages to go to next pagegs-cited-by with the data-cidgs-export with the data-cid(s)If the result contains {error: 'captcha'}:
navigate_page + evaluate_scriptdata-cid is the primary identifier (cluster ID) — used across all GS skillsnum=10 results per page (max 20)Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub yuanyuanma03/academic-research-skills --plugin gs-search