"""Python 3.10+, standard library only. Read /examples/README.md first.""" import hashlib import json import os from pathlib import Path import re import secrets import sys import urllib.error import urllib.parse import urllib.request ORIGIN = "https://postedly.com" PROTOCOL = "2025-06-18" class NoRedirect(urllib.request.HTTPRedirectHandler): def redirect_request(self, req, fp, code, msg, headers, newurl): raise RuntimeError("Unexpected redirect; credentials were not forwarded.") class Postedly: def __init__(self, access_token, opener=None): if not access_token or re.search(r"\s", access_token): raise ValueError("Supply an existing OAuth access token through a secure environment.") self.token = access_token self.opener = opener or urllib.request.build_opener(NoRedirect()) def request(self, path, method="GET", payload=None, body=None, content_type=None): url = urllib.parse.urljoin(ORIGIN, path) if urllib.parse.urlsplit(url)[:2] != ("https", "postedly.com"): raise ValueError("Refusing to send credentials to another origin.") headers = {"Authorization": f"Bearer {self.token}", "Accept": "application/json", "MCP-Protocol-Version": PROTOCOL} if payload is not None: body, content_type = json.dumps(payload).encode(), "application/json" if content_type: headers["Content-Type"] = content_type request = urllib.request.Request(url, data=body, headers=headers, method=method) try: with self.opener.open(request, timeout=30) as response: if response.status == 202 and path == "/mcp/send": return None return json.load(response) except urllib.error.HTTPError as error: # Do not print response bodies, credentials, contact details or private URLs. raise RuntimeError(f"HTTP {error.code}. No automatic retry; consult /agent-guide.md.") from None except (urllib.error.URLError, TimeoutError, OSError, ValueError): raise RuntimeError("Request outcome unconfirmed. Do not replay mutations. Read existing orders/status; see the recovery guide.") from None def review_link(self, quote_id): initialized = self.request("/mcp/send", "POST", {"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": PROTOCOL, "capabilities": {}, "clientInfo": {"name": "Postedly Python example", "version": "1.0.0"}}}) if initialized.get("error") or initialized.get("result", {}).get("protocolVersion") != PROTOCOL: raise RuntimeError("MCP initialization failed.") self.request("/mcp/send", "POST", {"jsonrpc": "2.0", "method": "notifications/initialized"}) result = self.request("/mcp/send", "POST", {"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "postedly_checkout", "arguments": {"quoteId": quote_id}}}) tool_result = result.get("result", {}) review = tool_result.get("structuredContent", {}) if result.get("error") or tool_result.get("isError") or review.get("requiresBrowserApproval") is not True: raise RuntimeError("Review link unavailable. Keep the existing quote; do not create a replacement order.") return review def prepare(self, file_bytes, filename, inputs, checkpoint=lambda state: None): service = inputs.get("service") if service not in ("fax", "letter", "certified", "postcard"): raise ValueError("Choose a supported document service.") if not 0 < len(file_bytes) <= 10_485_760: raise ValueError("File must be 1 byte through 10 MiB.") if not filename or len(filename) > 180 or re.search(r'[\r\n\x00/\\"]', filename): raise ValueError("Use a filename without paths, quotes or control characters, at most 180 characters.") catalog = self.request("/api/catalog") if not any(item["id"] == service and item["available"] for item in catalog["services"]): raise RuntimeError("This service is not currently available.") account = self.request("/api/session") if not account.get("verified") or account.get("email", "").lower() != inputs.get("sender", {}).get("email", "").lower(): raise RuntimeError("Sender email must match the verified OAuth account.") expected_hash = hashlib.sha256(file_bytes).hexdigest() boundary = "postedly-" + secrets.token_hex(24) # Actual bytes, never a filename/URL disguised as a file. Boundary is random. parts = [] for key, value in (("service", service), ("expectedSha256", expected_hash)): parts.append(f'--{boundary}\r\nContent-Disposition: form-data; name="{key}"\r\n\r\n{value}\r\n'.encode()) parts.extend([f'--{boundary}\r\nContent-Disposition: form-data; name="file"; filename="{filename}"\r\nContent-Type: application/octet-stream\r\n\r\n'.encode(), file_bytes, f"\r\n--{boundary}--\r\n".encode()]) document = self.request("/api/documents", "POST", body=b"".join(parts), content_type=f"multipart/form-data; boundary={boundary}") state = {"document": document} checkpoint(state) if document.get("sha256") != expected_hash or not document.get("id"): raise RuntimeError("Stored file checksum or document ID is invalid.") state["quote"] = self.request("/api/quotes", "POST", {"service": service, "documentId": document["id"], "recipient": inputs["recipient"], "sender": inputs["sender"], "options": inputs.get("options", {})}) checkpoint(state) # Only a review link: the sender approves and pays in the browser. state["review"] = self.review_link(state["quote"]["id"]) checkpoint(state) return state def status(self, order_id=None): return self.request("/api/orders/" + urllib.parse.quote(order_id, safe="") if order_id else "/api/orders") def main(): args = sys.argv[1:] if not args or (args[0] == "prepare" and len(args) != 4) or (args[0] == "status" and len(args) not in (2, 3)) or args[0] not in ("prepare", "status"): raise ValueError("Usage: python3 postedly.py prepare request.json document.pdf private-result.json | status private-result.json [order-id]") client = Postedly(os.environ.get("POSTEDLY_ACCESS_TOKEN")) output = args[3] if args[0] == "prepare" else args[1] # Never overwrite a previous run. Private links/contact details stay owner-only. descriptor = os.open(output, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) with os.fdopen(descriptor, "w", encoding="utf-8") as file: def checkpoint(state): file.seek(0) json.dump(state, file, indent=2) file.truncate() file.flush() os.fsync(file.fileno()) if args[0] == "prepare": client.prepare(Path(args[2]).read_bytes(), Path(args[2]).name, json.loads(Path(args[1]).read_text()), checkpoint) else: checkpoint(client.status(args[2] if len(args) == 3 else None)) print("Private result saved. For prepare, open review.url locally and approve only after checking the proof, recipient, total and terms.") if __name__ == "__main__": try: main() except Exception as error: print(str(error), file=sys.stderr) sys.exit(1)