Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 41 additions & 3 deletions integrations/catalog/posthog.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
],
"appUrl": "https://posthog.com",
"docsUrl": "https://posthog.com/docs/model-context-protocol",
"notes": "Relevant for product analytics and experimentation workflows.",
"notes": "Uses PostHog's official hosted MCP server. OAuth is preferred; the bearer-token option remains for clients or deployments that require a personal API key. The OAuth URL defaults to read-only mode; remove readonly=true only when write access has been approved.",
"popularityRank": 37,
"iconBg": "#1D4AFF",
"logoUrl": "https://cdn.simpleicons.org/posthog/FFFFFF",
Expand All @@ -18,8 +18,44 @@
"product",
"experiments"
],
"installHint": "Authenticate with a PostHog personal API key (PostHog → User settings → API keys, MCP Server preset) — sent as a Bearer token.",
"installHint": "Prefer OAuth. The default OAuth connection uses read-only MCP mode; edit the URL or use the bearer-key fallback only when a workflow needs approved write access. For API keys, create a PostHog personal API key with the MCP Server preset.",
"connectionOptions": [
{
"id": "oauth",
"provider": "mcp",
"auth": {
"strategy": "oauth2",
"oauth": {
"authorizationUrl": "https://oauth.posthog.com/oauth/authorize/",
"tokenUrl": "https://oauth.posthog.com/oauth/token/",
"registrationUrl": "https://oauth.posthog.com/oauth/register/",
"scopes": [
"openid",
"profile",
"email",
"organization:read",
"project:read",
"dashboard:read",
"insight:read",
"query:read",
"event_definition:read"
],
"pkce": true,
"clientAuthentication": "none",
"additionalAuthorizationParams": {
"resource": "https://mcp.posthog.com/mcp"
},
"additionalTokenParams": {
"resource": "https://mcp.posthog.com/mcp"
}
}
},
"transport": {
"kind": "shttp",
"url": "https://mcp.posthog.com/mcp?readonly=true",
"urlEditable": true
}
},
{
"id": "api-key",
"provider": "mcp",
Expand All @@ -31,7 +67,9 @@
"strategy": "bearer",
"credentialLabel": "PostHog personal API key",
"credentialPlaceholder": "Paste your PostHog personal API key",
"credentialHelp": "Create one under PostHog → User settings → API keys (MCP Server preset). Sent as Authorization: Bearer <token>."
"credentialHelp": "Create one under PostHog > User settings > API keys using the MCP Server preset. Sent as Authorization: Bearer <token>.",
"credentialSecretName": "POSTHOG_PERSONAL_API_KEY",
"saveCredentialAsSecretByDefault": true
}
}
]
Expand Down
43 changes: 43 additions & 0 deletions tests/test_catalogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,49 @@ def test_credential_fields_have_helper_text_and_link():
)


def test_posthog_catalog_prefers_oauth_with_safe_mcp_defaults():
posthog = next(
entry for entry in load_catalog_entries("integrations/catalog")
if entry["id"] == "posthog"
)

assert [option["id"] for option in posthog["connectionOptions"]] == [
"oauth",
"api-key",
]

oauth = posthog["connectionOptions"][0]
assert oauth["provider"] == "mcp"
assert oauth["transport"] == {
"kind": "shttp",
"url": "https://mcp.posthog.com/mcp?readonly=true",
"urlEditable": True,
}
oauth_config = oauth["auth"]["oauth"]
assert oauth_config["authorizationUrl"] == (
"https://oauth.posthog.com/oauth/authorize/"
)
assert oauth_config["tokenUrl"] == "https://oauth.posthog.com/oauth/token/"
assert oauth_config["registrationUrl"] == (
"https://oauth.posthog.com/oauth/register/"
)
assert oauth_config["pkce"] is True
assert oauth_config["clientAuthentication"] == "none"
assert oauth_config["additionalAuthorizationParams"] == {
"resource": "https://mcp.posthog.com/mcp"
}
assert oauth_config["additionalTokenParams"] == {
"resource": "https://mcp.posthog.com/mcp"
}
assert "query:read" in oauth_config["scopes"]
assert all(not scope.endswith(":write") for scope in oauth_config["scopes"])

api_key = posthog["connectionOptions"][1]
assert api_key["auth"]["strategy"] == "bearer"
assert api_key["auth"]["credentialSecretName"] == "POSTHOG_PERSONAL_API_KEY"
assert api_key["auth"]["saveCredentialAsSecretByDefault"] is True


def test_node_package_exports_catalogs():
script = """
import { INTEGRATION_CATALOG, AUTOMATION_CATALOG } from './index.js';
Expand Down
Loading