crossref-local 0.4.0__py3-none-any.whl → 0.5.0__py3-none-any.whl
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.
- crossref_local/__init__.py +18 -10
- crossref_local/_aio/__init__.py +30 -0
- crossref_local/_aio/_impl.py +238 -0
- crossref_local/_cache/__init__.py +15 -0
- crossref_local/{cache_export.py → _cache/export.py} +27 -10
- crossref_local/_cache/utils.py +93 -0
- crossref_local/_cli/__init__.py +9 -0
- crossref_local/_cli/cli.py +512 -0
- crossref_local/_cli/mcp.py +351 -0
- crossref_local/_cli/mcp_server.py +413 -0
- crossref_local/_core/__init__.py +58 -0
- crossref_local/{api.py → _core/api.py} +24 -5
- crossref_local/{citations.py → _core/citations.py} +55 -26
- crossref_local/{config.py → _core/config.py} +40 -22
- crossref_local/{db.py → _core/db.py} +32 -26
- crossref_local/{fts.py → _core/fts.py} +18 -14
- crossref_local/{models.py → _core/models.py} +11 -6
- crossref_local/_remote/__init__.py +56 -0
- crossref_local/_remote/base.py +356 -0
- crossref_local/_remote/collections.py +175 -0
- crossref_local/_server/__init__.py +140 -0
- crossref_local/_server/middleware.py +25 -0
- crossref_local/_server/models.py +129 -0
- crossref_local/_server/routes_citations.py +98 -0
- crossref_local/_server/routes_collections.py +282 -0
- crossref_local/_server/routes_compat.py +102 -0
- crossref_local/_server/routes_works.py +128 -0
- crossref_local/_server/server.py +19 -0
- crossref_local/aio.py +30 -206
- crossref_local/cache.py +100 -100
- crossref_local/cli.py +5 -515
- crossref_local/jobs.py +169 -0
- crossref_local/mcp_server.py +5 -410
- crossref_local/remote.py +5 -266
- crossref_local/server.py +5 -349
- {crossref_local-0.4.0.dist-info → crossref_local-0.5.0.dist-info}/METADATA +36 -11
- crossref_local-0.5.0.dist-info/RECORD +47 -0
- {crossref_local-0.4.0.dist-info → crossref_local-0.5.0.dist-info}/entry_points.txt +1 -1
- crossref_local/cli_mcp.py +0 -275
- crossref_local-0.4.0.dist-info/RECORD +0 -27
- /crossref_local/{cache_viz.py → _cache/viz.py} +0 -0
- /crossref_local/{cli_cache.py → _cli/cache.py} +0 -0
- /crossref_local/{cli_completion.py → _cli/completion.py} +0 -0
- /crossref_local/{cli_main.py → _cli/main.py} +0 -0
- /crossref_local/{impact_factor → _impact_factor}/__init__.py +0 -0
- /crossref_local/{impact_factor → _impact_factor}/calculator.py +0 -0
- /crossref_local/{impact_factor → _impact_factor}/journal_lookup.py +0 -0
- {crossref_local-0.4.0.dist-info → crossref_local-0.5.0.dist-info}/WHEEL +0 -0
crossref_local/cli_mcp.py
DELETED
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
"""MCP server management commands for crossref-local CLI."""
|
|
2
|
-
|
|
3
|
-
import json
|
|
4
|
-
import sys
|
|
5
|
-
|
|
6
|
-
import click
|
|
7
|
-
|
|
8
|
-
CONTEXT_SETTINGS = {"help_option_names": ["-h", "--help"]}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@click.group("mcp", context_settings=CONTEXT_SETTINGS)
|
|
12
|
-
def mcp():
|
|
13
|
-
"""MCP (Model Context Protocol) server management.
|
|
14
|
-
|
|
15
|
-
\b
|
|
16
|
-
Commands for running and managing the MCP server that enables
|
|
17
|
-
AI assistants like Claude to search academic papers.
|
|
18
|
-
|
|
19
|
-
\b
|
|
20
|
-
Quick start:
|
|
21
|
-
crossref-local mcp start # Start stdio server
|
|
22
|
-
crossref-local mcp start -t http # Start HTTP server
|
|
23
|
-
crossref-local mcp doctor # Check dependencies
|
|
24
|
-
crossref-local mcp installation # Show config snippets
|
|
25
|
-
"""
|
|
26
|
-
pass
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
@mcp.command("start", context_settings=CONTEXT_SETTINGS)
|
|
30
|
-
@click.option(
|
|
31
|
-
"-t",
|
|
32
|
-
"--transport",
|
|
33
|
-
type=click.Choice(["stdio", "sse", "http"]),
|
|
34
|
-
default="stdio",
|
|
35
|
-
help="Transport protocol (http recommended for remote)",
|
|
36
|
-
)
|
|
37
|
-
@click.option(
|
|
38
|
-
"--host",
|
|
39
|
-
default="localhost",
|
|
40
|
-
envvar="CROSSREF_LOCAL_MCP_HOST",
|
|
41
|
-
help="Host for HTTP/SSE transport",
|
|
42
|
-
)
|
|
43
|
-
@click.option(
|
|
44
|
-
"--port",
|
|
45
|
-
default=8082,
|
|
46
|
-
type=int,
|
|
47
|
-
envvar="CROSSREF_LOCAL_MCP_PORT",
|
|
48
|
-
help="Port for HTTP/SSE transport",
|
|
49
|
-
)
|
|
50
|
-
def start_cmd(transport: str, host: str, port: int):
|
|
51
|
-
"""Start the MCP server.
|
|
52
|
-
|
|
53
|
-
\b
|
|
54
|
-
Transports:
|
|
55
|
-
stdio - Standard I/O (default, for Claude Desktop local)
|
|
56
|
-
http - Streamable HTTP (recommended for remote/persistent)
|
|
57
|
-
sse - Server-Sent Events (deprecated as of MCP spec 2025-03-26)
|
|
58
|
-
|
|
59
|
-
\b
|
|
60
|
-
Examples:
|
|
61
|
-
crossref-local mcp start # stdio for Claude Desktop
|
|
62
|
-
crossref-local mcp start -t http # HTTP on localhost:8082
|
|
63
|
-
crossref-local mcp start -t http --port 9000 # Custom port
|
|
64
|
-
"""
|
|
65
|
-
try:
|
|
66
|
-
from .mcp_server import run_server
|
|
67
|
-
except ImportError:
|
|
68
|
-
click.echo(
|
|
69
|
-
"MCP server requires fastmcp. Install with:\n"
|
|
70
|
-
" pip install crossref-local[mcp]",
|
|
71
|
-
err=True,
|
|
72
|
-
)
|
|
73
|
-
sys.exit(1)
|
|
74
|
-
|
|
75
|
-
run_server(transport=transport, host=host, port=port)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
@mcp.command("doctor", context_settings=CONTEXT_SETTINGS)
|
|
79
|
-
def doctor_cmd():
|
|
80
|
-
"""Check MCP server dependencies and configuration.
|
|
81
|
-
|
|
82
|
-
Verifies that all required packages are installed and
|
|
83
|
-
the database is accessible.
|
|
84
|
-
"""
|
|
85
|
-
click.echo("MCP Server Health Check")
|
|
86
|
-
click.echo("=" * 40)
|
|
87
|
-
|
|
88
|
-
issues = []
|
|
89
|
-
|
|
90
|
-
# Check fastmcp
|
|
91
|
-
try:
|
|
92
|
-
import fastmcp
|
|
93
|
-
|
|
94
|
-
click.echo(f"[OK] fastmcp {fastmcp.__version__}")
|
|
95
|
-
except ImportError:
|
|
96
|
-
click.echo("[FAIL] fastmcp not installed")
|
|
97
|
-
issues.append("Install fastmcp: pip install crossref-local[mcp]")
|
|
98
|
-
|
|
99
|
-
# Check database
|
|
100
|
-
try:
|
|
101
|
-
from . import info
|
|
102
|
-
|
|
103
|
-
db_info = info()
|
|
104
|
-
works = db_info.get("works", 0)
|
|
105
|
-
click.echo(f"[OK] Database: {works:,} works")
|
|
106
|
-
except Exception as e:
|
|
107
|
-
click.echo(f"[FAIL] Database: {e}")
|
|
108
|
-
issues.append("Configure database: export CROSSREF_LOCAL_DB=/path/to/db")
|
|
109
|
-
|
|
110
|
-
# Check FTS index
|
|
111
|
-
try:
|
|
112
|
-
from . import info
|
|
113
|
-
|
|
114
|
-
db_info = info()
|
|
115
|
-
fts = db_info.get("fts_indexed", 0)
|
|
116
|
-
if fts > 0:
|
|
117
|
-
click.echo(f"[OK] FTS index: {fts:,} indexed")
|
|
118
|
-
else:
|
|
119
|
-
click.echo("[WARN] FTS index: not built")
|
|
120
|
-
issues.append("Build FTS index: make fts-build")
|
|
121
|
-
except Exception:
|
|
122
|
-
pass
|
|
123
|
-
|
|
124
|
-
click.echo()
|
|
125
|
-
if issues:
|
|
126
|
-
click.echo("Issues found:")
|
|
127
|
-
for issue in issues:
|
|
128
|
-
click.echo(f" - {issue}")
|
|
129
|
-
sys.exit(1)
|
|
130
|
-
else:
|
|
131
|
-
click.echo("All checks passed!")
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
@mcp.command("installation", context_settings=CONTEXT_SETTINGS)
|
|
135
|
-
@click.option(
|
|
136
|
-
"-t",
|
|
137
|
-
"--transport",
|
|
138
|
-
type=click.Choice(["stdio", "http"]),
|
|
139
|
-
default="stdio",
|
|
140
|
-
help="Transport type for config",
|
|
141
|
-
)
|
|
142
|
-
@click.option("--host", default="localhost", help="Host for HTTP transport")
|
|
143
|
-
@click.option("--port", default=8082, type=int, help="Port for HTTP transport")
|
|
144
|
-
def installation_cmd(transport: str, host: str, port: int):
|
|
145
|
-
"""Show MCP client configuration snippets.
|
|
146
|
-
|
|
147
|
-
Outputs JSON configuration for Claude Desktop or other MCP clients.
|
|
148
|
-
|
|
149
|
-
\b
|
|
150
|
-
Examples:
|
|
151
|
-
crossref-local mcp installation # stdio config
|
|
152
|
-
crossref-local mcp installation -t http # HTTP config
|
|
153
|
-
"""
|
|
154
|
-
if transport == "stdio":
|
|
155
|
-
config = {
|
|
156
|
-
"mcpServers": {
|
|
157
|
-
"crossref-local": {
|
|
158
|
-
"command": "crossref-local",
|
|
159
|
-
"args": ["mcp", "start"],
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
click.echo("Claude Desktop configuration (stdio):")
|
|
164
|
-
click.echo()
|
|
165
|
-
click.echo(
|
|
166
|
-
"Add to ~/Library/Application Support/Claude/claude_desktop_config.json"
|
|
167
|
-
)
|
|
168
|
-
click.echo("or ~/.config/claude/claude_desktop_config.json:")
|
|
169
|
-
click.echo()
|
|
170
|
-
else:
|
|
171
|
-
url = f"http://{host}:{port}/mcp"
|
|
172
|
-
config = {"mcpServers": {"crossref-local": {"url": url}}}
|
|
173
|
-
click.echo(f"Claude Desktop configuration (HTTP at {url}):")
|
|
174
|
-
click.echo()
|
|
175
|
-
click.echo("First start the server:")
|
|
176
|
-
click.echo(f" crossref-local mcp start -t http --host {host} --port {port}")
|
|
177
|
-
click.echo()
|
|
178
|
-
click.echo("Then add to claude_desktop_config.json:")
|
|
179
|
-
click.echo()
|
|
180
|
-
|
|
181
|
-
click.echo(json.dumps(config, indent=2))
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
@mcp.command("list-tools", context_settings=CONTEXT_SETTINGS)
|
|
185
|
-
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
186
|
-
def list_tools_cmd(as_json: bool):
|
|
187
|
-
"""List available MCP tools.
|
|
188
|
-
|
|
189
|
-
Shows all tools exposed by the MCP server with their descriptions.
|
|
190
|
-
"""
|
|
191
|
-
tools = [
|
|
192
|
-
{
|
|
193
|
-
"name": "search",
|
|
194
|
-
"description": "Search for academic works by title, abstract, or authors",
|
|
195
|
-
"parameters": ["query", "limit", "offset", "with_abstracts"],
|
|
196
|
-
},
|
|
197
|
-
{
|
|
198
|
-
"name": "search_by_doi",
|
|
199
|
-
"description": "Get detailed information about a work by DOI",
|
|
200
|
-
"parameters": ["doi", "as_citation"],
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
"name": "status",
|
|
204
|
-
"description": "Get database statistics and status",
|
|
205
|
-
"parameters": [],
|
|
206
|
-
},
|
|
207
|
-
{
|
|
208
|
-
"name": "enrich_dois",
|
|
209
|
-
"description": "Enrich DOIs with full metadata including citations",
|
|
210
|
-
"parameters": ["dois"],
|
|
211
|
-
},
|
|
212
|
-
{
|
|
213
|
-
"name": "cache_create",
|
|
214
|
-
"description": "Create a paper cache from search query",
|
|
215
|
-
"parameters": ["name", "query", "limit"],
|
|
216
|
-
},
|
|
217
|
-
{
|
|
218
|
-
"name": "cache_query",
|
|
219
|
-
"description": "Query cached papers with field filtering",
|
|
220
|
-
"parameters": ["name", "fields", "year_min", "year_max", "limit"],
|
|
221
|
-
},
|
|
222
|
-
{
|
|
223
|
-
"name": "cache_stats",
|
|
224
|
-
"description": "Get cache statistics",
|
|
225
|
-
"parameters": ["name"],
|
|
226
|
-
},
|
|
227
|
-
{
|
|
228
|
-
"name": "cache_list",
|
|
229
|
-
"description": "List all available caches",
|
|
230
|
-
"parameters": [],
|
|
231
|
-
},
|
|
232
|
-
{
|
|
233
|
-
"name": "cache_top_cited",
|
|
234
|
-
"description": "Get top cited papers from cache",
|
|
235
|
-
"parameters": ["name", "n", "year_min", "year_max"],
|
|
236
|
-
},
|
|
237
|
-
{
|
|
238
|
-
"name": "cache_citation_summary",
|
|
239
|
-
"description": "Get citation statistics for cached papers",
|
|
240
|
-
"parameters": ["name"],
|
|
241
|
-
},
|
|
242
|
-
{
|
|
243
|
-
"name": "cache_plot_scatter",
|
|
244
|
-
"description": "Generate year vs citations scatter plot",
|
|
245
|
-
"parameters": ["name", "output", "top_n"],
|
|
246
|
-
},
|
|
247
|
-
{
|
|
248
|
-
"name": "cache_plot_network",
|
|
249
|
-
"description": "Generate citation network visualization",
|
|
250
|
-
"parameters": ["name", "output", "max_nodes"],
|
|
251
|
-
},
|
|
252
|
-
{
|
|
253
|
-
"name": "cache_export",
|
|
254
|
-
"description": "Export cache to file (json, csv, bibtex, dois)",
|
|
255
|
-
"parameters": ["name", "output_path", "format", "fields"],
|
|
256
|
-
},
|
|
257
|
-
]
|
|
258
|
-
|
|
259
|
-
if as_json:
|
|
260
|
-
click.echo(json.dumps(tools, indent=2))
|
|
261
|
-
else:
|
|
262
|
-
click.echo("CrossRef Local MCP Tools")
|
|
263
|
-
click.echo("=" * 50)
|
|
264
|
-
click.echo()
|
|
265
|
-
for tool in tools:
|
|
266
|
-
click.echo(f" {tool['name']}")
|
|
267
|
-
click.echo(f" {tool['description']}")
|
|
268
|
-
if tool["parameters"]:
|
|
269
|
-
click.echo(f" Parameters: {', '.join(tool['parameters'])}")
|
|
270
|
-
click.echo()
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
def register_mcp_commands(cli_group):
|
|
274
|
-
"""Register MCP commands with the main CLI group."""
|
|
275
|
-
cli_group.add_command(mcp)
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
crossref_local/__init__.py,sha256=eCvA9q-nZSWCIoMZxINV5xsboXovv4YeqZfjfLzi820,3696
|
|
2
|
-
crossref_local/__main__.py,sha256=N1c1ESGgJkAwsSWXANUgmzxC1OJEIqw-cl9m4pmNP7s,110
|
|
3
|
-
crossref_local/aio.py,sha256=En2btSn3euRbEYav1919gsmdC8iQaMbgGUso-IThCwo,5490
|
|
4
|
-
crossref_local/api.py,sha256=4VGThHU3RZaH5dgjax69iUHfRlh7j91LaM00guDKtKs,7436
|
|
5
|
-
crossref_local/cache.py,sha256=sMrmiUJr8-zRBDXnHg0M_3q3MpgzT7V1bqMKb5kpKVg,12291
|
|
6
|
-
crossref_local/cache_export.py,sha256=DU44Rv894fZz6OnBETbgwYzwVOPg3zJ6sP85yE5EYbc,2519
|
|
7
|
-
crossref_local/cache_viz.py,sha256=0VAHK-i1xR5StEYrJ_IAs0HSk0MQNVFi4EjPtlZEwTY,8498
|
|
8
|
-
crossref_local/citations.py,sha256=QFahv84upNnXP_89A8bHxEbAdz7wHbh5LEniGcAiHas,12402
|
|
9
|
-
crossref_local/cli.py,sha256=OMgrWviTT6Q9wLPWyhb9qDiRlVAJCuRDwDVpddyRPUk,16352
|
|
10
|
-
crossref_local/cli_cache.py,sha256=8QykJ7-H313x7oKRw5fJ9Coay27Y8uBWGx5JR1VQ1_Y,6220
|
|
11
|
-
crossref_local/cli_completion.py,sha256=yzqwMbGbbqXJQHdztuaqji-AdFTd8zDDhHeNGdw4NpU,7341
|
|
12
|
-
crossref_local/cli_main.py,sha256=NgCGB5-ThofTRPoxxwZpsfCQTo5WIw8oP7zBSKhEiDQ,444
|
|
13
|
-
crossref_local/cli_mcp.py,sha256=JBGveR_K7M_EzmHb3G9xr1IZPHAf-vvht-yAn5IzkQM,8524
|
|
14
|
-
crossref_local/config.py,sha256=tBAqnnscLOIF5dobEjOA4b57OVfGeGhpnmRonYKt7ng,4839
|
|
15
|
-
crossref_local/db.py,sha256=x7dXQXjsFN4LavtkNAKTNw1cUBMG-2h53-Z-Xlq6aoQ,3696
|
|
16
|
-
crossref_local/fts.py,sha256=yZMh_vmtFentXKAFGTS4z7ZNNj7p_ItgfFP5i0yQltw,4448
|
|
17
|
-
crossref_local/mcp_server.py,sha256=BN1BByTI54Rh-QoMZA2wUTV7lxdX-fLvoiEaH3YP-W0,10974
|
|
18
|
-
crossref_local/models.py,sha256=b_yYb91O6RwEPpEqe2Wmdz12WIfE5itjEus4-fCLxLI,5476
|
|
19
|
-
crossref_local/remote.py,sha256=Ju4NewXsw_cNX4vq6OeSu8fKtyf9CLwno-4uWkpwAOM,8638
|
|
20
|
-
crossref_local/server.py,sha256=CpCZm5ZVLSPfcke1lGkvEOp1XsH6bUGm5M0i9pj343U,9059
|
|
21
|
-
crossref_local/impact_factor/__init__.py,sha256=pcgVCPogBisANYE5Vp2PHVGPgxoMsSXr-6utqVE97-4,559
|
|
22
|
-
crossref_local/impact_factor/calculator.py,sha256=eZ13URAZzPdRyAQpS8zXe_T33e2lm_gQhtoJCXbfIGM,15977
|
|
23
|
-
crossref_local/impact_factor/journal_lookup.py,sha256=Ztx6ZeWxfmPvA3KfcW5h_yz01XPstIdk91j3nu2Q-qw,8846
|
|
24
|
-
crossref_local-0.4.0.dist-info/METADATA,sha256=l-quaEeSKQwlveyZgKwZfW1SwyNsM9G8yZhGOHtGtMs,9508
|
|
25
|
-
crossref_local-0.4.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
26
|
-
crossref_local-0.4.0.dist-info/entry_points.txt,sha256=1LhHFzJ7VWhNmGY6yIGDJ5EhKTYCyU7CbLEooXQWhLQ,116
|
|
27
|
-
crossref_local-0.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|