printables-mcp 0.1.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 (37) hide show
  1. printables_mcp-0.1.0/.github/dependabot.yml +31 -0
  2. printables_mcp-0.1.0/.github/workflows/ci.yml +70 -0
  3. printables_mcp-0.1.0/.github/workflows/uv-publish.yml +53 -0
  4. printables_mcp-0.1.0/.gitignore +18 -0
  5. printables_mcp-0.1.0/.python-version +1 -0
  6. printables_mcp-0.1.0/CLAUDE.md +37 -0
  7. printables_mcp-0.1.0/Justfile +17 -0
  8. printables_mcp-0.1.0/LICENSE +21 -0
  9. printables_mcp-0.1.0/PKG-INFO +99 -0
  10. printables_mcp-0.1.0/README.md +69 -0
  11. printables_mcp-0.1.0/README.ru.md +69 -0
  12. printables_mcp-0.1.0/pyproject.toml +95 -0
  13. printables_mcp-0.1.0/src/printables_mcp/__init__.py +5 -0
  14. printables_mcp-0.1.0/src/printables_mcp/client.py +115 -0
  15. printables_mcp-0.1.0/src/printables_mcp/markdown.py +26 -0
  16. printables_mcp-0.1.0/src/printables_mcp/models.py +349 -0
  17. printables_mcp-0.1.0/src/printables_mcp/py.typed +0 -0
  18. printables_mcp-0.1.0/src/printables_mcp/queries.py +110 -0
  19. printables_mcp-0.1.0/src/printables_mcp/refs.py +88 -0
  20. printables_mcp-0.1.0/src/printables_mcp/server.py +297 -0
  21. printables_mcp-0.1.0/tests/conftest.py +126 -0
  22. printables_mcp-0.1.0/tests/fixtures/author_16.json +11 -0
  23. printables_mcp-0.1.0/tests/fixtures/author_models_16.json +81 -0
  24. printables_mcp-0.1.0/tests/fixtures/categories.json +1196 -0
  25. printables_mcp-0.1.0/tests/fixtures/files_3161.json +108 -0
  26. printables_mcp-0.1.0/tests/fixtures/licenses.json +121 -0
  27. printables_mcp-0.1.0/tests/fixtures/link_premium_error.json +16 -0
  28. printables_mcp-0.1.0/tests/fixtures/model_1202139.json +112 -0
  29. printables_mcp-0.1.0/tests/fixtures/model_3161.json +89 -0
  30. printables_mcp-0.1.0/tests/fixtures/model_missing.json +5 -0
  31. printables_mcp-0.1.0/tests/fixtures/search_benchy.json +117 -0
  32. printables_mcp-0.1.0/tests/test_client.py +105 -0
  33. printables_mcp-0.1.0/tests/test_live.py +67 -0
  34. printables_mcp-0.1.0/tests/test_markdown.py +26 -0
  35. printables_mcp-0.1.0/tests/test_refs.py +72 -0
  36. printables_mcp-0.1.0/tests/test_server.py +298 -0
  37. printables_mcp-0.1.0/uv.lock +1666 -0
@@ -0,0 +1,31 @@
1
+ version: 2
2
+
3
+ updates:
4
+ # Python tooling: update the dev dependency group only.
5
+ # allow=development limits PRs to non-production deps; the runtime contract
6
+ # (mcp, httpx2, pydantic, markdownify, anyio) is bumped by hand.
7
+ - package-ecosystem: "uv"
8
+ directory: "/"
9
+ schedule:
10
+ interval: "monthly"
11
+ allow:
12
+ - dependency-type: "development"
13
+ groups:
14
+ python-dev:
15
+ patterns:
16
+ - "*"
17
+ commit-message:
18
+ prefix: "chore"
19
+ include: "scope"
20
+
21
+ # GitHub Actions pinned in the workflows.
22
+ - package-ecosystem: "github-actions"
23
+ directory: "/"
24
+ schedule:
25
+ interval: "monthly"
26
+ groups:
27
+ github-actions:
28
+ patterns:
29
+ - "*"
30
+ commit-message:
31
+ prefix: "ci"
@@ -0,0 +1,70 @@
1
+ name: CI
2
+ on:
3
+ pull_request:
4
+ push:
5
+ branches: ["main"]
6
+ workflow_call:
7
+
8
+ concurrency:
9
+ group: ${{ github.workflow }}-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ jobs:
13
+ lint:
14
+ name: "Lint"
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v7
18
+ - name: Install uv
19
+ uses: astral-sh/setup-uv@v9.0.0
20
+ with:
21
+ enable-cache: true
22
+ cache-dependency-glob: uv.lock
23
+ - name: Install dependencies
24
+ run: uv sync --frozen
25
+ - name: Check lockfile
26
+ run: uv lock --check
27
+ - name: Ruff lint
28
+ run: uv run ruff check --output-format=github
29
+ - name: Ruff format
30
+ run: uv run ruff format --check
31
+ - name: Ty
32
+ run: uv run ty check
33
+
34
+ test:
35
+ name: "Test (${{ matrix.python }})"
36
+ runs-on: ubuntu-latest
37
+ strategy:
38
+ fail-fast: false
39
+ matrix:
40
+ python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
41
+ steps:
42
+ - uses: actions/checkout@v7
43
+ - name: Install uv
44
+ uses: astral-sh/setup-uv@v9.0.0
45
+ with:
46
+ enable-cache: true
47
+ cache-dependency-glob: uv.lock
48
+ python-version: ${{ matrix.python }}
49
+ - name: Install dependencies
50
+ run: uv sync --frozen
51
+ - name: Pytest
52
+ run: uv run pytest --cov
53
+
54
+ build:
55
+ name: "Build"
56
+ runs-on: ubuntu-latest
57
+ steps:
58
+ - uses: actions/checkout@v7
59
+ - name: Install uv
60
+ uses: astral-sh/setup-uv@v9.0.0
61
+ with:
62
+ enable-cache: true
63
+ cache-dependency-glob: uv.lock
64
+ - name: Build
65
+ run: uv build
66
+ # The installed wheel must import cleanly and expose all tools
67
+ - name: Smoke test the wheel
68
+ run: >-
69
+ uv run --isolated --no-project --with dist/*.whl
70
+ python -c "from printables_mcp.server import TOOLS, create_server; create_server(); assert len(TOOLS) == 8"
@@ -0,0 +1,53 @@
1
+ name: uv package publish
2
+ on:
3
+ release:
4
+ types: ["published"]
5
+
6
+ jobs:
7
+ ci:
8
+ name: "CI"
9
+ uses: ./.github/workflows/ci.yml
10
+
11
+ check-version:
12
+ name: "Check tag matches project version"
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v7
16
+ - name: Compare release tag with pyproject version
17
+ env:
18
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
19
+ run: |
20
+ python3 - <<'EOF'
21
+ import os
22
+ import sys
23
+ import tomllib
24
+
25
+ with open("pyproject.toml", "rb") as f:
26
+ version = tomllib.load(f)["project"]["version"]
27
+
28
+ tag = os.environ["RELEASE_TAG"].removeprefix("v")
29
+ if tag != version:
30
+ sys.exit(f"Release tag {tag!r} does not match project version {version!r}")
31
+ print(f"Release tag matches project version {version}")
32
+ EOF
33
+
34
+ publish:
35
+ name: "Build and publish release"
36
+ runs-on: ubuntu-latest
37
+ needs: [ci, check-version]
38
+ environment:
39
+ name: pypi
40
+ url: https://pypi.org/project/printables-mcp/
41
+ permissions:
42
+ id-token: write
43
+ steps:
44
+ - uses: actions/checkout@v7
45
+ - name: Install uv
46
+ uses: astral-sh/setup-uv@v9.0.0
47
+ with:
48
+ enable-cache: true
49
+ cache-dependency-glob: uv.lock
50
+ - name: Build
51
+ run: uv build
52
+ - name: Publish
53
+ run: uv publish
@@ -0,0 +1,18 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # Test artifacts
13
+ .coverage
14
+ .pytest_cache/
15
+
16
+ # Docs build
17
+ site/
18
+ .cache/
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,37 @@
1
+ # printables-mcp
2
+
3
+ Public PyPI package: an MCP server (stdio) for Printables.com built on the official `mcp` SDK 2.x (`MCPServer`). Console script `printables-mcp` → `printables_mcp.server:main`.
4
+
5
+ **Keep this file up to date** when the API knowledge or design decisions change.
6
+
7
+ ## Layout
8
+
9
+ src-layout, `src/printables_mcp/`:
10
+
11
+ - `client.py`: `PrintablesClient`, an async `httpx2` client with one `execute(query, variables)` method. Maps every failure to `PrintablesError`; retries network errors and 5xx (3 attempts, linear backoff).
12
+ - `queries.py`: the GraphQL documents.
13
+ - `models.py`: pydantic result models (structured tool output), built from raw payloads via `from_api`.
14
+ - `refs.py`: parsing model/author references (IDs, URLs, handles) and building site/media URLs.
15
+ - `markdown.py`: description HTML → Markdown (`markdownify`), site-relative targets made absolute.
16
+ - `server.py`: module-level tool functions (`TOOLS`), `create_server(transport=None)` registering them with read-only annotations, `main()`.
17
+
18
+ ## Printables API facts (verified by hand; introspection and field suggestions are disabled)
19
+
20
+ - Endpoint `https://api.printables.com/graphql/`; the website itself sits behind Cloudflare (403 for scripts), the API does not. An honest User-Agent is accepted.
21
+ - Validation errors come back as **HTTP 400 with a JSON `errors` body**: read the body before looking at the status. Out-of-range values (e.g. `limit: 101`) give a 400 with a non-JSON body.
22
+ - `searchPrints2(query, printType: print, limit ≤ 100, offset, ordering: SearchChoicesEnum, categoryId: ID, paid: PaidEnum{all,free,paid}, licenses: [ID], publishedDateLimitDays: Int, hasMake: Boolean)` → `{totalCount, items}`; `totalCount` caps at 10000.
23
+ - `print(id)` returns `null` for a missing model. `printDuration` is hours as a decimal string, `weight` grams, `ratingAvg` a decimal string, `price` a decimal string or null, `premium` = club-only.
24
+ - `getDownloadLink(id, printId, fileType: stl|gcode|sla|other|pack, source: model_detail)` → `{ok, errors{field messages}, output{link ttl}}`; paid/club files fail with `cannot_download_premium_file_as_anonymous_user`.
25
+ - `user(id)` accepts a numeric ID or `"@handle"` (case-insensitive) and returns `null` when unknown. `userModels(userId, limit, cursor, ordering)` → `{cursor, items}`; ordering is a string (`[-]date_published`, `likes_count`, `download_count`, `rating_avg`, `makes_count`), cursor is `""` on an empty page.
26
+
27
+ ## Decisions
28
+
29
+ - Own implementation, not a fork of any existing Printables MCP server.
30
+ - Links only: the server never writes files to disk.
31
+ - Per-file download failures are returned per file; only model-level failures raise `ToolError`.
32
+
33
+ ## Conventions
34
+
35
+ - ruff `select = ["ALL"]` (preview), ty `all = "error"`, pytest with 100% branch coverage. Suppressions use `# ruff: ignore[rule-name]`.
36
+ - Tests use `httpx2.MockTransport` with recorded responses in `tests/fixtures/` and an in-memory `mcp.Client`; live tests are marked `live` and excluded by default (`just test-live`).
37
+ - Conventional Commits, GPG-signed, no Co-Authored-By trailer.
@@ -0,0 +1,17 @@
1
+ # Show available recipes.
2
+ help:
3
+ @just --list --unsorted
4
+
5
+ # Check formatting, lint rules and types.
6
+ lint:
7
+ uv run ruff format --check
8
+ uv run ruff check
9
+ uv run ty check
10
+
11
+ # Run the test suite with coverage.
12
+ test:
13
+ uv run pytest --cov
14
+
15
+ # Run the end-to-end tests against the real Printables API.
16
+ test-live:
17
+ uv run pytest -m live
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Fedor Ratschew
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.
@@ -0,0 +1,99 @@
1
+ Metadata-Version: 2.5
2
+ Name: printables-mcp
3
+ Version: 0.1.0
4
+ Summary: MCP server for Printables.com: search 3D models, read model cards, list files and get download links
5
+ Project-URL: Homepage, https://github.com/feodor-ra/printables-mcp
6
+ Project-URL: Repository, https://github.com/feodor-ra/printables-mcp
7
+ Project-URL: Issues, https://github.com/feodor-ra/printables-mcp/issues
8
+ Author-email: Fedor Ratschew <feodor.ra@me.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: 3d-printing,llm,mcp,model-context-protocol,printables
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: anyio>=4.9
25
+ Requires-Dist: httpx2>=2.10
26
+ Requires-Dist: markdownify>=1.2
27
+ Requires-Dist: mcp<3,>=2.3
28
+ Requires-Dist: pydantic>=2.12
29
+ Description-Content-Type: text/markdown
30
+
31
+ # printables-mcp
32
+
33
+ **English** · [Русский](README.ru.md)
34
+
35
+ [![PyPI - Version](https://img.shields.io/pypi/v/printables-mcp)](https://pypi.org/project/printables-mcp/)
36
+ ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/printables-mcp)
37
+ ![PyPI - Status](https://img.shields.io/pypi/status/printables-mcp)
38
+ [![CI](https://github.com/feodor-ra/printables-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/feodor-ra/printables-mcp/actions/workflows/ci.yml)
39
+
40
+ **An [MCP](https://modelcontextprotocol.io) server for [Printables.com](https://www.printables.com)**: lets an AI agent search 3D models, read model cards, list files and get direct download links.
41
+
42
+ It talks to the public Printables GraphQL API directly: no HTML scraping, no browser, no account. All tools are read-only and return structured results (JSON with an output schema), so agents get exact fields instead of prose.
43
+
44
+ ## Installation
45
+
46
+ ```bash
47
+ uv tool install printables-mcp
48
+ ```
49
+
50
+ Then register the `printables-mcp` command with your MCP client. Claude Code:
51
+
52
+ ```bash
53
+ claude mcp add printables -s user -- printables-mcp
54
+ ```
55
+
56
+ Any other client that speaks stdio:
57
+
58
+ ```json
59
+ {
60
+ "mcpServers": {
61
+ "printables": { "command": "printables-mcp" }
62
+ }
63
+ }
64
+ ```
65
+
66
+ Without installing: `uvx printables-mcp`.
67
+
68
+ ## Tools
69
+
70
+ | Tool | What it does |
71
+ |---|---|
72
+ | `search_models` | Text search with pagination (`limit`, `offset`, total count) and filters: category, price (`free` / `paid`), licenses, published within N days, has user prints. Orderings: best match, popular, latest, rating, makes count. |
73
+ | `get_model` | Full model card: description as Markdown, tags, category path, license, materials, printer, print time, filament weight, images, PDF, remix sources, stats, price. |
74
+ | `list_model_files` | Every file group in one request: model files (STL/3MF/STEP…), G-code with printer, material, layer height, nozzle and print time, SLA files, other files, ZIP packs. |
75
+ | `get_download_links` | Direct download URLs (valid 24 h) for all or selected files, fetched in parallel. Files of paid or club-only models come back with a per-file reason instead of failing the call. |
76
+ | `list_categories` | All categories with their full paths (IDs for the search filter). |
77
+ | `list_licenses` | All licenses (IDs for the search filter). |
78
+ | `get_author` | Author profile by ID, handle or profile URL. |
79
+ | `list_author_models` | An author's models, cursor-paginated, ordered by newest, oldest, likes, downloads, rating or makes. |
80
+
81
+ Models and authors can be passed as IDs or as printables.com URLs (locale prefixes such as `/de/` are fine).
82
+
83
+ ## Limitations
84
+
85
+ - Anonymous access only: paid and Printables Club models are visible, but their files cannot be downloaded.
86
+ - The API is undocumented and may change without notice; the end-to-end suite (`just test-live`) checks it against the live service.
87
+
88
+ ## Development
89
+
90
+ ```bash
91
+ uv sync
92
+ just lint # ruff format/check + ty
93
+ just test # pytest with 100% branch coverage
94
+ just test-live # end-to-end tests against the real API
95
+ ```
96
+
97
+ ## License
98
+
99
+ [MIT](LICENSE)
@@ -0,0 +1,69 @@
1
+ # printables-mcp
2
+
3
+ **English** · [Русский](README.ru.md)
4
+
5
+ [![PyPI - Version](https://img.shields.io/pypi/v/printables-mcp)](https://pypi.org/project/printables-mcp/)
6
+ ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/printables-mcp)
7
+ ![PyPI - Status](https://img.shields.io/pypi/status/printables-mcp)
8
+ [![CI](https://github.com/feodor-ra/printables-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/feodor-ra/printables-mcp/actions/workflows/ci.yml)
9
+
10
+ **An [MCP](https://modelcontextprotocol.io) server for [Printables.com](https://www.printables.com)**: lets an AI agent search 3D models, read model cards, list files and get direct download links.
11
+
12
+ It talks to the public Printables GraphQL API directly: no HTML scraping, no browser, no account. All tools are read-only and return structured results (JSON with an output schema), so agents get exact fields instead of prose.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ uv tool install printables-mcp
18
+ ```
19
+
20
+ Then register the `printables-mcp` command with your MCP client. Claude Code:
21
+
22
+ ```bash
23
+ claude mcp add printables -s user -- printables-mcp
24
+ ```
25
+
26
+ Any other client that speaks stdio:
27
+
28
+ ```json
29
+ {
30
+ "mcpServers": {
31
+ "printables": { "command": "printables-mcp" }
32
+ }
33
+ }
34
+ ```
35
+
36
+ Without installing: `uvx printables-mcp`.
37
+
38
+ ## Tools
39
+
40
+ | Tool | What it does |
41
+ |---|---|
42
+ | `search_models` | Text search with pagination (`limit`, `offset`, total count) and filters: category, price (`free` / `paid`), licenses, published within N days, has user prints. Orderings: best match, popular, latest, rating, makes count. |
43
+ | `get_model` | Full model card: description as Markdown, tags, category path, license, materials, printer, print time, filament weight, images, PDF, remix sources, stats, price. |
44
+ | `list_model_files` | Every file group in one request: model files (STL/3MF/STEP…), G-code with printer, material, layer height, nozzle and print time, SLA files, other files, ZIP packs. |
45
+ | `get_download_links` | Direct download URLs (valid 24 h) for all or selected files, fetched in parallel. Files of paid or club-only models come back with a per-file reason instead of failing the call. |
46
+ | `list_categories` | All categories with their full paths (IDs for the search filter). |
47
+ | `list_licenses` | All licenses (IDs for the search filter). |
48
+ | `get_author` | Author profile by ID, handle or profile URL. |
49
+ | `list_author_models` | An author's models, cursor-paginated, ordered by newest, oldest, likes, downloads, rating or makes. |
50
+
51
+ Models and authors can be passed as IDs or as printables.com URLs (locale prefixes such as `/de/` are fine).
52
+
53
+ ## Limitations
54
+
55
+ - Anonymous access only: paid and Printables Club models are visible, but their files cannot be downloaded.
56
+ - The API is undocumented and may change without notice; the end-to-end suite (`just test-live`) checks it against the live service.
57
+
58
+ ## Development
59
+
60
+ ```bash
61
+ uv sync
62
+ just lint # ruff format/check + ty
63
+ just test # pytest with 100% branch coverage
64
+ just test-live # end-to-end tests against the real API
65
+ ```
66
+
67
+ ## License
68
+
69
+ [MIT](LICENSE)
@@ -0,0 +1,69 @@
1
+ # printables-mcp
2
+
3
+ [English](README.md) · **Русский**
4
+
5
+ [![PyPI - Version](https://img.shields.io/pypi/v/printables-mcp)](https://pypi.org/project/printables-mcp/)
6
+ ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/printables-mcp)
7
+ ![PyPI - Status](https://img.shields.io/pypi/status/printables-mcp)
8
+ [![CI](https://github.com/feodor-ra/printables-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/feodor-ra/printables-mcp/actions/workflows/ci.yml)
9
+
10
+ **[MCP](https://modelcontextprotocol.io)-сервер для [Printables.com](https://www.printables.com).** Через него ИИ-агент ищет 3D-модели, читает их карточки, смотрит список файлов и получает прямые ссылки на скачивание.
11
+
12
+ Сервер обращается напрямую к публичному GraphQL API Printables: без парсинга HTML, без браузера и без аккаунта. Все инструменты только читают данные и возвращают структурированный результат (JSON со схемой вывода), поэтому агент получает точные поля, а не текст.
13
+
14
+ ## Установка
15
+
16
+ ```bash
17
+ uv tool install printables-mcp
18
+ ```
19
+
20
+ Затем подключите команду `printables-mcp` в MCP-клиенте. Claude Code:
21
+
22
+ ```bash
23
+ claude mcp add printables -s user -- printables-mcp
24
+ ```
25
+
26
+ Любой другой клиент с транспортом stdio:
27
+
28
+ ```json
29
+ {
30
+ "mcpServers": {
31
+ "printables": { "command": "printables-mcp" }
32
+ }
33
+ }
34
+ ```
35
+
36
+ Без установки: `uvx printables-mcp`.
37
+
38
+ ## Инструменты
39
+
40
+ | Инструмент | Что делает |
41
+ |---|---|
42
+ | `search_models` | Поиск по тексту с пагинацией (`limit`, `offset`, общее число результатов) и фильтрами: категория, цена (`free` / `paid`), лицензии, опубликовано за N дней, есть фото печати. Сортировки: по релевантности, популярности, новизне, рейтингу, числу печатей. |
43
+ | `get_model` | Полная карточка модели: описание в Markdown, теги, путь категории, лицензия, материалы, принтер, время печати, вес филамента, фото, PDF, источники ремикса, статистика, цена. |
44
+ | `list_model_files` | Все группы файлов одним запросом: файлы модели (STL/3MF/STEP…), G-code с принтером, материалом, высотой слоя, соплом и временем печати, файлы SLA, прочие файлы, ZIP-архивы. |
45
+ | `get_download_links` | Прямые ссылки на скачивание (живут 24 часа) для всех или выбранных файлов, запрашиваются параллельно. Для файлов платных моделей и моделей Printables Club по каждому файлу приходит причина отказа, остальные ссылки при этом выдаются. |
46
+ | `list_categories` | Все категории с полным путём (ID для фильтра поиска). |
47
+ | `list_licenses` | Все лицензии (ID для фильтра поиска). |
48
+ | `get_author` | Профиль автора по ID, нику или ссылке на профиль. |
49
+ | `list_author_models` | Модели автора постранично (курсор), сортировка: новые, старые, по лайкам, скачиваниям, рейтингу или числу печатей. |
50
+
51
+ Модели и авторов можно передавать по ID или ссылкой на printables.com (префиксы локали вроде `/de/` поддерживаются).
52
+
53
+ ## Ограничения
54
+
55
+ - Доступ только анонимный: платные модели и модели Printables Club видны, но их файлы скачать нельзя.
56
+ - API не документирован и может поменяться без предупреждения. Сквозные тесты (`just test-live`) проверяют его на живом сервисе.
57
+
58
+ ## Разработка
59
+
60
+ ```bash
61
+ uv sync
62
+ just lint # ruff format/check + ty
63
+ just test # pytest со 100% покрытием веток
64
+ just test-live # сквозные тесты против реального API
65
+ ```
66
+
67
+ ## Лицензия
68
+
69
+ [MIT](LICENSE)
@@ -0,0 +1,95 @@
1
+ [project]
2
+ name = "printables-mcp"
3
+ version = "0.1.0"
4
+ description = "MCP server for Printables.com: search 3D models, read model cards, list files and get download links"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Fedor Ratschew", email = "feodor.ra@me.com" },
8
+ ]
9
+ requires-python = ">=3.10"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ keywords = ["mcp", "model-context-protocol", "printables", "3d-printing", "llm"]
13
+ classifiers = [
14
+ "Development Status :: 4 - Beta",
15
+ "Intended Audience :: Developers",
16
+ "Operating System :: OS Independent",
17
+ "Programming Language :: Python :: 3 :: Only",
18
+ "Programming Language :: Python :: 3.10",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Programming Language :: Python :: 3.14",
23
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
24
+ "Typing :: Typed",
25
+ ]
26
+ dependencies = [
27
+ "anyio>=4.9",
28
+ "httpx2>=2.10",
29
+ "markdownify>=1.2",
30
+ "mcp>=2.3,<3",
31
+ "pydantic>=2.12",
32
+ ]
33
+
34
+ [project.scripts]
35
+ printables-mcp = "printables_mcp.server:main"
36
+
37
+ [project.urls]
38
+ Homepage = "https://github.com/feodor-ra/printables-mcp"
39
+ Repository = "https://github.com/feodor-ra/printables-mcp"
40
+ Issues = "https://github.com/feodor-ra/printables-mcp/issues"
41
+
42
+ [build-system]
43
+ requires = ["hatchling>=1.27"]
44
+ build-backend = "hatchling.build"
45
+
46
+ [tool.ruff]
47
+ line-length = 120
48
+ preview = true
49
+
50
+ [tool.ruff.format]
51
+ quote-style = "double"
52
+
53
+ [tool.ruff.lint]
54
+ select = ["ALL"]
55
+ ignore = [
56
+ "CPY", # flake8-copyright: no per-file copyright notices
57
+ "missing-trailing-comma", # COM812: conflicts with the formatter
58
+ "relative-imports", # TID252: relative imports inside the package are welcome
59
+ ]
60
+
61
+ [tool.ruff.lint.pydocstyle]
62
+ convention = "google"
63
+
64
+ [tool.ruff.lint.per-file-ignores]
65
+ "tests/**" = [
66
+ "assert", # S101: pytest is built on assert
67
+ "implicit-namespace-package", # INP001: the tests directory is not a package
68
+ "magic-value-comparison", # PLR2004: comparing to literal counts is normal in tests
69
+ "import-private-name", # PLC2701: tests exercise the package's private internals
70
+ ]
71
+
72
+ [tool.ty.rules]
73
+ all = "error"
74
+
75
+ [tool.pytest.ini_options]
76
+ testpaths = ["tests"]
77
+ addopts = "--strict-config --strict-markers -m 'not live'"
78
+ markers = ["live: hits the real Printables API (run with `-m live`)"]
79
+
80
+ [tool.coverage.run]
81
+ source = ["printables_mcp"]
82
+ branch = true
83
+
84
+ [tool.coverage.report]
85
+ show_missing = true
86
+ fail_under = 100
87
+
88
+ [dependency-groups]
89
+ dev = [
90
+ "anyio~=4.15.1",
91
+ "pytest~=9.2.0",
92
+ "pytest-cov~=7.1.0",
93
+ "ruff==0.17.3",
94
+ "ty==0.0.95",
95
+ ]
@@ -0,0 +1,5 @@
1
+ """MCP server for Printables.com."""
2
+
3
+ from importlib.metadata import version
4
+
5
+ __version__ = version("printables-mcp")