{
  "$schema": "https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json",
  "name": "com.havetml/havetml",
  "title": "HaveTML",
  "description": "Publish HTML, Markdown, YAML and JSON artifacts as permanent, commentable share links.",
  "version": "1.0.0",
  "websiteUrl": "https://havetml.com/connect",
  "icons": [
    {
      "src": "https://havetml.com/icon",
      "mimeType": "image/png",
      "sizes": [
        "32x32"
      ]
    },
    {
      "src": "https://havetml.com/apple-icon",
      "mimeType": "image/png",
      "sizes": [
        "180x180"
      ]
    }
  ],
  "repository": {
    "source": "github",
    "url": "https://github.com/hass-disrupt/havetml"
  },
  "remotes": [
    {
      "type": "streamable-http",
      "url": "https://havetml.com/api/mcp",
      "supportedProtocolVersions": [
        "2025-06-18",
        "2025-03-26"
      ],
      "headers": [
        {
          "name": "Authorization",
          "description": "Bearer <token>, where the token is a HaveTML API token (havetml_…). Clients that speak OAuth can skip this: an unauthenticated request gets a 401 pointing at HaveTML's authorization server instead.",
          "isRequired": false,
          "isSecret": true,
          "placeholder": "Bearer havetml_…"
        }
      ]
    }
  ],
  "serverInfo": {
    "name": "havetml",
    "version": "1.0.0"
  },
  "authentication": {
    "required": true,
    "schemes": [
      "oauth2",
      "bearer"
    ],
    "authorizationUrl": "https://havetml.com/oauth/authorize",
    "tokenUrl": "https://havetml.com/oauth/token",
    "registrationUrl": "https://havetml.com/oauth/register",
    "resourceMetadataUrl": "https://havetml.com/.well-known/oauth-protected-resource/api/mcp",
    "documentationUrl": "https://havetml.com/connect",
    "scopes": [
      "artifacts"
    ]
  },
  "tools": [
    {
      "name": "upload_artifact",
      "title": "Upload artifact to HaveTML",
      "description": "Upload HTML, Markdown, YAML or JSON and get a permanent share link; re-uploading versions it.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "filename": {
            "type": "string"
          },
          "content": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "project": {
            "type": "string"
          },
          "json": {
            "type": "object"
          },
          "visibility": {
            "type": "string"
          },
          "folder_id": {
            "type": "string"
          },
          "folder_path": {
            "type": "string"
          },
          "create_missing": {
            "type": "boolean"
          }
        },
        "required": [
          "filename",
          "content"
        ]
      },
      "annotations": {
        "title": "Upload artifact to HaveTML",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "get_artifact",
      "title": "Get artifact with JSON state, comments, and metadata",
      "description": "Read an artifact's JSON state, comments, annotations and metadata.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          }
        },
        "required": [
          "slug"
        ]
      },
      "annotations": {
        "title": "Get artifact with JSON state, comments, and metadata",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "list_artifacts",
      "title": "List HaveTML artifacts",
      "description": "List your artifacts, optionally scoped to one project, folder or category.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string"
          },
          "folder": {
            "type": "string"
          },
          "category": {
            "type": "string"
          }
        }
      },
      "annotations": {
        "title": "List HaveTML artifacts",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "search_skills",
      "title": "Search HaveTML skills",
      "description": "Search public skills — SKILL.md artifacts an agent can install and load.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string"
          },
          "limit": {
            "type": "number"
          }
        }
      },
      "annotations": {
        "title": "Search HaveTML skills",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "set_artifact_visibility",
      "title": "Change who can see an existing artifact",
      "description": "Move an existing artifact between private, circle, unlisted and public.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "visibility": {
            "type": "string"
          }
        },
        "required": [
          "slug",
          "visibility"
        ]
      },
      "annotations": {
        "title": "Change who can see an existing artifact",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "create_encrypted_artifact",
      "title": "Create an encrypted artifact from ciphertext",
      "description": "Store an envelope encrypted on your own machine, so HaveTML holds only ciphertext.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "content_type": {
            "type": "string"
          },
          "envelope": {
            "type": "string"
          },
          "project": {
            "type": "string"
          },
          "visibility": {
            "type": "string"
          },
          "folder_id": {
            "type": "string"
          },
          "folder_path": {
            "type": "string"
          },
          "create_missing": {
            "type": "boolean"
          }
        },
        "required": [
          "slug",
          "content_type",
          "envelope"
        ]
      },
      "annotations": {
        "title": "Create an encrypted artifact from ciphertext",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "create_project",
      "title": "Create HaveTML project",
      "description": "Create a project — a shareable folder of artifacts with its own page.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          }
        },
        "required": [
          "name"
        ]
      },
      "annotations": {
        "title": "Create HaveTML project",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "list_projects",
      "title": "List HaveTML projects",
      "description": "List your projects with their slugs, names and artifact counts.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      },
      "annotations": {
        "title": "List HaveTML projects",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "set_project_default_visibility",
      "title": "Set a project's default visibility",
      "description": "Choose what new artifacts filed into a project inherit; moves nothing already in it.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string"
          },
          "visibility": {
            "type": "string"
          }
        },
        "required": [
          "project"
        ]
      },
      "annotations": {
        "title": "Set a project's default visibility",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "add_comment",
      "title": "Add comment to artifact",
      "description": "Add a comment to an artifact, optionally pinned to a spot or threaded.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "anchor": {
            "type": "object"
          },
          "parent_id": {
            "type": "string"
          },
          "version": {
            "type": "number"
          }
        },
        "required": [
          "slug",
          "body"
        ]
      },
      "annotations": {
        "title": "Add comment to artifact",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "list_comments",
      "title": "List artifact comments",
      "description": "List every comment on an artifact, including threaded replies.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          }
        },
        "required": [
          "slug"
        ]
      },
      "annotations": {
        "title": "List artifact comments",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "invite_collaborator",
      "title": "Invite collaborator to artifact",
      "description": "Invite someone by email to view or edit one artifact.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "role": {
            "type": "string"
          }
        },
        "required": [
          "slug",
          "email"
        ]
      },
      "annotations": {
        "title": "Invite collaborator to artifact",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "list_collaborators",
      "title": "List artifact collaborators",
      "description": "List the people with access to an artifact.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          }
        },
        "required": [
          "slug"
        ]
      },
      "annotations": {
        "title": "List artifact collaborators",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "revoke_collaborator",
      "title": "Revoke artifact access",
      "description": "Revoke a collaborator's access to an artifact.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "email": {
            "type": "string"
          }
        },
        "required": [
          "slug",
          "email"
        ]
      },
      "annotations": {
        "title": "Revoke artifact access",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "invite_project_member",
      "title": "Invite member to project",
      "description": "Invite someone by email to a project; editors inherit edit access to its artifacts.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "role": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "email"
        ]
      },
      "annotations": {
        "title": "Invite member to project",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "list_project_members",
      "title": "List project members",
      "description": "List the people with access to a project.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string"
          }
        },
        "required": [
          "project"
        ]
      },
      "annotations": {
        "title": "List project members",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "revoke_project_member",
      "title": "Revoke project access",
      "description": "Revoke a member's access to a project.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string"
          },
          "email": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "email"
        ]
      },
      "annotations": {
        "title": "Revoke project access",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "create_canvas",
      "title": "Create a HaveTML canvas",
      "description": "Create a canvas: a board of cards, stickies and the connections between them.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "visibility": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "nodes": {
            "type": "array"
          },
          "edges": {
            "type": "array"
          },
          "folder_id": {
            "type": "string"
          },
          "folder_path": {
            "type": "string"
          },
          "create_missing": {
            "type": "boolean"
          }
        },
        "required": [
          "project"
        ]
      },
      "annotations": {
        "title": "Create a HaveTML canvas",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "get_canvas",
      "title": "Read a HaveTML canvas",
      "description": "Read a canvas board: its nodes, edges, notes and comment threads.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          }
        },
        "required": [
          "slug"
        ]
      },
      "annotations": {
        "title": "Read a HaveTML canvas",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "update_canvas",
      "title": "Update a HaveTML canvas",
      "description": "Rename a board, rewrite its notes, or replace the nodes and edges on it.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "nodes": {
            "type": "array"
          },
          "edges": {
            "type": "array"
          },
          "viewport": {
            "type": "object"
          },
          "base_rev": {
            "type": "number"
          }
        },
        "required": [
          "slug"
        ]
      },
      "annotations": {
        "title": "Update a HaveTML canvas",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "add_canvas_node",
      "title": "Add a node to a canvas",
      "description": "Add one node to a canvas without touching what is already on it.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "ref": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "data": {
            "type": "object"
          },
          "parent": {
            "type": "string"
          },
          "unsorted": {
            "type": "boolean"
          },
          "x": {
            "type": "number"
          },
          "y": {
            "type": "number"
          },
          "w": {
            "type": "number"
          },
          "h": {
            "type": "number"
          }
        },
        "required": [
          "slug"
        ]
      },
      "annotations": {
        "title": "Add a node to a canvas",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "add_canvas_edge",
      "title": "Connect two nodes on a canvas",
      "description": "Draw an edge between two nodes already on a canvas.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "from": {
            "type": "string"
          },
          "to": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "rel": {
            "type": "string"
          },
          "data": {
            "type": "object"
          }
        },
        "required": [
          "slug",
          "from",
          "to"
        ]
      },
      "annotations": {
        "title": "Connect two nodes on a canvas",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "list_events",
      "title": "List artifact change events",
      "description": "Poll for JSON-state updates and new comments on your artifacts.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "since": {
            "type": "string"
          },
          "limit": {
            "type": "number"
          }
        }
      },
      "annotations": {
        "title": "List artifact change events",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "register_webhook",
      "title": "Register an artifact webhook",
      "description": "Register an HTTPS endpoint to receive signed artifact, comment and decision events.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "events": {
            "type": "array"
          }
        },
        "required": [
          "url"
        ]
      },
      "annotations": {
        "title": "Register an artifact webhook",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "list_webhooks",
      "title": "List artifact webhooks",
      "description": "List your webhooks with their scope, events and last delivery status.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      },
      "annotations": {
        "title": "List artifact webhooks",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "delete_webhook",
      "title": "Delete an artifact webhook",
      "description": "Stop delivering to a webhook and drop its pending deliveries.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ]
      },
      "annotations": {
        "title": "Delete an artifact webhook",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "create_decision",
      "title": "Create a decision on an artifact",
      "description": "Open a decision on an artifact: a question that needs resolving.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "context_md": {
            "type": "string"
          },
          "selection_mode": {
            "type": "string"
          },
          "options": {
            "type": "array"
          },
          "allow_other": {
            "type": "boolean"
          },
          "due_at": {
            "type": "string"
          }
        },
        "required": [
          "slug",
          "title"
        ]
      },
      "annotations": {
        "title": "Create a decision on an artifact",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "list_decisions",
      "title": "List decisions on an artifact",
      "description": "List the decisions on an artifact, with their assignees.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          }
        },
        "required": [
          "slug"
        ]
      },
      "annotations": {
        "title": "List decisions on an artifact",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "get_decision",
      "title": "Get a single decision",
      "description": "Read one decision by id, with its full detail and assignees.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "decision_id": {
            "type": "string"
          }
        },
        "required": [
          "decision_id"
        ]
      },
      "annotations": {
        "title": "Get a single decision",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "assign_decision",
      "title": "Assign a decision to someone",
      "description": "Record who should decide an open decision, by user id or email.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "decision_id": {
            "type": "string"
          },
          "user_id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          }
        },
        "required": [
          "decision_id"
        ]
      },
      "annotations": {
        "title": "Assign a decision to someone",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "revoke_assignment",
      "title": "Revoke a decision assignment",
      "description": "Remove an assignee from a decision; the decision stays open.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "assignee_id": {
            "type": "string"
          }
        },
        "required": [
          "assignee_id"
        ]
      },
      "annotations": {
        "title": "Revoke a decision assignment",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "decide_decision",
      "title": "Make a decision",
      "description": "Set a decision's outcome and rationale, locking the record permanently.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "decision_id": {
            "type": "string"
          },
          "choices": {
            "type": "array"
          },
          "other": {
            "type": "string"
          },
          "outcome": {
            "type": "string"
          },
          "note": {
            "type": "string"
          },
          "rationale": {
            "type": "string"
          }
        },
        "required": [
          "decision_id"
        ]
      },
      "annotations": {
        "title": "Make a decision",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "supersede_decision",
      "title": "Supersede a decided decision",
      "description": "Replace a decided decision with a new one; the original stays readable and locked.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "decision_id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "outcome": {
            "type": "string"
          },
          "rationale": {
            "type": "string"
          }
        },
        "required": [
          "decision_id",
          "title",
          "outcome",
          "rationale"
        ]
      },
      "annotations": {
        "title": "Supersede a decided decision",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "update_decision",
      "title": "Update an open decision",
      "description": "Change an open decision's title or context.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "decision_id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "context_md": {
            "type": "string"
          },
          "selection_mode": {
            "type": "string"
          },
          "options": {
            "type": "array"
          },
          "allow_other": {
            "type": "boolean"
          },
          "due_at": {
            "type": "string"
          }
        },
        "required": [
          "decision_id"
        ]
      },
      "annotations": {
        "title": "Update an open decision",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "delete_decision",
      "title": "Delete an open decision",
      "description": "Delete a decision that has not been decided yet.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "decision_id": {
            "type": "string"
          }
        },
        "required": [
          "decision_id"
        ]
      },
      "annotations": {
        "title": "Delete an open decision",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "list_templates",
      "title": "List HaveTML templates",
      "description": "Browse ready-to-copy templates: working artifacts with their state and starter prompt.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      },
      "annotations": {
        "title": "List HaveTML templates",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "get_template",
      "title": "Read a HaveTML template",
      "description": "Read one template's starter prompt, demo state and demo link before building from it.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "template": {
            "type": "string"
          }
        },
        "required": [
          "template"
        ]
      },
      "annotations": {
        "title": "Read a HaveTML template",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "use_template",
      "title": "Use a HaveTML template",
      "description": "Copy a template's demo into your account as a private artifact you can edit.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "template": {
            "type": "string"
          },
          "project": {
            "type": "string"
          }
        },
        "required": [
          "template"
        ]
      },
      "annotations": {
        "title": "Use a HaveTML template",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "set_artifact_custom_slug",
      "title": "Give a published artifact a readable URL",
      "description": "Give a public artifact a readable /f/ path, or release one, without renaming it.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "custom_slug": {
            "type": "string"
          }
        },
        "required": [
          "slug",
          "custom_slug"
        ]
      },
      "annotations": {
        "title": "Give a published artifact a readable URL",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "add_relation",
      "title": "Relate two artifacts",
      "description": "Draw a typed link between two artifacts, such as supersedes or depends on.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "from_slug": {
            "type": "string"
          },
          "to_slug": {
            "type": "string"
          },
          "rel": {
            "type": "string"
          },
          "label": {
            "type": "string"
          }
        },
        "required": [
          "from_slug",
          "to_slug"
        ]
      },
      "annotations": {
        "title": "Relate two artifacts",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "list_relations",
      "title": "List artifact relations",
      "description": "List the typed links between your artifacts, for one artifact or one project.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "project": {
            "type": "string"
          }
        }
      },
      "annotations": {
        "title": "List artifact relations",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "remove_relation",
      "title": "Remove an artifact relation",
      "description": "Delete one artifact relation by id; neither artifact is touched.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ]
      },
      "annotations": {
        "title": "Remove an artifact relation",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "get_artifact_content",
      "title": "Read an artifact's source",
      "description": "Read an artifact's source for the current version or an earlier one.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "version": {
            "type": "number"
          }
        },
        "required": [
          "slug"
        ]
      },
      "annotations": {
        "title": "Read an artifact's source",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "update_artifact_json",
      "title": "Update an artifact's JSON state",
      "description": "Change an artifact's live JSON state without a new version; replace mode drops keys.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "json": {
            "type": "object"
          },
          "mode": {
            "type": "string"
          }
        },
        "required": [
          "slug",
          "json"
        ]
      },
      "annotations": {
        "title": "Update an artifact's JSON state",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "list_media",
      "title": "List an artifact's media",
      "description": "List the images, fonts and stylesheets stored with an artifact, and media quota used.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          }
        },
        "required": [
          "slug"
        ]
      },
      "annotations": {
        "title": "List an artifact's media",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "remove_media",
      "title": "Remove one media file from an artifact",
      "description": "Delete one stored media file from an artifact and free its quota.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "path": {
            "type": "string"
          }
        },
        "required": [
          "slug",
          "path"
        ]
      },
      "annotations": {
        "title": "Remove one media file from an artifact",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "list_notes",
      "title": "Read an artifact's notes",
      "description": "Read the notes written beside an artifact.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          }
        },
        "required": [
          "slug"
        ]
      },
      "annotations": {
        "title": "Read an artifact's notes",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "add_note",
      "title": "Add a note to an artifact",
      "description": "Append a note to an artifact's notes, keeping what is already there.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "body": {
            "type": "string"
          }
        },
        "required": [
          "slug",
          "body"
        ]
      },
      "annotations": {
        "title": "Add a note to an artifact",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "update_notes",
      "title": "Rewrite an artifact's notes",
      "description": "Replace an artifact's notes with new markdown, discarding what was there.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "body": {
            "type": "string"
          }
        },
        "required": [
          "slug",
          "body"
        ]
      },
      "annotations": {
        "title": "Rewrite an artifact's notes",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "propose_canvas_layout",
      "title": "Propose a new layout for a canvas",
      "description": "Work out a tidier layout for a board and return it without moving anything.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "strategy": {
            "type": "string"
          },
          "scope": {
            "type": "string"
          },
          "node_ids": {
            "type": "array"
          },
          "keep_columns": {
            "type": "boolean"
          },
          "max_move": {
            "type": "number"
          },
          "add_summary_sticky": {
            "type": "boolean"
          }
        },
        "required": [
          "slug"
        ]
      },
      "annotations": {
        "title": "Propose a new layout for a canvas",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "create_folder",
      "title": "Create a folder inside a HaveTML project",
      "description": "Create a folder inside a project to group artifacts; visibility is unchanged.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "parent_folder_id": {
            "type": "string"
          },
          "parent_path": {
            "type": "string"
          },
          "create_missing": {
            "type": "boolean"
          }
        },
        "required": [
          "project",
          "name"
        ]
      },
      "annotations": {
        "title": "Create a folder inside a HaveTML project",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "list_folders",
      "title": "List folders in a HaveTML project",
      "description": "List every folder in a project with its path and artifact count.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string"
          }
        },
        "required": [
          "project"
        ]
      },
      "annotations": {
        "title": "List folders in a HaveTML project",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "move_artifact",
      "title": "Move an artifact into a folder",
      "description": "Move an artifact into a folder or back to the project root.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "project": {
            "type": "string"
          },
          "folder_id": {
            "type": "string"
          },
          "folder_path": {
            "type": "string"
          },
          "create_missing": {
            "type": "boolean"
          }
        },
        "required": [
          "slug"
        ]
      },
      "annotations": {
        "title": "Move an artifact into a folder",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "rename_folder",
      "title": "Rename a folder",
      "description": "Rename a folder; artifact URLs are unaffected.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "folder_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "folder_id",
          "name"
        ]
      },
      "annotations": {
        "title": "Rename a folder",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "move_folder",
      "title": "Move a folder under another folder",
      "description": "Move a folder, with its contents, under another folder or to the top level.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "folder_id": {
            "type": "string"
          },
          "parent_folder_id": {
            "type": "string"
          }
        },
        "required": [
          "folder_id"
        ]
      },
      "annotations": {
        "title": "Move a folder under another folder",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "delete_folder",
      "title": "Delete a folder, keeping its contents",
      "description": "Delete a folder; its artifacts and subfolders move up one level.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "folder_id": {
            "type": "string"
          }
        },
        "required": [
          "folder_id"
        ]
      },
      "annotations": {
        "title": "Delete a folder, keeping its contents",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "get_project",
      "title": "Read a project",
      "description": "Read a project's name, description, counts and pinned design system.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string"
          }
        },
        "required": [
          "project"
        ]
      },
      "annotations": {
        "title": "Read a project",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "set_project_design_system",
      "title": "Pin a project's design system",
      "description": "Pin an artifact as a project's design system, or unpin it.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          }
        },
        "required": [
          "project"
        ]
      },
      "annotations": {
        "title": "Pin a project's design system",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "propose_folder_organise",
      "title": "Propose a folder structure for a project, without changing anything",
      "description": "Work out a folder structure for a project and return it for approval; writes nothing.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string"
          },
          "placements": {
            "type": "array"
          },
          "renames": {
            "type": "array"
          },
          "create": {
            "type": "array"
          }
        },
        "required": [
          "project"
        ]
      },
      "annotations": {
        "title": "Propose a folder structure for a project, without changing anything",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "apply_folder_organise",
      "title": "Apply a folder proposal the invoker has approved",
      "description": "Apply an approved folder proposal; refuses if the project changed since.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string"
          },
          "placements": {
            "type": "array"
          },
          "renames": {
            "type": "array"
          },
          "create": {
            "type": "array"
          },
          "preview_id": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "preview_id"
        ]
      },
      "annotations": {
        "title": "Apply a folder proposal the invoker has approved",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "undo_folder_organise",
      "title": "Put a folder organise back the way it was",
      "description": "Reverse an applied folder organise using the undo plan from its reply.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "undo": {
            "type": "object"
          }
        },
        "required": [
          "undo"
        ]
      },
      "annotations": {
        "title": "Put a folder organise back the way it was",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "list_connections",
      "title": "List the MCP servers you have connected",
      "description": "List the remote MCP servers connected to your account; credentials are never included.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      },
      "annotations": {
        "title": "List the MCP servers you have connected",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "list_connected_tools",
      "title": "List the tools enabled on one connected MCP server",
      "description": "List the tools the owner has enabled on one connection; disabled tools cannot be called.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "connection_id": {
            "type": "string"
          }
        },
        "required": [
          "connection_id"
        ]
      },
      "annotations": {
        "title": "List the tools enabled on one connected MCP server",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "call_connected_tool",
      "title": "Call one tool on a connected MCP server",
      "description": "Run one tool on a connected MCP server; the reply comes back fenced as untrusted data.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "connection_id": {
            "type": "string"
          },
          "tool_name": {
            "type": "string"
          },
          "arguments": {
            "type": "object"
          },
          "slug": {
            "type": "string"
          }
        },
        "required": [
          "connection_id",
          "tool_name"
        ]
      },
      "annotations": {
        "title": "Call one tool on a connected MCP server",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": true
      }
    }
  ],
  "resources": [],
  "prompts": [
    {
      "name": "publish_encrypted",
      "title": "Publish a file to HaveTML, encrypted",
      "description": "How to encrypt locally with the HaveTML helper, then upload only the ciphertext."
    }
  ],
  "_meta": {
    "com.havetml/server-card": {
      "documentationUrl": "https://havetml.com/docs#mcp",
      "installUrl": "https://havetml.com/connect",
      "readmeUrl": "https://github.com/hass-disrupt/havetml/blob/main/docs/mcp/README.md",
      "maxRequestBodyBytes": 4718592,
      "maxArtifactBytes": 52428800,
      "pricing": "free",
      "defaultArtifactVisibility": "private"
    }
  }
}