pdf-table-pull-lite 1.1.0__tar.gz → 1.2.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.
Files changed (23) hide show
  1. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/CHANGELOG.md +7 -0
  2. {pdf_table_pull_lite-1.1.0/pdf_table_pull_lite.egg-info → pdf_table_pull_lite-1.2.0}/PKG-INFO +11 -2
  3. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/README.md +9 -0
  4. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0/pdf_table_pull_lite.egg-info}/PKG-INFO +11 -2
  5. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/pdf_table_pull_lite.egg-info/requires.txt +1 -1
  6. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/pdf_table_pull_lite.py +1 -1
  7. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/pdf_table_pull_lite_mcp.py +22 -3
  8. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/pyproject.toml +2 -2
  9. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/server.json +2 -2
  10. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/tests/test_mcp.py +11 -3
  11. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/LICENSE +0 -0
  12. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/MANIFEST.in +0 -0
  13. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/llms.txt +0 -0
  14. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/pdf_table_pull_lite.egg-info/SOURCES.txt +0 -0
  15. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/pdf_table_pull_lite.egg-info/dependency_links.txt +0 -0
  16. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/pdf_table_pull_lite.egg-info/entry_points.txt +0 -0
  17. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/pdf_table_pull_lite.egg-info/top_level.txt +0 -0
  18. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/setup.cfg +0 -0
  19. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/tests/fixtures/empty.pdf +0 -0
  20. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/tests/fixtures/plain.pdf +0 -0
  21. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/tests/fixtures/ruled.pdf +0 -0
  22. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/tests/fixtures/scanned.pdf +0 -0
  23. {pdf_table_pull_lite-1.1.0 → pdf_table_pull_lite-1.2.0}/tests/test_lite.py +0 -0
@@ -2,6 +2,13 @@
2
2
 
3
3
  What changed in pdf-table-pull-lite, newest first.
4
4
 
5
+ ## 1.2.0 - 2026-11-04
6
+
7
+ - MCP tool now has safety labels (tool annotations) so AI apps know what it does:
8
+ readOnlyHint false, destructiveHint true, idempotentHint true, openWorldHint false.
9
+ - The tool description now says when to use it and when not to.
10
+ - Needs mcp 1.10 or newer.
11
+
5
12
  ## 1.1.0 - 2026-11-04
6
13
 
7
14
  - New: a free MCP server, `pdf-table-pull-lite-mcp`. It gives AI apps one tool, `extract_pdf_tables`.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pdf-table-pull-lite
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: Pull the tables out of a text PDF into CSV files. Runs locally. CLI and MCP server.
5
5
  Author: Tidy Byte Tools
6
6
  License-Expression: MIT
@@ -27,9 +27,18 @@ Requires-Python: >=3.10
27
27
  Description-Content-Type: text/markdown
28
28
  License-File: LICENSE
29
29
  Requires-Dist: pdfplumber>=0.10
30
- Requires-Dist: mcp<2,>=1.2
30
+ Requires-Dist: mcp<2,>=1.10
31
31
  Dynamic: license-file
32
32
 
33
+ <p>
34
+ <a href="https://github.com/tidybytetools">
35
+ <picture>
36
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/tidybytetools/pdf-table-pull-lite/main/assets/tidybytetools-lockup-dark.png">
37
+ <img alt="Tidy Byte Tools" src="https://raw.githubusercontent.com/tidybytetools/pdf-table-pull-lite/main/assets/tidybytetools-lockup-light.png" height="44">
38
+ </picture>
39
+ </a>
40
+ </p>
41
+
33
42
  # pdf-table-pull-lite
34
43
 
35
44
  [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/tidybytetools/pdf-table-pull-lite/blob/main/LICENSE)
@@ -1,3 +1,12 @@
1
+ <p>
2
+ <a href="https://github.com/tidybytetools">
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/tidybytetools/pdf-table-pull-lite/main/assets/tidybytetools-lockup-dark.png">
5
+ <img alt="Tidy Byte Tools" src="https://raw.githubusercontent.com/tidybytetools/pdf-table-pull-lite/main/assets/tidybytetools-lockup-light.png" height="44">
6
+ </picture>
7
+ </a>
8
+ </p>
9
+
1
10
  # pdf-table-pull-lite
2
11
 
3
12
  [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/tidybytetools/pdf-table-pull-lite/blob/main/LICENSE)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pdf-table-pull-lite
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: Pull the tables out of a text PDF into CSV files. Runs locally. CLI and MCP server.
5
5
  Author: Tidy Byte Tools
6
6
  License-Expression: MIT
@@ -27,9 +27,18 @@ Requires-Python: >=3.10
27
27
  Description-Content-Type: text/markdown
28
28
  License-File: LICENSE
29
29
  Requires-Dist: pdfplumber>=0.10
30
- Requires-Dist: mcp<2,>=1.2
30
+ Requires-Dist: mcp<2,>=1.10
31
31
  Dynamic: license-file
32
32
 
33
+ <p>
34
+ <a href="https://github.com/tidybytetools">
35
+ <picture>
36
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/tidybytetools/pdf-table-pull-lite/main/assets/tidybytetools-lockup-dark.png">
37
+ <img alt="Tidy Byte Tools" src="https://raw.githubusercontent.com/tidybytetools/pdf-table-pull-lite/main/assets/tidybytetools-lockup-light.png" height="44">
38
+ </picture>
39
+ </a>
40
+ </p>
41
+
33
42
  # pdf-table-pull-lite
34
43
 
35
44
  [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/tidybytetools/pdf-table-pull-lite/blob/main/LICENSE)
@@ -1,2 +1,2 @@
1
1
  pdfplumber>=0.10
2
- mcp<2,>=1.2
2
+ mcp<2,>=1.10
@@ -11,7 +11,7 @@ Usage:
11
11
  """
12
12
  import argparse, csv, os, re, sys
13
13
 
14
- __version__ = "1.1.0"
14
+ __version__ = "1.2.0"
15
15
  PRO_URL = "https://tidybyte.gumroad.com/l/hkxqxh"
16
16
  PRO_LINE = f"Need Excel output, scanned PDFs or tables joined across pages? pdf-table-pull (paid): {PRO_URL}"
17
17
 
@@ -4,20 +4,39 @@ Run: uvx --from git+https://github.com/tidybytetools/pdf-table-pull-lite pdf-ta
4
4
  """
5
5
  import csv, io, os
6
6
  from mcp.server.fastmcp import FastMCP
7
+ from mcp.types import ToolAnnotations
7
8
  import pdf_table_pull_lite as lite
8
9
 
9
10
  mcp = FastMCP("pdf-table-pull-lite")
10
11
 
11
12
 
12
- @mcp.tool()
13
+ @mcp.tool(
14
+ title="Extract PDF tables to CSV",
15
+ annotations=ToolAnnotations(
16
+ title="Extract PDF tables to CSV",
17
+ readOnlyHint=False, # writes CSV files when output_dir is set
18
+ destructiveHint=True, # may replace CSV files with the same names in output_dir
19
+ idempotentHint=True, # same input gives the same output
20
+ openWorldHint=False, # local files only, no network
21
+ ),
22
+ )
13
23
  def extract_pdf_tables(path: str, pages: str = "", strategy: str = "auto", output_dir: str = "") -> list[str]:
14
24
  """Pull the tables out of a local text PDF.
15
25
 
26
+ Use this when you need the rows and columns of a table from a PDF on this
27
+ computer, for example to load them into a spreadsheet, pandas or a database.
28
+ Do not use it for scanned PDFs or photos (there is no OCR), for PDFs on the web
29
+ (download the file first), or when you want the whole document as text
30
+ (use a PDF-to-Markdown or text tool instead).
31
+
16
32
  path: full path to a PDF on this computer.
17
33
  pages: optional, like "1,3-5". Empty means all pages.
18
- strategy: "auto" (default), "lines" (ruled borders) or "text" (lined up by spacing).
34
+ strategy: "auto" (default, tries borders first, then spacing), "lines" (tables with
35
+ ruled borders) or "text" (tables lined up by spacing). Try "text" if "auto" misses
36
+ a table that has no border lines.
19
37
  output_dir: optional. If set, each table is saved there as a CSV and the file paths
20
- are returned. If empty, the CSV text of each table is returned.
38
+ are returned. Files named pageN_tableM.csv that already exist there are replaced.
39
+ If empty, nothing is written and the CSV text of each table is returned.
21
40
 
22
41
  Scanned (image-only) pages have no text and are skipped. Returns [] if no tables.
23
42
  """
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pdf-table-pull-lite"
7
- version = "1.1.0"
7
+ version = "1.2.0"
8
8
  description = "Pull the tables out of a text PDF into CSV files. Runs locally. CLI and MCP server."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -13,7 +13,7 @@ authors = [{name = "Tidy Byte Tools"}]
13
13
  requires-python = ">=3.10"
14
14
  dependencies = [
15
15
  "pdfplumber>=0.10",
16
- "mcp>=1.2,<2",
16
+ "mcp>=1.10,<2",
17
17
  ]
18
18
  keywords = ["pdf", "table", "csv", "extract", "pdf-to-csv", "pdfplumber", "cli", "mcp", "mcp-server"]
19
19
  classifiers = [
@@ -8,13 +8,13 @@
8
8
  "source": "github"
9
9
  },
10
10
  "websiteUrl": "https://github.com/tidybytetools/pdf-table-pull-lite",
11
- "version": "1.1.0",
11
+ "version": "1.2.0",
12
12
  "packages": [
13
13
  {
14
14
  "registryType": "pypi",
15
15
  "registryBaseUrl": "https://pypi.org",
16
16
  "identifier": "pdf-table-pull-lite",
17
- "version": "1.1.0",
17
+ "version": "1.2.0",
18
18
  "runtimeHint": "uvx",
19
19
  "transport": {
20
20
  "type": "stdio"
@@ -15,15 +15,23 @@ async def _run():
15
15
  async with stdio_client(params) as (r, w):
16
16
  async with ClientSession(r, w) as s:
17
17
  await s.initialize()
18
- tools = [t.name for t in (await s.list_tools()).tools]
18
+ listed = (await s.list_tools()).tools
19
+ tools = [t.name for t in listed]
20
+ ann = listed[0].annotations
19
21
  res = await s.call_tool("extract_pdf_tables", {"path": os.path.abspath(os.path.join(HERE, "fixtures", "ruled.pdf")), "pages": "1"})
20
- return tools, res
22
+ return tools, res, ann
21
23
 
22
24
 
23
25
  @unittest.skipIf(ClientSession is None, "mcp not installed")
24
26
  class MCP(unittest.TestCase):
25
27
  def test_lists_and_calls_tool(self):
26
- tools, res = asyncio.run(_run())
28
+ tools, res, ann = asyncio.run(_run())
29
+ self.assertIsNotNone(ann)
30
+ self.assertIs(ann.readOnlyHint, False)
31
+ self.assertIs(ann.destructiveHint, True)
32
+ self.assertIs(ann.idempotentHint, True)
33
+ self.assertIs(ann.openWorldHint, False)
34
+
27
35
  self.assertEqual(tools, ["extract_pdf_tables"])
28
36
  self.assertFalse(res.isError)
29
37
  text = " ".join(c.text for c in res.content if getattr(c, "type", "") == "text")