mirror of
https://github.com/BillyOutlast/posthog.com.git
synced 2026-02-04 03:11:21 +01:00
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:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -32,3 +32,6 @@ src/components/Layout/Fonts.scss
|
||||
.env
|
||||
*Type.ts
|
||||
.env.development
|
||||
|
||||
# Generated data files
|
||||
src/data/mcp-tools.json
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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> = {}
|
||||
|
||||
|
||||
74
gatsby/utils/fetchMCPTools.ts
Normal file
74
gatsby/utils/fetchMCPTools.ts
Normal 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))
|
||||
}
|
||||
76
src/components/Docs/MCPTools.tsx
Normal file
76
src/components/Docs/MCPTools.tsx
Normal 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
|
||||
Reference in New Issue
Block a user