Skip to main content
Glama
deadrime

posthog-toolkit-mcp

by deadrime
README.md
# posthog-toolkit-mcp

An MCP server for PostHog, on PostHog Cloud or a self-hosted instance: HogQL queries, event and property
definitions, session replays and the REST API — with guards that keep an agent from sending the API key elsewhere
or writing by accident.

## Tools

| Tool | What it does |
|---|---|
| `posthog_query` | Runs a HogQL query. Refuses insight placeholders like `{filters}` before sending, and says when PostHog cut the results at its default `LIMIT 100`. |
| `posthog_event_definitions` | Event names seen in the project, with last-seen time; optional substring `search`. |
| `posthog_property_definitions` | Event or person property names with their types. |
| `posthog_replays` | Session recordings of a `distinct_id` in a time window, newest first, with links. |
| `posthog_projects` | Projects of the organization. Works with personal API keys scoped to specific projects. |
| `posthog_api_get` | GET any PostHog REST endpoint; `{project_id}` in the path is filled in. |
| `posthog_api_request` | Any method, including writes. Registered only with `POSTHOG_ALLOW_WRITE`. |

## Configuration

| Variable | |
|---|---|
| `POSTHOG_HOST` | Required. `https://us.posthog.com`, `https://eu.posthog.com`, or your self-hosted URL. |
| `POSTHOG_API_KEY` | Required. A personal API key (`phx_...`). A project token (`phc_...`) is rejected at startup — it can only send events. |
| `POSTHOG_PROJECT_ID` | Default project for the tools and for `{project_id}` in paths. |
| `POSTHOG_ALLOW_WRITE` | `1`, `true` or `yes` registers `posthog_api_request`. Off by default. |
| `POSTHOG_MAX_RESPONSE_CHARS` | Cap on a tool response. Default `100000`. |
| `POSTHOG_TIMEOUT_MS` | Request timeout. Default `120000`. |

The key needs read access to the project (and user read access for `posthog_projects`; without it the tool falls
back to the organization project list).

## Install

```json
{
  "mcpServers": {
    "posthog": {
      "command": "npx",
      "args": ["-y", "posthog-toolkit-mcp"],
      "env": {
        "POSTHOG_HOST": "https://posthog.example.com",
        "POSTHOG_API_KEY": "${POSTHOG_API_KEY}",
        "POSTHOG_PROJECT_ID": "1"
      }
    }
  }
}
```

In Claude Code this block goes into the project's `.mcp.json`; keep the key itself out of the file, e.g. in the
`env` block of `.claude/settings.local.json`, and pin the version (`posthog-toolkit-mcp@0.1.0`) so every machine runs
the same server.

## Security

- Read-only by default; writes need `POSTHOG_ALLOW_WRITE`.
- Requests go only to the `POSTHOG_HOST` origin: a path like `//other-host/...` is refused before the API key
  could leave with it.
- Project ids are validated as numbers before they reach a URL.

## Development

```
npm install
npm run typecheck  # tsc --noEmit
npm run build      # esbuild bundles src/index.ts into dist/server.mjs with no runtime dependencies
npm run smoke      # stdio checks: configuration errors, tool list, guards that fire before any network call
npm run check      # all three
```

| File | |
|---|---|
| `src/index.ts` | Entry point: builds the server from the environment and connects stdio. |
| `src/config.ts` | Reads and validates environment variables. |
| `src/posthog-client.ts` | PostHog API client; refuses paths that would leave `POSTHOG_HOST`. |
| `src/schemas.ts` | Zod input schemas of the tools; handler argument types are inferred from them. |
| `src/server.ts` | Tool registration and result formatting. |
| `src/hogql.ts` | HogQL literals, insight placeholder detection, the recordings query. |

The bundle is a single file on purpose: `npx` starts it without installing any dependencies.

## License

MIT — see [LICENSE](LICENSE). Dependencies bundled into `dist/server.mjs` keep their own licenses, listed in
[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).