pdfco-mcp 0.0.1__py3-none-any.whl → 0.0.3__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.
pdfco/mcp/__init__.py CHANGED
@@ -1,8 +1,27 @@
1
+ import sys
1
2
  from pdfco.mcp.server import mcp
2
3
  from pdfco.mcp.tools.apis import conversion, job, file, modification, form, search, searchable, security, document, extraction, editing
3
4
 
4
5
  def main():
5
- mcp.run(transport="stdio")
6
+ if len(sys.argv) > 1:
7
+ transport = sys.argv[1]
8
+ if transport == "stdio":
9
+ mcp.run(transport=transport)
10
+ elif transport == "sse":
11
+ if len(sys.argv) < 2:
12
+ raise ValueError("SSE transport requires a port number")
13
+ port = int(sys.argv[2])
14
+ mcp.run(transport=transport, host="0.0.0.0", port=port)
15
+ elif transport == "streamable-http":
16
+ if len(sys.argv) < 3:
17
+ raise ValueError("Streamable HTTP transport requires a port number and path")
18
+ port = int(sys.argv[2])
19
+ path = sys.argv[3]
20
+ mcp.run(transport=transport, host="0.0.0.0", port=port, path=path)
21
+ else:
22
+ raise ValueError(f"Invalid transport: {transport}")
23
+ else:
24
+ mcp.run(transport="stdio")
6
25
 
7
26
  if __name__ == "__main__":
8
27
  main()
pdfco/mcp/server.py CHANGED
@@ -1,3 +1,3 @@
1
- from mcp.server.fastmcp import FastMCP
1
+ from fastmcp import FastMCP
2
2
 
3
3
  mcp = FastMCP("pdfco")
@@ -1,7 +1,7 @@
1
1
  from contextlib import asynccontextmanager
2
2
  from httpx import AsyncClient
3
3
  import os, sys
4
- from typing import AsyncGenerator
4
+ from typing import AsyncGenerator, Optional
5
5
  import importlib.metadata
6
6
 
7
7
  __BASE_URL = "https://api.pdf.co"
@@ -11,11 +11,19 @@ __version__ = importlib.metadata.version('pdfco-mcp')
11
11
  print(f"pdfco-mcp version: {__version__}", file=sys.stderr)
12
12
 
13
13
  @asynccontextmanager
14
- async def PDFCoClient() -> AsyncGenerator[AsyncClient, None]:
15
- if not X_API_KEY:
16
- raise ValueError("""X_API_KEY is not set. Please set X_API_KEY in the environment variables in your MCP server.
17
- To get the API key please sign up at https://pdf.co and you can get the API key from the dashboard.
18
- ex) .cursor/mcp.json
14
+ async def PDFCoClient(api_key: str = None) -> AsyncGenerator[AsyncClient, None]:
15
+ # Use provided API key, fall back to environment variable
16
+ x_api_key = api_key or X_API_KEY
17
+
18
+ if not x_api_key:
19
+ raise ValueError("""API key is required. Please provide an API key as a parameter or set X_API_KEY in the environment variables.
20
+
21
+ To get the API key:
22
+ 1. Sign up at https://pdf.co
23
+ 2. Get the API key from the dashboard
24
+ 3. Either set it as an environment variable or provide it as a parameter
25
+
26
+ Environment variable setup example (.cursor/mcp.json):
19
27
  ```json
20
28
  {
21
29
  "mcpServers": {
@@ -31,12 +39,14 @@ async def PDFCoClient() -> AsyncGenerator[AsyncClient, None]:
31
39
  }
32
40
  }
33
41
  ```
42
+
43
+ Or provide the API key as a parameter when calling the tool.
34
44
  """)
35
45
 
36
46
  client = AsyncClient(
37
47
  base_url=__BASE_URL,
38
48
  headers={
39
- "x-api-key": X_API_KEY,
49
+ "x-api-key": x_api_key,
40
50
  "User-Agent": f"pdfco-mcp/{__version__}",
41
51
  },
42
52
  )
pdfco/mcp/services/pdf.py CHANGED
@@ -2,30 +2,30 @@ import sys
2
2
  from pdfco.mcp.models import BaseResponse, ConversionParams
3
3
  from pdfco.mcp.services.client import PDFCoClient
4
4
 
5
- async def convert_to(_from: str, _to: str, params: ConversionParams) -> BaseResponse:
6
- return await request(f'{_from}/convert/to/{_to}', params)
5
+ async def convert_to(_from: str, _to: str, params: ConversionParams, api_key: str = None) -> BaseResponse:
6
+ return await request(f'{_from}/convert/to/{_to}', params, api_key=api_key)
7
7
 
8
- async def convert_from(_to: str, _from: str, params: ConversionParams) -> BaseResponse:
9
- return await request(f'{_to}/convert/from/{_from}', params)
8
+ async def convert_from(_to: str, _from: str, params: ConversionParams, api_key: str = None) -> BaseResponse:
9
+ return await request(f'{_to}/convert/from/{_from}', params, api_key=api_key)
10
10
 
11
- async def merge_pdf(params: ConversionParams) -> BaseResponse:
12
- return await request(f'pdf/merge2', params)
11
+ async def merge_pdf(params: ConversionParams, api_key: str = None) -> BaseResponse:
12
+ return await request(f'pdf/merge2', params, api_key=api_key)
13
13
 
14
- async def split_pdf(params: ConversionParams) -> BaseResponse:
15
- return await request(f'pdf/split', params)
14
+ async def split_pdf(params: ConversionParams, api_key: str = None) -> BaseResponse:
15
+ return await request(f'pdf/split', params, api_key=api_key)
16
16
 
17
- async def get_pdf_form_fields_info(params: ConversionParams) -> BaseResponse:
18
- return await request('pdf/info/fields', params)
17
+ async def get_pdf_form_fields_info(params: ConversionParams, api_key: str = None) -> BaseResponse:
18
+ return await request('pdf/info/fields', params, api_key=api_key)
19
19
 
20
- async def fill_pdf_form_fields(params: ConversionParams, fields: list = None, annotations: list = None) -> BaseResponse:
20
+ async def fill_pdf_form_fields(params: ConversionParams, fields: list = None, annotations: list = None, api_key: str = None) -> BaseResponse:
21
21
  custom_payload = {}
22
22
  if fields:
23
23
  custom_payload["fields"] = fields
24
24
  if annotations:
25
25
  custom_payload["annotations"] = annotations
26
- return await request('pdf/edit/add', params, custom_payload=custom_payload)
26
+ return await request('pdf/edit/add', params, custom_payload=custom_payload, api_key=api_key)
27
27
 
28
- async def pdf_add(params: ConversionParams, **kwargs) -> BaseResponse:
28
+ async def pdf_add(params: ConversionParams, api_key: str = None, **kwargs) -> BaseResponse:
29
29
  """General PDF Add function that supports all PDF Add API parameters"""
30
30
  custom_payload = {}
31
31
 
@@ -34,48 +34,48 @@ async def pdf_add(params: ConversionParams, **kwargs) -> BaseResponse:
34
34
  if value is not None and value != "":
35
35
  custom_payload[key] = value
36
36
 
37
- return await request('pdf/edit/add', params, custom_payload=custom_payload)
37
+ return await request('pdf/edit/add', params, custom_payload=custom_payload, api_key=api_key)
38
38
 
39
- async def find_text_in_pdf(params: ConversionParams, search_string: str, regex_search: bool = False, word_matching_mode: str = None) -> BaseResponse:
39
+ async def find_text_in_pdf(params: ConversionParams, search_string: str, regex_search: bool = False, word_matching_mode: str = None, api_key: str = None) -> BaseResponse:
40
40
  custom_payload = {
41
41
  "searchString": search_string,
42
42
  "regexSearch": regex_search
43
43
  }
44
44
  if word_matching_mode:
45
45
  custom_payload["wordMatchingMode"] = word_matching_mode
46
- return await request('pdf/find', params, custom_payload=custom_payload)
46
+ return await request('pdf/find', params, custom_payload=custom_payload, api_key=api_key)
47
47
 
48
- async def find_table_in_pdf(params: ConversionParams) -> BaseResponse:
49
- return await request('pdf/find/table', params)
48
+ async def find_table_in_pdf(params: ConversionParams, api_key: str = None) -> BaseResponse:
49
+ return await request('pdf/find/table', params, api_key=api_key)
50
50
 
51
- async def make_pdf_searchable(params: ConversionParams) -> BaseResponse:
52
- return await request('pdf/makesearchable', params)
51
+ async def make_pdf_searchable(params: ConversionParams, api_key: str = None) -> BaseResponse:
52
+ return await request('pdf/makesearchable', params, api_key=api_key)
53
53
 
54
- async def make_pdf_unsearchable(params: ConversionParams) -> BaseResponse:
55
- return await request('pdf/makeunsearchable', params)
54
+ async def make_pdf_unsearchable(params: ConversionParams, api_key: str = None) -> BaseResponse:
55
+ return await request('pdf/makeunsearchable', params, api_key=api_key)
56
56
 
57
- async def get_pdf_info(params: ConversionParams) -> BaseResponse:
58
- return await request('pdf/info', params)
57
+ async def get_pdf_info(params: ConversionParams, api_key: str = None) -> BaseResponse:
58
+ return await request('pdf/info', params, api_key=api_key)
59
59
 
60
- async def add_pdf_password(params: ConversionParams, **kwargs) -> BaseResponse:
61
- return await request('pdf/security/add', params, custom_payload=kwargs)
60
+ async def add_pdf_password(params: ConversionParams, api_key: str = None, **kwargs) -> BaseResponse:
61
+ return await request('pdf/security/add', params, custom_payload=kwargs, api_key=api_key)
62
62
 
63
- async def remove_pdf_password(params: ConversionParams) -> BaseResponse:
64
- return await request('pdf/security/remove', params)
63
+ async def remove_pdf_password(params: ConversionParams, api_key: str = None) -> BaseResponse:
64
+ return await request('pdf/security/remove', params, api_key=api_key)
65
65
 
66
- async def parse_invoice(params: ConversionParams) -> BaseResponse:
67
- return await request('ai-invoice-parser', params)
66
+ async def parse_invoice(params: ConversionParams, api_key: str = None) -> BaseResponse:
67
+ return await request('ai-invoice-parser', params, api_key=api_key)
68
68
 
69
- async def extract_pdf_attachments(params: ConversionParams) -> BaseResponse:
70
- return await request('pdf/attachments/extract', params)
69
+ async def extract_pdf_attachments(params: ConversionParams, api_key: str = None) -> BaseResponse:
70
+ return await request('pdf/attachments/extract', params, api_key=api_key)
71
71
 
72
- async def request(endpoint: str, params: ConversionParams, custom_payload: dict = None) -> BaseResponse:
72
+ async def request(endpoint: str, params: ConversionParams, custom_payload: dict = None, api_key: str = None) -> BaseResponse:
73
73
  payload = params.parse_payload(async_mode=True)
74
74
  if custom_payload:
75
75
  payload.update(custom_payload)
76
76
 
77
77
  try:
78
- async with PDFCoClient() as client:
78
+ async with PDFCoClient(api_key=api_key) as client:
79
79
  url = f"/v1/{endpoint}"
80
80
  print(f"Requesting {url} with payload {payload}", file=sys.stderr)
81
81
  response = await client.post(url, json=payload)
@@ -4,7 +4,6 @@ from pdfco.mcp.models import BaseResponse, ConversionParams
4
4
 
5
5
  from pydantic import Field
6
6
 
7
-
8
7
  @mcp.tool()
9
8
  async def pdf_to_json(
10
9
  url: str = Field(description="URL to the source file. Supports publicly accessible links including Google Drive, Dropbox, PDF.co Built-In Files Storage. Use 'upload_file' tool to upload local files."),
@@ -17,12 +16,13 @@ async def pdf_to_json(
17
16
  line_grouping: str = Field(description="Enables line grouping within table cells when set to '1'. (Optional)", default="0"),
18
17
  password: str = Field(description="Password of the PDF file. (Optional)", default=""),
19
18
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
19
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
20
20
  ) -> BaseResponse:
21
21
  """
22
22
  Convert PDF and scanned images into JSON representation with text, fonts, images, vectors, and formatting preserved using the /pdf/convert/to/json2 endpoint.
23
23
  Ref: https://developer.pdf.co/api-reference/pdf-to-json/basic.md
24
24
  """
25
- return await convert_to("pdf", "json2", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, unwrap=unwrap, rect=rect, lang=lang, line_grouping=line_grouping, password=password, name=name))
25
+ return await convert_to("pdf", "json2", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, unwrap=unwrap, rect=rect, lang=lang, line_grouping=line_grouping, password=password, name=name), api_key=api_key)
26
26
 
27
27
  @mcp.tool()
28
28
  async def pdf_to_csv(
@@ -36,12 +36,13 @@ async def pdf_to_csv(
36
36
  line_grouping: str = Field(description="Enables line grouping within table cells when set to '1'. (Optional)", default="0"),
37
37
  password: str = Field(description="Password of the PDF file. (Optional)", default=""),
38
38
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
39
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
39
40
  ) -> BaseResponse:
40
41
  """
41
42
  Convert PDF and scanned images into CSV representation with layout, columns, rows, and tables.
42
43
  Ref: https://developer.pdf.co/api-reference/pdf-to-csv.md
43
44
  """
44
- return await convert_to("pdf", "csv", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, unwrap=unwrap, rect=rect, lang=lang, line_grouping=line_grouping, password=password, name=name))
45
+ return await convert_to("pdf", "csv", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, unwrap=unwrap, rect=rect, lang=lang, line_grouping=line_grouping, password=password, name=name, api_key=api_key))
45
46
 
46
47
  @mcp.tool()
47
48
  async def pdf_to_text(
@@ -55,12 +56,13 @@ async def pdf_to_text(
55
56
  line_grouping: str = Field(description="Enables line grouping within table cells when set to '1'. (Optional)", default="0"),
56
57
  password: str = Field(description="Password of the PDF file. (Optional)", default=""),
57
58
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
59
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
58
60
  ) -> BaseResponse:
59
61
  """
60
62
  Convert PDF and scanned images to text with layout preserved.
61
63
  Ref: https://developer.pdf.co/api-reference/pdf-to-text/basic.md
62
64
  """
63
- return await convert_to("pdf", "text", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, unwrap=unwrap, rect=rect, lang=lang, line_grouping=line_grouping, password=password, name=name))
65
+ return await convert_to("pdf", "text", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, unwrap=unwrap, rect=rect, lang=lang, line_grouping=line_grouping, password=password, name=name, api_key=api_key))
64
66
 
65
67
  @mcp.tool()
66
68
  async def pdf_to_xls(
@@ -74,12 +76,13 @@ async def pdf_to_xls(
74
76
  line_grouping: str = Field(description="Enables line grouping within table cells when set to '1'. (Optional)", default="0"),
75
77
  password: str = Field(description="Password of the PDF file. (Optional)", default=""),
76
78
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
79
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
77
80
  ) -> BaseResponse:
78
81
  """
79
82
  Convert PDF and scanned images to XLS (Excel 97-2003) format.
80
83
  Ref: https://developer.pdf.co/api-reference/pdf-to-excel/xls.md
81
84
  """
82
- return await convert_to("pdf", "xls", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, unwrap=unwrap, rect=rect, lang=lang, line_grouping=line_grouping, password=password, name=name))
85
+ return await convert_to("pdf", "xls", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, unwrap=unwrap, rect=rect, lang=lang, line_grouping=line_grouping, password=password, name=name, api_key=api_key))
83
86
 
84
87
  @mcp.tool()
85
88
  async def pdf_to_xlsx(
@@ -93,12 +96,13 @@ async def pdf_to_xlsx(
93
96
  line_grouping: str = Field(description="Enables line grouping within table cells when set to '1'. (Optional)", default="0"),
94
97
  password: str = Field(description="Password of the PDF file. (Optional)", default=""),
95
98
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
99
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
96
100
  ) -> BaseResponse:
97
101
  """
98
102
  Convert PDF and scanned images to XLSX (Excel 2007+) format.
99
103
  Ref: https://developer.pdf.co/api-reference/pdf-to-excel/xlsx.md
100
104
  """
101
- return await convert_to("pdf", "xlsx", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, unwrap=unwrap, rect=rect, lang=lang, line_grouping=line_grouping, password=password, name=name))
105
+ return await convert_to("pdf", "xlsx", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, unwrap=unwrap, rect=rect, lang=lang, line_grouping=line_grouping, password=password, name=name, api_key=api_key))
102
106
 
103
107
  @mcp.tool()
104
108
  async def pdf_to_xml(
@@ -112,12 +116,13 @@ async def pdf_to_xml(
112
116
  line_grouping: str = Field(description="Enables line grouping within table cells when set to '1'. (Optional)", default="0"),
113
117
  password: str = Field(description="Password of the PDF file. (Optional)", default=""),
114
118
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
119
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
115
120
  ) -> BaseResponse:
116
121
  """
117
122
  Convert PDF and scanned images to XML format.
118
123
  Ref: https://developer.pdf.co/api-reference/pdf-to-xml.md
119
124
  """
120
- return await convert_to("pdf", "xml", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, unwrap=unwrap, rect=rect, lang=lang, line_grouping=line_grouping, password=password, name=name))
125
+ return await convert_to("pdf", "xml", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, unwrap=unwrap, rect=rect, lang=lang, line_grouping=line_grouping, password=password, name=name, api_key=api_key))
121
126
 
122
127
  @mcp.tool()
123
128
  async def pdf_to_html(
@@ -131,12 +136,13 @@ async def pdf_to_html(
131
136
  line_grouping: str = Field(description="Enables line grouping within table cells when set to '1'. (Optional)", default="0"),
132
137
  password: str = Field(description="Password of the PDF file. (Optional)", default=""),
133
138
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
139
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
134
140
  ) -> BaseResponse:
135
141
  """
136
142
  Convert PDF and scanned images to HTML format.
137
143
  Ref: https://developer.pdf.co/api-reference/pdf-to-html.md
138
144
  """
139
- return await convert_to("pdf", "html", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, unwrap=unwrap, rect=rect, lang=lang, line_grouping=line_grouping, password=password, name=name))
145
+ return await convert_to("pdf", "html", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, unwrap=unwrap, rect=rect, lang=lang, line_grouping=line_grouping, password=password, name=name, api_key=api_key))
140
146
 
141
147
  @mcp.tool()
142
148
  async def pdf_to_image(
@@ -151,6 +157,7 @@ async def pdf_to_image(
151
157
  password: str = Field(description="Password of the PDF file. (Optional)", default=""),
152
158
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
153
159
  type: str = Field(description="Type of image to convert to. (jpg, png, webp, tiff) (Optional)", default="jpg", choices=["jpg", "png", "webp", "tiff"]),
160
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
154
161
  ) -> BaseResponse:
155
162
  """
156
163
  Convert PDF and scanned images to various image formats (JPG, PNG, WebP, TIFF).
@@ -160,7 +167,7 @@ async def pdf_to_image(
160
167
  - https://developer.pdf.co/api-reference/pdf-to-image/webp.md
161
168
  - https://developer.pdf.co/api-reference/pdf-to-image/tiff.md
162
169
  """
163
- return await convert_to("pdf", type, ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, unwrap=unwrap, rect=rect, lang=lang, line_grouping=line_grouping, password=password, name=name))
170
+ return await convert_to("pdf", type, ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, unwrap=unwrap, rect=rect, lang=lang, line_grouping=line_grouping, password=password, name=name, api_key=api_key))
164
171
 
165
172
  @mcp.tool()
166
173
  async def document_to_pdf(
@@ -170,12 +177,13 @@ async def document_to_pdf(
170
177
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
171
178
  pages: str = Field(description="Comma-separated page indices (e.g., '0, 1, 2-' or '1, 3-7'). Use '!' for inverted page numbers (e.g., '!0' for last page). Processes all pages if None. (Optional)", default=""),
172
179
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
180
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
173
181
  ) -> BaseResponse:
174
182
  """
175
183
  Convert various document types (DOC, DOCX, RTF, TXT, XLS, XLSX, CSV, HTML, JPG, PNG, TIFF, WEBP) into PDF.
176
184
  Ref: https://developer.pdf.co/api-reference/pdf-from-document/doc.md
177
185
  """
178
- return await convert_from("pdf", "doc", ConversionParams(url=url, autosize=autosize, httpusername=httpusername, httppassword=httppassword, pages=pages, name=name))
186
+ return await convert_from("pdf", "doc", ConversionParams(url=url, autosize=autosize, httpusername=httpusername, httppassword=httppassword, pages=pages, name=name, api_key=api_key))
179
187
 
180
188
  @mcp.tool()
181
189
  async def csv_to_pdf(
@@ -185,12 +193,13 @@ async def csv_to_pdf(
185
193
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
186
194
  pages: str = Field(description="Comma-separated page indices (e.g., '0, 1, 2-' or '1, 3-7'). Use '!' for inverted page numbers (e.g., '!0' for last page). Processes all pages if None. (Optional)", default=""),
187
195
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
196
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
188
197
  ) -> BaseResponse:
189
198
  """
190
199
  Convert CSV or spreadsheet files (XLS, XLSX) to PDF.
191
200
  Ref: https://developer.pdf.co/api-reference/pdf-from-document/csv.md
192
201
  """
193
- return await convert_from("pdf", "csv", ConversionParams(url=url, autosize=autosize, httpusername=httpusername, httppassword=httppassword, pages=pages, name=name))
202
+ return await convert_from("pdf", "csv", ConversionParams(url=url, autosize=autosize, httpusername=httpusername, httppassword=httppassword, pages=pages, name=name, api_key=api_key))
194
203
 
195
204
  @mcp.tool()
196
205
  async def image_to_pdf(
@@ -199,13 +208,14 @@ async def image_to_pdf(
199
208
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
200
209
  pages: str = Field(description="Comma-separated page indices (e.g., '0, 1, 2-' or '1, 3-7'). Use '!' for inverted page numbers (e.g., '!0' for last page). Processes all pages if None. (Optional)", default=""),
201
210
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
211
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
202
212
  ) -> BaseResponse:
203
213
  """
204
214
  Convert various image formats (JPG, PNG, TIFF) to PDF.
205
215
  Ref: https://developer.pdf.co/api-reference/pdf-from-image.md
206
216
  ```
207
217
  """
208
- return await convert_from("pdf", "image", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, name=name))
218
+ return await convert_from("pdf", "image", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, pages=pages, name=name, api_key=api_key))
209
219
 
210
220
  @mcp.tool()
211
221
  async def webpage_to_pdf(
@@ -221,6 +231,7 @@ async def webpage_to_pdf(
221
231
  httpusername: str = Field(description="HTTP auth user name if required to access source url. (Optional)", default=""),
222
232
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
223
233
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
234
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
224
235
  ) -> BaseResponse:
225
236
  """
226
237
  Convert external webpage URL to PDF.
@@ -237,7 +248,7 @@ async def webpage_to_pdf(
237
248
  ```html
238
249
  <span style='font-size:10px'>Page <span class='pageNumber'></span> of <span class='totalPages'></span>.</span>
239
250
  """
240
- return await convert_from("pdf", "url", ConversionParams(url=url, margins=margins, paperSize=paperSize, orientation=orientation, printBackground=printBackground, mediaType=mediaType, DoNotWaitFullLoad=DoNotWaitFullLoad, header=header, footer=footer, httpusername=httpusername, httppassword=httppassword, name=name))
251
+ return await convert_from("pdf", "url", ConversionParams(url=url, margins=margins, paperSize=paperSize, orientation=orientation, printBackground=printBackground, mediaType=mediaType, DoNotWaitFullLoad=DoNotWaitFullLoad, header=header, footer=footer, httpusername=httpusername, httppassword=httppassword, name=name, api_key=api_key))
241
252
 
242
253
  @mcp.tool()
243
254
  async def html_to_pdf(
@@ -253,6 +264,7 @@ async def html_to_pdf(
253
264
  httpusername: str = Field(description="HTTP auth user name if required to access source url. (Optional)", default=""),
254
265
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
255
266
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
267
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
256
268
  ) -> BaseResponse:
257
269
  """
258
270
  Convert HTML to PDF.
@@ -269,7 +281,7 @@ async def html_to_pdf(
269
281
  ```html
270
282
  <span style='font-size:10px'>Page <span class='pageNumber'></span> of <span class='totalPages'></span>.</span>
271
283
  """
272
- return await convert_from("pdf", "html", ConversionParams(html=html, margins=margins, paperSize=paperSize, orientation=orientation, printBackground=printBackground, mediaType=mediaType, DoNotWaitFullLoad=DoNotWaitFullLoad, header=header, footer=footer, httpusername=httpusername, httppassword=httppassword, name=name))
284
+ return await convert_from("pdf", "html", ConversionParams(html=html, margins=margins, paperSize=paperSize, orientation=orientation, printBackground=printBackground, mediaType=mediaType, DoNotWaitFullLoad=DoNotWaitFullLoad, header=header, footer=footer, httpusername=httpusername, httppassword=httppassword, name=name, api_key=api_key))
273
285
 
274
286
  @mcp.tool()
275
287
  async def email_to_pdf(
@@ -279,12 +291,13 @@ async def email_to_pdf(
279
291
  margins: str = Field(description="Set to CSS style margins like 10px, 5mm, 5in for all sides or 5px 5px 5px 5px (the order of margins is top, right, bottom, left). (Optional)", default=""),
280
292
  paperSize: str = Field(description="A4 is set by default. Can be Letter, Legal, Tabloid, Ledger, A0, A1, A2, A3, A4, A5, A6 or a custom size. Custom size can be set in px (pixels), mm or in (inches) with width and height separated by space like this: 200 300, 200px 300px, 200mm 300mm, 20cm 30cm or 6in 8in. (Optional)", default=""),
281
293
  orientation: str = Field(description="Set to Portrait or Landscape. Portrait is set by default. (Optional)", default=""),
294
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
282
295
  ) -> BaseResponse:
283
296
  """
284
297
  Convert email to PDF.
285
298
  Ref: https://developer.pdf.co/api-reference/pdf-from-email.md
286
299
  """
287
- return await convert_from("pdf", "email", ConversionParams(url=url, embedAttachments=embedAttachments, convertAttachments=convertAttachments, margins=margins, paperSize=paperSize, orientation=orientation))
300
+ return await convert_from("pdf", "email", ConversionParams(url=url, embedAttachments=embedAttachments, convertAttachments=convertAttachments, margins=margins, paperSize=paperSize, orientation=orientation, api_key=api_key))
288
301
 
289
302
  @mcp.tool()
290
303
  async def excel_to_csv(
@@ -293,12 +306,13 @@ async def excel_to_csv(
293
306
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
294
307
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
295
308
  worksheetIndex: str = Field(description="Index of the worksheet to convert. (Optional)", default=""),
309
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
296
310
  ) -> BaseResponse:
297
311
  """
298
312
  Convert Excel(XLS, XLSX) to CSV.
299
313
  Ref: https://developer.pdf.co/api-reference/convert-from-excel/csv.md
300
314
  """
301
- return await convert_to("xls", "csv", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, name=name, worksheetIndex=worksheetIndex))
315
+ return await convert_to("xls", "csv", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, name=name, worksheetIndex=worksheetIndex, api_key=api_key))
302
316
 
303
317
  @mcp.tool()
304
318
  async def excel_to_json(
@@ -307,12 +321,13 @@ async def excel_to_json(
307
321
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
308
322
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
309
323
  worksheetIndex: str = Field(description="Index of the worksheet to convert. (Optional)", default=""),
324
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
310
325
  ) -> BaseResponse:
311
326
  """
312
327
  Convert Excel(XLS, XLSX) to JSON.
313
328
  Ref: https://developer.pdf.co/api-reference/convert-from-excel/json.md
314
329
  """
315
- return await convert_to("xls", "json", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, name=name, worksheetIndex=worksheetIndex))
330
+ return await convert_to("xls", "json", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, name=name, worksheetIndex=worksheetIndex, api_key=api_key))
316
331
 
317
332
  @mcp.tool()
318
333
  async def excel_to_html(
@@ -321,12 +336,13 @@ async def excel_to_html(
321
336
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
322
337
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
323
338
  worksheetIndex: str = Field(description="Index of the worksheet to convert. (Optional)", default=""),
339
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
324
340
  ) -> BaseResponse:
325
341
  """
326
342
  Convert Excel(XLS, XLSX) to HTML.
327
343
  Ref: https://developer.pdf.co/api-reference/convert-from-excel/html.md
328
344
  """
329
- return await convert_to("xls", "html", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, name=name, worksheetIndex=worksheetIndex))
345
+ return await convert_to("xls", "html", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, name=name, worksheetIndex=worksheetIndex, api_key=api_key))
330
346
 
331
347
  @mcp.tool()
332
348
  async def excel_to_txt(
@@ -335,12 +351,13 @@ async def excel_to_txt(
335
351
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
336
352
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
337
353
  worksheetIndex: str = Field(description="Index of the worksheet to convert. (Optional)", default=""),
354
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
338
355
  ) -> BaseResponse:
339
356
  """
340
357
  Convert Excel(XLS, XLSX) to TXT.
341
358
  Ref: https://developer.pdf.co/api-reference/convert-from-excel/text.md
342
359
  """
343
- return await convert_to("xls", "txt", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, name=name, worksheetIndex=worksheetIndex))
360
+ return await convert_to("xls", "txt", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, name=name, worksheetIndex=worksheetIndex, api_key=api_key))
344
361
 
345
362
  @mcp.tool()
346
363
  async def excel_to_xml(
@@ -349,12 +366,13 @@ async def excel_to_xml(
349
366
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
350
367
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
351
368
  worksheetIndex: str = Field(description="Index of the worksheet to convert. (Optional)", default=""),
369
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
352
370
  ) -> BaseResponse:
353
371
  """
354
372
  Convert Excel(XLS, XLSX) to XML.
355
373
  Ref: https://developer.pdf.co/api-reference/convert-from-excel/xml.md
356
374
  """
357
- return await convert_to("xls", "xml", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, name=name, worksheetIndex=worksheetIndex))
375
+ return await convert_to("xls", "xml", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, name=name, worksheetIndex=worksheetIndex, api_key=api_key))
358
376
 
359
377
  @mcp.tool()
360
378
  async def excel_to_pdf(
@@ -363,9 +381,10 @@ async def excel_to_pdf(
363
381
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
364
382
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
365
383
  worksheetIndex: str = Field(description="Index of the worksheet to convert. (Optional)", default=""),
384
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
366
385
  ) -> BaseResponse:
367
386
  """
368
387
  Convert Excel(XLS, XLSX) to PDF.
369
388
  Ref: https://developer.pdf.co/api-reference/convert-from-excel/pdf.md
370
389
  """
371
- return await convert_to("xls", "pdf", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, name=name, worksheetIndex=worksheetIndex))
390
+ return await convert_to("xls", "pdf", ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, name=name, worksheetIndex=worksheetIndex, api_key=api_key))
@@ -10,6 +10,7 @@ async def pdf_info_reader(
10
10
  httpusername: str = Field(description="HTTP auth user name if required to access source url. (Optional)", default=""),
11
11
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
12
12
  password: str = Field(description="Password of the PDF file. (Optional)", default=""),
13
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
13
14
  ) -> BaseResponse:
14
15
  """
15
16
  Get detailed information about a PDF document - number of pages, metadata, security, form fields, and more.
@@ -22,4 +23,4 @@ async def pdf_info_reader(
22
23
  password=password,
23
24
  )
24
25
 
25
- return await get_pdf_info(params)
26
+ return await get_pdf_info(params, api_key=api_key)
@@ -19,6 +19,7 @@ async def pdf_add_annotations_images_fields(
19
19
  expiration: int = Field(description="Set the expiration time for the output link in minutes. After this specified duration, any generated output file(s) will be automatically deleted. (Optional)", default=60),
20
20
  encrypt: bool = Field(description="Encrypt output file. (Optional)", default=False),
21
21
  flatten: bool = Field(description="Flatten filled form fields and annotations into PDF content. Set to true to disable editing of filled form fields in the output PDF. (Optional)", default=False),
22
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
22
23
  ) -> BaseResponse:
23
24
  """
24
25
  Add text, images, forms, other PDFs, fill forms, links to external sites and external PDF files. You can update or modify PDF and scanned PDF files.
@@ -68,4 +69,4 @@ async def pdf_add_annotations_images_fields(
68
69
  if flatten:
69
70
  add_params["flatten"] = flatten
70
71
 
71
- return await pdf_add(params, **add_params)
72
+ return await pdf_add(params, **add_params, api_key=api_key)
@@ -8,18 +8,19 @@ from pydantic import Field
8
8
  @mcp.tool()
9
9
  async def ai_invoice_parser(
10
10
  url: str = Field(description="URL to the source PDF file. Supports publicly accessible links including Google Drive, Dropbox, PDF.co Built-In Files Storage. Use 'upload_file' tool to upload local files."),
11
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
11
12
  ) -> BaseResponse:
12
13
  """
13
14
  AI Invoice Parser: Extracts data from invoices using AI.
14
15
  Ref: https://developer.pdf.co/api-reference/ai-invoice-parser.md
15
16
  """
16
17
 
17
- # Pass arguments directly; ConversionParams now handles Optional[str] with default=None
18
+ # Pass arguments directly; ConversionParams now handles str with default=None
18
19
  params = ConversionParams(
19
20
  url=url,
20
21
  )
21
22
 
22
- return await parse_invoice(params)
23
+ return await parse_invoice(params, api_key=api_key)
23
24
 
24
25
 
25
26
  @mcp.tool()
@@ -28,6 +29,7 @@ async def extract_attachments(
28
29
  httpusername: str = Field(description="HTTP auth user name if required to access source url. (Optional)", default=""),
29
30
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
30
31
  password: str = Field(description="Password of PDF file. (Optional)", default=""),
32
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
31
33
  ) -> BaseResponse:
32
34
  """
33
35
  Extracts attachments from a source PDF file.
@@ -39,4 +41,4 @@ async def extract_attachments(
39
41
  httppassword=httppassword if httppassword else None,
40
42
  password=password if password else None,
41
43
  )
42
- return await extract_pdf_attachments(params)
44
+ return await extract_pdf_attachments(params, api_key=api_key)
@@ -7,13 +7,14 @@ from pydantic import Field
7
7
 
8
8
  @mcp.tool()
9
9
  async def upload_file(
10
- file_path: str = Field(description="The absolute path to the file to upload"),
10
+ file_path: str = Field(description="The absolute path to the file to upload"),
11
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None)
11
12
  ) -> BaseResponse:
12
13
  """
13
14
  Upload a file to the PDF.co API
14
15
  """
15
16
  try:
16
- async with PDFCoClient() as client:
17
+ async with PDFCoClient(api_key=api_key) as client:
17
18
  response = await client.post(
18
19
  "/v1/file/upload",
19
20
  files={
@@ -11,6 +11,7 @@ async def read_pdf_forms_info(
11
11
  httpusername: str = Field(description="HTTP auth user name if required to access source url. (Optional)", default=""),
12
12
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
13
13
  password: str = Field(description="Password of PDF file. (Optional)", default=""),
14
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
14
15
  ) -> BaseResponse:
15
16
  """
16
17
  Extracts information about fillable PDF fields from an input PDF file.
@@ -23,7 +24,7 @@ async def read_pdf_forms_info(
23
24
  password=password,
24
25
  )
25
26
 
26
- return await get_pdf_form_fields_info(params)
27
+ return await get_pdf_form_fields_info(params, api_key=api_key)
27
28
 
28
29
  @mcp.tool(name="fill_forms")
29
30
  async def fill_pdf_forms(
@@ -32,6 +33,7 @@ async def fill_pdf_forms(
32
33
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
33
34
  httpusername: str = Field(description="HTTP auth user name if required to access source url. (Optional)", default=""),
34
35
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
36
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
35
37
  ) -> BaseResponse:
36
38
  """
37
39
  Fill existing form fields in a PDF document.
@@ -56,7 +58,7 @@ async def fill_pdf_forms(
56
58
  name=name,
57
59
  )
58
60
 
59
- return await fill_pdf_form_fields(params, fields=fields)
61
+ return await fill_pdf_form_fields(params, fields=fields, api_key=api_key)
60
62
 
61
63
  @mcp.tool(name="create_fillable_forms")
62
64
  async def create_fillable_forms(
@@ -65,6 +67,7 @@ async def create_fillable_forms(
65
67
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
66
68
  httpusername: str = Field(description="HTTP auth user name if required to access source url. (Optional)", default=""),
67
69
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
70
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
68
71
  ) -> BaseResponse:
69
72
  """
70
73
  Create new fillable form elements in a PDF document.
@@ -99,4 +102,4 @@ async def create_fillable_forms(
99
102
  name=name,
100
103
  )
101
104
 
102
- return await fill_pdf_form_fields(params, annotations=annotations)
105
+ return await fill_pdf_form_fields(params, annotations=annotations, api_key=api_key)
@@ -8,7 +8,8 @@ from pydantic import Field
8
8
 
9
9
  @mcp.tool()
10
10
  async def get_job_check(
11
- job_id: str = Field(description="The ID of the job to get the status of")
11
+ job_id: str = Field(description="The ID of the job to get the status of"),
12
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None)
12
13
  ) -> BaseResponse:
13
14
  """
14
15
  Check the status and results of a job
@@ -20,7 +21,7 @@ async def get_job_check(
20
21
  - unknown: unknown background job id. Available only when force is set to true for input request.
21
22
  """
22
23
  try:
23
- async with PDFCoClient() as client:
24
+ async with PDFCoClient(api_key=api_key) as client:
24
25
  response = await client.post("/v1/job/check", json={
25
26
  "jobId": job_id,
26
27
  })
@@ -42,7 +43,8 @@ async def get_job_check(
42
43
  async def wait_job_completion(
43
44
  job_id: str = Field(description="The ID of the job to get the status of"),
44
45
  interval: int = Field(description="The interval to check the status of the job (seconds)", default=1),
45
- timeout: int = Field(description="The timeout to wait for the job to complete (seconds)", default=300)
46
+ timeout: int = Field(description="The timeout to wait for the job to complete (seconds)", default=300),
47
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None)
46
48
  ) -> BaseResponse:
47
49
  """
48
50
  Wait for a job to complete
@@ -52,7 +54,7 @@ async def wait_job_completion(
52
54
  credits_used = 0
53
55
  credits_remaining = 0
54
56
  while True:
55
- response = await get_job_check(job_id)
57
+ response = await get_job_check(job_id, api_key=api_key)
56
58
  job_check_count += 1
57
59
  credits_used += response.credits_used
58
60
  credits_remaining = response.credits_remaining
@@ -11,12 +11,13 @@ async def pdf_merge(
11
11
  httpusername: str = Field(description="HTTP auth user name if required to access source url. (Optional)", default=""),
12
12
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
13
13
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
14
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
14
15
  ) -> BaseResponse:
15
16
  """
16
17
  Merge PDF from two or more PDF, DOC, XLS, images, even ZIP with documents and images into a new PDF.
17
18
  Ref: https://developer.pdf.co/api-reference/merge/various-files.md
18
19
  """
19
- return await merge_pdf(ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, name=name))
20
+ return await merge_pdf(ConversionParams(url=url, httpusername=httpusername, httppassword=httppassword, name=name), api_key=api_key)
20
21
 
21
22
  @mcp.tool()
22
23
  async def pdf_split(
@@ -26,6 +27,7 @@ async def pdf_split(
26
27
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
27
28
  password: str = Field(description="Password of the PDF file. (Optional)", default=""),
28
29
  name: str = Field(description="Base file name for the generated output files. (Optional)", default=""),
30
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
29
31
  ) -> BaseResponse:
30
32
  """
31
33
  Split a PDF into multiple PDF files using page indexes or page ranges.
@@ -40,4 +42,4 @@ async def pdf_split(
40
42
  name=name,
41
43
  )
42
44
 
43
- return await split_pdf(params)
45
+ return await split_pdf(params, api_key=api_key)
@@ -15,6 +15,7 @@ async def find_text(
15
15
  wordMatchingMode: str = Field(description="Values can be either SmartMatch, ExactMatch, or None. (Optional)", default=None),
16
16
  password: str = Field(description="Password of the PDF file. (Optional)", default=""),
17
17
  regexSearch: bool = Field(description="Set to True to enable regular expressions in the search string. (Optional)", default=False),
18
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
18
19
  ) -> BaseResponse:
19
20
  """
20
21
  Find text in PDF and get coordinates. Supports regular expressions.
@@ -28,7 +29,7 @@ async def find_text(
28
29
  password=password,
29
30
  )
30
31
 
31
- return await find_text_in_pdf(params, searchString, regexSearch, wordMatchingMode)
32
+ return await find_text_in_pdf(params, searchString, regexSearch, wordMatchingMode, api_key=api_key)
32
33
 
33
34
 
34
35
  @mcp.tool(name="find_table")
@@ -38,6 +39,7 @@ async def find_table(
38
39
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
39
40
  pages: str = Field(description="Comma-separated list of page indices (or ranges) to process. Leave empty for all pages. Example: '0,2-5,7-'. The first-page index is 0. (Optional)", default=""),
40
41
  password: str = Field(description="Password of the PDF file. (Optional)", default=""),
42
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
41
43
  ) -> BaseResponse:
42
44
  """
43
45
  Find tables in PDF and get their coordinates.
@@ -51,4 +53,4 @@ async def find_table(
51
53
  password=password,
52
54
  )
53
55
 
54
- return await find_table_in_pdf(params)
56
+ return await find_table_in_pdf(params, api_key=api_key)
@@ -14,6 +14,7 @@ async def pdf_make_searchable(
14
14
  pages: str = Field(description="Comma-separated page indices (e.g., '0, 1, 2-' or '1, 3-7'). Use '!' for inverted page numbers (e.g., '!0' for last page). Processes all pages if None. (Optional)", default=""),
15
15
  password: str = Field(description="Password of the PDF file. (Optional)", default=""),
16
16
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
17
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
17
18
  ) -> BaseResponse:
18
19
  """
19
20
  Convert scanned PDF documents or image files into a text-searchable PDF.
@@ -30,7 +31,7 @@ async def pdf_make_searchable(
30
31
  name=name,
31
32
  )
32
33
 
33
- return await make_pdf_searchable(params)
34
+ return await make_pdf_searchable(params, api_key=api_key)
34
35
 
35
36
 
36
37
  @mcp.tool()
@@ -41,6 +42,7 @@ async def pdf_make_unsearchable(
41
42
  pages: str = Field(description="Comma-separated page indices (e.g., '0, 1, 2-' or '1, 3-7'). Use '!' for inverted page numbers (e.g., '!0' for last page). Processes all pages if None. (Optional)", default=""),
42
43
  password: str = Field(description="Password of the PDF file. (Optional)", default=""),
43
44
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
45
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
44
46
  ) -> BaseResponse:
45
47
  """
46
48
  Make existing PDF document non-searchable by removing the text layer from it.
@@ -55,4 +57,4 @@ async def pdf_make_unsearchable(
55
57
  name=name,
56
58
  )
57
59
 
58
- return await make_pdf_unsearchable(params)
60
+ return await make_pdf_unsearchable(params, api_key=api_key)
@@ -23,6 +23,7 @@ async def pdf_add_password(
23
23
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
24
24
  password: str = Field(description="Password of the PDF file if it's already password-protected. (Optional)", default=""),
25
25
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
26
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
26
27
  ) -> BaseResponse:
27
28
  """
28
29
  Add password protection to a PDF file.
@@ -70,7 +71,7 @@ async def pdf_add_password(
70
71
  if print_quality is not None:
71
72
  additional_params["PrintQuality"] = print_quality
72
73
 
73
- return await add_pdf_password(params, **additional_params)
74
+ return await add_pdf_password(params, **additional_params, api_key=api_key)
74
75
 
75
76
 
76
77
  @mcp.tool()
@@ -80,6 +81,7 @@ async def pdf_remove_password(
80
81
  httppassword: str = Field(description="HTTP auth password if required to access source url. (Optional)", default=""),
81
82
  password: str = Field(description="Password of the PDF file to be removed. (Optional)", default=""),
82
83
  name: str = Field(description="File name for the generated output. (Optional)", default=""),
84
+ api_key: str = Field(description="PDF.co API key. If not provided, will use X_API_KEY environment variable. (Optional)", default=None),
83
85
  ) -> BaseResponse:
84
86
  """
85
87
  Remove password protection from a PDF file.
@@ -93,4 +95,4 @@ async def pdf_remove_password(
93
95
  name=name,
94
96
  )
95
97
 
96
- return await remove_pdf_password(params)
98
+ return await remove_pdf_password(params, api_key=api_key)
@@ -0,0 +1,199 @@
1
+ Metadata-Version: 2.4
2
+ Name: pdfco-mcp
3
+ Version: 0.0.3
4
+ Summary: Add your description here
5
+ License-File: LICENSE
6
+ Requires-Python: >=3.12
7
+ Requires-Dist: fastmcp>=2.6.1
8
+ Requires-Dist: httpx>=0.28.1
9
+ Requires-Dist: langchain-community>=0.3.21
10
+ Requires-Dist: langchain[google-genai]>=0.3.23
11
+ Requires-Dist: langgraph>=0.3.30
12
+ Requires-Dist: mcp[cli]>=1.6.0
13
+ Description-Content-Type: text/markdown
14
+
15
+ # PDF.co MCP Server
16
+
17
+ PDF.co MCP Server provides [PDF.co API](https://pdf.co) functionality through the Model Context Protocol (MCP), enabling AI assistants to easily perform various PDF processing tasks.
18
+
19
+ ## 🚀 Key Features
20
+
21
+ ### 📄 PDF Conversion Tools
22
+ - **PDF → Various Formats**: Convert PDFs to JSON, CSV, Text, Excel (XLS/XLSX), XML, HTML, Images (JPG/PNG/WebP/TIFF)
23
+ - **Various Formats → PDF**: Convert documents (DOC/DOCX/RTF/TXT), spreadsheets (CSV/XLS/XLSX), images, web pages, HTML, emails (MSG/EML) to PDF
24
+ - **Excel Conversions**: Convert Excel files to CSV, JSON, HTML, TXT, XML, PDF
25
+
26
+ ### 🛠️ PDF Editing & Modification
27
+ - **PDF Merging**: Combine multiple PDF files into one
28
+ - **PDF Splitting**: Split PDFs by specific pages or page ranges
29
+ - **Add Annotations & Images**: Add text, links, images, shapes to PDFs
30
+ - **Form Operations**: Read PDF form field information, fill forms, create new form elements
31
+
32
+ ### 🔍 PDF Search & Analysis
33
+ - **Text Search**: Search text in PDFs (supports regular expressions)
34
+ - **Table Detection**: Find table locations and coordinates in PDFs
35
+ - **AI Invoice Parser**: Extract invoice data using AI
36
+ - **PDF Information**: Get detailed information including metadata, page count, security info
37
+
38
+ ### 🔒 Security & Accessibility
39
+ - **Password Protection**: Add/remove password protection to PDFs
40
+ - **Searchability**: Make PDFs searchable via OCR or remove text layers
41
+ - **Attachment Extraction**: Extract attachments from PDFs
42
+
43
+ ### 💼 File Management
44
+ - **File Upload**: Upload local files to PDF.co servers
45
+ - **Job Status Tracking**: Monitor progress and results of asynchronous operations
46
+
47
+ ## ⚙️ Configuration
48
+
49
+ ### 🔑 Get API Key
50
+ 1. Sign up at [PDF.co website](https://pdf.co)
51
+ 2. Get your API key from the dashboard
52
+
53
+ ### MCP Server Setup
54
+
55
+ #### Cursor IDE Configuration
56
+ Add the following to your `.cursor/mcp.json` file:
57
+
58
+ ```json
59
+ {
60
+ "mcpServers": {
61
+ "pdfco": {
62
+ "command": "uvx",
63
+ "args": ["pdfco-mcp"],
64
+ "env": {
65
+ "X_API_KEY": "YOUR_API_KEY_HERE"
66
+ }
67
+ }
68
+ }
69
+ }
70
+ ```
71
+
72
+ #### Claude Desktop Configuration
73
+ Add the following to your `claude_desktop_config.json` file:
74
+
75
+ ```json
76
+ {
77
+ "mcpServers": {
78
+ "pdfco": {
79
+ "command": "uvx",
80
+ "args": ["pdfco-mcp"],
81
+ "env": {
82
+ "X_API_KEY": "YOUR_API_KEY_HERE"
83
+ }
84
+ }
85
+ }
86
+ }
87
+ ```
88
+
89
+ ## 🔧 Available Tools
90
+
91
+ ### PDF Conversion Tools
92
+ - `pdf_to_json`: Convert PDF and scanned images into JSON representation with text, fonts, images, vectors, and formatting preserved
93
+ - `pdf_to_csv`: Convert PDF and scanned images into CSV representation with layout, columns, rows, and tables
94
+ - `pdf_to_text`: Convert PDF and scanned images to text with layout preserved
95
+ - `pdf_to_xls`: Convert PDF and scanned images to XLS (Excel 97-2003) format
96
+ - `pdf_to_xlsx`: Convert PDF and scanned images to XLSX (Excel 2007+) format
97
+ - `pdf_to_xml`: Convert PDF and scanned images to XML format
98
+ - `pdf_to_html`: Convert PDF and scanned images to HTML format
99
+ - `pdf_to_image`: Convert PDF and scanned images to various image formats (JPG, PNG, WebP, TIFF)
100
+
101
+ ### Document to PDF Conversion Tools
102
+ - `document_to_pdf`: Convert various document types (DOC, DOCX, RTF, TXT, XLS, XLSX, CSV, HTML, JPG, PNG, TIFF, WEBP) into PDF
103
+ - `csv_to_pdf`: Convert CSV or spreadsheet files (XLS, XLSX) to PDF
104
+ - `image_to_pdf`: Convert various image formats (JPG, PNG, TIFF) to PDF
105
+ - `webpage_to_pdf`: Convert external webpage URL to PDF
106
+ - `html_to_pdf`: Convert HTML to PDF
107
+ - `email_to_pdf`: Convert email to PDF
108
+
109
+ ### Excel Conversion Tools
110
+ - `excel_to_csv`: Convert Excel(XLS, XLSX) to CSV
111
+ - `excel_to_json`: Convert Excel(XLS, XLSX) to JSON
112
+ - `excel_to_html`: Convert Excel(XLS, XLSX) to HTML
113
+ - `excel_to_txt`: Convert Excel(XLS, XLSX) to TXT
114
+ - `excel_to_xml`: Convert Excel(XLS, XLSX) to XML
115
+ - `excel_to_pdf`: Convert Excel(XLS, XLSX) to PDF
116
+
117
+ ### PDF Editing Tools
118
+ - `pdf_add_annotations_images_fields`: Add text, images, forms, other PDFs, fill forms, links to external sites and external PDF files. You can update or modify PDF and scanned PDF files
119
+ - `pdf_merge`: Merge PDF from two or more PDF, DOC, XLS, images, even ZIP with documents and images into a new PDF
120
+ - `pdf_split`: Split a PDF into multiple PDF files using page indexes or page ranges
121
+
122
+ ### PDF Form Tools
123
+ - `read_pdf_forms_info`: Extracts information about fillable PDF fields from an input PDF file
124
+ - `fill_pdf_forms`: Fill existing form fields in a PDF document
125
+ - `create_fillable_forms`: Create new fillable form elements in a PDF document
126
+
127
+ ### PDF Search Tools
128
+ - `find_text`: Find text in PDF and get coordinates. Supports regular expressions
129
+ - `find_table`: Find tables in PDF and get their coordinates
130
+
131
+ ### PDF Analysis Tools
132
+ - `ai_invoice_parser`: AI Invoice Parser: Extracts data from invoices using AI
133
+ - `extract_attachments`: Extracts attachments from a source PDF file
134
+ - `pdf_info_reader`: Get detailed information about a PDF document - number of pages, metadata, security, form fields, and more
135
+
136
+ ### PDF Security Tools
137
+ - `pdf_add_password`: Add password protection to a PDF file
138
+ - `pdf_remove_password`: Remove password protection from a PDF file
139
+
140
+ ### PDF Searchability Tools
141
+ - `pdf_make_searchable`: Convert scanned PDF documents or image files into a text-searchable PDF. Runs OCR and adds an invisible text layer that can be used for text search
142
+ - `pdf_make_unsearchable`: Make existing PDF document non-searchable by removing the text layer from it
143
+
144
+ ### File Management Tools
145
+ - `upload_file`: Upload a file to the PDF.co API
146
+ - `get_job_check`: Check the status and results of a job. Status can be: working, success, failed, aborted, or unknown
147
+ - `wait_job_completion`: Wait for a job to complete
148
+
149
+ ## 📖 Usage Examples
150
+
151
+ ### Convert PDF to Text
152
+ ```
153
+ Convert this PDF file to text: https://example.com/document.pdf
154
+ ```
155
+
156
+ ### Merge Multiple Images into PDF
157
+ ```
158
+ Create a PDF from these images: image1.jpg, image2.png, image3.jpg
159
+ ```
160
+
161
+ ### Search for Specific Text in PDF
162
+ ```
163
+ Find the word "contract" in this PDF document
164
+ ```
165
+
166
+ ### Fill PDF Form Fields
167
+ ```
168
+ Fill the name field in this PDF form with "John Doe"
169
+ ```
170
+
171
+ ### Convert Web Page to PDF
172
+ ```
173
+ Convert https://example.com webpage to PDF
174
+ ```
175
+
176
+ ### Extract Invoice Data
177
+ ```
178
+ Extract invoice information from this PDF using AI
179
+ ```
180
+
181
+ ### Add Password Protection
182
+ ```
183
+ Add password protection to this PDF file
184
+ ```
185
+
186
+
187
+ ## 📞 Support & Contact
188
+
189
+ - **PDF.co**: https://pdf.co
190
+ - **PDF.co API Documentation**: https://developer.pdf.co
191
+ - **Issue Reports**: Please report issues through GitHub Issues
192
+
193
+ ## 📄 License
194
+
195
+ This project is distributed under the MIT License.
196
+
197
+ ---
198
+
199
+ **Note**: A valid PDF.co API key is required to use this tool. Create a free account at [PDF.co](https://pdf.co) to get your API key.
@@ -0,0 +1,23 @@
1
+ pdfco/mcp/__init__.py,sha256=xfKRNYaFEREhWjiM_r4GAiXyld1DkLzE96OOaj28AMs,1054
2
+ pdfco/mcp/models.py,sha256=pnU9e18fQHrab27sYG1qr7ORhAkVFk70WpAkXSisu9Q,5602
3
+ pdfco/mcp/server.py,sha256=C82IrVqxNhICyxNn4oeJ_IFl0_NOuO1EqDIeAT03Dc0,52
4
+ pdfco/mcp/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ pdfco/mcp/services/client.py,sha256=OKmVSbjEoXCwvWKXcPh2PmEogWlyBuJhmQZBbRL_0RY,1722
6
+ pdfco/mcp/services/pdf.py,sha256=oV1P46epAI0pAURMxu9-gqtvGlYFKQy1mxzWCVku760,4779
7
+ pdfco/mcp/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ pdfco/mcp/tools/apis/conversion.py,sha256=EsvSljSRr37JIxTV892UJWbOQSkRtsz3hNR-engITBE,37424
9
+ pdfco/mcp/tools/apis/document.py,sha256=6-yfxzhRZHXtJJI6pePzxrw5e0EjrKNwXub2wHO1-w4,1320
10
+ pdfco/mcp/tools/apis/editing.py,sha256=Q8gSn9WyZzBS9lCJEo3z7OnoaiyweJ34DiP8yFao-yI,4632
11
+ pdfco/mcp/tools/apis/extraction.py,sha256=EGU1pfgFN0H44FKmq31kDc8GP99qkR9s-GQkM33dmb0,1987
12
+ pdfco/mcp/tools/apis/file.py,sha256=_LC-kKMIeuyrhlfR221WcqgqR9u-CjeQ9ido5t4Oglc,1119
13
+ pdfco/mcp/tools/apis/form.py,sha256=9uLm9rNsxCzVYUJ2uBwU2scGTRBmPM4gM3-6ma74KNM,4684
14
+ pdfco/mcp/tools/apis/job.py,sha256=rU-wm2CygYRxqaIe1NZQ5oYWBtLpbL6cdjeuIC8QSvU,3347
15
+ pdfco/mcp/tools/apis/modification.py,sha256=yPKwXjKpDOCo67YCHuWUOjGLqTqIZWKq0IOIJAxf5Js,2823
16
+ pdfco/mcp/tools/apis/search.py,sha256=-phrQbI5waPBvnI7ReWtLTMXzt1s6dSmHs-D7HMbdig,3296
17
+ pdfco/mcp/tools/apis/searchable.py,sha256=ZkD4LbRbbE16GILjNAbxmVBwugburCL9bNIsAh61jco,3482
18
+ pdfco/mcp/tools/apis/security.py,sha256=qeOqZUO11UuoPTwHb-DEfoLdkJp_Jvh7nzPm54ATYXw,5490
19
+ pdfco_mcp-0.0.3.dist-info/METADATA,sha256=mUQx55y16o7kO909iGNmX1mWurqjfHPPjj9eexByVu0,7113
20
+ pdfco_mcp-0.0.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
21
+ pdfco_mcp-0.0.3.dist-info/entry_points.txt,sha256=Ja_Ud8LbrhKYUmQMo6hxd11SQX_vx7cwrqvco6ClwB4,45
22
+ pdfco_mcp-0.0.3.dist-info/licenses/LICENSE,sha256=DjYg-0Ei_vaAyXg45y8_otZRHJe-L1cU7cKhyf5gtFo,1063
23
+ pdfco_mcp-0.0.3.dist-info/RECORD,,
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 PDF.co
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,30 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: pdfco-mcp
3
- Version: 0.0.1
4
- Summary: Add your description here
5
- Requires-Python: >=3.12
6
- Requires-Dist: httpx>=0.28.1
7
- Requires-Dist: langchain-community>=0.3.21
8
- Requires-Dist: langchain[google-genai]>=0.3.23
9
- Requires-Dist: langgraph>=0.3.30
10
- Requires-Dist: mcp[cli]>=1.6.0
11
- Description-Content-Type: text/markdown
12
-
13
- # PDF.co MCP
14
-
15
- #### Sample `.cursor/mcp.json` for test in cursor
16
- ```json
17
- {
18
- "mcpServers": {
19
- "pdfco": {
20
- "command": "uvx",
21
- "args": [
22
- "pdfco-mcp"
23
- ],
24
- "env": {
25
- "X_API_KEY": "YOUR_API_KEY" // To get the API key please sign up at https://pdf.co and you can get the API key from the dashboard
26
- }
27
- }
28
- }
29
- }
30
- ```
@@ -1,22 +0,0 @@
1
- pdfco/mcp/__init__.py,sha256=S-GhB7vAGoUDpg47kP74gKck2XFJ_2UNjgpxqGS774U,256
2
- pdfco/mcp/models.py,sha256=pnU9e18fQHrab27sYG1qr7ORhAkVFk70WpAkXSisu9Q,5602
3
- pdfco/mcp/server.py,sha256=5pBIKZJJ3Um5LsdrT9HvlGy4oB4n6t5Opu8razv2A5A,63
4
- pdfco/mcp/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- pdfco/mcp/services/client.py,sha256=vZq9EhkDyAstuGtfIFkN9Mf1HgMElkIstbuF_LXl2M0,1359
6
- pdfco/mcp/services/pdf.py,sha256=CL1kiZew9GOgbmeaFf0ecjCSFAc-U1G9ySvV2ueSGSY,4135
7
- pdfco/mcp/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- pdfco/mcp/tools/apis/conversion.py,sha256=6snda-ZmZz81Mgf0o7FF9DUkRWzRfMHTWF-0-cxSvt8,34285
9
- pdfco/mcp/tools/apis/document.py,sha256=-_gJC0MrziZWfqn-akZZdSNpN75NryJEPLQEwE5Yh5Q,1163
10
- pdfco/mcp/tools/apis/editing.py,sha256=aQbRNakUhlj9mYew8BjTweA5wEXVq2z1-WH0DiWptes,4475
11
- pdfco/mcp/tools/apis/extraction.py,sha256=cnXQjCZ2PBwBUWNEiAUGMZJbN_6I3ZLdGqdDWEfUrRc,1683
12
- pdfco/mcp/tools/apis/file.py,sha256=nWaSlG4Okcc30f2kfi8w28QeJBgeR2khcXoAxM6cpEU,966
13
- pdfco/mcp/tools/apis/form.py,sha256=irPlTPiJjrBWJIplpt0YC7BaRduFdP2SXQ-Y444Pa94,4213
14
- pdfco/mcp/tools/apis/job.py,sha256=1Fv28EFy6oOeB_WFM4gMCN7XPX2HIxWV3uV8sl6SZEU,3035
15
- pdfco/mcp/tools/apis/modification.py,sha256=GcZTI0z3PVSyuSOOHHPsqX590mWM4yRBhewMfdUKiHs,2509
16
- pdfco/mcp/tools/apis/search.py,sha256=4_FBBcIB4PpZ_E_ExDwlTXUEHaoiCEgyfXkFcYM117E,2982
17
- pdfco/mcp/tools/apis/searchable.py,sha256=7HEs-Siz8rUZbyxV0jS81uLQZJejJpb5SWNDZOBVHCU,3168
18
- pdfco/mcp/tools/apis/security.py,sha256=CGVXnCvHyPbSeKWAlExlsVELgn_Vtd4U_nt1IuY3NUs,5176
19
- pdfco_mcp-0.0.1.dist-info/METADATA,sha256=PRTBvaTTiuhoGlHUx-wevn9XkwI-XwfRHKCRYxb7P6Q,688
20
- pdfco_mcp-0.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
21
- pdfco_mcp-0.0.1.dist-info/entry_points.txt,sha256=Ja_Ud8LbrhKYUmQMo6hxd11SQX_vx7cwrqvco6ClwB4,45
22
- pdfco_mcp-0.0.1.dist-info/RECORD,,