feat: load tools on build for mcp server (#12510)

* load tools on build for mcp server

* relative import

* Update fetchMCPTools.ts

* Update MCPTools.tsx
This commit is contained in:
Joshua Snyder
2025-08-21 17:24:36 +02:00
committed by GitHub
parent 133491ef62
commit cd1e257282
5 changed files with 169 additions and 63 deletions

3
.gitignore vendored
View File

@@ -32,3 +32,6 @@ src/components/Layout/Fonts.scss
.env
*Type.ts
.env.development
# Generated data files
src/data/mcp-tools.json

View File

@@ -9,6 +9,7 @@ import WindsurfSnippet from "./_snippets/windsurf.mdx"
import VSCodeSnippet from "./_snippets/vscode.mdx"
import ClaudeCodeSnippet from "./_snippets/claude-code.mdx"
import ZedSnippet from "./_snippets/zed.mdx"
import MCPTools from '../../../src/components/Docs/MCPTools'
The PostHog [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) server enables your AI agents and tools to directly interact with PostHog's products.
@@ -84,68 +85,7 @@ We recommend the following best practices to mitigate security risks when using
Tools trigger actions on behalf of the user based on the goals and information already in the context of the LLM. Here's a list of tools we provide:
### Organization & project management
| Tool | Purpose |
| -- | -- |
| `organizations-get` | Get the organizations the user has access to. |
| `switch-organization` | Change the active organization from the default organization. |
| `organization-details-get` | Get the details of the active organization. |
| `projects-get` | Fetches projects that the user has access to in the current organization. |
| `switch-project` | Change the active project from the default project. |
| `property-definitions` | Get event and property definitions for the project. |
### Feature flags
| Tool | Purpose |
| -- | -- |
| `feature-flag-get-all` | Get all feature flags in the project. |
| `feature-flag-get-definition` | Get the definition of a feature flag. |
| `create-feature-flag` | Creates a new feature flag in the project. |
| `update-feature-flag` | Update a feature flag in the project. |
| `delete-feature-flag` | Delete a feature flag in the project. |
### Insights & analytics
| Tool | Purpose |
| -- | -- |
| `insights-get-all` | Get all insights in the project with optional filtering. |
| `insight-get` | Get a specific insight by ID. |
| `insight-create-from-query` | Save a query as an insight. |
| `insight-update` | Update an existing insight by ID. |
| `insight-delete` | Delete an insight by ID. |
| `insight-query` | Execute a query on an existing insight to get its results/data. |
| `get-sql-insight` | Queries project's PostHog data based on a provided natural language question. |
### Dashboards
| Tool | Purpose |
| -- | -- |
| `dashboards-get-all` | Get all dashboards in the project with optional filtering. |
| `dashboard-get` | Get a specific dashboard by ID. |
| `dashboard-create` | Create a new dashboard in the project. |
| `dashboard-update` | Update an existing dashboard by ID. |
| `dashboard-delete` | Delete a dashboard by ID. |
| `add-insight-to-dashboard` | Add an existing insight to a dashboard. |
### Error tracking
| Tool | Purpose |
| -- | -- |
| `list-errors` | List errors in the project. |
| `error-details` | Get the details of an error in the project. |
### Documentation
| Tool | Purpose |
| -- | -- |
| `docs-search` | Search the PostHog documentation for information. |
### LLM observability
| Tool | Purpose |
| -- | -- |
| `get-llm-total-costs-for-project` | Fetches the total LLM daily costs for each model for a project over a given number of days. |
<MCPTools />
## Next Steps

View File

@@ -2,14 +2,27 @@ import { GatsbyNode } from 'gatsby'
import fetch from 'node-fetch'
import path from 'path'
import fs from 'fs'
import { fetchAndProcessMCPTools, writeMCPToolsToFile } from './utils/fetchMCPTools'
export const PAGEVIEW_CACHE_KEY = 'onPreBootstrap@@posthog-pageviews'
export const MCP_TOOLS_CACHE_KEY = 'onPreBootstrap@@mcp-tools'
export const onPreBootstrap: GatsbyNode['onPreBootstrap'] = async ({ cache }) => {
// Copy hedgehog mode assets to public folder
const source = path.resolve('node_modules/@posthog/hedgehog-mode/assets')
const hedgehogModeDir = path.resolve(__dirname, '../public/hedgehog-mode')
fs.cpSync(source, hedgehogModeDir, { recursive: true })
// Fetch and process MCP tool definitions
const mcpToolsData = await fetchAndProcessMCPTools()
writeMCPToolsToFile(mcpToolsData)
// Cache the data if successful
if (!mcpToolsData.error && mcpToolsData.categories) {
await cache.set(MCP_TOOLS_CACHE_KEY, mcpToolsData.categories)
}
if (process.env.POSTHOG_APP_API_KEY && !(await cache.get(PAGEVIEW_CACHE_KEY))) {
const pageViews: Record<string, number> = {}

View File

@@ -0,0 +1,74 @@
import fetch from 'node-fetch'
import path from 'path'
import fs from 'fs'
const MCP_TOOLS_URL = 'https://raw.githubusercontent.com/PostHog/mcp/refs/heads/main/schema/tool-definitions.json'
interface MCPTool {
category?: string
summary: string
}
interface ToolCategory {
name: string
tools: Array<{
name: string
summary: string
}>
}
export async function fetchAndProcessMCPTools(): Promise<{
categories: ToolCategory[] | null
error: boolean
}> {
try {
const response = await fetch(MCP_TOOLS_URL)
if (response.status !== 200) {
throw new Error(`Failed to fetch MCP tools: ${response.status}`)
}
const mcpTools = (await response.json()) as Record<string, MCPTool>
// Process the tools into categories
const toolCategories: Record<string, Array<{ name: string; summary: string }>> = {}
Object.entries(mcpTools).forEach(([toolName, toolDef]) => {
const category = toolDef.category || 'Uncategorized'
if (!toolCategories[category]) {
toolCategories[category] = []
}
toolCategories[category].push({
name: toolName,
summary: toolDef.summary,
})
})
// Sort tools within each category alphabetically
Object.values(toolCategories).forEach((tools) => {
tools.sort((a, b) => a.name.localeCompare(b.name))
})
// Convert to array format and sort categories
const categoriesArray = Object.entries(toolCategories)
.map(([name, tools]) => ({ name, tools }))
.sort((a, b) => a.name.localeCompare(b.name))
return {
categories: categoriesArray,
error: false,
}
} catch (error) {
console.error('Error fetching MCP tools:', error)
return {
categories: null,
error: true,
}
}
}
export function writeMCPToolsToFile(data: { categories: ToolCategory[] | null; error: boolean }): void {
const mcpToolsPath = path.resolve(__dirname, '../../src/data/mcp-tools.json')
fs.mkdirSync(path.dirname(mcpToolsPath), { recursive: true })
fs.writeFileSync(mcpToolsPath, JSON.stringify(data, null, 2))
}

View File

@@ -0,0 +1,76 @@
import React from 'react'
import mcpToolsData from '../../data/mcp-tools.json'
interface Tool {
name: string
summary: string
}
interface ToolCategory {
name: string
tools: Tool[]
}
const MCPTools: React.FC = () => {
const { categories: toolCategories, error } = mcpToolsData as {
categories: ToolCategory[] | null
error: boolean
}
if (error) {
return (
<div className="p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded">
<p className="text-red-800 dark:text-red-200">
Tools unavailable. Please view the repo{' '}
<a
href="https://github.com/posthog/mcp"
className="underline font-semibold"
target="_blank"
rel="noopener noreferrer"
>
https://github.com/posthog/mcp
</a>{' '}
to see tools.
</p>
</div>
)
}
if (!toolCategories || toolCategories.length === 0) {
return (
<div className="p-4 bg-gray-50 dark:bg-gray-800 rounded">
<p className="text-gray-600 dark:text-gray-400">Loading tools...</p>
</div>
)
}
return (
<>
{toolCategories.map((category) => (
<div key={category.name} className="mb-8">
<h3>{category.name}</h3>
<table>
<thead>
<tr>
<th>Tool</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
{category.tools.map((tool) => (
<tr key={tool.name}>
<td>
<code>{tool.name}</code>
</td>
<td>{tool.summary}</td>
</tr>
))}
</tbody>
</table>
</div>
))}
</>
)
}
export default MCPTools