crossref-local 0.4.0__py3-none-any.whl → 0.5.1__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.
Files changed (50) hide show
  1. crossref_local/__init__.py +24 -10
  2. crossref_local/_aio/__init__.py +30 -0
  3. crossref_local/_aio/_impl.py +238 -0
  4. crossref_local/_cache/__init__.py +15 -0
  5. crossref_local/{cache_export.py → _cache/export.py} +27 -10
  6. crossref_local/_cache/utils.py +93 -0
  7. crossref_local/_cli/__init__.py +9 -0
  8. crossref_local/_cli/cli.py +389 -0
  9. crossref_local/_cli/mcp.py +351 -0
  10. crossref_local/_cli/mcp_server.py +457 -0
  11. crossref_local/_cli/search.py +199 -0
  12. crossref_local/_core/__init__.py +62 -0
  13. crossref_local/{api.py → _core/api.py} +26 -5
  14. crossref_local/{citations.py → _core/citations.py} +55 -26
  15. crossref_local/{config.py → _core/config.py} +40 -22
  16. crossref_local/{db.py → _core/db.py} +32 -26
  17. crossref_local/_core/export.py +344 -0
  18. crossref_local/{fts.py → _core/fts.py} +37 -14
  19. crossref_local/{models.py → _core/models.py} +120 -6
  20. crossref_local/_remote/__init__.py +56 -0
  21. crossref_local/_remote/base.py +378 -0
  22. crossref_local/_remote/collections.py +175 -0
  23. crossref_local/_server/__init__.py +140 -0
  24. crossref_local/_server/middleware.py +25 -0
  25. crossref_local/_server/models.py +143 -0
  26. crossref_local/_server/routes_citations.py +98 -0
  27. crossref_local/_server/routes_collections.py +282 -0
  28. crossref_local/_server/routes_compat.py +102 -0
  29. crossref_local/_server/routes_works.py +178 -0
  30. crossref_local/_server/server.py +19 -0
  31. crossref_local/aio.py +30 -206
  32. crossref_local/cache.py +100 -100
  33. crossref_local/cli.py +5 -515
  34. crossref_local/jobs.py +169 -0
  35. crossref_local/mcp_server.py +5 -410
  36. crossref_local/remote.py +5 -266
  37. crossref_local/server.py +5 -349
  38. {crossref_local-0.4.0.dist-info → crossref_local-0.5.1.dist-info}/METADATA +36 -11
  39. crossref_local-0.5.1.dist-info/RECORD +49 -0
  40. {crossref_local-0.4.0.dist-info → crossref_local-0.5.1.dist-info}/entry_points.txt +1 -1
  41. crossref_local/cli_mcp.py +0 -275
  42. crossref_local-0.4.0.dist-info/RECORD +0 -27
  43. /crossref_local/{cache_viz.py → _cache/viz.py} +0 -0
  44. /crossref_local/{cli_cache.py → _cli/cache.py} +0 -0
  45. /crossref_local/{cli_completion.py → _cli/completion.py} +0 -0
  46. /crossref_local/{cli_main.py → _cli/main.py} +0 -0
  47. /crossref_local/{impact_factor → _impact_factor}/__init__.py +0 -0
  48. /crossref_local/{impact_factor → _impact_factor}/calculator.py +0 -0
  49. /crossref_local/{impact_factor → _impact_factor}/journal_lookup.py +0 -0
  50. {crossref_local-0.4.0.dist-info → crossref_local-0.5.1.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