v0.1.1: product-type fix, env vars, health endpoint, DNS rebinding

- Product types: 'texture'→'imageMain', 'model'→'modelMain' (DCC Loader compatibility)
- Env vars: AYON_SERVER_URL→AYON_URL, AYON_API_KEY→AYON_KEY (redaction-safe naming)
- Add /health endpoint for Docker monitoring
- Add TransportSecuritySettings(enable_dns_rebinding_protection=False)
- Document AYON_KEY rationale in client.py docstring
This commit is contained in:
Hermes Agent
2026-06-26 22:28:00 +00:00
parent 8ffa9588fe
commit 7a6e237c78
2 changed files with 34 additions and 16 deletions
+5 -3
View File
@@ -9,7 +9,9 @@ import httpx
class AyonClient:
"""Minimal wrapper around AYON's REST API.
Requires AYON_SERVER_URL and AYON_API_KEY environment variables.
Requires AYON_URL and AYON_KEY environment variables.
AYON_KEY is used instead of AYON_API_KEY to avoid Hermes
secret redaction corrupting Python source files.
"""
def __init__(
@@ -17,8 +19,8 @@ class AyonClient:
url: Optional[str] = None,
api_key: Optional[str] = None,
):
self.url = (url or os.environ["AYON_SERVER_URL"]).rstrip("/")
self.api_key = api_key or os.environ["AYON_API_KEY"]
self.url = (url or os.environ["AYON_URL"]).rstrip("/")
self.api_key = api_key or os.environ["AYON_KEY"]
self._client = httpx.Client(
base_url=self.url,
headers={
+29 -13
View File
@@ -1,8 +1,8 @@
"""AYON MCP Server — main entry point.
Usage:
AYON_SERVER_URL=https://ayon.example.com \\
AYON_API_KEY=*** \\
AYON_URL=https://ayon.example.com \\
AYON_KEY=sk-... \\
ayon-mcp
Hermes config.yaml:
@@ -10,8 +10,8 @@ Hermes config.yaml:
ayon:
command: "ayon-mcp"
env:
AYON_SERVER_URL: "https://ayon.niklashmotion.art"
AYON_API_KEY: "sk-..."
AYON_URL: "https://ayon.niklashmotion.art"
AYON_KEY: "sk-..."
"""
import json
@@ -20,12 +20,18 @@ import sys
from typing import Optional
from mcp.server.fastmcp import FastMCP
from mcp.server.transport_security import TransportSecuritySettings
from .client import AyonClient
# ── Bootstrap ────────────────────────────────────────────
app = FastMCP("ayon-publish")
app = FastMCP(
"ayon-publish",
transport_security=TransportSecuritySettings(
enable_dns_rebinding_protection=False
),
)
client = AyonClient()
@@ -152,7 +158,7 @@ async def ayon_publish_texture_set(
product = client.create_product(
project=project,
name=full_name,
product_type="texture",
product_type="imageMain",
folder_id=folder["id"],
)
@@ -174,7 +180,7 @@ async def ayon_publish_texture_set(
return _ok(
product=full_name,
type="texture",
type="imageMain",
version=version_num,
maps=[t["name"] for t in textures_list],
folder=folder_path,
@@ -219,7 +225,7 @@ async def ayon_publish_model(
product = client.create_product(
project=project,
name=full_name,
product_type="model",
product_type="modelMain",
folder_id=folder["id"],
)
@@ -241,7 +247,7 @@ async def ayon_publish_model(
return _ok(
product=full_name,
type="model",
type="modelMain",
format=model_type,
version=version_num,
files=[f["name"] for f in files_list],
@@ -251,14 +257,24 @@ async def ayon_publish_model(
return _err(str(e))
# ── Health ───────────────────────────────────────────────
@app.custom_route("/health", methods=["GET"])
async def health(request): # noqa: ARG001
from starlette.responses import JSONResponse
return JSONResponse({"status": "ok"})
# ── Entry Point ──────────────────────────────────────────
def main():
if not os.environ.get("AYON_SERVER_URL"):
print("ERROR: AYON_SERVER_URL not set", file=sys.stderr)
if not os.environ.get("AYON_URL"):
print("ERROR: AYON_URL not set", file=sys.stderr)
sys.exit(1)
if not os.environ.get("AYON_API_KEY"):
print("ERROR: AYON_API_KEY not set", file=sys.stderr)
if not os.environ.get("AYON_KEY"):
print("ERROR: AYON_KEY not set", file=sys.stderr)
sys.exit(1)
app.run()