crossref-local 0.3.1__py3-none-any.whl → 0.4.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.
@@ -10,24 +10,27 @@ Usage:
10
10
  """
11
11
 
12
12
  import json
13
- from typing import Optional
14
13
 
15
14
  from fastmcp import FastMCP
16
15
 
17
- from . import search, get, count, info, __version__
18
- from .impact_factor import ImpactFactorCalculator
16
+
17
+ from . import (
18
+ get as _get,
19
+ info as _info,
20
+ search as _search,
21
+ )
19
22
 
20
23
  # Initialize MCP server
21
24
  mcp = FastMCP(
22
25
  name="crossref-local",
23
26
  instructions="Local CrossRef database with 167M+ works and full-text search. "
24
- "Use search_works to find papers, get_work for DOI lookup, count_works for counts, "
25
- "database_info for stats, and calculate_impact_factor for journal metrics.",
27
+ "Use search to find papers, search_by_doi for DOI lookup, enrich_dois to add "
28
+ "citation counts and references, and status for stats.",
26
29
  )
27
30
 
28
31
 
29
32
  @mcp.tool()
30
- def search_works(
33
+ def search(
31
34
  query: str,
32
35
  limit: int = 10,
33
36
  offset: int = 0,
@@ -48,11 +51,11 @@ def search_works(
48
51
  JSON string with search results including total count and matching works.
49
52
 
50
53
  Examples:
51
- search_works("machine learning")
52
- search_works("CRISPR", limit=20)
53
- search_works("neural network AND memory", with_abstracts=True)
54
+ search("machine learning")
55
+ search("CRISPR", limit=20)
56
+ search("neural network AND memory", with_abstracts=True)
54
57
  """
55
- results = search(query, limit=min(limit, 100), offset=offset)
58
+ results = _search(query, limit=min(limit, 100), offset=offset)
56
59
 
57
60
  works_data = []
58
61
  for work in results.works:
@@ -80,7 +83,7 @@ def search_works(
80
83
 
81
84
 
82
85
  @mcp.tool()
83
- def get_work(doi: str, as_citation: bool = False) -> str:
86
+ def search_by_doi(doi: str, as_citation: bool = False) -> str:
84
87
  """Get detailed information about a work by DOI.
85
88
 
86
89
  Args:
@@ -91,10 +94,10 @@ def get_work(doi: str, as_citation: bool = False) -> str:
91
94
  JSON string with work metadata, or formatted citation string.
92
95
 
93
96
  Examples:
94
- get_work("10.1038/nature12373")
95
- get_work("10.1126/science.aax0758", as_citation=True)
97
+ search_by_doi("10.1038/nature12373")
98
+ search_by_doi("10.1126/science.aax0758", as_citation=True)
96
99
  """
97
- work = get(doi)
100
+ work = _get(doi)
98
101
 
99
102
  if work is None:
100
103
  return json.dumps({"error": f"DOI not found: {doi}"})
@@ -106,69 +109,277 @@ def get_work(doi: str, as_citation: bool = False) -> str:
106
109
 
107
110
 
108
111
  @mcp.tool()
109
- def count_works(query: str) -> str:
110
- """Count matching works without fetching results.
112
+ def status() -> str:
113
+ """Get database statistics and status.
111
114
 
112
- Faster than search when you only need the count.
115
+ Returns:
116
+ JSON string with database path, work count, FTS index count, and citation count.
117
+ """
118
+ db_info = _info()
119
+ return json.dumps(db_info, indent=2)
120
+
121
+
122
+ @mcp.tool()
123
+ def enrich_dois(dois: list[str]) -> str:
124
+ """Enrich DOIs with full metadata including citation counts and references.
125
+
126
+ Use this after search() to get detailed metadata for papers.
127
+ The search() tool returns basic info (title, authors, year, journal).
128
+ This tool adds: citation_count, references, volume, issue, publisher, etc.
129
+
130
+ Typical workflow:
131
+ 1. search("epilepsy seizure prediction") -> get DOIs
132
+ 2. enrich_dois([doi1, doi2, ...]) -> get full metadata
113
133
 
114
134
  Args:
115
- query: FTS5 search query
135
+ dois: List of DOIs to enrich (e.g., ["10.1038/nature12373", "10.1126/science.aax0758"])
116
136
 
117
137
  Returns:
118
- JSON string with count.
138
+ JSON string with enriched works including citation_count and references.
119
139
 
120
140
  Examples:
121
- count_works("CRISPR")
122
- count_works("machine learning AND deep")
141
+ enrich_dois(["10.1038/nature12373"])
142
+ enrich_dois(["10.1038/s41467-017-02577-y", "10.1093/brain/aww019"])
123
143
  """
124
- n = count(query)
125
- return json.dumps({"query": query, "count": n})
144
+ from . import get_many as _get_many
145
+
146
+ works = _get_many(dois)
147
+
148
+ works_data = []
149
+ for work in works:
150
+ works_data.append(work.to_dict())
151
+
152
+ return json.dumps(
153
+ {
154
+ "requested": len(dois),
155
+ "found": len(works_data),
156
+ "works": works_data,
157
+ },
158
+ indent=2,
159
+ )
126
160
 
127
161
 
128
162
  @mcp.tool()
129
- def database_info() -> str:
130
- """Get database statistics and status.
163
+ def cache_create(
164
+ name: str,
165
+ query: str,
166
+ limit: int = 1000,
167
+ ) -> str:
168
+ """Create a paper cache from search query.
169
+
170
+ Fetches full metadata for papers matching query and saves to disk cache.
171
+ Use this to build a reusable paper collection for a research topic.
172
+
173
+ Args:
174
+ name: Cache name (e.g., "epilepsy", "alzheimers")
175
+ query: FTS search query
176
+ limit: Max papers to cache (default: 1000)
131
177
 
132
178
  Returns:
133
- JSON string with database path, work count, FTS index count, and citation count.
179
+ JSON with cache info (path, paper count, size)
180
+
181
+ Example:
182
+ cache_create("epilepsy", "epilepsy seizure prediction", limit=500)
134
183
  """
135
- db_info = info()
136
- return json.dumps(db_info, indent=2)
184
+ from . import cache
185
+
186
+ info = cache.create(name, query=query, limit=limit)
187
+ return json.dumps(info.to_dict(), indent=2)
137
188
 
138
189
 
139
190
  @mcp.tool()
140
- def calculate_impact_factor(
141
- journal: str,
142
- year: int = 2023,
143
- window: int = 2,
191
+ def cache_query(
192
+ name: str,
193
+ fields: list[str] | None = None,
194
+ include_abstract: bool = False,
195
+ include_references: bool = False,
196
+ include_citations: bool = False,
197
+ year_min: int | None = None,
198
+ year_max: int | None = None,
199
+ journal: str | None = None,
200
+ limit: int | None = None,
144
201
  ) -> str:
145
- """Calculate impact factor for a journal.
202
+ """Query cached papers with field filtering.
146
203
 
147
- Impact factor = citations in target year / articles in window years.
204
+ Returns minimal data to reduce context usage. Specify only fields needed.
148
205
 
149
206
  Args:
150
- journal: Journal name or ISSN (e.g., "Nature", "Science", "0028-0836")
151
- year: Target year for citation count (default: 2023)
152
- window: Number of years for article window (default: 2 for standard IF)
207
+ name: Cache name
208
+ fields: Explicit field list (e.g., ["doi", "title", "year"])
209
+ include_abstract: Include abstract (default: False)
210
+ include_references: Include references list (default: False)
211
+ include_citations: Include citation_count (default: False)
212
+ year_min: Filter by minimum year
213
+ year_max: Filter by maximum year
214
+ journal: Filter by journal name (substring match)
215
+ limit: Max results to return
153
216
 
154
217
  Returns:
155
- JSON string with journal name, article count, citation count, and impact factor.
218
+ JSON array of filtered papers
156
219
 
157
220
  Examples:
158
- calculate_impact_factor("Nature")
159
- calculate_impact_factor("Science", year=2022)
160
- calculate_impact_factor("Cell", window=5) # 5-year impact factor
221
+ cache_query("epilepsy", fields=["doi", "title", "year"])
222
+ cache_query("epilepsy", year_min=2020, include_citations=True, limit=50)
223
+ """
224
+ from . import cache
225
+
226
+ papers = cache.query(
227
+ name,
228
+ fields=fields,
229
+ include_abstract=include_abstract,
230
+ include_references=include_references,
231
+ include_citations=include_citations,
232
+ year_min=year_min,
233
+ year_max=year_max,
234
+ journal=journal,
235
+ limit=limit,
236
+ )
237
+ return json.dumps({"count": len(papers), "papers": papers}, indent=2)
238
+
239
+
240
+ @mcp.tool()
241
+ def cache_stats(name: str) -> str:
242
+ """Get cache statistics.
243
+
244
+ Returns year distribution, top journals, citation stats without loading full data.
245
+
246
+ Args:
247
+ name: Cache name
248
+
249
+ Returns:
250
+ JSON with statistics (paper_count, year_range, top_journals, etc.)
251
+ """
252
+ from . import cache
253
+
254
+ stats = cache.stats(name)
255
+ return json.dumps(stats, indent=2)
256
+
257
+
258
+ @mcp.tool()
259
+ def cache_list() -> str:
260
+ """List all available caches.
261
+
262
+ Returns:
263
+ JSON array of cache info (name, path, paper_count, size)
264
+ """
265
+ from . import cache
266
+
267
+ caches = cache.list_caches()
268
+ return json.dumps([c.to_dict() for c in caches], indent=2)
269
+
270
+
271
+ @mcp.tool()
272
+ def cache_top_cited(
273
+ name: str,
274
+ n: int = 20,
275
+ year_min: int | None = None,
276
+ year_max: int | None = None,
277
+ ) -> str:
278
+ """Get top cited papers from cache.
279
+
280
+ Args:
281
+ name: Cache name
282
+ n: Number of papers to return
283
+ year_min: Filter by minimum year
284
+ year_max: Filter by maximum year
285
+
286
+ Returns:
287
+ JSON array of top cited papers
288
+ """
289
+ from .cache_viz import get_top_cited
290
+
291
+ papers = get_top_cited(name, n=n, year_min=year_min, year_max=year_max)
292
+ return json.dumps(papers, indent=2)
293
+
294
+
295
+ @mcp.tool()
296
+ def cache_citation_summary(name: str) -> str:
297
+ """Get citation statistics for cached papers.
298
+
299
+ Returns mean, median, max citations and counts of highly cited papers.
300
+
301
+ Args:
302
+ name: Cache name
303
+
304
+ Returns:
305
+ JSON with citation statistics
161
306
  """
162
- try:
163
- with ImpactFactorCalculator() as calc:
164
- result = calc.calculate_impact_factor(
165
- journal_identifier=journal,
166
- target_year=year,
167
- window_years=window,
168
- )
169
- return json.dumps(result, indent=2)
170
- except Exception as e:
171
- return json.dumps({"error": str(e)})
307
+ from .cache_viz import get_citation_summary
308
+
309
+ summary = get_citation_summary(name)
310
+ return json.dumps(summary, indent=2)
311
+
312
+
313
+ @mcp.tool()
314
+ def cache_plot_scatter(
315
+ name: str,
316
+ output: str,
317
+ top_n: int = 10,
318
+ ) -> str:
319
+ """Generate year vs citations scatter plot.
320
+
321
+ Saves plot to file and returns top cited papers.
322
+
323
+ Args:
324
+ name: Cache name
325
+ output: Output file path (png/pdf/svg)
326
+ top_n: Number of top papers to label on plot
327
+
328
+ Returns:
329
+ JSON with output path and top papers list
330
+ """
331
+ from .cache_viz import plot_year_citations
332
+
333
+ result = plot_year_citations(name, output=output, top_n=top_n)
334
+ return json.dumps(result, indent=2)
335
+
336
+
337
+ @mcp.tool()
338
+ def cache_plot_network(
339
+ name: str,
340
+ output: str,
341
+ max_nodes: int = 100,
342
+ ) -> str:
343
+ """Generate citation network visualization.
344
+
345
+ Creates interactive HTML graph showing citation relationships.
346
+
347
+ Args:
348
+ name: Cache name
349
+ output: Output HTML file path
350
+ max_nodes: Maximum papers to include
351
+
352
+ Returns:
353
+ JSON with network stats
354
+ """
355
+ from .cache_viz import plot_citation_network
356
+
357
+ result = plot_citation_network(name, output=output, max_nodes=max_nodes)
358
+ return json.dumps(result, indent=2)
359
+
360
+
361
+ @mcp.tool()
362
+ def cache_export(
363
+ name: str,
364
+ output_path: str,
365
+ format: str = "json",
366
+ fields: list[str] | None = None,
367
+ ) -> str:
368
+ """Export cache to file.
369
+
370
+ Args:
371
+ name: Cache name
372
+ output_path: Output file path
373
+ format: Export format (json, csv, bibtex, dois)
374
+ fields: Fields to include (for json/csv)
375
+
376
+ Returns:
377
+ JSON with output path
378
+ """
379
+ from . import cache
380
+
381
+ path = cache.export(name, output_path, format=format, fields=fields)
382
+ return json.dumps({"exported": path, "format": format})
172
383
 
173
384
 
174
385
  def run_server(
crossref_local/models.py CHANGED
File without changes
crossref_local/remote.py CHANGED
@@ -199,6 +199,11 @@ class RemoteClient:
199
199
  authors=item.get("authors", []),
200
200
  year=item.get("year"),
201
201
  journal=item.get("journal"),
202
+ volume=item.get("volume"),
203
+ issue=item.get("issue"),
204
+ page=item.get("page"),
205
+ abstract=item.get("abstract"),
206
+ citation_count=item.get("citation_count"),
202
207
  )
203
208
  works.append(work)
204
209
  return works
crossref_local/server.py CHANGED
@@ -4,11 +4,11 @@ This server provides proper full-text search using FTS5 index,
4
4
  unlike the Django API which only scans a limited subset.
5
5
 
6
6
  Usage:
7
- crossref-local api # Run on default port 3333
7
+ crossref-local api # Run on default port 8333
8
8
  crossref-local api --port 8080 # Custom port
9
9
 
10
10
  # Or directly:
11
- uvicorn crossref_local.server:app --host 0.0.0.0 --port 3333
11
+ uvicorn crossref_local.server:app --host 0.0.0.0 --port 8333
12
12
  """
13
13
 
14
14
  import time
@@ -18,14 +18,14 @@ from fastapi import FastAPI, Query, HTTPException
18
18
  from fastapi.middleware.cors import CORSMiddleware
19
19
  from pydantic import BaseModel
20
20
 
21
- from . import fts
21
+ from . import fts, __version__
22
22
  from .db import get_db
23
23
  from .models import Work
24
24
 
25
25
  app = FastAPI(
26
26
  title="CrossRef Local API",
27
27
  description="Fast full-text search across 167M+ scholarly works",
28
- version="1.1.0",
28
+ version=__version__,
29
29
  )
30
30
 
31
31
  # CORS middleware
@@ -61,7 +61,7 @@ class SearchResponse(BaseModel):
61
61
 
62
62
  class InfoResponse(BaseModel):
63
63
  name: str = "CrossRef Local API"
64
- version: str = "1.1.0"
64
+ version: str = __version__
65
65
  status: str = "running"
66
66
  mode: str = "local"
67
67
  total_papers: int
@@ -75,7 +75,7 @@ def root():
75
75
  """API root with endpoint information."""
76
76
  return {
77
77
  "name": "CrossRef Local API",
78
- "version": "1.1.0",
78
+ "version": __version__,
79
79
  "status": "running",
80
80
  "endpoints": {
81
81
  "health": "/health",
@@ -341,7 +341,7 @@ def api_stats_compat():
341
341
  }
342
342
 
343
343
 
344
- def run_server(host: str = "0.0.0.0", port: int = 3333):
344
+ def run_server(host: str = "0.0.0.0", port: int = 8333):
345
345
  """Run the FastAPI server."""
346
346
  import uvicorn
347
347
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crossref-local
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: Local CrossRef database with 167M+ works and full-text search
5
5
  Project-URL: Homepage, https://github.com/ywatanabe1989/crossref_local
6
6
  Project-URL: Repository, https://github.com/ywatanabe1989/crossref_local
@@ -43,6 +43,12 @@ Requires-Dist: networkx>=3.0; extra == 'viz'
43
43
  Requires-Dist: pyvis>=0.3; extra == 'viz'
44
44
  Description-Content-Type: text/markdown
45
45
 
46
+ <!-- ---
47
+ !-- Timestamp: 2026-01-16 19:15:51
48
+ !-- Author: ywatanabe
49
+ !-- File: /home/ywatanabe/proj/crossref-local/README.md
50
+ !-- --- -->
51
+
46
52
  # CrossRef Local
47
53
 
48
54
  Local CrossRef database with 167M+ scholarly works, full-text search, and impact factor calculation.
@@ -55,6 +61,22 @@ Local CrossRef database with 167M+ scholarly works, full-text search, and impact
55
61
  <img src="examples/readme_figure.png" alt="CrossRef Local Demo" width="800"/>
56
62
  </p>
57
63
 
64
+ <details>
65
+ <summary><strong>MCP Demo Video</strong></summary>
66
+
67
+ <p align="center">
68
+ <a href="https://scitex.ai/media/videos/crossref-local-v0.3.1-demo.mp4">
69
+ <img src="examples/demo_mcp_out/crossref-local-v0.3.1-demo-thumbnail_6m55s.png" alt="Demo Video Thumbnail" width="600"/>
70
+ </a>
71
+ </p>
72
+
73
+ Live demonstration of MCP server integration with Claude Code for `epilepsy seizure prediction` literature review:
74
+ - Full-text search on title, abstracts, and keywords across 167M papers (22ms response)
75
+
76
+ 📄 [Full demo documentation](examples/demo_mcp.org) | 📊 [Generated diagrams](examples/demo_mcp_out/)
77
+
78
+ </details>
79
+
58
80
  <details>
59
81
  <summary><strong>Why CrossRef Local?</strong></summary>
60
82
 
@@ -135,9 +157,8 @@ async def main():
135
157
 
136
158
  ```bash
137
159
  crossref-local search "CRISPR genome editing" -n 5
138
- crossref-local get 10.1038/nature12373
139
- crossref-local impact-factor Nature -y 2023 # IF: 54.067
140
- crossref-local info # Database stats
160
+ crossref-local search-by-doi 10.1038/nature12373
161
+ crossref-local status # Configuration and database stats
141
162
  ```
142
163
 
143
164
  With abstracts (`-a` flag):
@@ -160,53 +181,56 @@ Found 4 matches in 128.4ms
160
181
 
161
182
  Start the FastAPI server:
162
183
  ```bash
163
- crossref-local api --host 0.0.0.0 --port 3333
184
+ crossref-local run-server-http --host 0.0.0.0 --port 8333
164
185
  ```
165
186
 
166
187
  Endpoints:
167
188
  ```bash
168
189
  # Search works (FTS5)
169
- curl "http://localhost:3333/works?q=CRISPR&limit=10"
190
+ curl "http://localhost:8333/works?q=CRISPR&limit=10"
170
191
 
171
192
  # Get by DOI
172
- curl "http://localhost:3333/works/10.1038/nature12373"
193
+ curl "http://localhost:8333/works/10.1038/nature12373"
173
194
 
174
195
  # Batch DOI lookup
175
- curl -X POST "http://localhost:3333/works/batch" \
196
+ curl -X POST "http://localhost:8333/works/batch" \
176
197
  -H "Content-Type: application/json" \
177
198
  -d '{"dois": ["10.1038/nature12373", "10.1126/science.aax0758"]}'
178
199
 
179
200
  # Database info
180
- curl "http://localhost:3333/info"
201
+ curl "http://localhost:8333/info"
181
202
  ```
182
203
 
183
- Remote access via SSH tunnel:
204
+ HTTP mode (connect to running server):
184
205
  ```bash
185
- # On local machine
186
- ssh -L 3333:127.0.0.1:3333 nas
206
+ # On local machine (if server is remote)
207
+ ssh -L 8333:127.0.0.1:8333 your-server
187
208
 
188
209
  # Python client
189
- from crossref_local import configure_remote
190
- configure_remote("http://localhost:3333")
210
+ from crossref_local import configure_http
211
+ configure_http("http://localhost:8333")
212
+
213
+ # Or via CLI
214
+ crossref-local --http search "CRISPR"
191
215
  ```
192
216
 
193
217
  </details>
194
218
 
195
219
  <details>
196
- <summary><strong>MCP Server (Claude Desktop)</strong></summary>
220
+ <summary><strong>MCP Server</strong></summary>
197
221
 
198
- Run as MCP server for Claude Desktop integration:
222
+ Run as MCP (Model Context Protocol) server:
199
223
  ```bash
200
- crossref-local serve
224
+ crossref-local run-server-mcp
201
225
  ```
202
226
 
203
- Add to Claude Desktop config (`~/.config/claude/claude_desktop_config.json`):
227
+ Local MCP client configuration:
204
228
  ```json
205
229
  {
206
230
  "mcpServers": {
207
231
  "crossref-local": {
208
232
  "command": "crossref-local",
209
- "args": ["serve"],
233
+ "args": ["run-server-mcp"],
210
234
  "env": {
211
235
  "CROSSREF_LOCAL_DB": "/path/to/crossref.db"
212
236
  }
@@ -215,12 +239,27 @@ Add to Claude Desktop config (`~/.config/claude/claude_desktop_config.json`):
215
239
  }
216
240
  ```
217
241
 
242
+ Remote MCP via HTTP (recommended):
243
+ ```bash
244
+ # On server: start persistent MCP server
245
+ crossref-local run-server-mcp -t http --host 0.0.0.0 --port 8082
246
+ ```
247
+ ```json
248
+ {
249
+ "mcpServers": {
250
+ "crossref-remote": {
251
+ "url": "http://your-server:8082/mcp"
252
+ }
253
+ }
254
+ }
255
+ ```
256
+
257
+ See [docs/remote-deployment.md](docs/remote-deployment.md) for systemd and Docker setup.
258
+
218
259
  Available tools:
219
- - `search_works` - Full-text search across 167M+ papers
220
- - `get_work` - Get paper by DOI
221
- - `count_works` - Count matching papers
222
- - `database_info` - Database statistics
223
- - `calculate_impact_factor` - Journal impact factor
260
+ - `search` - Full-text search across 167M+ papers
261
+ - `search_by_doi` - Get paper by DOI
262
+ - `status` - Database statistics
224
263
 
225
264
  </details>
226
265
 
@@ -0,0 +1,27 @@
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,,
@@ -1,3 +1,3 @@
1
1
  [console_scripts]
2
- crossref-local = crossref_local.cli:main
2
+ crossref-local = crossref_local.cli_main:main
3
3
  crossref-local-mcp = crossref_local.mcp_server:main
@@ -1,20 +0,0 @@
1
- crossref_local/__init__.py,sha256=AJIkriNQBf61SPoi-cfxNr25pdoQMS3KvLhsNoCfJmQ,3316
2
- crossref_local/__main__.py,sha256=N1c1ESGgJkAwsSWXANUgmzxC1OJEIqw-cl9m4pmNP7s,110
3
- crossref_local/aio.py,sha256=En2btSn3euRbEYav1919gsmdC8iQaMbgGUso-IThCwo,5490
4
- crossref_local/api.py,sha256=h2lpoA7qsCzxBTv0Na3Etgk0hZCWZFKmalreIYsmOhw,5343
5
- crossref_local/citations.py,sha256=QFahv84upNnXP_89A8bHxEbAdz7wHbh5LEniGcAiHas,12402
6
- crossref_local/cli.py,sha256=WMk7GxJtTf2ZCH1ldkcUmX-643n5DE11kGu_K7AkOrA,15132
7
- crossref_local/config.py,sha256=4LGZJ3CmsA9YRv48FkEqVR2xljuSjl0MYiMrT8ljk14,5050
8
- crossref_local/db.py,sha256=x7dXQXjsFN4LavtkNAKTNw1cUBMG-2h53-Z-Xlq6aoQ,3696
9
- crossref_local/fts.py,sha256=yZMh_vmtFentXKAFGTS4z7ZNNj7p_ItgfFP5i0yQltw,4448
10
- crossref_local/mcp_server.py,sha256=KDcBvVMXrhemO7cS4kBMfEvp0Qb-LDsVbnPhnLaaC-4,5796
11
- crossref_local/models.py,sha256=b_yYb91O6RwEPpEqe2Wmdz12WIfE5itjEus4-fCLxLI,5476
12
- crossref_local/remote.py,sha256=p8P0zotkNYchqqKGOsqcFiHR10qD4pYmJ26-ltyqO4s,8389
13
- crossref_local/server.py,sha256=lEc0EA3jVx31q1EEYOaT4cr9l2_fGpoQZmpYdnoGxFQ,9034
14
- crossref_local/impact_factor/__init__.py,sha256=pcgVCPogBisANYE5Vp2PHVGPgxoMsSXr-6utqVE97-4,559
15
- crossref_local/impact_factor/calculator.py,sha256=eZ13URAZzPdRyAQpS8zXe_T33e2lm_gQhtoJCXbfIGM,15977
16
- crossref_local/impact_factor/journal_lookup.py,sha256=Ztx6ZeWxfmPvA3KfcW5h_yz01XPstIdk91j3nu2Q-qw,8846
17
- crossref_local-0.3.1.dist-info/METADATA,sha256=Wiqa6MGJXMgMFI3qXss4IcLr0wo20Jsbl9UgAfyXrrU,8480
18
- crossref_local-0.3.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
19
- crossref_local-0.3.1.dist-info/entry_points.txt,sha256=BZbDvHLHzlKzFc-dqLAFwPrWGmGq5yFuD3vslzbmRnk,111
20
- crossref_local-0.3.1.dist-info/RECORD,,