mcp-html-sync-server

mcp-html-sync-server

2.2

The MCP HTML Sync Server is a real-time HTML syncing tool designed for AI agents to dynamically manage HTML pages. It supports real-time updates through WebSockets, script and stylesheet management, and has lightweight deployment options including Docker and NPX.

MCP HTML Sync Server npm version Docker Pulls

Code of Conduct | Contributing | Security

A real-time HTML syncing server with hot reload capabilities, built using the Model Context Protocol (MCP). This server enables AI agents to create, update, and destroy HTML pages dynamically, with all connected clients receiving updates in real-time.

Features

MCP HTML Sync Server
  • Real-time HTML Syncing: Create and update HTML content with instant updates to all connected clients
  • WebSocket Hot Reload: All connected browsers automatically refresh when content changes
  • Script Management: Add JavaScript scripts to pages, either via CDN URLs or inline content
  • Stylesheet Management: Add CSS stylesheets to pages via CDN URLs
  • MCP Integration: Designed specifically for AI agents using the Model Context Protocol
  • Page Lifecycle Management: Automatic expiration of pages after configurable time periods
  • Connection Limits: Configurable maximum page count with automatic cleanup of oldest pages
  • Simple API: Easy-to-use MCP tools for page creation, updating, and destruction
  • Lightweight: Minimal dependencies and efficient resource usage

Architecture

flowchart LR
    AI[AI Agent] -->|MCP Protocol| MCP[MCP HTML Sync Server]
    MCP -->|Create/Update/Destroy/AddScripts/AddStylesheets| PM[Page Manager]
    PM -->|Store| Pages[(HTML Pages, Scripts & Stylesheets)]
    User[User Browser] -->|HTTP Request| HTTP[HTTP Server]
    HTTP -->|Fetch Page, Scripts & Stylesheets| PM
    User <-->|WebSocket| WS[WebSocket Server]
    WS <-->|Real-time Updates| PM

Installation

Using Docker

docker pull yujiosaka/mcp-html-sync-server
docker run -p 3000:3000 yujiosaka/mcp-html-sync-server
Docker Environment Variables

Instead of using an .env file, you can pass environment variables directly to the Docker container at runtime:

docker run -p 3000:3000 \
  -e SERVER_PORT=3000 \
  -e BASE_URL=http://localhost:3000/ \
  -e PAGE_MAX_AGE=1h \
  -e PAGE_MAX_COUNT=1000 \
  yujiosaka/mcp-html-sync-server

This approach is recommended for production deployments as it allows you to configure the server without modifying the container image.

Using NPX

NODE_ENV=production npx mcp-html-sync-server

From Source

# Clone the repository
git clone https://github.com/yujiosaka/mcp-html-sync-server.git
cd mcp-html-sync-server

# Install dependencies
bun install

# Copy the example environment file
bun run config

# Start the server
bun run start

Configuration

Edit the .env file to configure the server:

# Host address for the HTTP server (used for binding the server)
SERVER_HOST=localhost
# Port number for the HTTP server (used for binding the server)
SERVER_PORT=3000
# Base URL for the application (used for generating view URLs)
BASE_URL=http://localhost:3000/
# Maximum age of pages before they expire (e.g., 1h = 1 hour, uses ms library format)
PAGE_MAX_AGE=1h
# Maximum number of pages that can be stored (oldest pages are removed when limit is reached)
PAGE_MAX_COUNT=1000

Configuration Options

OptionDescriptionDefaultFormat
SERVER_HOSTHost address for binding the HTTP serverlocalhosthostname
SERVER_PORTPort number for the HTTP server3000number
BASE_URLBase URL for generating view URLshttp://localhost:3000/URL
PAGE_MAX_AGEMaximum age of pages before expiration1htime string (e.g., 1h, 30m, 1d)
PAGE_MAX_COUNTMaximum number of pages to keep1000number

Usage with MCP

Integration with Claude Desktop

Add this to your claude_desktop_config.json:

Docker
{
  "mcpServers": {
    "html-sync-server": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-p",
        "3000:3000",
        "-e", "SERVER_PORT=3000",
        "-e", "BASE_URL=http://localhost:3000/",
        "-e", "PAGE_MAX_AGE=1h",
        "-e", "PAGE_MAX_COUNT=1000",
        "yujiosaka/mcp-html-sync-server"
      ]
    }
  }
}
NPX
{
  "mcpServers": {
    "html-sync-server": {
      "command": "npx",
      "args": ["-y", "mcp-html-sync-server"],
      "env": {
        "NODE_ENV": "production"
      }
    }
  }
}

Integration with VS Code

For quick installation, use one of the one-click install buttons below:

Install with NPX in VS Code Install with NPX in VS Code Insiders

Install with Docker in VS Code Install with Docker in VS Code Insiders

Manual Installation

For manual installation, add the following JSON block to your User Settings (JSON) file in VS Code. You can do this by pressing Ctrl + Shift + P and typing Preferences: Open Settings (JSON).

Optionally, you can add it to a file called .vscode/mcp.json in your workspace. This will allow you to share the configuration with others.

Note that the mcp key is not needed in the .vscode/mcp.json file.

{
  "mcp": {
    "servers": {
      "html-sync-server": {
        "command": "npx",
        "args": ["-y", "mcp-html-sync-server"],
        "env": {
          "NODE_ENV": "production"
        }
      }
    }
  }
}

For Docker installation:

{
  "mcp": {
    "servers": {
      "html-sync-server": {
        "command": "docker",
        "args": [
          "run",
          "-i",
          "--rm",
          "-p", "3000:3000",
          "-e", "SERVER_PORT=3000",
          "-e", "BASE_URL=http://localhost:3000/",
          "-e", "PAGE_MAX_AGE=1h",
          "-e", "PAGE_MAX_COUNT=1000",
          "yujiosaka/mcp-html-sync-server"
        ]
      }
    }
  }
}

MCP Tools

The server provides the following MCP tools that can be used by AI agents:

1. Create a Page

Creates a new HTML page with the specified content.

Tool Name: create_page

Input Schema:

{
  "type": "object",
  "properties": {
    "body": {
      "type": "string",
      "description": "HTML content for the page body (only the inner content)"
    },
    "scripts": {
      "type": "array",
      "description": "Optional array of JavaScript scripts to include in the page",
      "items": {
        "type": "object",
        "properties": {
          "src": {
            "type": "string",
            "description": "URL for external script"
          },
          "content": {
            "type": "string",
            "description": "Content for inline script"
          }
        },
        "description": "Either src or content must be provided",
        "oneOf": [
          { "required": ["src"] },
          { "required": ["content"] }
        ]
      }
    },
    "stylesheets": {
      "type": "array",
      "description": "Optional array of CSS stylesheets to include in the page",
      "items": {
        "type": "object",
        "properties": {
          "href": {
            "type": "string",
            "description": "URL for external stylesheet"
          }
        },
        "required": ["href"]
      }
    }
  },
  "required": ["body"]
}

Example Request:

{
  "name": "create_page",
  "arguments": {
    "body": "<h1>Hello World</h1><p>This is my page content.</p><button id='confetti-btn'>Click for Confetti!</button>",
    "scripts": [
      { "src": "https://cdn.jsdelivr.net/npm/bootstrap@5.3.5/dist/js/bootstrap.bundle.min.js" }
    ],
    "stylesheets": [
      { "href": "https://cdn.jsdelivr.net/npm/bootstrap@5.3.5/dist/css/bootstrap.min.css" }
    ]
  }
}

Example Response:

{
  "content": [
    {
      "type": "text",
      "text": "Page created successfully! A URL is provided below to view your page."
    },
    {
      "type": "text",
      "text": "View your HTML page in URL: http://localhost:3000/abc123"
    },
    {
      "type": "text",
      "text": "ID: abc123\nExpires at: 2023-04-15T12:34:56.789Z\n\nUse this ID for future updates before expiration."
    }
  ],
  "metadata": {
    "id": "abc123",
    "url": "http://localhost:3000/abc123",
    "expires_at": "2023-04-15T12:34:56.789Z"
  }
}

2. Update a Page

Updates an existing page with new content. All connected clients will see the updates in real-time. If the page does not exist (has been removed or expired), an error response will be returned.

Tool Name: update_page

Input Schema:

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "ID of the page to update"
    },
    "body": {
      "type": "string",
      "description": "New HTML content for the page body (only the inner content)"
    }
  },
  "required": ["id", "body"]
}

Example Request:

{
  "name": "update_page",
  "arguments": {
    "id": "abc123",
    "body": "<h1>Updated Content</h1><p>This content has been updated.</p>"
  }
}

Example Response:

{
  "content": [
    {
      "type": "text",
      "text": "Page updated successfully! A URL is provided below to view your updated page."
    },
    {
      "type": "text",
      "text": "View your HTML page in URL: http://localhost:3000/abc123"
    },
    {
      "type": "text",
      "text": "ID: abc123\nExpires at: 2023-04-15T12:34:56.789Z\n\nUse this ID for future updates before expiration."
    }
  ],
  "metadata": {
    "id": "abc123",
    "url": "http://localhost:3000/abc123",
    "expires_at": "2023-04-15T12:34:56.789Z"
  }
}

3. Destroy a Page

Removes a page and disconnects all clients.

Tool Name: destroy_page

Input Schema:

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "ID of the page to destroy"
    }
  },
  "required": ["id"]
}

Example Request:

{
  "name": "destroy_page",
  "arguments": {
    "id": "abc123"
  }
}

Example Response:

{
  "success": true
}

4. Add Scripts to a Page

Adds JavaScript scripts to an existing page. All connected clients will receive the scripts in real-time.

Tool Name: add_scripts

Input Schema:

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "ID of the page to add scripts to"
    },
    "scripts": {
      "type": "array",
      "description": "Array of JavaScript scripts to add to the page",
      "items": {
        "type": "object",
        "properties": {
          "src": {
            "type": "string",
            "description": "URL for external script"
          },
          "content": {
            "type": "string",
            "description": "Content for inline script"
          }
        },
        "description": "Either src or content must be provided",
        "oneOf": [
          { "required": ["src"] },
          { "required": ["content"] }
        ]
      }
    }
  },
  "required": ["id", "scripts"]
}

Example Request:

{
  "name": "add_scripts",
  "arguments": {
    "id": "abc123",
    "scripts": [
      { "content": "alert('Hello World!')" }
    ]
  }
}

Example Response:

{
  "content": [
    {
      "type": "text",
      "text": "Scripts added successfully! A URL is provided below to view your page."
    },
    {
      "type": "text",
      "text": "View your HTML page in URL: http://localhost:3000/abc123"
    },
    {
      "type": "text",
      "text": "ID: abc123\nExpires at: 2023-04-15T12:34:56.789Z\n\nUse this ID for future updates before expiration."
    }
  ],
  "metadata": {
    "id": "abc123",
    "url": "http://localhost:3000/abc123",
    "expires_at": "2023-04-15T12:34:56.789Z"
  }
}

5. Add Stylesheets to a Page

Adds CSS stylesheets to an existing page. All connected clients will receive the stylesheets in real-time.

Tool Name: add_stylesheets

Input Schema:

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "ID of the page to add stylesheets to"
    },
    "stylesheets": {
      "type": "array",
      "description": "Array of CSS stylesheets to add to the page",
      "items": {
        "type": "object",
        "properties": {
          "href": {
            "type": "string",
            "description": "URL for external stylesheet"
          }
        },
        "required": ["href"]
      }
    }
  },
  "required": ["id", "stylesheets"]
}

Example Request:

{
  "name": "add_stylesheets",
  "arguments": {
    "id": "abc123",
    "stylesheets": [
      { "href": "https://cdn.jsdelivr.net/npm/bootstrap@5.3.5/dist/css/bootstrap.min.css" }
    ]
  }
}

Example Response:

{
  "content": [
    {
      "type": "text",
      "text": "Stylesheets added successfully! A URL is provided below to view your page."
    },
    {
      "type": "text",
      "text": "View your HTML page in URL: http://localhost:3000/abc123"
    },
    {
      "type": "text",
      "text": "ID: abc123\nExpires at: 2023-04-15T12:34:56.789Z\n\nUse this ID for future updates before expiration."
    }
  ],
  "metadata": {
    "id": "abc123",
    "url": "http://localhost:3000/abc123",
    "expires_at": "2023-04-15T12:34:56.789Z"
  }
}

How It Works

  1. AI agents interact with the server through the Model Context Protocol (MCP)
  2. The MCP server processes requests to create, update, or destroy HTML pages
  3. Users view these pages through URLs provided by the AI agent
  4. Real-time updates are delivered to all connected clients via WebSockets

Manual Testing

The project includes a manual test script (manual-test.ts) that demonstrates how to use the MCP server. This script:

  1. Creates a new HTML page with canvas-confetti from CDN
  2. Updates the page content
  3. Adds stylesheets to trigger text animations
  4. Adds scripts to trigger confetti animations
  5. Deletes the page

To run the manual test:

# Run the test script
bun manual-test.ts

The script will provide URLs that you can open in your browser to see the page and observe real-time updates. It uses an interactive approach with confirmation prompts between each step, allowing you to verify the changes in your browser before proceeding to the next step.

This test script is particularly useful for:

  • Verifying that the MCP server is working correctly
  • Understanding the flow of creating, updating, and destroying pages
  • Observing real-time WebSocket updates in the browser

Development

# Run in development mode with auto-reload
bun run dev

# Build the project
bun run build

# Run linting
bun run check

# Fix linting issues
bun run check:write

Troubleshooting

Port Already in Use

If you see an error like the following when starting the server:

[2025-04-28 18:28:48.370 +0900] ERROR: Error starting server
    err: {
      "type": "Error",
      "message": "Failed to start server. Is port 3000 in use?",
      "stack":
          Error
              at serve (unknown)
              at [kRealListen] (node:http:565:41)
              at listen (node:http:542:35)
              at <anonymous> (/Users/yujiisobe/work/mcp-html-sync-server/node_modules/fastify/lib/server.js:265:12)
              at processTicksAndRejections (unknown:7:39)
      "code": "EADDRINUSE",
      "syscall": "listen",
      "errno": 0
    }

This means that port 3000 (or whatever port you've configured) is already being used by another application. To resolve this:

  1. Change the port: Edit the .env file and change the SERVER_PORT to a different value (e.g., 3001, 8080, etc.)

  2. Stop the other application: Find and stop the application that's using port 3000. You can use one of these commands to find processes using the port:

    # On macOS/Linux
    lsof -i :3000
    
    # On Windows
    netstat -ano | findstr :3000
    
  3. Restart your computer: In some cases, a restart can clear orphaned processes that might be holding onto the port.

When using the server with Claude Desktop or VS Code, you may also see JSON parsing errors if the port is already in use. These errors occur because the server can't start properly and is returning error messages instead of valid JSON responses.

Building Docker Image

docker build -t yujiosaka/mcp-html-sync-server .

License

This project is licensed under the MIT License. See for details.