open-artifacts
Provides Discord OAuth sign-in, allowing viewers to identify themselves and enabling artifact.user() to return the viewer's Discord identity after consent.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@open-artifactsCreate a poll page with buttons and store responses."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Open Artifacts
A self-hosted take on Claude Artifacts, open to any agent. Your AI agent writes an HTML page, publishes it over MCP, and hands you a shareable URL. The page is not a screenshot — it can store data, recognise who is viewing it, and save new versions of itself.
Built because Artifacts is a good idea that shouldn't require using one particular assistant. Works with opencode, Claude Code, Cursor, or anything else that speaks MCP.
you ──"make me a poll"──> agent ──MCP──> server ──> https://poll.art.example.comWhat you get
Publish from your agent. Seven MCP tools: publish, update, list, read, delete, plus read/write of a page's stored data. No upload button anywhere — the agent does it.
Pages that hold state.
window.artifact.dbgives a page a small shared database, so a poll, a checklist or a sign-up sheet actually remembers what people did.Pages that know who's looking.
window.artifact.user()returns the viewer's Discord identity, once they consent. Per-viewer data stays private to that viewer.Pages that rewrite themselves. A page can save a new version of itself, and every version is kept and restorable.
Real isolation. Each artifact is served from its own subdomain under a CSP that blocks its own network access, so one page can never read another's data.
Discord sign-in, API tokens per agent, and private / unlisted / public links.
Stack: Node + Express, SQLite via node:sqlite (no database dependency), React + Vite dashboard.
Three runtime dependencies in total.
New here? Start with docs/USAGE.md — how to connect an agent and what to ask it.
AGENTS.md is what the agent itself reads: the rules a page has to follow and a worked
example. The UI brief is docs/FRONTEND_BRIEF.md.
Running it
npm install
npm run build # builds the dashboard into dist/
npm start # http://localhost:8787Open http://localhost:8787, sign in, then go to Connections to create a token and copy the MCP snippet into opencode, Claude Code or Cursor.
With no Discord app configured, /auth/discord signs you into a local account so the server is usable
out of the box. Configure Discord for real accounts:
DISCORD_CLIENT_ID=… # OAuth2 app credentials
DISCORD_CLIENT_SECRET=… # redirect URI: <DASHBOARD_ORIGIN>/auth/callback
SESSION_SECRET=… # otherwise generated once into data/.session-secret
ARTIFACT_HOST=art.example.com
PROTOCOL=https
NODE_ENV=productionARTIFACT_HOST needs a wildcard DNS record and certificate (*.art.example.com), because every
artifact is served from its own subdomain. Locally *.localhost resolves without any setup.
Tests
npm testAn integration suite on Node's built-in runner — no framework, no fixtures. It boots the real server against a temporary database and drives it over HTTP, covering the things that would otherwise break quietly: MCP publishing and token auth, version history and restore, subdomain isolation and the CSP, visibility enforcement, and every authorisation rule in the runtime broker (capability gating, per-viewer data privacy, anonymous read-but-not-write).
Working on the frontend
DASHBOARD_ORIGIN=http://localhost:5199 npm run server # terminal 1 — API on :8787
npm run dev # terminal 2 — Vite on :5199, proxies /api /auth /mcpDASHBOARD_ORIGIN has to match the origin the dashboard is actually served from, since it is both the
frame-ancestors value and the origin the runtime bridge posts to.
Related MCP server: webserver-mcp
Deploying
Files are in deploy/. Order matters: get it working over HTTP first, then add TLS.
git clone … /srv/artifacts && cd /srv/artifacts
npm ci && npm run build
cp .env.example .env # fill in Discord credentials and SESSION_SECRET
pm2 start deploy/ecosystem.config.cjs # edit ARTIFACT_HOST in it first
pm2 save && pm2 startup
sudo cp deploy/nginx.conf /etc/nginx/sites-available/artifacts
sudo ln -s /etc/nginx/sites-available/artifacts /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginxDNS: two records, both to the server — art.example.com and *.art.example.com.
TLS: deploy/nginx.conf contains no ssl_* directives on purpose; certbot writes those.
But certbot --nginx alone will not work here — a wildcard certificate cannot be issued over
HTTP-01, and artifacts need one. Use a DNS-01 challenge:
sudo certbot certonly --preferred-challenges dns --manual \
-d art.example.com -d '*.art.example.com'Then point nginx at the certificate (re-run with --nginx, or add the ssl_certificate lines
yourself) and set PROTOCOL=https so cookies are marked Secure.
Discord: add https://art.example.com/auth/callback to the app's OAuth2 redirect URIs.
Two nginx settings are load-bearing and easy to lose in a rewrite: proxy_set_header Host $host
(without it every subdomain collapses into one artifact) and client_max_body_size 12m (the default
1 MB rejects publishes with a bare 413).
How it fits together
agent --MCP--> server --stores--> SQLite
|
+--> art.example.com dashboard (session cookie, REST API)
+--> <id>.art.example.com the artifact page, its own originTwo origins, deliberately. If every artifact shared one origin, one page could read another's
localStorage. The artifact origin serves the page and nothing else — no API, no session, and a CSP
that blocks its own network access.
Because the page therefore cannot call the server, window.artifact.* posts messages to the dashboard
window, which replays them against the API using the viewer's own cookie. A page opened directly, with
no dashboard parent, forwards itself to the viewer route.
Runtime API
Available to a published page when the artifact declares the matching capability.
Call | Capability | Notes |
|
| |
|
| Replaces the document |
|
| Merges into it |
|
| |
|
| |
|
| The viewer, or |
|
| Saves a new version; owner only |
Collections under data/users/me/… resolve to the caller's own id and are private to them. Everything
else is shared by every viewer. Reading shared data works signed out; writing needs an account.
Viewers are asked for consent once per artifact before any of this runs.
Limits
There is no asset store. Pages inline images as data: URIs and load fonts and libraries from an
allowlist (cdnjs, jsDelivr, the Tailwind play CDN, code.jquery.com, Google Fonts). A page may be up to
10 MB — override with MAX_HTML_BYTES.
Layout
server/
index.js express wiring and Discord OAuth routes
config.js hosts, origins, subdomain parsing
db.js node:sqlite schema and queries
auth.js sessions, API tokens, Discord exchange
routes.js dashboard REST API and the runtime broker
serve.js artifact subdomain serving, CSP, bridge injection
mcp.js MCP tools for agents
src/
App.tsx the whole dashboard
app.css design tokens and styles
lib/ API client, contract types, formatters
test/ integration suite, run with `npm test`
deploy/ nginx site and PM2 process fileData lives in data/artifacts.db (SQLite, WAL). Back it up by copying that directory.
License
MIT — see LICENSE.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
No tool schema history has been recorded yet.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
- StacktreeOAuthee.stacktr
Publish HTML to private, unguessable, replace-in-place URLs from any MCP-compatible AI agent.
Deploy AI-generated HTML/CSS/JS to instant public HTTPS URLs from any MCP-compatible agent.
Publish, update, read, rename, and share single-URL web pages from any AI agent.
Publish HTML, files, or a URL to a permanent public URL, then update it — from any MCP agent.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenancePublishes HTML pages straight from your AI assistant to a shareable URL, then lets you manage them - update, list, search, fetch, and delete pages in a public or private workspace. Turns "share what I just made" into a single tool call from Claude, Cursor, or any MCP client.MIT
- FlicenseNot gradedqualityDmaintenanceEnables AI agents to edit and serve a static website via natural language, providing file management tools over MCP and HTTP hosting.-
- AlicenseNot gradedqualityAmaintenanceEnables agents to publish HTML artifacts to permanent, shareable, versioned pages on Artifyde via MCP.105MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to deploy HTML pages and manage them (list, archive, move, rename) in a versioned library via MCP tools.25MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/xfwil/open-artifacts'
If you have feedback or need assistance with the MCP directory API, please join our Discord server