Official agent skill

Implementing MCP Tools

by PostHog in PostHog/posthog-foss

Guide for exposing PostHog product endpoints as MCP tools. An agent skill from PostHog/posthog-foss.

OfficialMITAuto-check passedBackend & APIs

Install Implementing MCP Tools

skills CLI
$ npx skills add PostHog/posthog-foss --skill implementing-mcp-tools -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install PostHog/posthog-foss implementing-mcp-tools --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/PostHog/posthog-foss.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/implementing-mcp-tools .claude/skills/implementing-mcp-tools && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
implementing-mcp-tools
GitHub stars
721
Token cost
~3.7k tokens
SKILL.md length
1,471 words
Files
1
Skills in repo
213
Repo updated
First seen
Licence
MIT

At a glance

Guide for exposing PostHog product endpoints as MCP tools. An agent skill from PostHog/posthog-foss.

  • Works in 3 steps: Serializers have explicit field types… → Plain ViewSet methods have… → Query parameters use @validated_request…
  • Updating API endpoints
  • SKILL.md covers Quick workflow, Before you scaffold: fix the…, When to add MCP tools and Tool design, plus 4 more sections
  • Calls pnpm

What it does

Implementing MCP Tools is an agent skill from PostHog/posthog-foss, published by the product's own GitHub organization. Guide for exposing PostHog product endpoints as MCP tools. Use when creating new or updating API endpoints, adding MCP tool definitions, scaffolding YAML configs, or writing serializers with good descriptions. Covers the full pipeline from Django serializer to generated TypeScript tool handler.

Its SKILL.md is about 3.7k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Backend & APIs, covering MCP servers, Project scaffolding and Backend development. It works with PostHog, Django and TypeScript. The repository describes itself as: PostHog FOSS is a read-only mirror of PostHog, with all proprietary code removed. NOTE: This repo is synced automatically from the main PostHog repo. Please raise any issues and… The licence is MIT.

When your agent uses it

  • Updating API endpoints
  • Adding MCP tool definitions
  • Scaffolding YAML configs
  • Writing serializers with good descriptions

Example prompts

  • “/implementing-mcp-tools”

Workflow steps

3 steps, taken from the first numbered list in SKILL.md.

  1. Serializers have explicit field types and help_text —
  2. Plain ViewSet methods have @extend_schema(request=...) —
  3. Query parameters use @validated_request or @extend_schema with a query serializer —

What it can do on your machine

Read from SKILL.md and the folder at commit 2c48221. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • pnpm

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use pnpm, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Implementing MCP Tools loads about 3.7k tokens when it runs. Until then it costs about 80 tokens; SKILL.md has 1,471 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~80
When it runs · the whole SKILL.md, loaded when a task matches
~3.7k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from PostHog/posthog-foss at commit 2c48221, republished under its MIT licence (© PostHog). 1,471 words, ~3,744 tokens.

Download SKILL.mdSave it as .claude/skills/implementing-mcp-tools/SKILL.md (or your agent's skills folder).
name
implementing-mcp-tools
description
Guide for exposing PostHog product endpoints as MCP tools. Use when creating new or updating API endpoints, adding MCP tool definitions, scaffolding YAML configs, or writing serializers with good descriptions. Covers the full pipeline from Django serializer to generated TypeScript tool handler.

Implementing MCP tools

Read the full guide at docs/published/handbook/engineering/ai/implementing-mcp-tools.md.

Quick workflow

sh
# 1. Scaffold a starter YAML with all operations disabled.
#    --product discovers endpoints via their x-product attribution.
#    ViewSets in products/<name>/backend/ are auto-attributed via module
#    path. ViewSets elsewhere need
#    @extend_schema(extensions={"x-product": "<product>"}).
pnpm --filter=@posthog/mcp run scaffold-yaml -- --product your_product \
    --output ../../products/your_product/mcp/tools.yaml

# 2. Configure the YAML — enable tools, add descriptions, and annotations for PATCH/POST/PUT
#    (scopes come from the API when omitted)
#    Place in products/<product>/mcp/*.yaml (preferred) or services/mcp/definitions/*.yaml

# 3. Add a HogQL system table in posthog/hogql/database/schema/system.py
#    and a model reference in products/posthog_ai/skills/querying-posthog-data/references/

# 4. Generate handlers and schemas
hogli build:openapi

# 5. Refresh the tool input schema snapshots (CI unit tests fail on a stale snapshot)
pnpm --filter=@posthog/mcp exec vitest run tests/unit/tool-schema-snapshots.test.ts -u
# A tool behind a new `feature_flag` needs that flag in the test's `featureFlags` map, set to the value that shows the tool:
# true for a plain gate, the variant string for a variant gate, a non-true value for a `disable` gate.

# 6. Only when the YAML uses ui_apps: regenerate the UI apps (CI checks they are current)
pnpm --filter=@posthog/mcp run generate:ui-apps

Before you scaffold: fix the backend first

The codegen pipeline can only generate correct tools if the Django backend exposes correct types. Read the type system guide for the full picture.

Before scaffolding YAML, verify:

  1. Serializers have explicit field types and help_text — these flow all the way to Zod .describe() in the generated tool. Missing descriptions = agents guessing at parameters. Use ListField(child=serializers.CharField()) instead of bare ListField(), and @extend_schema_field(PydanticModel) on JSONField subclasses to get typed Zod output (see products/alerts/backend/presentation/views/alert.py for the pattern).
  2. Plain ViewSet methods have @extend_schema(request=...) — without it, drf-spectacular can't discover the request body and the generated tool gets z.object({}) (zero parameters). ModelViewSet with a serializer_class is fine; plain ViewSet with manual validation is not.
  3. Query parameters use @validated_request or @extend_schema with a query serializer — otherwise boolean and array query params may produce type mismatches in the generated code.

If a generated tool has an empty or wrong schema, the fix is almost always on the Django side, not in the YAML config. For a full audit checklist and before/after examples, use the improving-drf-endpoints skill.

When to add MCP tools

When a product exposes API endpoints that agents should be able to call. MCP tools are atomic capabilities (list, get, create, update, delete) — not workflows.

If you're adding a new endpoint, check whether it should be agent-accessible. If yes, add a YAML definition and generate the tool.

Tool design

Tools should be basic capabilities — atomic CRUD operations and simple actions. Agents compose these primitives into higher-level workflows.

Good: "List feature flags", "Get experiment by ID", "Create a survey". Bad: "Search for session recordings of an experiment" — bundles multiple concerns.

Tool naming constraints

Tool names and feature identifiers are validated at build time and in CI. Violations fail the build.

Tool names
  • Format: lowercase kebab-case — only [a-z0-9-], no leading/trailing hyphens
  • Length: 52 characters or fewer
  • Convention: domain-action, e.g. cohorts-create, dashboard-get, feature-flags-list
Keep action verbs out of compact tool domains

The single-exec prompt builds its compact domain index with ToolDomainExtractor. Large families can split at an intermediate segment. Without action trimming, experiment-freeze-exposure can advertise the redundant domain experiment-freeze instead of experiment.

Whenever you add or rename an action tool, check the TRAILING_ACTIONS set in the same change. If a rendered domain can end in an operation verb that is not already present, add the verb. Cover it in services/mcp/tests/unit/instructions.test.ts. This applies even when the verb is not the final segment of the full tool name.

Add operation verbs such as freeze, publish, or emit. Do not add resource or capability nouns such as config, logs, stats, or schedule merely to make the prompt shorter; those remain useful discovery domains.

Feature identifiers
  • Format: lowercase snake*case — only [a-z0-9*], must start with a letter
  • Convention: should match the product folder name, e.g. error_tracking, feature_flags
Why 52 characters?

MCP clients enforce different limits on tool names. The 52-char limit is the safe zone that works across all known clients:

ClientLimitNotes
MCP spec (draft)1–128 chars, [A-Za-z0-9_\-.]Official recommendation, not enforced
Claude Code64 charsHard limit; prefixes tool names with mcp____
Cursor60 chars combinedserver_name + tool_name; tools over this are silently filtered
OpenAI API^[a-zA-Z0-9_-]+$, 64 charsNo dots allowed

With the server name "posthog" (7 chars) plus a separator, tool names must stay at or below 52 characters to fit within Cursor's 60-char combined limit.

CI enforcement
  • pnpm --filter=@posthog/mcp lint-tool-names — validates length and pattern for YAML and JSON definitions
  • A vitest test validates all runtime TOOL_MAP and GENERATED_TOOL_MAP entries

YAML definitions

YAML files configure which operations are exposed as MCP tools. See existing definitions for patterns:

  • products/<product>/mcp/*.yaml — preferred, keeps config close to the code
  • services/mcp/definitions/*.yaml — fallback for functionality without a product folder

The build pipeline discovers YAML files from both paths.

Key fields
yaml
category: Human readable name
feature: snake_case_name # should match the product folder name (used for runtime filtering)
url_prefix: /path # frontend app route, used for enrich_url links
tools:
  your-tool-name: # kebab-case
    operation: operationId_from_openapi
    enabled: true
    # Optional:
    scopes: # defaults to the scopes the API requires (from the OpenAPI spec)
      - your_product:read
    annotations: # defaults for GET and DELETE; required for PATCH, POST and PUT
      readOnly: true
      destructive: false
      idempotent: true
    title: List things
    description: >
      Human-friendly description for the LLM.
    list: true
    enrich_url: '{id}'
    param_overrides:
      name:
        description: Custom description for the LLM
    response: # filter response fields (applied per-item on list endpoints)
      include: [id, key, name] # keep only these fields (dot-path wildcards supported)
      exclude: [filters.groups.*.properties] # remove these fields
      # include and exclude are mutually exclusive
      selectable: true # add optional `fields` param so the agent picks a subset of `include` per call
      # (constrained to the allowlist); omit `fields` to return the full set. Requires `include`.
      strip_nulls: true # remove keys whose value is `null`, applied after include/exclude
      # Use it on tools that echo a nested serializer schema, where the unset optional fields
      # dominate the payload. Rejected with `list: true`, where per-row null removal makes the
      # TOON table larger. Use `exclude` to drop the fields on a list tool instead.
    feature_flag: my-flag-key # gate this tool behind a PostHog feature flag
    feature_flag_behavior: enable # 'enable' (default) or 'disable'

When scopes is omitted, the generator uses the scopes the API requires, so the tool cannot drift from the endpoint. Set scopes by hand only when the API computes them per request (the generator fails and says so) or to gate a tool more tightly. A scopes list that misses a scope the API requires fails codegen, with a GitHub annotation on CI. When the API picks the scopes per request, list the action in the viewset's request_dependent_scope_actions. The spec then marks the operation with x-request-dependent-scopes, codegen skips the check for it, and its tools must declare scopes. annotations default to the HTTP method for GET (read-only) and DELETE (destructive). PATCH, POST and PUT vary too much (a PATCH can be a soft delete or non-idempotent), so declare annotations for them.

When a tool needs custom logic around the request, set hooks: <path under src/tools/> and default-export an object with beforeRequest, afterResponse or onError from that module, written export default { onError } satisfies ToolHooks<Params> so a typo fails typecheck (see ToolHooks in src/tools/tool-hooks.ts). Use it to read state before a write or to turn a known error into a result, rather than shadowing the generated tool with a hand-written one.

Unknown keys are rejected at build time (Zod .strict()).

Show full SKILL.md (628 more words)Show less
Gating tools with feature flags

Add feature_flag to any tool (standard or query wrapper) to gate its exposure on a PostHog feature flag evaluated at MCP init time for the current user.

  • feature_flag_behavior: enable (default) — tool is shown only when the flag is on. Use for rolling out new tools.
  • feature_flag_behavior: disable — tool is hidden when the flag is on. Use for sunsetting old tools.

Reusing the same flag key with both behaviors performs an atomic swap: flag on → new tool visible, old tool hidden; flag off → old tool visible, new tool hidden. Useful for A/B testing tool variations.

Flags are evaluated in parallel at init via evaluateFeatureFlags. If a flag can't be evaluated (service error, missing flag), enable-gated tools are excluded and disable-gated tools are included — fail-closed for new tools, fail-open for existing ones.

Enabling or renaming a tool

The MCP server and Django deploy separately. A tool that reaches clients before its route lands returns 404 on every call until the Django deploy catches up. That hits a whole agent fleet at once.

  • Land the route first. Ship the endpoint, then enable the tool in a later change. A tool with enabled: true in the same commit as a brand-new route is live in clients as soon as the MCP server deploys.
  • Or gate it. Add feature_flag with feature_flag_behavior: enable and turn the flag on once the route is serving.
  • Keep the old name on a rename. Leave the previous tool name in the YAML, pointing at the same operation, until the new name has deployed everywhere. Sunset it with feature_flag_behavior: disable on the same flag key, which swaps the two atomically.
Deprecating a tool

A rename or a removal has two stages. Do not stop after the first one.

  1. Alias, while callers migrate. Register the old name as a thin wrapper that calls the current handler and adds a _deprecation_notice to the response. The call still succeeds, and the agent learns the new name. See services/mcp/src/tools/skills/deprecatedAliases.ts, spread into TOOL_MAP in services/mcp/src/tools/index.ts. Use an alias only when the replacement accepts the same arguments.
  2. Redirect, when you delete the alias. In the same change, add the old name to DEPRECATED_TOOL_REDIRECTS in services/mcp/src/tools/exec.ts. The call then fails with a deprecated_tool error that names the replacement, instead of the generic Unknown tool: "...". State any argument changes in the text — see the self-driving-inbox-get entry.

Go directly to stage 2 when the replacement is not a drop-in. An alias that quietly drops renamed parameters is worse than a call that fails.

Keep the redirect entry until the old name stops receiving traffic. isRecordableToolName records $mcp_exec_target_tool only for a name the server owns: a live tool, or a DEPRECATED_TOOL_REDIRECTS key. If you delete the entry too early, the remaining calls become unattributable in MCP analytics, and you can no longer tell whether anything still uses the old name.

A tool that a feature flag removes is a different case. It keeps its definition, declares superseded_by in the YAML, and flagGatedToolMessage answers the call.

Syncing after endpoint changes
sh
pnpm --filter=@posthog/mcp run scaffold-yaml -- --sync-all

Idempotent and non-destructive — adds new operations as enabled: false, removes stale ones.

Serializer descriptions

Descriptions flow through the entire pipeline:

text
Django serializer field → OpenAPI spec → Zod schema → MCP tool description

These descriptions are what agents read to understand tool parameters.

  • Use help_text on serializer fields — it becomes the OpenAPI description.
  • Use param_overrides in YAML to override generated descriptions with imperative instructions.
  • Be specific about formats, constraints, and valid values.
  • Avoid jargon that an LLM wouldn't understand without context.

HogQL system tables

Every list/get endpoint should have a corresponding HogQL system table in posthog/hogql/database/schema/system.py. This lets agents query data via SQL.

Each system table must include a team_id column for data isolation.

When adding a system table, also add a model reference file (models-<domain>.md) in products/posthog_ai/skills/querying-posthog-data/references/ and register it in products/posthog_ai/skills/querying-posthog-data/SKILL.md under Data Schema.

© PostHog, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .agents/skills/implementing-mcp-tools of PostHog/posthog-foss.

Open the folder on GitHubat commit 2c48221

Compare with similar skills

Implementing MCP Tools next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Implementing MCP Tools compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Implementing MCP Tools this skillPostHog/posthog-foss721—~3.7kAutomated safety check: PassMIT
OpenAPI to MCP Servermcp-use/mcp-use11k—~5.2kAutomated safety check: PassApache-2.0
Tandem Browserhydro13/tandem-browser616—~9.1kAutomated safety check: PassMIT
FastAPI Project Templateswshobson/agents40k11 repos~901Automated safety check: PassMIT
Migration CodegenAHS12/thoth-blueprint626—~425Automated safety check: PassGPL-3.0
Spring ExploreAmplicode/spring-skills126—~4.1kAutomated safety check: PassNone

Similar skills

  • OpenAPI to MCP Server

    mcp-use/mcp-use

    Turns an OpenAPI or Swagger spec into an MCP server with the mcp-use TypeScript SDK, mapping each operation to a tool, wiring auth, testing and deploying.

    11k GitHub stars~5.2k tokensUpdated today
    Backend & APIsAuto-check passed
  • Tandem Browser

    hydro13/tandem-browser

    Use Tandem Browser's MCP server (local and remote agents) or HTTP API (local and remote agents) to inspect, browse, and interact with the user's shared browser safely.

    616 GitHub stars~9.1k tokensUpdated 5 days ago
    Agent WorkflowsAuto-check passed
  • Scaffolds FastAPI projects with a layered app layout, dependency injection through Depends, async handlers and database access, middleware and pytest setup.

    40k GitHub starsUsed in 11 repos~901 tokens
    Backend & APIsAuto-check passed
  • Migration Codegen

    AHS12/thoth-blueprint

    Change Laravel, TypeORM, or Django migration generation and generated SQL parsing.

    626 GitHub stars~425 tokensUpdated 1 mo ago
    Backend & APIsAuto-check passed
  • Spring Explore

    Amplicode/spring-skills

    Explores a Spring Boot application and builds primary context: tech stack, module structure, domain entities, REST endpoints.

    126 GitHub stars~4.1k tokensUpdated 1 mo ago
    Backend & APIsAuto-check passed
  • Django Expert

    Jeffallan/claude-skills

    Builds Django apps and Django REST Framework APIs: models with indexes, ORM query optimization, serializers, viewsets and JWT authentication, with tests.

    12k GitHub stars~1.5k tokensUpdated 4 days ago
    Backend & APIsAuto-check passed

More from PostHog/posthog-foss

All 213 skills in this repo
  • Authoring Log Alerts

    PostHog/posthog-foss

    Official

    Author useful, low-noise log alerts on services in a PostHog project.

    721 GitHub stars~3k tokensUpdated today
    Auto-check passed
  • Autoresolving PR Conflicts

    PostHog/posthog-foss

    Official

    Operating procedure for the conflict-autoresolver agent: sweep open PostHog/posthog PRs that conflict with master, resolve the trivial conflicts (generated artifacts deterministically, source…

    721 GitHub stars~4.2k tokensUpdated today
    Auto-check passed
  • Official

    Help users debug PostHog Error Tracking stack-trace symbolication for any supported platform — JavaScript/TypeScript web, React Native (Hermes), Android (Proguard / R8), or iOS / macOS (dSYM).

    721 GitHub stars~2.2k tokensUpdated today
    Auto-check passed
  • Exploring Apm Traces

    PostHog/posthog-foss

    Official

    Investigates distributed application performance using PostHog APM (OpenTelemetry span) data via MCP.

    721 GitHub stars~3.5k tokensUpdated today
    Auto-check passed
  • Exploring LLM Traces

    PostHog/posthog-foss

    Official

    Debug and inspect LLM/AI agent traces using PostHog's MCP tools.

    721 GitHub stars~4.4k tokensUpdated today
    Auto-check passed
  • Investigate Metric

    PostHog/posthog-foss

    Official

    Diagnose why a product metric changed (dropped, spiked, or plateaued) by orchestrating breakdowns, actors, paths, lifecycle, retention, and annotations queries.

    721 GitHub stars~1.9k tokensUpdated today
    Auto-check passed

Questions about Implementing MCP Tools

What does Implementing MCP Tools do?

Guide for exposing PostHog product endpoints as MCP tools. An agent skill from PostHog/posthog-foss. Implementing MCP Tools is an agent skill from PostHog/posthog-foss, published by the product's own GitHub organization. Guide for exposing PostHog product endpoints as MCP tools.

When should I use Implementing MCP Tools?

Implementing MCP Tools fits situations like: updating API endpoints; adding MCP tool definitions; scaffolding YAML configs; writing serializers with good descriptions.

How do I install Implementing MCP Tools in Claude Code?

Run `npx skills add PostHog/posthog-foss --skill implementing-mcp-tools -a claude-code`. Or copy the skill folder (.agents/skills/implementing-mcp-tools in PostHog/posthog-foss) into .claude/skills/implementing-mcp-tools in your project. Claude Code loads it when a task matches its description.

How do I install Implementing MCP Tools in Codex?

Run `npx skills add PostHog/posthog-foss --skill implementing-mcp-tools -a codex`. Or copy the skill folder (.agents/skills/implementing-mcp-tools in PostHog/posthog-foss) into .agents/skills/implementing-mcp-tools in your project. Codex loads it when a task matches its description.

Can I use Implementing MCP Tools in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add PostHog/posthog-foss --skill implementing-mcp-tools -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/implementing-mcp-tools, .gemini/skills/implementing-mcp-tools, .github/skills/implementing-mcp-tools and .opencode/skills/implementing-mcp-tools in your project.

What does Implementing MCP Tools need to run?

Going by SKILL.md and its folder, Implementing MCP Tools needs the command-line tools its instructions call (pnpm).

Does Implementing MCP Tools access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Implementing MCP Tools safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Implementing MCP Tools use?

Implementing MCP Tools is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Implementing MCP Tools use?

About 3.7k tokens (SKILL.md is roughly 15k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Implementing MCP Tools?

Skills that share tags, products or a category with Implementing MCP Tools: OpenAPI to MCP Server (mcp-use/mcp-use, 11k stars), Tandem Browser (hydro13/tandem-browser, 616 stars), FastAPI Project Templates (wshobson/agents, 40k stars) and Migration Codegen (AHS12/thoth-blueprint, 626 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Implementing MCP Tools?

PostHog (a GitHub organization, an official publisher) maintains it in PostHog/posthog-foss, which has 721 GitHub stars. The repository holds 213 skills in this directory. The repository was last updated on October 7, 2026.

Source: PostHog/posthog-foss on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.