Skip to content
32 changes: 16 additions & 16 deletions cli/mcp/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,18 @@ export function setServerStartTime(time: number): void {

const getErrorsInput = z.object({
type: z.enum(["compile", "runtime", "bundle", "hmr", "module"]).optional().describe(
"Filter by error type",
"Filter by error type. Example: 'compile'. Omit to return all types.",
),
file: z.string().optional().describe("Filter by file path"),
limit: z.number().optional().default(50).describe("Maximum number of errors to return"),
file: z.string().optional().describe("Filter by file path. Example: 'app/page.tsx'. Omit to return errors from all files."),
limit: z.number().optional().default(50).describe("Maximum number of errors to return. Defaults to 50."),
});

type GetErrorsInput = z.infer<typeof getErrorsInput>;

export const vfGetErrors: MCPTool<GetErrorsInput, DevError[]> = {
name: "vf_get_errors",
description:
"Get compilation, runtime, and build errors from the dev server. Use this to debug issues with your code.",
"Use this when you need to check for compilation, runtime, bundle, HMR, or module errors in the dev server. Returns error details including file path, line number, and message. Do not use for server logs — use vf_get_logs instead.",
inputSchema: getErrorsInput,
execute: async (input) => {
const errors = getErrorCollector().getAll({
Expand All @@ -60,21 +60,21 @@ export const vfGetErrors: MCPTool<GetErrorsInput, DevError[]> = {
};

const getLogsInput = z.object({
level: z.enum(["debug", "info", "warn", "error"]).optional().describe("Filter by log level"),
level: z.enum(["debug", "info", "warn", "error"]).optional().describe("Filter by log level. Example: 'error'. Omit to return all levels."),
source: z.string().optional().describe(
"Filter by log source (e.g., 'server', 'hmr', 'transform')",
"Filter by log source. Example: 'server', 'hmr', 'transform'. Omit to return all sources.",
),
pattern: z.string().optional().describe("Filter by pattern (case-insensitive substring match)"),
limit: z.number().optional().default(100).describe("Maximum number of log entries to return"),
since: z.number().optional().describe("Only return logs after this timestamp"),
pattern: z.string().optional().describe("Filter by pattern (case-insensitive substring match). Example: 'timeout'."),
limit: z.number().optional().default(100).describe("Maximum number of log entries to return. Defaults to 100."),
since: z.number().optional().describe("Only return logs after this Unix timestamp in milliseconds."),
});

type GetLogsInput = z.infer<typeof getLogsInput>;

export const vfGetLogs: MCPTool<GetLogsInput, LogEntry[]> = {
name: "vf_get_logs",
description:
"Get recent server logs. Use this to understand what the server is doing and debug runtime issues.",
"Use this when you need to inspect server logs to understand runtime behavior or debug request handling. Returns log entries with timestamp, level, source, and message. Do not use for build/compile errors — use vf_get_errors instead.",
inputSchema: getLogsInput,
execute: async (input) => {
return getLogBuffer().query({
Expand All @@ -89,7 +89,7 @@ export const vfGetLogs: MCPTool<GetLogsInput, LogEntry[]> = {

const clearCacheInput = z.object({
type: z.enum(["all", "modules", "mdx"]).optional().default("all").describe(
"Type of cache to clear",
"Type of cache to clear. Example: 'modules'. Defaults to 'all'.",
),
});

Expand All @@ -103,7 +103,7 @@ interface ClearCacheOutput {
export const vfClearCache: MCPTool<ClearCacheInput, ClearCacheOutput> = {
name: "vf_clear_cache",
description:
"Clear module and build caches. Use this when changes aren't being reflected or to force a rebuild.",
"Use this when the dev server shows stale modules or MDX content. Clears the specified cache directories. Do not use to fix code errors — those require code changes.",
inputSchema: clearCacheInput,
execute: async (input) => {
const fs = createFileSystem();
Expand Down Expand Up @@ -143,7 +143,7 @@ export function createVfGetStatus(
): MCPTool<GetStatusInput, ServerStatus> {
return {
name: "vf_get_status",
description: "Get the current status of the dev server including error counts and uptime.",
description: "Use this when you need to check if the dev server is running, its uptime, or current error/warning counts. Do not use for detailed error info — use vf_get_errors instead.",
Comment thread
ariskemper marked this conversation as resolved.
Outdated
inputSchema: getStatusInput,
execute: async () => {
const errors = getErrorCollector();
Expand All @@ -167,9 +167,9 @@ export function createVfGetStatus(
export const vfGetStatus = createVfGetStatus();

const clearErrorsInput = z.object({
file: z.string().optional().describe("Clear errors for a specific file only"),
file: z.string().optional().describe("Clear errors for a specific file only. Example: 'app/page.tsx'. Omit to clear all files."),
type: z.enum(["compile", "runtime", "bundle", "hmr", "module"]).optional().describe(
"Clear errors of a specific type only",
"Clear errors of a specific type only. Example: 'compile'. Omit to clear all types.",
),
});

Expand All @@ -181,7 +181,7 @@ interface ClearErrorsOutput {

export const vfClearErrors: MCPTool<ClearErrorsInput, ClearErrorsOutput> = {
name: "vf_clear_errors",
description: "Clear errors from the error collector. Useful after fixing issues.",
description: "Use this when you want to clear accumulated errors from the error collector, optionally filtering by file or type. Returns the number of cleared errors.",
inputSchema: clearErrorsInput,
execute: async (input) => {
const collector = getErrorCollector();
Expand Down
10 changes: 5 additions & 5 deletions cli/mcp/tools/catalog-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ type ListExamplesInput = z.infer<typeof listExamplesInput>;
export const vfListExamples: MCPTool<ListExamplesInput, ExampleInfo[]> = {
name: "vf_list_examples",
description:
"List example projects that demonstrate Veryfront features. Use these as references or starting points for new projects.",
"Use this when you need to browse example projects that demonstrate Veryfront features and integrations. Do not use for project templates — use vf_list_templates instead.",
inputSchema: listExamplesInput,
execute: () => Promise.resolve(EXAMPLES),
};
Expand All @@ -351,7 +351,7 @@ type ListTemplatesInput = z.infer<typeof listTemplatesInput>;
export const vfListTemplates: MCPTool<ListTemplatesInput, TemplateInfo[]> = {
name: "vf_list_templates",
description:
"List available project templates. Use this to help users choose the right starting point for their project.",
"Use this when you need to list available project templates for creating new projects. Do not use for example projects — use vf_list_examples instead.",
inputSchema: listTemplatesInput,
execute: () => Promise.resolve(TEMPLATES),
};
Expand All @@ -373,7 +373,7 @@ type ListIntegrationsInput = z.infer<typeof listIntegrationsInput>;
export const vfListIntegrations: MCPTool<ListIntegrationsInput, IntegrationInfo[]> = {
name: "vf_list_integrations",
description:
"List available service integrations (Gmail, Slack, GitHub, etc.). These can be added to AI projects to give agents access to external services.",
"Use this when you need to list available service integrations (Gmail, Slack, GitHub, etc.) that can be added to AI projects. Do not use for templates — use vf_list_templates instead.",
inputSchema: listIntegrationsInput,
execute: (input) => {
const { category } = input;
Expand All @@ -393,7 +393,7 @@ type ListUsecasesInput = z.infer<typeof listUsecasesInput>;
export const vfListUsecases: MCPTool<ListUsecasesInput, UsecaseInfo[]> = {
name: "vf_list_usecases",
description:
"List pre-configured use-case templates. Each includes recommended integrations and UI layout for common scenarios.",
"Use this when you need to browse pre-configured use-case templates with recommended integrations and UI layouts. Do not use for raw templates — use vf_list_templates instead.",
inputSchema: listUsecasesInput,
execute: () => Promise.resolve(USECASES),
};
Expand Down Expand Up @@ -439,7 +439,7 @@ interface CreateProjectResult {
export const vfCreateProject: MCPTool<CreateProjectInput, CreateProjectResult> = {
name: "vf_create_project",
description:
"Create a new Veryfront project from a template. This is the MCP equivalent of 'veryfront init'. Returns the project directory and next steps.",
"Use this when you need to create a new Veryfront project from a template. Returns the project directory and next steps. Do not use for scaffolding individual files — use vf_scaffold instead.",
inputSchema: createProjectInput,
execute: (input) =>
withSpan(
Expand Down
20 changes: 10 additions & 10 deletions cli/mcp/tools/dev-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const hotReloadInput = z.object({
file: z
.string()
.optional()
.describe("Specific file to trigger reload for (optional - reloads all if not specified)"),
.describe("Specific file to trigger reload for. Example: 'app/page.tsx'. Omit to reload all."),
});

type HotReloadInput = z.infer<typeof hotReloadInput>;
Expand All @@ -31,7 +31,7 @@ interface HotReloadResult {
export const vfHotReload: MCPTool<HotReloadInput, HotReloadResult> = {
name: "vf_hot_reload",
description:
"Trigger a hot reload of the dev server. Use after making changes to see them instantly.",
"Use this when you need to trigger a hot module reload for a specific file or the entire project. Do not use for full server restart.",
inputSchema: hotReloadInput,
execute: () =>
Promise.resolve({
Expand Down Expand Up @@ -71,7 +71,7 @@ interface DebugContextResult {
export const vfGetDebugContext: MCPTool<GetDebugContextInput, DebugContextResult> = {
name: "vf_get_debug_context",
description:
"Get the current server context including project info, environment, and mode. Useful for debugging server configuration issues.",
"Use this when you need the dev server's debug context including configuration and active routes. Do not use for error details — use vf_get_errors instead.",
inputSchema: getDebugContextInput,
execute: (input) =>
withSpan(
Expand Down Expand Up @@ -112,7 +112,7 @@ export const vfGetDebugContext: MCPTool<GetDebugContextInput, DebugContextResult
// ============================================================================

const triggerHmrInput = z.object({
path: z.string().describe("File path that changed (e.g., 'app/page.tsx')"),
path: z.string().describe("File path that changed. Example: 'app/page.tsx'."),
port: z.number().int().min(1).max(65535).optional().default(8080).describe(
"Dev server port (defaults to 8080)",
),
Expand All @@ -128,7 +128,7 @@ interface TriggerHmrResult {
export const vfTriggerHmr: MCPTool<TriggerHmrInput, TriggerHmrResult> = {
name: "vf_trigger_hmr",
description:
"Trigger Hot Module Replacement for a specific file. The browser will update without a full reload.",
"Use this when you need to force an HMR update for a specific file path. Do not use for full page reload — use vf_hot_reload instead.",
Comment thread
ariskemper marked this conversation as resolved.
Outdated
inputSchema: triggerHmrInput,
execute: (input) => {
const metrics = ReloadNotifier.getMetrics();
Expand All @@ -154,7 +154,7 @@ export const vfTriggerHmr: MCPTool<TriggerHmrInput, TriggerHmrResult> = {

const previewRouteInput = z.object({
route: z.string().startsWith("/", "Route must start with /").describe(
"Route path to preview (e.g., '/', '/dashboard', '/api/users')",
"Route path to preview. Example: '/', '/dashboard', '/api/users'.",
),
port: z.number().int().min(1).max(65535).optional().default(8080).describe(
"Dev server port (defaults to 8080)",
Expand All @@ -163,7 +163,7 @@ const previewRouteInput = z.object({
.enum(["html", "json", "status"])
.optional()
.default("status")
.describe("Output format: html (full page), json (API response), status (just HTTP status)"),
.describe("Output format: 'html' for full page, 'json' for API response, 'status' for just HTTP status. Defaults to 'status'."),
});

type PreviewRouteInput = z.infer<typeof previewRouteInput>;
Expand All @@ -181,7 +181,7 @@ interface PreviewRouteResult {
export const vfPreviewRoute: MCPTool<PreviewRouteInput, PreviewRouteResult> = {
name: "vf_preview_route",
description:
"Preview a route by making a request to the dev server. Returns the rendered output, HTTP status, and render time. Perfect for testing changes instantly.",
"Use this when you need to test-render a route and inspect the response. Do not use for listing routes — use vf_list_routes instead.",
inputSchema: previewRouteInput,
execute: (input) =>
withSpan(
Expand Down Expand Up @@ -262,7 +262,7 @@ interface WaitForReadyResult {
export const vfWaitForReady: MCPTool<WaitForReadyInput, WaitForReadyResult> = {
name: "vf_wait_for_ready",
description:
"Wait for the server to be ready by polling the health endpoint. Use this after starting the server to ensure it's accepting requests.",
"Use this when you need to wait for the dev server to become ready after restart. Do not use to check current status — use vf_get_status instead.",
Comment thread
ariskemper marked this conversation as resolved.
Outdated
inputSchema: waitForReadyInput,
execute: (input) =>
withSpan(
Expand Down Expand Up @@ -350,7 +350,7 @@ interface FlywheelStatus {
export const vfGetFlywheelStatus: MCPTool<GetFlywheelStatusInput, FlywheelStatus> = {
name: "vf_get_flywheel_status",
description:
"Get aggregated status for the development flywheel. Shows server state, error counts, log summary, and HMR status in one view.",
"Use this when you need a comprehensive status overview combining server health, error counts, and HMR statistics. Do not use for detailed error or log content — use vf_get_errors or vf_get_logs instead.",
inputSchema: getFlywheelStatusInput,
execute: (input) =>
withSpan(
Expand Down
4 changes: 2 additions & 2 deletions cli/mcp/tools/introspection-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const getSchemaInput = z.object({
const vfGetSchema: MCPTool = {
name: "vf_get_schema",
description:
"Get the CLI command schema for discovering available commands, arguments, and flags.",
"Use this when you need to discover available CLI commands, their arguments, and flags. Do not use for project info — use vf_get_project_info instead.",
inputSchema: getSchemaInput,
execute: async (input: { command?: string; category?: string }) => {
if (input.command) {
Expand All @@ -26,7 +26,7 @@ const getProjectInfoInput = z.object({});

const vfGetProjectInfo: MCPTool = {
name: "vf_get_project_info",
description: "Get project metadata including project slug, version, and environment.",
description: "Use this when you need project metadata including project slug, version, and environment. Do not use for CLI commands — use vf_get_schema instead.",
inputSchema: getProjectInfoInput,
execute: async () => {
const { getEnvironmentConfig } = await import("veryfront/config");
Expand Down
8 changes: 4 additions & 4 deletions cli/mcp/tools/project-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type ListRoutesInput = z.infer<typeof listRoutesInput>;
export const vfListRoutes: MCPTool<ListRoutesInput, RouteInfo[]> = {
name: "vf_list_routes",
description:
"Discover all routes in the project. Returns pages, API routes, layouts, and special routes. Use this to understand the project structure before making changes.",
"Use this when you need to discover all routes in the project including pages, API routes, and layouts. Do not use for rendering a route — use vf_preview_route instead.",
inputSchema: listRoutesInput,
execute: (input) =>
withSpan(
Expand Down Expand Up @@ -143,7 +143,7 @@ async function getProjectName(projectDir: string, fs: FileSystem): Promise<strin
export const vfGetProjectContext: MCPTool<GetProjectContextInput, ProjectContext> = {
name: "vf_get_project_context",
description:
"Get deep understanding of the project structure, conventions, and capabilities. Use this at the start of any coding session to understand the project before making changes.",
"Use this when you need to understand the project structure, conventions, and capabilities at the start of a coding session. Do not use for route listing — use vf_list_routes instead.",
inputSchema: getProjectContextInput,
execute: (input) =>
withSpan(
Expand Down Expand Up @@ -220,7 +220,7 @@ function toRelativePath(absolutePath: string, projectDir: string): string {
export const vfGetComponentTree: MCPTool<GetComponentTreeInput, ComponentTreeResult> = {
name: "vf_get_component_tree",
description:
"Analyze the component hierarchy for a route. Shows layouts, providers, and components that render on this route. Helps understand the rendering structure.",
"Use this when you need to analyze the component hierarchy for a specific route including layouts, providers, and nested components. Do not use for listing all routes — use vf_list_routes instead.",
inputSchema: getComponentTreeInput,
execute: (input) =>
withSpan(
Expand Down Expand Up @@ -376,7 +376,7 @@ async function scanForProjects(
export const vfListLocalProjects: MCPTool<ListLocalProjectsInput, LocalProjectInfo[]> = {
name: "vf_list_local_projects",
description:
"Discover Veryfront projects on the local filesystem. Scans for veryfront.config.ts files and returns project info including template type and integrations.",
"Use this when you need to discover Veryfront projects on the local filesystem by scanning for veryfront.config.ts files. Do not use for project structure details — use vf_get_project_context instead.",
inputSchema: listLocalProjectsInput,
execute: (input) =>
withSpan(
Expand Down
4 changes: 2 additions & 2 deletions cli/mcp/tools/scaffold-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ const SCAFFOLD_CONFIGS: Record<ScaffoldType, ScaffoldConfig> = {
export const vfScaffold: MCPTool<ScaffoldInput, ScaffoldResult> = {
name: "vf_scaffold",
description:
"Generate new entities (pages, API routes, layouts, components, AI tools, agents, prompts) with proper conventions. This is the recommended way to create new files in a Veryfront project.",
"Use this when you need to generate new pages, API routes, layouts, components, AI tools, agents, or prompts with proper Veryfront conventions. Do not use for creating entire projects — use vf_create_project instead.",
inputSchema: scaffoldInput,
execute: (input) =>
withSpan(
Expand Down Expand Up @@ -401,7 +401,7 @@ const CONVENTIONS: Record<string, Convention> = {
export const vfGetConventions: MCPTool<GetConventionsInput, Convention[]> = {
name: "vf_get_conventions",
description:
"Get Veryfront coding conventions and best practices. Use this as guardrails when writing code to ensure consistency with the project standards.",
"Use this when you need Veryfront coding conventions and best practices for routing, API, components, AI, or styling. Do not use for project structure — use vf_get_project_context instead.",
inputSchema: getConventionsInput,
execute: (input) => {
if (input.topic === "all") return Promise.resolve(Object.values(CONVENTIONS));
Expand Down
4 changes: 2 additions & 2 deletions cli/mcp/tools/skill-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ interface GetSkillsResult {
export const vfGetSkills: MCPTool<GetSkillsInput, GetSkillsResult> = {
name: "vf_get_skills",
description:
"Discover available Agent Skills for Veryfront development. Skills provide procedural knowledge for using MCP tools effectively. Call without name param to list all skills, or with name to get full skill content.",
"Use this when you need to discover available Agent Skills or load a specific skill's procedural knowledge. Call without name to list all skills, or with name to get full content. Do not use for skill reference docs — use vf_get_skill_reference instead.",
inputSchema: getSkillsInput,
execute: (input) =>
withSpan(
Expand Down Expand Up @@ -169,7 +169,7 @@ interface GetSkillReferenceResult {
export const vfGetSkillReference: MCPTool<GetSkillReferenceInput, GetSkillReferenceResult> = {
name: "vf_get_skill_reference",
description:
"Get a specific reference document from a skill. Use this to load detailed documentation on demand.",
"Use this when you need to load a specific reference document from a skill. Do not use for skill discovery — use vf_get_skills instead.",
inputSchema: getSkillReferenceInput,
execute: async (input) => {
const fs = getFs();
Expand Down
Loading
Loading