priorwork-mcp 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- priorwork_mcp-0.1.0/.gitignore +58 -0
- priorwork_mcp-0.1.0/PKG-INFO +77 -0
- priorwork_mcp-0.1.0/README.md +59 -0
- priorwork_mcp-0.1.0/priorwork_mcp.py +138 -0
- priorwork_mcp-0.1.0/pyproject.toml +36 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Ignore NeurIPS papers directory
|
|
2
|
+
*_papers/
|
|
3
|
+
*_paper_hashes.json
|
|
4
|
+
paper_sections_index*
|
|
5
|
+
|
|
6
|
+
# Data directories (PDFs, indexes, text store)
|
|
7
|
+
data/
|
|
8
|
+
tests/test_data/
|
|
9
|
+
|
|
10
|
+
# Ignore environment files
|
|
11
|
+
.env
|
|
12
|
+
.env.*
|
|
13
|
+
|
|
14
|
+
# Python virtual environment
|
|
15
|
+
.venv/
|
|
16
|
+
venv/
|
|
17
|
+
ENV/
|
|
18
|
+
|
|
19
|
+
# Python cache files
|
|
20
|
+
__pycache__/
|
|
21
|
+
*.py[cod]
|
|
22
|
+
*$py.class
|
|
23
|
+
|
|
24
|
+
# Package build artifacts
|
|
25
|
+
*.egg-info/
|
|
26
|
+
build/
|
|
27
|
+
dist/
|
|
28
|
+
|
|
29
|
+
# Index files (large)
|
|
30
|
+
*.zip
|
|
31
|
+
*.index
|
|
32
|
+
test_index*/
|
|
33
|
+
paper_index_gte_temp/
|
|
34
|
+
|
|
35
|
+
# Log files
|
|
36
|
+
*.log
|
|
37
|
+
|
|
38
|
+
# macOS system files
|
|
39
|
+
.DS_Store
|
|
40
|
+
.DS_Store?
|
|
41
|
+
._*
|
|
42
|
+
.Spotlight-V100
|
|
43
|
+
.Trashes
|
|
44
|
+
ehthumbs.db
|
|
45
|
+
Thumbs.db # Exclude PDFs from git tracking
|
|
46
|
+
tests/test_data/citation_test_pdfs/*.pdf
|
|
47
|
+
|
|
48
|
+
# Temporary and generated files
|
|
49
|
+
.coverage
|
|
50
|
+
coverage.xml
|
|
51
|
+
test_confidence_display.py
|
|
52
|
+
|
|
53
|
+
# Test generation script (one-time use, requires full corpus)
|
|
54
|
+
generate_citation_test.py
|
|
55
|
+
|
|
56
|
+
# IDE settings
|
|
57
|
+
.vscode/
|
|
58
|
+
usage.db
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: priorwork-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP server for priorwork.fyi — academic ML paper search for Claude Code and Cursor
|
|
5
|
+
Project-URL: Homepage, https://priorwork.fyi
|
|
6
|
+
Project-URL: Repository, https://github.com/stefanmagureanu/Steference-review
|
|
7
|
+
License: MIT
|
|
8
|
+
Keywords: academic-search,machine-learning,mcp,model-context-protocol,papers,semantic-search
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Requires-Dist: httpx>=0.24.0
|
|
16
|
+
Requires-Dist: mcp>=1.2.0
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# priorwork-mcp
|
|
20
|
+
|
|
21
|
+
MCP server for [priorwork.fyi](https://priorwork.fyi) — semantic search over 114,000+ papers
|
|
22
|
+
from major ML, NLP, and Computer Vision conferences (NeurIPS, CVPR, ICML, ICLR, ACL, EMNLP,
|
|
23
|
+
ICCV, AISTATS, and more), directly from Claude Code, Cursor, or any MCP client.
|
|
24
|
+
|
|
25
|
+
## Tools
|
|
26
|
+
|
|
27
|
+
| Tool | Description |
|
|
28
|
+
|---|---|
|
|
29
|
+
| `search_papers` | Semantic search from a natural-language query — returns ranked papers with authors, venue, year, similarity score, download URL, and abstract snippet |
|
|
30
|
+
| `search_by_pdf_url` | Give it a public PDF link (e.g. an arXiv PDF) and get semantically similar papers from the index |
|
|
31
|
+
| `list_indexes` | List the available paper indexes and their sizes |
|
|
32
|
+
|
|
33
|
+
## Setup
|
|
34
|
+
|
|
35
|
+
### Claude Code
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
claude mcp add priorwork -- uvx priorwork-mcp
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Cursor / other MCP clients
|
|
42
|
+
|
|
43
|
+
Add to your MCP configuration:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"mcpServers": {
|
|
48
|
+
"priorwork": {
|
|
49
|
+
"command": "uvx",
|
|
50
|
+
"args": ["priorwork-mcp"]
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Configuration
|
|
57
|
+
|
|
58
|
+
Configuration is via environment variables (pass with `-e KEY=value` in `claude mcp add`,
|
|
59
|
+
or an `"env"` block in JSON configs):
|
|
60
|
+
|
|
61
|
+
| Variable | Required | Description |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `PRIORWORK_API_KEY` | No | API key from priorwork.fyi (enables authenticated features) |
|
|
64
|
+
| `PRIORWORK_API_URL` | No | Override the API base URL (default `https://priorwork.fyi`) |
|
|
65
|
+
|
|
66
|
+
## Example
|
|
67
|
+
|
|
68
|
+
> "Find prior work on spatiotemporal forecasting with graph neural networks"
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
1. Taming Local Effects in Graph-based Spatiotemporal Forecasting — Andrea Cini, et al. (2023 · NeurIPS) [score: 0.802]
|
|
72
|
+
2. FourierGNN: Rethinking Multivariate Time Series Forecasting from a Pure Graph Perspective — ...
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## License
|
|
76
|
+
|
|
77
|
+
MIT
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# priorwork-mcp
|
|
2
|
+
|
|
3
|
+
MCP server for [priorwork.fyi](https://priorwork.fyi) — semantic search over 114,000+ papers
|
|
4
|
+
from major ML, NLP, and Computer Vision conferences (NeurIPS, CVPR, ICML, ICLR, ACL, EMNLP,
|
|
5
|
+
ICCV, AISTATS, and more), directly from Claude Code, Cursor, or any MCP client.
|
|
6
|
+
|
|
7
|
+
## Tools
|
|
8
|
+
|
|
9
|
+
| Tool | Description |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `search_papers` | Semantic search from a natural-language query — returns ranked papers with authors, venue, year, similarity score, download URL, and abstract snippet |
|
|
12
|
+
| `search_by_pdf_url` | Give it a public PDF link (e.g. an arXiv PDF) and get semantically similar papers from the index |
|
|
13
|
+
| `list_indexes` | List the available paper indexes and their sizes |
|
|
14
|
+
|
|
15
|
+
## Setup
|
|
16
|
+
|
|
17
|
+
### Claude Code
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
claude mcp add priorwork -- uvx priorwork-mcp
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Cursor / other MCP clients
|
|
24
|
+
|
|
25
|
+
Add to your MCP configuration:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"mcpServers": {
|
|
30
|
+
"priorwork": {
|
|
31
|
+
"command": "uvx",
|
|
32
|
+
"args": ["priorwork-mcp"]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Configuration
|
|
39
|
+
|
|
40
|
+
Configuration is via environment variables (pass with `-e KEY=value` in `claude mcp add`,
|
|
41
|
+
or an `"env"` block in JSON configs):
|
|
42
|
+
|
|
43
|
+
| Variable | Required | Description |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| `PRIORWORK_API_KEY` | No | API key from priorwork.fyi (enables authenticated features) |
|
|
46
|
+
| `PRIORWORK_API_URL` | No | Override the API base URL (default `https://priorwork.fyi`) |
|
|
47
|
+
|
|
48
|
+
## Example
|
|
49
|
+
|
|
50
|
+
> "Find prior work on spatiotemporal forecasting with graph neural networks"
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
1. Taming Local Effects in Graph-based Spatiotemporal Forecasting — Andrea Cini, et al. (2023 · NeurIPS) [score: 0.802]
|
|
54
|
+
2. FourierGNN: Rethinking Multivariate Time Series Forecasting from a Pure Graph Perspective — ...
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## License
|
|
58
|
+
|
|
59
|
+
MIT
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""MCP server for priorwork.fyi — academic ML paper search.
|
|
2
|
+
|
|
3
|
+
Set PRIORWORK_API_KEY to your API key from priorwork.fyi.
|
|
4
|
+
Set PRIORWORK_API_URL to override the base URL (optional).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import httpx
|
|
9
|
+
from mcp.server.fastmcp import FastMCP
|
|
10
|
+
|
|
11
|
+
API_URL = os.getenv("PRIORWORK_API_URL", "https://priorwork.fyi").rstrip("/")
|
|
12
|
+
API_KEY = os.getenv("PRIORWORK_API_KEY", "")
|
|
13
|
+
|
|
14
|
+
mcp = FastMCP("priorwork")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _headers() -> dict:
|
|
18
|
+
return {"X-API-Key": API_KEY} if API_KEY else {}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _format_results(results: list) -> str:
|
|
22
|
+
if not results:
|
|
23
|
+
return "No results found."
|
|
24
|
+
lines = []
|
|
25
|
+
for i, r in enumerate(results, 1):
|
|
26
|
+
title = r.get("title", "Unknown title")
|
|
27
|
+
authors = r.get("authors", "")
|
|
28
|
+
year = r.get("year", "")
|
|
29
|
+
venue = r.get("conference") or r.get("venue", "")
|
|
30
|
+
score = r.get("similarity", r.get("score", 0))
|
|
31
|
+
url = r.get("download_url") or r.get("url", "")
|
|
32
|
+
abstract = r.get("abstract", "")
|
|
33
|
+
|
|
34
|
+
header = f"{i}. {title}"
|
|
35
|
+
if authors:
|
|
36
|
+
header += f" — {authors}"
|
|
37
|
+
meta = " · ".join(filter(None, [str(year) if year else "", venue]))
|
|
38
|
+
if meta:
|
|
39
|
+
header += f" ({meta})"
|
|
40
|
+
header += f" [score: {score:.3f}]"
|
|
41
|
+
lines.append(header)
|
|
42
|
+
if url:
|
|
43
|
+
lines.append(f" {url}")
|
|
44
|
+
if abstract:
|
|
45
|
+
lines.append(f" {abstract[:250].strip()}...")
|
|
46
|
+
lines.append("")
|
|
47
|
+
return "\n".join(lines).strip()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _flatten_results(data: dict) -> list:
|
|
51
|
+
# PDF search responses nest results per uploaded file: {"files": [{"results": [...]}]}
|
|
52
|
+
if isinstance(data.get("files"), list):
|
|
53
|
+
flat: list = []
|
|
54
|
+
for f in data["files"]:
|
|
55
|
+
if isinstance(f, dict):
|
|
56
|
+
flat.extend(f.get("results") or [])
|
|
57
|
+
return flat
|
|
58
|
+
results = data.get("results", [])
|
|
59
|
+
if isinstance(results, dict):
|
|
60
|
+
flat = []
|
|
61
|
+
for v in results.values():
|
|
62
|
+
flat.extend(v if isinstance(v, list) else [])
|
|
63
|
+
return flat
|
|
64
|
+
return results
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@mcp.tool()
|
|
68
|
+
def search_papers(query: str, max_results: int = 10) -> str:
|
|
69
|
+
"""Search for academic ML papers semantically related to a text query.
|
|
70
|
+
|
|
71
|
+
Returns a ranked list of papers with titles, authors, year, venue,
|
|
72
|
+
similarity score, download URL, and abstract snippet.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
query: Natural language description of the research topic or question.
|
|
76
|
+
max_results: Number of results to return (1-10, default 10).
|
|
77
|
+
"""
|
|
78
|
+
max_results = max(1, min(10, max_results))
|
|
79
|
+
with httpx.Client(timeout=30) as client:
|
|
80
|
+
resp = client.post(
|
|
81
|
+
f"{API_URL}/api/query",
|
|
82
|
+
json={"query": query, "max_results": max_results},
|
|
83
|
+
headers=_headers(),
|
|
84
|
+
)
|
|
85
|
+
resp.raise_for_status()
|
|
86
|
+
return _format_results(_flatten_results(resp.json()))
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@mcp.tool()
|
|
90
|
+
def search_by_pdf_url(url: str, max_results: int = 10) -> str:
|
|
91
|
+
"""Search for academic ML papers related to a paper at a given PDF URL.
|
|
92
|
+
|
|
93
|
+
Downloads the PDF from the URL (e.g. an arXiv PDF link), extracts its
|
|
94
|
+
content, and returns semantically similar papers from the index.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
url: Public URL to a PDF file (http or https).
|
|
98
|
+
max_results: Number of results to return (1-10, default 10).
|
|
99
|
+
"""
|
|
100
|
+
max_results = max(1, min(10, max_results))
|
|
101
|
+
with httpx.Client(timeout=60) as client:
|
|
102
|
+
resp = client.post(
|
|
103
|
+
f"{API_URL}/api/search/pdf-url",
|
|
104
|
+
json={"url": url, "max_results": max_results},
|
|
105
|
+
headers=_headers(),
|
|
106
|
+
)
|
|
107
|
+
resp.raise_for_status()
|
|
108
|
+
return _format_results(_flatten_results(resp.json()))
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@mcp.tool()
|
|
112
|
+
def list_indexes() -> str:
|
|
113
|
+
"""List the paper indexes available on priorwork.fyi and their paper counts."""
|
|
114
|
+
with httpx.Client(timeout=10) as client:
|
|
115
|
+
resp = client.get(f"{API_URL}/api/indexes", headers=_headers())
|
|
116
|
+
resp.raise_for_status()
|
|
117
|
+
data = resp.json()
|
|
118
|
+
indexes = data.get("indexes", [])
|
|
119
|
+
if not indexes:
|
|
120
|
+
return "No indexes available."
|
|
121
|
+
lines = []
|
|
122
|
+
for idx in indexes:
|
|
123
|
+
name = idx.get("name", "unknown")
|
|
124
|
+
count = idx.get("paper_count", "?")
|
|
125
|
+
provider = idx.get("provider", "")
|
|
126
|
+
line = f" - {name}: {count:,} papers" if isinstance(count, int) else f" - {name}: {count} papers"
|
|
127
|
+
if provider:
|
|
128
|
+
line += f" ({provider})"
|
|
129
|
+
lines.append(line)
|
|
130
|
+
return "Available indexes:\n" + "\n".join(lines)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def main():
|
|
134
|
+
mcp.run()
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
if __name__ == "__main__":
|
|
138
|
+
main()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "priorwork-mcp"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "MCP server for priorwork.fyi — academic ML paper search for Claude Code and Cursor"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
keywords = ["mcp", "model-context-protocol", "academic-search", "machine-learning", "papers", "semantic-search"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Intended Audience :: Science/Research",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
19
|
+
]
|
|
20
|
+
dependencies = [
|
|
21
|
+
"mcp>=1.2.0",
|
|
22
|
+
"httpx>=0.24.0",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.scripts]
|
|
26
|
+
priorwork-mcp = "priorwork_mcp:main"
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://priorwork.fyi"
|
|
30
|
+
Repository = "https://github.com/stefanmagureanu/Steference-review"
|
|
31
|
+
|
|
32
|
+
[tool.hatch.build.targets.wheel]
|
|
33
|
+
packages = ["priorwork_mcp.py"]
|
|
34
|
+
|
|
35
|
+
[tool.hatch.build.targets.sdist]
|
|
36
|
+
include = ["priorwork_mcp.py", "README.md", "pyproject.toml"]
|