npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

playcanvas-mcp-server

v4.1.0

Published

One shared HTTP MCP server that lets any number of Claude Code sessions edit a live PlayCanvas Editor tab through a Chrome extension bridge, including reading/downloading and replacing a project's asset files via the PlayCanvas REST API. Every session con

Readme

playcanvas-mcp-server

One shared MCP server that lets Claude (or any MCP client) edit a live PlayCanvas Editor tab. Every Claude Code session connects to the same server over Streamable HTTP, and that one server holds the single WebSocket to the editor. There is exactly one server process per machine — no per-session processes, no election, no relaying.

It began as a from-scratch, plain-JavaScript rebuild of @playcanvas/editor-mcp-server (MIT) and keeps the same extension-facing RPC contract. Unofficial — not affiliated with or endorsed by PlayCanvas. It pairs with the Chrome extension in ../extension/ (or the original PlayCanvas extension, which speaks the same protocol).

v4 restores the MCP protocol. v1 was a per-session stdio MCP server; v2 made it a single shared Streamable HTTP MCP server; v3 briefly dropped MCP for a plain HTTP API; v4 is the Streamable HTTP MCP server again, now meant to be registered for every session. The MCP client config is an HTTP url (see below), and something has to start the server (the OnRush plugin's SessionStart hook starts and warms it; standalone users run it themselves).

How it works

Claude session 1 ──HTTP /mcp ──┐
Claude session 2 ──HTTP /mcp ──┼──►  server.mjs  ──(WebSocket :52000, path /)──◄── extension/main.js ──► window.editor API
Claude session N ──HTTP /mcp ──┘     (one process)
  • One server, many sessions. The server listens on a single port and serves two kinds of client on it:
    • POST/GET/DELETE /mcp — every Claude Code session, over Streamable HTTP. Each session gets its own MCP session id (mcp-session-id); all of them register the same tools pointing at the same editor socket.
    • ws://…/ (path /) — the PlayCanvas Editor Chrome extension. One at a time; extra tabs are ignored.
  • No per-session process. With HTTP transport the MCP client (Claude Code) connects to a URL — it does not spawn a child process per session. So the server must already be running; nothing collapses to zero the way a stdio server does when a window closes.
  • Started by a SessionStart hook, stops when idle. The server has no persistence of its own. The OnRush plugin registers the MCP for every session and vendors a SessionStart hook (hooks/ensure-server.sh) that starts it if it isn't already up and keeps it warm between sessions; it exits itself after --idle-timeout minutes with no MCP sessions and no editor connected, and the next session's hook restarts it. (Because Claude Code enumerates a server's tools at session start, a cold start — the server wasn't up yet when the session began — needs a one-time session reconnect before its tools are usable; see the skill.)
  • Single instance. If a second server is launched on a port that's already taken, it sees EADDRINUSE and exits cleanly, leaving the incumbent alone.

Quick start (standalone / MCP client config)

// .mcp.json in your project root
{
  "mcpServers": {
    "playcanvas-editor": {
      "type": "http",
      "url": "http://127.0.0.1:52000/mcp"
    }
  }
}

Then start the server (it isn't spawned for you with HTTP transport):

npx -y playcanvas-mcp-server@4 -p 52000
# or, from a checkout:  node server.mjs -p 52000

Load the Chrome extension, open your PlayCanvas Editor tab, and click CONNECT in the extension popup (same port). The server declares its own MCP instructions, so the client learns the connection rules automatically — no per-project rules files needed.

Installed through the OnRush marketplace, all of this is automatic: onrush wires the .mcp.json HTTP entry for every session and vendors a SessionStart hook that starts and warms the server — you don't run anything by hand.

Files

  • server.mjs — entry point. An Express app that serves the MCP endpoint (/mcp, one Streamable HTTP session per Claude window) plus a /health probe, and routes the / WebSocket upgrade to the extension bridge. Owns the idle-timeout and single-instance behavior. All of it on one port, one process.
  • wss.mjs — the extension bridge (WSS). Holds the single editor socket, runs the RPC protocol ({ id, name, args } out, { id, res } back), and exposes raw / call / callImage that the tools use. It does not bind a port itself — server.mjs hands it matching upgrades via handleUpgrade.
  • tools.mjs — the MCP tools Claude sees. Each handler just forwards to an extension method by name (create_entitiesentities:create). The method names here and the wsc.method(...) names in ../extension/main.js are the contract between the two halves. Most tools drive the editor's live data model; a few (download_asset, replace_asset_file, set_script_text, the store tools) go through the PlayCanvas REST API from the editor tab instead, so they move raw asset file bytes and auto-target the tab's current project/branch.

Logging discipline: everything logs to stderr (console.error); stdout is left clean.

Setup (from a checkout)

cd playcanvas/server
npm install
node server.mjs -p 52000

Endpoints

  • GET /health{ ok, pid, extension, sessions }. Used by the ensure hook to decide whether a server is already running before starting another.
  • POST /mcp → MCP requests. An initialize with no session id creates a new session; subsequent requests carry the mcp-session-id header.
  • GET /mcp → the server→client SSE stream for a session.
  • DELETE /mcp → tear a session down.

CLI

-p, --port <n>           Port for BOTH /mcp and the extension WebSocket (default 52000).
    --idle-timeout <min> Stop after <min> idle minutes — no MCP sessions and no
                         extension connected (default 15; 0 disables). Also via
                         PLAYCANVAS_IDLE_TIMEOUT.
-h, --help

Behavior notes

  • Idle shutdown: the server is "occupied" while any MCP session is connected or the editor extension is paired. When both are empty for the idle window it exits and frees the port; the next session's hook starts a fresh one. Set --idle-timeout 0 (or run it manually) to keep it up indefinitely.
  • Server restart under a live session: if the server idle-stops (or is killed) while a Claude window still thinks it has a session, the next tool call gets No valid session and the client re-initializes. Sessions are cheap to recreate; no editor state is lost (that lives in the editor, not the server).
  • Shared editor, shared state: all sessions relay through one extension socket, so calls from concurrent sessions interleave at the editor — last write wins on conflicting edits, same as two humans in one editor tab.
  • The original wraps viewport:capture as image/jpeg; the extension actually produces WebP, so this rebuild reports image/webp.