Announcing CIMD support for MCP Client registration
Learn more

Should you use PostHog MCP or PostHog API for building AI Agents?

Saif Ali Shaik
Founding Developer Advocate

TL;DR

  • PostHog's MCP server is a hosted proxy over the same REST API, so coverage overlaps heavily. The MCP surfaces read and write tools across analytics, flags, experiments, error tracking, surveys, and CDP; the API adds what the MCP leaves out: event ingestion, high-volume or scheduled export, and a versioned contract.
  • MCP auth defaults to OAuth, with a personal API key (phx_) as fallback and enterprise ID-JAG through your IdP. The direct API supports personal API keys, project secret keys for server-to-server access, and OAuth. Your credential model changes with the path you pick.
  • Event capture is API-only. If your agent or pipeline needs to send events into PostHog, that runs against the public capture endpoint with a project token, not the MCP.
  • For multi-tenant B2B agents, both paths hand you one credential per user, and PostHog rate limits are per team. Neither path gives you a vault, rotation, or revocation. That is infrastructure you own regardless.
  • Scalekit's PostHog connector handles per-user OAuth, token storage, and rotation for the MCP surface, adds scoped tools and a 90-day audit trail, so the MCP vs API decision does not change your auth infrastructure.

The decision in front of you

Your agent needs to read and write PostHog. PostHog ships a hosted MCP server at mcp.posthog.com and a full REST API. They are not interchangeable: different capability shape, different auth paths, different operational surface in production. The MCP is newer, and most teams have used the API before but not the server. This article gives you the tradeoffs per axis, working Scalekit code to connect either way, and a recommendation grounded in what your agent actually does.

What PostHog MCP and PostHog API actually are

These are the two objects under comparison. One is a hosted tool layer; the other is the raw HTTP surface it sits on top of.

PostHog MCP

PostHog's Model Context Protocol server is a free, hosted endpoint at https://mcp.posthog.com/mcp that exposes PostHog's products as function-calling tools to any MCP client. The authentication server routes you to the correct region, US or EU, based on the account you sign in with. It acts as a proxy: it stores no analytics data and executes every tool call against your PostHog project. Because it carries hundreds of tools, it ships a token-optimized CLI mode with a single exec tool by default on clients like Claude and Codex, and a standard tools mode elsewhere.

PostHog API

The PostHog REST API lets you capture, query, create, update, and delete nearly everything in PostHog. It splits into two families: public POST-only endpoints for event capture and flag evaluation, authenticated with a project token, and private endpoints for querying and managing data, authenticated with a personal API key, a project secret key, or OAuth. You own endpoint selection, query construction, pagination, and error handling. In return you get a stable, downloadable OpenAPI contract.

Comparing them where it matters for agents

The comparison runs across four axes: what the agent can do, the auth path, what you own in production, and when each one wins. Because the MCP proxies the same API, the gaps are less about missing CRUD and more about ingestion, bulk data, and determinism.

What your agent can actually do

The MCP covers the operations that make up most product-analytics agent work: running HogQL and SQL with execute-sql, reading insights and dashboards, creating and rolling out feature flags, managing experiments, triaging error tracking issues, and creating surveys. The API covers all of that plus the surfaces the MCP does not expose.

Capability
PostHog MCP
PostHog API
Natural-language HogQL and SQL queries
Yes
Yes, you construct the query
Read insights and dashboards
Yes
Yes
Create and update feature flags
Yes
Yes
Manage experiments (A/B tests)
Yes
Yes
Triage error tracking issues
Yes
Yes
Create surveys and read response stats
Yes
Yes
Configure CDP destinations (hog functions)
Yes
Yes
Docs search and LLM-formatted output
Yes
No
Event ingestion and capture
No
Yes
High-volume or scheduled data export
Limited
Yes
Deterministic, versioned contract (OpenAPI)
No
Yes
Non-user service credential (headless)
Partial
Yes

The load-bearing gap is ingestion. Sending events into PostHog runs against the public capture endpoint with a project token; there is no capture tool on the MCP. The second gap is scale: MCP tool calls execute against the same API and hit the same limits, so PostHog's own guidance points bulk workloads at batch exports and endpoints rather than per-call analytics tools.

The auth path each one puts you on

The MCP defaults to OAuth, which works out of the box with the PostHog wizard. If a client cannot do OAuth, you fall back to a personal API key (phx_) created with the MCP Server preset, which scopes access to a single project. On enterprise plans, you can manage MCP access centrally through your identity provider using enterprise-managed authorization (ID-JAG), instead of per-user OAuth or keys.

What the API adds for headless agents

The private API accepts three credential types: personal API keys (phx_) tied to your account, project secret keys (phs_, in beta) for server-to-server access with no user attached, and OAuth (pha_ and phr_ tokens) for apps other users connect. Public capture stays on the project token. The project secret key is the true non-user credential a background pipeline wants; the MCP's key fallback is always tied to a person and a project.

What multi-tenant B2B inherits from each

In the OAuth model, both paths give you one PostHog credential per user. PostHog rate limits apply per team across every user and key in the organization, so a shared credential is a single-user design by construction; it does not survive a second tenant. Per-user isolation is required whichever path you choose. The token type differs; the isolation requirement does not.

What you own in production

The MCP manages tool schemas, region routing, and LLM-ready formatting for you, and it exposes controls that reduce blast radius: a read-only mode, tool filtering by feature or name, and pinning to a specific organization or project. What it does not manage is token storage, refresh, revocation on disconnect, or tenant isolation. With the direct API you own the full stack: endpoint selection, request construction, pagination, retries, and the token lifecycle. The tradeoff is control. The API is versioned through a downloadable OpenAPI spec, so a deterministic pipeline can pin a contract; MCP tool schemas evolve as PostHog updates the server.

When to use MCP, when to use the API

Use PostHog MCP when your agent is interactive and analytics-shaped, and you want coverage without writing schemas.

  • A user asks questions in natural language and the agent runs HogQL, reads insights, or ships a feature flag.
  • You want tool discovery and LLM-ready schemas across many PostHog product areas at once.
  • The agent orchestrates PostHog alongside other MCP tools and you want one consistent tool-call surface.
  • You are prototyping a product-analytics or error-triage agent and want it working the same day.

Use the PostHog API directly when the work is ingestion, scale, or deterministic.

  • The agent or pipeline captures or batches events into PostHog; ingestion is API-only.
  • You need high-volume or scheduled export, where batch exports and endpoints carry higher limits.
  • You need a versioned contract for a background pipeline, pinned through the OpenAPI spec.
  • You need a non-user service credential for server-to-server automation, with no person attached.

Recommended reading: MCP vs APIs, how are they different and single vs multi-tenant tool calling.

Connecting PostHog to your agent with Scalekit

Scalekit's PostHog connector wraps PostHog's MCP surface as prebuilt, per-user tools. Your code talks to Scalekit; Scalekit runs the OAuth flow, vaults the token, refreshes it, and executes each call under the right user. The examples below use Python and the Anthropic Claude SDK. The connection name is posthogmcp, and tools are named posthogmcp_*.

Install and authorize the connected account

Create a connection named posthogmcp in the Scalekit dashboard first; the name is case-sensitive and must match your code. The identifier is your app's authenticated user, resolved server-side, never supplied by the client.

import os from scalekit import ScalekitClient scalekit = ScalekitClient( env_url=os.environ["SCALEKIT_ENV_URL"], client_id=os.environ["SCALEKIT_CLIENT_ID"], client_secret=os.environ["SCALEKIT_CLIENT_SECRET"], ) actions = scalekit.actions CONNECTION = "posthogmcp" identifier = "user_123" # your app's user, resolved from your own session account = actions.get_or_create_connected_account( connection_name=CONNECTION, identifier=identifier, ) if account.connected_account.status != "ACTIVE": link = actions.get_authorization_link( connection_name=CONNECTION, identifier=identifier, ) print("Authorize PostHog:", link.link) input("Press Enter after authorizing...")

Discover the scoped tool surface

Before showing the loop, note what discovery does. The agent is not loading the full PostHog catalog; it loads the tools this user's connected account is authorized to call, already in Anthropic's native format. Narrowing by tool_names is a second layer of surface reduction on top of per-user scoping.

scoped, _ = actions.tools.list_scoped_tools( identifier=identifier, filter={ "connection_names": [CONNECTION], "tool_names": [ "posthogmcp_query_run", "posthogmcp_feature_flag_get_all", "posthogmcp_error_tracking_issues_list", ], }, page_size=100, ) llm_tools = [ { "name": t.tool.definition.name, "description": t.tool.definition.description, "input_schema": t.tool.definition.input_schema, } for t in scoped.tools ]

Run the agent loop

The loop is the standard Anthropic Messages API pattern. Send the conversation with the current tools; if Claude emits tool_use, execute each call through Scalekit under the user's identifier, append the results, and continue until stop_reason is end_turn.

import anthropic client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"]) messages = [ {"role": "user", "content": "What are the top 5 errors this week, and is the new-onboarding flag rolled out?"} ] while True: response = client.messages.create( model="claude-sonnet-4-6", max_tokens=1024, tools=llm_tools, messages=messages, ) if response.stop_reason != "tool_use": print("".join(b.text for b in response.content if b.type == "text")) break messages.append({"role": "assistant", "content": response.content}) tool_results = [] for block in response.content: if block.type != "tool_use": continue result = actions.execute_tool( tool_name=block.name, connection_name=CONNECTION, identifier=identifier, tool_input=block.input, ) tool_results.append({ "type": "tool_result", "tool_use_id": block.id, "content": str(result), }) messages.append({"role": "user", "content": tool_results})

The token for PostHog never enters your process or the model context. Swap the framework freely: the same list_scoped_tools and execute_tool pair backs the LangChain, CrewAI, and Google ADK adapters. For a fuller walkthrough, see building a multi-user PostHog agent with Claude.

Why build PostHog agents on Scalekit

The MCP vs API choice is real, but it is not the hard part of a production PostHog agent. The hard part is per-user identity, a bounded tool surface, and an audit trail. Scalekit is the layer that handles those.

Per-user scoped tools, not a 200-tool catalog

PostHog's server carries hundreds of tools, and PostHog itself ships CLI mode and filtering to keep that surface from flooding context. Scalekit's connector exposes around 200 prebuilt PostHog tools and scopes them per user: list_scoped_tools returns only what this connected account is authorized to call. That matters for two reasons. An LLM handed a large catalog selects the wrong tool and hallucinates parameters, and every tool in context burns tokens before the agent does any work. Scoping from a full catalog to the handful a user needs is the accuracy lever and the cost lever at once. The fix is not better prompting; it is surface reduction.

Downstream tool-calling audit logs

Every execute_tool call runs against a connected account, so who authorized, which agent ran, which tool, and what came back are recorded as one linked event. The PostHog connector keeps a 90-day audit trail. That answers "what did the agent do on behalf of user X on Tuesday" as a single filtered query, not a three-week investigation. More on the model is in agent tool observability and audit trails for agent auth.

Virtual MCP for multi-tool, multi-tenant agents

A standard MCP server exposes every tool it has. A PostHog analytics agent that only reads insights does not need flag deletion or CDP writes in scope. Scalekit's Virtual MCP Servers enforce least privilege at the tool level: one server definition per agent role, declaring exactly which tools it sees and whose credentials it acts with. Per-user isolation comes from session tokens; one definition serves all users, and a short-lived token is minted per run scoped to that user's connected accounts. No MCP server to deploy, host, or maintain. Setup is a one-time configuration; runtime is a token mint. The endpoint is static; the identity is per-user. See single vs multi-tenant tool calling for the full model.

The credential problem that exists on both paths

Both paths look solved in a demo and unsolved at the second tenant. This is the part that determines whether the agent survives production.

N users mean N PostHog credentials

Whether you chose MCP OAuth or the API's OAuth, every user in a multi-tenant agent has their own PostHog credential. Fifty customers is fifty tokens to store encrypted, isolate per tenant, refresh before expiry, and revoke on disconnect. A user can revoke consent inside PostHog at any time, and your agent only learns about it from a failed call unless you are watching for it. PostHog's per-team rate limits reinforce the point: a single shared credential cannot express per-user access, so it is not an option past one tenant. This is exactly the kind of secure token management problem that scales poorly when handled in-house.

Where Scalekit fits

Scalekit's PostHog connector handles the OAuth flow, encrypted token storage, refresh, and revocation for the MCP surface, keyed to a per-user identifier. Credentials never touch the agent runtime. The MCP vs API decision then changes what your agent can do, not what you have to build for auth. For cost planning, the free tier covers 1M monthly active users and 10K connected accounts.

Which one to build against

If your agent is interactive and analytics-shaped, reading insights, running HogQL, triaging errors, or shipping flags on request, build against the MCP surface; the tools are maintained for you and you are operational the same day. If your agent captures events, exports at volume, or runs as a deterministic background pipeline, use the API directly, because ingestion, bulk export, and a versioned contract live there and not on the MCP. Most production products end up doing both: the MCP for user-facing questions, the API for ingestion and scheduled jobs. Either way, the per-user credential problem is identical, and that is the piece that needs production-grade infrastructure. The access control for multi-tenant AI agents challenge applies regardless of which PostHog surface you use.

Start building

Browse the Scalekit PostHog connector docs and the PostHog connector page, or read PostHog's own MCP server docs and REST API docs.

Building a PostHog agent and want a second pair of eyes on the auth model? Join the Scalekit Slack community, or talk to us for immediate help.

No items found.
Agent
Auth Quickstart
On this page
Share this article
Agent
Auth Quickstart

Acquire enterprise customers with
zero upfront cost.

Every feature unlocked. No hidden fees.