ИНТЕГРАЦИИ / ДЛЯ СКРИПТОВ И АГЕНТОВ
Одна библиотека.
Интерфейс, API и MCP.
На сайте и в программных запросах используются одни и те же 33 генератора.
Можно искать крепления, менять размеры и получать CAD или пробник для печати.
REST API
GET /api/models?q=…Поиск по названию, устройству и применению. Семейство можно передать параметром group.
GET /api/models/{id}Полное описание и схема числовых параметров с исходными значениями.
POST /api/generate/{id}Строит CAD, STEP, FCStd, STL деталей и сетку просмотра.
POST /api/probe/{id}Строит пробник с учётом ориентации печати и создаёт 3MF.
GET /api/jobs/{job_id}Статус queued, running, completed или failed. Готовый результат содержит адреса файлов.
Размеры — в миллиметрах, углы — в градусах. Передавайте только изменённые параметры. Неизвестные ключи и недопустимые значения отклоняются.
curl -G --data-urlencode 'q=крышка' 'https://fastening.home.mivx.ru/api/models'curl -X POST 'https://fastening.home.mivx.ru/api/probe/cantilever' \
-H 'Content-Type: application/json' \
-d '{"parameters":{"beam_length":32,"clearance":0.3}}'Задачи и файлы
HTTP 200 возвращает готовый результат. При HTTP 202 сохраните statusUrl и опрашивайте его с учётом retryAfter. Поле status = completed означает успешное завершение; failed содержит сообщение об ошибке. При HTTP 429 очередь занята — повторите запрос позднее.
Результат содержит assets: адрес каталога файлов. В нём находятся demo.step, demo.FCStd и parameters.json, а у пробника — probe.stl и fit-test.3mf. Физическая печать автоматически не запускается.
Результаты хранятся в ограниченном кэше: сохраняйте нужные файлы локально. Готовые исходные пробники уже прошли нарезку. Для новых размеров читайте print.status: passed — серверная нарезка пройдена; project_ready и sliced: false — 3MF подготовлен и требует нарезки в Bambu Studio. Проект сохраняет профиль P2S 0,4 мм / PETG / 0,20 мм, автоматические поддержки и полный завершающий G-код.
{
"jobId": "example-g",
"status": "queued",
"statusUrl": "/api/jobs/example-g",
"retryAfter": 1
}curl 'https://fastening.home.mivx.ru/api/jobs/JOB_ID'MCP для агентов
Подключите Streamable HTTP endpoint https://fastening.home.mivx.ru/mcp. Поддерживаются версия 2026-07-28 с метаданными каждого запроса и версии 2025-11-25 / 2025-06-18 / 2025-03-26 с initialize. Сервер работает без сессий.
list_fastenersНайти механизм по слову или семейству.
get_fastenerПолучить описание, схему параметров и ссылки на файлы.
generate_modelСгенерировать CAD по числовым параметрам.
generate_probeПодготовить печатный пробник из того же набора размеров.
get_jobПолучить состояние задачи и ссылки на результат.
Также доступны ресурсы fastening://catalog, fastening://skill и шаблоны исходников генераторов. Ответы MCP содержат ссылки и параметры; большие массивы сетки остаются в REST API.
curl -X POST 'https://fastening.home.mivx.ru/mcp' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2026-07-28' \
-H 'Mcp-Method: tools/list' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientInfo":{"name":"my-agent","version":"1.0.0"},"io.modelcontextprotocol/clientCapabilities":{}}}}'Готовый skill и Python-клиент
Skill описывает выбор крепления, параметры, ожидание задач, скачивание файлов и границы CAD-проверки. Клиент использует стандартную библиотеку Python, автоматически ждёт завершения задачи и защищает существующие файлы от перезаписи.
python3 client.py list --query 'защёлка'
python3 client.py show cantilever
python3 client.py probe cantilever --parameters '{"beam_length":32}' --output ./probePython-клиент целиком
"""Standard-library client for Fastening Lab queries, CAD and print coupons."""
import argparse
import json
import os
import tempfile
import time
from pathlib import Path
from urllib.error import HTTPError
from urllib.parse import urlencode, urljoin, urlsplit
from urllib.request import Request, urlopen
def request(base, route, body=None):
url = urljoin(base.rstrip("/") + "/", route)
if urlsplit(url).netloc != urlsplit(base).netloc:
raise ValueError("Unexpected API origin")
data = None if body is None else json.dumps(body).encode()
req = Request(
url,
data=data,
headers={"Content-Type": "application/json", "Accept": "application/json"},
)
try:
with urlopen(req, timeout=30) as response:
return json.load(response)
except HTTPError as error:
message = error.read().decode(errors="replace")
raise ValueError(f"HTTP {error.code}: {message[:600]}") from None
def wait(base, result, timeout=900):
deadline = time.monotonic() + timeout
while result.get("status") in {"queued", "running"}:
if time.monotonic() > deadline:
raise TimeoutError(
"The CAD job is still running; poll " + result["statusUrl"]
)
time.sleep(max(0.5, min(5, result.get("retryAfter", 1))))
result = request(base, result["statusUrl"])
if result.get("status") == "failed":
raise ValueError(result.get("error", "CAD job failed"))
return result
def download(base, route, output):
url = urljoin(base.rstrip("/") + "/", route)
if urlsplit(url).netloc != urlsplit(base).netloc:
raise ValueError("Unexpected artifact origin")
with tempfile.TemporaryDirectory(dir=output.parent) as tmp:
staged = Path(tmp) / output.name
with urlopen(url, timeout=90) as response, staged.open("wb") as stream:
expected = response.headers.get("Content-Length")
received = 0
while chunk := response.read(1024 * 1024):
stream.write(chunk)
received += len(chunk)
if expected is not None and received != int(expected):
raise ValueError("Incomplete download; no output file was published")
os.link(staged, output)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--base-url", default="https://fastening.home.mivx.ru")
commands = parser.add_subparsers(dest="command", required=True)
search = commands.add_parser("list")
search.add_argument("--query", default="")
show = commands.add_parser("show")
show.add_argument("model_id")
for name in ("generate", "probe"):
cmd = commands.add_parser(name)
cmd.add_argument("model_id")
cmd.add_argument("--parameters", default="{}")
cmd.add_argument("--output", type=Path)
args = parser.parse_args()
if args.command == "list":
result = request(args.base_url, "/api/models?" + urlencode({"q": args.query}))
elif args.command == "show":
result = request(args.base_url, "/api/models/" + args.model_id)
else:
result = wait(
args.base_url,
request(
args.base_url,
f"/api/{args.command}/{args.model_id}",
{"parameters": json.loads(args.parameters)},
),
)
if args.output:
args.output.mkdir(parents=True, exist_ok=True)
files = (
["fit-test.3mf", "probe.stl", "parameters.json"]
if args.command == "probe"
else ["demo.step", "demo.FCStd", "parameters.json"]
)
if any((args.output / name).exists() for name in files):
raise FileExistsError(
"Output files already exist; choose a new directory"
)
for name in files:
download(
args.base_url, result["assets"] + "/" + name, args.output / name
)
model = result.pop("model", None)
if model:
result.update(model_id=model["id"], parameters=model["parameters"])
print(json.dumps(result, ensure_ascii=False, indent=2))
if __name__ == "__main__":
try:
main()
except (ValueError, OSError) as error:
raise SystemExit(str(error)) from None
Что подтверждают проверки
Проверяются геометрия, валидность CAD-тел, обратное чтение STEP и пересечения на контрольных стадиях движения. Это не физическая проверка усилия, удержания или ресурса. Y-Zipper — экспериментальная геометрия. Некоторые металлические детали представлены габаритными моделями.