@mandujs/mcp 0.18.2 → 0.18.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/tools/spec.ts CHANGED
@@ -15,7 +15,16 @@ import fs from "fs/promises";
15
15
  export const specToolDefinitions: Tool[] = [
16
16
  {
17
17
  name: "mandu_list_routes",
18
- description: "List all routes in the current Mandu project (reads from .mandu/routes.manifest.json)",
18
+ description:
19
+ "List all routes registered in the Mandu project, read from .mandu/routes.manifest.json. " +
20
+ "Route kinds: " +
21
+ "'api' (REST endpoint — app/**/route.ts, exports named GET/POST/PUT/PATCH/DELETE handler functions), " +
22
+ "'page' (SSR page — app/**/page.tsx, React component supporting client-side hydration islands). " +
23
+ "Special files auto-detected by the filesystem router (not user-created routes): " +
24
+ "layout.tsx (shared wrapper rendered around child routes), " +
25
+ "error.tsx (error boundary for the route subtree), " +
26
+ "loading.tsx (suspense fallback shown while page data loads). " +
27
+ "Each route may have an associated slotModule (server data loader) and contractModule (Zod API schema).",
19
28
  inputSchema: {
20
29
  type: "object",
21
30
  properties: {},
@@ -24,13 +33,17 @@ export const specToolDefinitions: Tool[] = [
24
33
  },
25
34
  {
26
35
  name: "mandu_get_route",
27
- description: "Get details of a specific route by ID",
36
+ description:
37
+ "Get full details of a specific route by its ID. " +
38
+ "Returns the complete route spec: kind, URL pattern, module paths (app, slot, contract, component), " +
39
+ "HTTP methods, and hydration configuration (for page routes with client islands). " +
40
+ "Use this before modifying a route to understand its current configuration.",
28
41
  inputSchema: {
29
42
  type: "object",
30
43
  properties: {
31
44
  routeId: {
32
45
  type: "string",
33
- description: "The route ID to retrieve",
46
+ description: "The route ID to retrieve (use mandu_list_routes to see all IDs)",
34
47
  },
35
48
  },
36
49
  required: ["routeId"],
@@ -38,7 +51,15 @@ export const specToolDefinitions: Tool[] = [
38
51
  },
39
52
  {
40
53
  name: "mandu_add_route",
41
- description: "Add a new route by scaffolding files in app/ and optionally in spec/slots/ and spec/contracts/",
54
+ description:
55
+ "Scaffold a new route by creating source files in app/ and registering it in the manifest. " +
56
+ "For 'api' routes: creates app/{path}/route.ts with a GET handler stub. " +
57
+ "For 'page' routes: creates app/{path}/page.tsx with a React component stub. " +
58
+ "withSlot=true (default): also creates spec/slots/{routeId}.slot.ts — " +
59
+ "the server-side data loader that runs on every request before rendering and injects typed props into the page. " +
60
+ "withContract=true: also creates spec/contracts/{routeId}.contract.ts — " +
61
+ "Zod schemas for request/response validation, enabling typed handlers, OpenAPI generation, and ATE L2/L3 testing. " +
62
+ "Automatically runs generateManifest() after creation to link all files.",
42
63
  inputSchema: {
43
64
  type: "object",
44
65
  properties: {
@@ -49,15 +70,15 @@ export const specToolDefinitions: Tool[] = [
49
70
  kind: {
50
71
  type: "string",
51
72
  enum: ["api", "page"],
52
- description: "Route type: api (route.ts) or page (page.tsx)",
73
+ description: "Route type: 'api' creates route.ts with HTTP handlers, 'page' creates page.tsx with a React component",
53
74
  },
54
75
  withSlot: {
55
76
  type: "boolean",
56
- description: "Scaffold a slot file in spec/slots/ (default: true)",
77
+ description: "Also scaffold a server-side data loader at spec/slots/{routeId}.slot.ts (default: true)",
57
78
  },
58
79
  withContract: {
59
80
  type: "boolean",
60
- description: "Scaffold a contract file in spec/contracts/",
81
+ description: "Also scaffold a Zod contract at spec/contracts/{routeId}.contract.ts (default: false)",
61
82
  },
62
83
  },
63
84
  required: ["path", "kind"],
@@ -65,13 +86,18 @@ export const specToolDefinitions: Tool[] = [
65
86
  },
66
87
  {
67
88
  name: "mandu_delete_route",
68
- description: "Delete a route's app/ files and rescan (preserves slot/contract files)",
89
+ description:
90
+ "Delete a route's app/ source file and regenerate the manifest. " +
91
+ "Only removes the app/{path}/route.ts or page.tsx file — " +
92
+ "slot files (spec/slots/) and contract files (spec/contracts/) are intentionally preserved, " +
93
+ "as they may be reused when the route is recreated. " +
94
+ "Use mandu_list_routes before deleting to confirm the correct routeId.",
69
95
  inputSchema: {
70
96
  type: "object",
71
97
  properties: {
72
98
  routeId: {
73
99
  type: "string",
74
- description: "The route ID to delete",
100
+ description: "The route ID to delete (use mandu_list_routes to find it)",
75
101
  },
76
102
  },
77
103
  required: ["routeId"],
@@ -79,7 +105,10 @@ export const specToolDefinitions: Tool[] = [
79
105
  },
80
106
  {
81
107
  name: "mandu_validate_manifest",
82
- description: "Validate the current routes manifest (.mandu/routes.manifest.json)",
108
+ description:
109
+ "Validate the routes manifest (.mandu/routes.manifest.json) for structural integrity. " +
110
+ "Checks required fields, valid route kinds, correct module paths, and manifest schema version. " +
111
+ "Run this after manual manifest edits, after upgrading Mandu, or when routes behave unexpectedly.",
83
112
  inputSchema: {
84
113
  type: "object",
85
114
  properties: {},
@@ -54,7 +54,7 @@ export function getProjectPaths(rootDir: string) {
54
54
  export function isInsideProject(filePath: string, rootDir: string): boolean {
55
55
  const resolved = path.resolve(filePath);
56
56
  const root = path.resolve(rootDir);
57
- return resolved.startsWith(root);
57
+ return resolved === root || resolved.startsWith(root + path.sep);
58
58
  }
59
59
 
60
60
  /**
@@ -73,7 +73,9 @@ export async function readJsonFile<T>(filePath: string): Promise<T | null> {
73
73
  }
74
74
 
75
75
  /**
76
- * Write JSON file safely
76
+ * Write JSON file safely.
77
+ * Note: Callers are responsible for ensuring filePath is within the project root.
78
+ * All internal callers use paths derived from getProjectPaths() which are scoped to projectRoot.
77
79
  */
78
80
  export async function writeJsonFile(filePath: string, data: unknown): Promise<void> {
79
81
  const dir = path.dirname(filePath);