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).