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

@ownego/selfhog-mcp

v0.1.1

Published

Run PostHog's MCP server against a self-hosted PostHog instance

Readme

selfhog-mcp

Run PostHog's MCP server against a self-hosted PostHog instance.

Unofficial. Not affiliated with PostHog Inc. The server itself is PostHog's, from services/mcp, used unmodified under the MIT license — see NOTICE. This project adds a container entrypoint and an installer, nothing more.

Not to be confused with @posthog/mcp on npm, which is a tracking SDK rather than a server.

PostHog's hosted MCP server at mcp.posthog.com routes only to PostHog Cloud, so self-hosted instances cannot use it.

Install

npx @ownego/selfhog-mcp init \
  --host https://posthog.example.com \
  --key phx_your_personal_api_key

That checks the instance and the key, pulls the image, starts a container that survives reboots, waits for it to be ready, and registers it with Claude Code at user scope — once, for every directory, not just the one you ran npx from. Restart Claude Code afterwards.

Before doing anything else, init calls the instance's current-user API with the key you gave it. A container's /readyz only checks its own embedded Redis, not whether --host actually points at a reachable PostHog instance — without this check, a typo'd host or a stale key would only surface later, as an opaque 500 on your first tool call. A bad host or key now fails init immediately, before anything is pulled or registered, with a message that says which it was.

Create the key at https://<your-instance>/settings/user-api-keys?preset=mcp_server.

Requires Docker.

Flags

| Flag | Effect | |---|---| | --no-pull | Skip docker pull and let docker run/docker start use whatever image is already on this machine — if the image isn't present locally either, docker itself will still reach the network and fail with its own message. For local image development, or a machine with no network access that has already pulled the image once. | | --skip-verify | Skip the instance/key check. For setting up before the instance is reachable. | | --replace | Take over a name another MCP server already holds. Without it, init refuses and leaves the existing one alone. | | --server-name <name> | Register under a different name. Accepted by uninstall too, so the pair stays symmetric. |

Upgrading

Re-run the same init. It always re-pulls the image (unless --no-pull is given), and recreates the container if anything it depends on has moved: a different --host, a different SELFHOG_PORT, a different SELFHOG_IMAGE, or a newer build of the tag it is already on. An up-to-date container is left running untouched, so re-running init is cheap and safe.

If the pull itself fails but the image is already present locally — offline, or a locally built image that was never pushed — init warns that it is proceeding with the local copy (which may be stale) instead of failing outright. It only fails the pull outright when no usable image exists locally either.

What it runs

One long-lived container holding the PostHog MCP server and a small Redis that the server requires. Clients talk to it over HTTP on localhost:8787, so there is no extra process per editor session.

Your API key is not stored in the container. It lives in your MCP client's config and travels per request, so one container can serve several people, each with their own key.

Commands

| Command | Effect | |---|---| | init --host <url> --key <phx_...> | Verify, pull, start, and register. Safe to re-run. | | status | Show whether the container is running, its port, and which instance it points at. | | stop | Remove the container. | | uninstall | Remove the container and the user-scope client registration. |

Environment variables

| Variable | Effect | |---|---| | POSTHOG_API_BASE_URL | Fallback for --host. | | POSTHOG_PERSONAL_API_KEY | Fallback for --key. | | SELFHOG_PORT | Host port to publish on (default 8787). | | SELFHOG_IMAGE | Image to run (default ghcr.io/ownego/selfhog-mcp:latest). | | SELFHOG_CONTAINER | Container name (default selfhog-mcp). Change it, along with SELFHOG_PORT and --server-name, to run two instances side by side. |

Re-running init under a name it already owns re-registers rather than skipping. That is what makes a rotated API key take effect: the stored header is rewritten with the current key. It works by removing the entry and adding it back, because claude mcp add refuses a name that is already taken.

That removal is also why init checks who holds the name before it starts. Left unchecked, re-registering would delete a server this tool never created. So if the name belongs to something else, init stops before pulling anything, tells you where that server points, and leaves it alone. Pass --replace to take the name over, or --server-name to register under a different one.

Other MCP clients

init only knows how to drive Claude Code's CLI. If claude mcp add is not available, or you use a different client, init prints a JSON block to paste instead. It is an ordinary HTTP MCP server entry:

{
  "mcpServers": {
    "posthog": {
      "type": "http",
      "url": "http://localhost:8787/mcp",
      "headers": { "Authorization": "Bearer phx_your_personal_api_key" }
    }
  }
}

Merge it into your client's user-wide config: ~/.claude.json for Claude Code (the same scope claude mcp add --scope user writes to), ~/.cursor/mcp.json for Cursor, claude_desktop_config.json for Claude Desktop. The container itself is already running by that point — only the client registration is manual.

Memory

One container, measured on the published image:

| Constraint | Behaviour | |---|---| | unconstrained | ~780 MiB for its first minute, settling near 220 MiB once V8 collects | | -m 512m | comfortable — 323 MiB used | | -m 256m | runs, but at 253/256 MiB with no headroom |

The first-minute figure is not a requirement. Node sizes its heap to the memory it is given, so the container adapts to a cap rather than needing the peak. If you are placing it somewhere with a limit, 512 MB is a sensible floor.

Known rough edges

Some tools will fail on smaller instances. The tool catalogue is generated from all of PostHog's products, and a self-hosted deployment does not implement every endpoint behind them. Narrow the catalogue with the upstream query parameters, for example ?features=flags,sql,insights or ?tools=execute-sql,dashboard-get appended to the MCP URL.

There is no version to pin to. PostHog's Docker Hub release tags have not moved since 2023-05-17 and hobby deploys track master, so images here are tagged sha-<posthog-commit> with a rolling latest. If you need to match your instance exactly, pin the SHA.

Advanced

MCP_MODE=stdio runs the image as a stdio MCP server instead, for clients that spawn the process themselves:

claude mcp add --scope user posthog -- docker run -i --rm \
  -e MCP_MODE=stdio \
  -e POSTHOG_API_BASE_URL=https://posthog.example.com \
  -e POSTHOG_AUTH_HEADER="Bearer phx_..." \
  ghcr.io/ownego/selfhog-mcp

-e MCP_MODE=stdio is required: the image defaults to MCP_MODE=http, and without the flag this command starts the HTTP daemon, never speaks JSON-RPC, and hangs until the client gives up.

This costs a container per editor session and puts the key in the container's environment, so init is the better default.

License

MIT — see LICENSE. NOTICE carries the bundled PostHog server's own MIT grant and attribution.