@mandujs/mcp 0.37.2 → 0.37.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.
@@ -9,13 +9,53 @@ globs:
9
9
  - "app/**/client.tsx"
10
10
  ---
11
11
 
12
- # Mandu UI Skill
13
-
14
- Mandu Island 아키텍처에 UI 컴포넌트 라이브러리를 통합하는 가이드입니다.
15
-
16
- ## 핵심 원칙
17
-
18
- 1. **Headless First**: Radix UI 기반으로 동작과 스타일 분리
12
+ # Mandu UI Skill
13
+
14
+ Mandu Island 아키텍처에 UI 컴포넌트 라이브러리를 통합하는 가이드입니다.
15
+
16
+ ## Agent Workflow Contract
17
+
18
+ This skill is a Domain addendum. It must not replace `mandu-agent-workflow`.
19
+ Use it only after `mandu.agent.plan` selects UI, design, styling, component, or hydration domains.
20
+
21
+ Canonical workflow step: `plan -> apply -> verify`.
22
+
23
+ Preferred MCP tools:
24
+
25
+ | Step | Tools |
26
+ |------|-------|
27
+ | plan | `mandu.agent.plan`, `mandu.design.get`, `mandu.component.list` |
28
+ | apply | `mandu.agent.apply`, `mandu.component.add` |
29
+ | verify | `mandu.agent.verify`, `mandu.design.check`, `mandu.lint` |
30
+ | repair | `mandu.agent.repair` |
31
+
32
+ Allowed file edits:
33
+
34
+ - `components/ui/**/*.tsx`
35
+ - Route-local island/client components named in the plan
36
+ - Styling utilities only when they are required by the selected component
37
+
38
+ Verification command:
39
+
40
+ ```bash
41
+ mandu agent verify --changed --json --write
42
+ ```
43
+
44
+ Common failures:
45
+
46
+ - Adding UI libraries before reading the existing design/component inventory
47
+ - Mixing server components and island-only UI imports
48
+ - Skipping accessibility or design checks for interactive components
49
+
50
+ Repair path:
51
+
52
+ ```bash
53
+ mandu agent repair --from .mandu/agent-verify.json --json
54
+ ```
55
+
56
+ ## 핵심 원칙
57
+
58
+ 1. **Headless First**: Radix UI 기반으로 동작과 스타일 분리
19
59
  2. **Copy-Paste**: shadcn/ui 방식으로 소유권 유지
20
60
  3. **Accessibility**: WCAG 2.1 AA 수준 준수
21
61
  4. **Island 호환**: 클라이언트 컴포넌트로 올바르게 분리
@@ -29,9 +69,11 @@ Icons: Lucide React
29
69
  Utilities: clsx, tailwind-merge, cva
30
70
  ```
31
71
 
32
- ## 빠른 시작
33
-
34
- ### shadcn/ui 초기화
72
+ ## Setup Examples
73
+
74
+ Use these examples only after `mandu.agent.plan` selects UI library setup.
75
+
76
+ ### shadcn/ui 초기화
35
77
 
36
78
  ```bash
37
79
  bunx shadcn-ui@latest init
@@ -469,24 +469,30 @@ export default function Counter({ initial = 0, step = 1 }: CounterProps) {
469
469
  }
470
470
  \`\`\`
471
471
 
472
- ## Step 2: 페이지에서 사용
473
-
474
- \`\`\`tsx
475
- // app/counter/page.tsx
476
-
477
- import Counter from "./client";
478
-
479
- export default function CounterPage() {
480
- return (
472
+ ## Step 2: 서버 페이지에서 partial로 사용
473
+
474
+ \`\`\`tsx
475
+ // app/counter/page.tsx
476
+
477
+ import { partial } from "@mandujs/core/client";
478
+ import Counter from "./client";
479
+
480
+ const CounterPartial = partial({
481
+ component: Counter,
482
+ priority: "visible",
483
+ });
484
+
485
+ export default function CounterPage() {
486
+ return (
481
487
  <div style={{ padding: "20px" }}>
482
488
  <h1>Counter Demo</h1>
483
489
  <p>아래 카운터는 클라이언트에서 hydration됩니다.</p>
484
-
485
- {/* Island 컴포넌트 */}
486
- <Counter initial={10} step={5} />
487
-
488
- <p style={{ marginTop: "20px", color: "#666" }}>
489
- 이 텍스트는 정적 HTML입니다.
490
+
491
+ {/* Inline client region */}
492
+ <CounterPartial.Render initial={10} step={5} />
493
+
494
+ <p style={{ marginTop: "20px", color: "#666" }}>
495
+ 이 텍스트는 정적 HTML입니다.
490
496
  </p>
491
497
  </div>
492
498
  );
@@ -618,10 +624,13 @@ export default function UserList() {
618
624
 
619
625
  ## Mandu.island() API (고급)
620
626
 
621
- 서버 데이터와 클라이언트 상태를 분리하려면:
622
-
623
- \`\`\`typescript
624
- // spec/slots/todos.client.ts
627
+ 서버 데이터와 클라이언트 상태를 분리하는 page-level Island가 필요하면
628
+ \`Mandu.island({ setup, render })\`를 사용합니다. \`island("visible",
629
+ Component)\`는 지원하지 않습니다. 서버 페이지 안에 inline으로 렌더링할
630
+ 영역은 \`partial()\`을 사용하세요.
631
+
632
+ \`\`\`typescript
633
+ // spec/slots/todos.client.ts
625
634
 
626
635
  import { Mandu } from "@mandujs/core/client";
627
636
  import { useState } from "react";
package/src/server.ts CHANGED
@@ -52,7 +52,7 @@ import { resourceHandlers, resourceDefinitions } from "./resources/handlers.js";
52
52
  import { findProjectRoot } from "./utils/project.js";
53
53
 
54
54
  import { ActivityMonitor } from "./activity-monitor.js";
55
- import { type McpProfile, isValidProfile } from "./profiles.js";
55
+ import { type McpProfile, resolveMcpProfile } from "./profiles.js";
56
56
 
57
57
  /**
58
58
  * MCP 서버 버전
@@ -130,9 +130,8 @@ export class ManduMcpServer {
130
130
  this.projectRoot = projectRoot;
131
131
  this.monitor = new ActivityMonitor(projectRoot);
132
132
 
133
- // Resolve profile from environment variable (default: "full")
134
- const envProfile = process.env.MANDU_MCP_PROFILE ?? "full";
135
- this.profile = isValidProfile(envProfile) ? envProfile : "full";
133
+ // Resolve profile from environment variable (default: "agent-core")
134
+ this.profile = resolveMcpProfile(process.env.MANDU_MCP_PROFILE);
136
135
 
137
136
  // MCP Server 초기화
138
137
  this.server = new Server(
@@ -0,0 +1,443 @@
1
+ import type { Tool } from "@modelcontextprotocol/sdk/types.js";
2
+ import path from "path";
3
+ import {
4
+ buildAgentApplyReport,
5
+ buildAgentContext,
6
+ buildAgentPlan,
7
+ buildAgentRepairReport,
8
+ buildAgentSyncReport,
9
+ buildAgentVerifyReport,
10
+ writeAgentApplyReport,
11
+ writeAgentManifest,
12
+ writeAgentPlan,
13
+ writeAgentRepairReport,
14
+ writeAgentVerifyReport,
15
+ } from "@mandujs/core/agent";
16
+
17
+ interface AgentContextInput {
18
+ cwd?: unknown;
19
+ includeDiagnose?: unknown;
20
+ includeGit?: unknown;
21
+ writeManifest?: unknown;
22
+ }
23
+
24
+ interface AgentVerifyInput {
25
+ cwd?: unknown;
26
+ changedOnly?: unknown;
27
+ includeDiagnose?: unknown;
28
+ includeGit?: unknown;
29
+ includeGuard?: unknown;
30
+ includeContract?: unknown;
31
+ staged?: unknown;
32
+ base?: unknown;
33
+ writeReport?: unknown;
34
+ }
35
+
36
+ interface AgentPlanInput {
37
+ cwd?: unknown;
38
+ intent?: unknown;
39
+ writePlan?: unknown;
40
+ }
41
+
42
+ interface AgentApplyInput {
43
+ cwd?: unknown;
44
+ from?: unknown;
45
+ dryRun?: unknown;
46
+ writeReport?: unknown;
47
+ }
48
+
49
+ interface AgentSyncInput {
50
+ cwd?: unknown;
51
+ target?: unknown;
52
+ dryRun?: unknown;
53
+ }
54
+
55
+ interface AgentRepairInput {
56
+ cwd?: unknown;
57
+ from?: unknown;
58
+ apply?: unknown;
59
+ writeReport?: unknown;
60
+ }
61
+
62
+ function boolOrDefault(value: unknown, fallback: boolean): boolean {
63
+ if (value === undefined) return fallback;
64
+ if (typeof value === "boolean") return value;
65
+ return fallback;
66
+ }
67
+
68
+ function resolveCwd(projectRoot: string, value: unknown): string {
69
+ const root = path.resolve(projectRoot);
70
+ const resolved =
71
+ typeof value === "string" && value.length > 0
72
+ ? path.resolve(root, value)
73
+ : root;
74
+ if (resolved !== root && !resolved.startsWith(root + path.sep)) {
75
+ throw new Error("cwd must stay inside the MCP project root");
76
+ }
77
+ return resolved;
78
+ }
79
+
80
+ async function runAgentContext(
81
+ projectRoot: string,
82
+ input: AgentContextInput,
83
+ ) {
84
+ const cwd = resolveCwd(projectRoot, input.cwd);
85
+ const context = await buildAgentContext(cwd, {
86
+ includeDiagnose: boolOrDefault(input.includeDiagnose, true),
87
+ includeGit: boolOrDefault(input.includeGit, true),
88
+ });
89
+
90
+ if (boolOrDefault(input.writeManifest, false)) {
91
+ const { path, manifest } = await writeAgentManifest(cwd, context);
92
+ return {
93
+ ...context,
94
+ manifest: {
95
+ path,
96
+ written: true,
97
+ schemaVersion: manifest.schemaVersion,
98
+ },
99
+ };
100
+ }
101
+
102
+ return context;
103
+ }
104
+
105
+ async function runAgentPlan(
106
+ projectRoot: string,
107
+ input: AgentPlanInput,
108
+ ) {
109
+ const cwd = resolveCwd(projectRoot, input.cwd);
110
+ const intent = typeof input.intent === "string" ? input.intent.trim() : "";
111
+ if (!intent) {
112
+ throw new Error("intent is required for mandu.agent.plan");
113
+ }
114
+
115
+ const plan = buildAgentPlan({ intent });
116
+
117
+ if (boolOrDefault(input.writePlan, false)) {
118
+ const { path, plan: written } = await writeAgentPlan(cwd, plan);
119
+ return {
120
+ ...written,
121
+ plan: {
122
+ path,
123
+ written: true,
124
+ schemaVersion: written.schemaVersion,
125
+ },
126
+ };
127
+ }
128
+
129
+ return plan;
130
+ }
131
+
132
+ async function runAgentApply(
133
+ projectRoot: string,
134
+ input: AgentApplyInput,
135
+ ) {
136
+ const cwd = resolveCwd(projectRoot, input.cwd);
137
+ const report = await buildAgentApplyReport(cwd, {
138
+ from: typeof input.from === "string" && input.from.length > 0 ? input.from : undefined,
139
+ dryRun: boolOrDefault(input.dryRun, true),
140
+ });
141
+
142
+ if (boolOrDefault(input.writeReport, false)) {
143
+ const { path, report: written } = await writeAgentApplyReport(cwd, report);
144
+ return {
145
+ ...written,
146
+ report: {
147
+ path,
148
+ written: true,
149
+ schemaVersion: written.schemaVersion,
150
+ },
151
+ };
152
+ }
153
+
154
+ return report;
155
+ }
156
+
157
+ async function runAgentVerify(
158
+ projectRoot: string,
159
+ input: AgentVerifyInput,
160
+ ) {
161
+ const cwd = resolveCwd(projectRoot, input.cwd);
162
+ const report = await buildAgentVerifyReport(cwd, {
163
+ changedOnly: boolOrDefault(input.changedOnly, true),
164
+ includeDiagnose: boolOrDefault(input.includeDiagnose, true),
165
+ includeGit: boolOrDefault(input.includeGit, true),
166
+ includeGuard: boolOrDefault(input.includeGuard, true),
167
+ includeContract: boolOrDefault(input.includeContract, true),
168
+ staged: boolOrDefault(input.staged, false),
169
+ base: typeof input.base === "string" && input.base.length > 0 ? input.base : undefined,
170
+ });
171
+
172
+ if (boolOrDefault(input.writeReport, false)) {
173
+ const { path, report: written } = await writeAgentVerifyReport(cwd, report);
174
+ return {
175
+ ...written,
176
+ report: {
177
+ path,
178
+ written: true,
179
+ schemaVersion: written.schemaVersion,
180
+ },
181
+ };
182
+ }
183
+
184
+ return report;
185
+ }
186
+
187
+ async function runAgentRepair(
188
+ projectRoot: string,
189
+ input: AgentRepairInput,
190
+ ) {
191
+ const cwd = resolveCwd(projectRoot, input.cwd);
192
+ const report = await buildAgentRepairReport(cwd, {
193
+ from: typeof input.from === "string" && input.from.length > 0 ? input.from : undefined,
194
+ apply: boolOrDefault(input.apply, false),
195
+ });
196
+
197
+ if (boolOrDefault(input.writeReport, false)) {
198
+ const { path, report: written } = await writeAgentRepairReport(cwd, report);
199
+ return {
200
+ ...written,
201
+ report: {
202
+ path,
203
+ written: true,
204
+ schemaVersion: written.schemaVersion,
205
+ },
206
+ };
207
+ }
208
+
209
+ return report;
210
+ }
211
+
212
+ async function runAgentSync(
213
+ projectRoot: string,
214
+ input: AgentSyncInput,
215
+ ) {
216
+ const cwd = resolveCwd(projectRoot, input.cwd);
217
+ const target =
218
+ input.target === "codex" ||
219
+ input.target === "claude" ||
220
+ input.target === "gemini" ||
221
+ input.target === "all"
222
+ ? input.target
223
+ : "all";
224
+ return buildAgentSyncReport(cwd, {
225
+ target,
226
+ dryRun: boolOrDefault(input.dryRun, false),
227
+ });
228
+ }
229
+
230
+ export const agentToolDefinitions: Tool[] = [
231
+ {
232
+ name: "mandu.agent.context",
233
+ description:
234
+ "Official agent-core entry point. Returns one structured project context for Codex/Claude/Gemini: project metadata, routes/APIs, partials/islands, slots/contracts, guard summary, diagnostics, git state, and the canonical context -> plan -> apply -> verify -> repair workflow.",
235
+ annotations: {
236
+ readOnlyHint: true,
237
+ },
238
+ inputSchema: {
239
+ type: "object",
240
+ properties: {
241
+ cwd: {
242
+ type: "string",
243
+ description: "Project directory to inspect. Defaults to the MCP project root.",
244
+ },
245
+ includeDiagnose: {
246
+ type: "boolean",
247
+ description: "Include diagnose summary and normalized diagnostics. Defaults to true.",
248
+ },
249
+ includeGit: {
250
+ type: "boolean",
251
+ description: "Include git branch and changed-file summary. Defaults to true.",
252
+ },
253
+ writeManifest: {
254
+ type: "boolean",
255
+ description:
256
+ "Write .mandu/agent-manifest.json while building context. Defaults to false.",
257
+ },
258
+ },
259
+ required: [],
260
+ },
261
+ },
262
+ {
263
+ name: "mandu.agent.plan",
264
+ description:
265
+ "Official agent-core planning entry point. Converts a natural-language Mandu task into a conservative domain plan with files to inspect, files likely to create, preferred MCP/domain tools, risks, and verification commands.",
266
+ annotations: {
267
+ readOnlyHint: true,
268
+ },
269
+ inputSchema: {
270
+ type: "object",
271
+ properties: {
272
+ cwd: {
273
+ type: "string",
274
+ description: "Project directory to plan against. Defaults to the MCP project root.",
275
+ },
276
+ intent: {
277
+ type: "string",
278
+ description: "Natural-language task request, for example: add authenticated dashboard.",
279
+ },
280
+ writePlan: {
281
+ type: "boolean",
282
+ description: "Write .mandu/agent-plan.json while planning. Defaults to false.",
283
+ },
284
+ },
285
+ required: ["intent"],
286
+ },
287
+ },
288
+ {
289
+ name: "mandu.agent.apply",
290
+ description:
291
+ "Official agent-core apply preview. Reads an agent plan and returns ordered intent-level actions. This initial implementation is dry-run only and does not mutate project files.",
292
+ annotations: {
293
+ readOnlyHint: true,
294
+ },
295
+ inputSchema: {
296
+ type: "object",
297
+ properties: {
298
+ cwd: {
299
+ type: "string",
300
+ description: "Project directory. Defaults to the MCP project root.",
301
+ },
302
+ from: {
303
+ type: "string",
304
+ description: "Plan path relative to cwd. Defaults to .mandu/agent-plan.json.",
305
+ },
306
+ dryRun: {
307
+ type: "boolean",
308
+ description: "Return a dry-run action report. Defaults to true.",
309
+ },
310
+ writeReport: {
311
+ type: "boolean",
312
+ description: "Write .mandu/agent-apply.json. Defaults to false.",
313
+ },
314
+ },
315
+ required: [],
316
+ },
317
+ },
318
+ {
319
+ name: "mandu.agent.verify",
320
+ description:
321
+ "Official agent-core verification entry point. Returns one structured report that combines changed files, diagnose, route manifest, guard, contract consistency, normalized diagnostics, and suggested follow-up commands.",
322
+ annotations: {
323
+ readOnlyHint: true,
324
+ },
325
+ inputSchema: {
326
+ type: "object",
327
+ properties: {
328
+ cwd: {
329
+ type: "string",
330
+ description: "Project directory to verify. Defaults to the MCP project root.",
331
+ },
332
+ changedOnly: {
333
+ type: "boolean",
334
+ description: "Filter guard/contract findings to changed files when git data exists. Defaults to true.",
335
+ },
336
+ includeDiagnose: {
337
+ type: "boolean",
338
+ description: "Run diagnose and include normalized diagnose diagnostics. Defaults to true.",
339
+ },
340
+ includeGit: {
341
+ type: "boolean",
342
+ description: "Collect git changed files. Defaults to true.",
343
+ },
344
+ includeGuard: {
345
+ type: "boolean",
346
+ description: "Run architecture guard if the routes manifest is available. Defaults to true.",
347
+ },
348
+ includeContract: {
349
+ type: "boolean",
350
+ description: "Run contract/slot consistency checks if the routes manifest is available. Defaults to true.",
351
+ },
352
+ staged: {
353
+ type: "boolean",
354
+ description: "Use staged changes only. Defaults to false.",
355
+ },
356
+ base: {
357
+ type: "string",
358
+ description: "Optional git base ref for changed-file detection.",
359
+ },
360
+ writeReport: {
361
+ type: "boolean",
362
+ description: "Write .mandu/agent-verify.json while verifying. Defaults to false.",
363
+ },
364
+ },
365
+ required: [],
366
+ },
367
+ },
368
+ {
369
+ name: "mandu.agent.repair",
370
+ description:
371
+ "Official agent-core repair entry point. Reads an agent verify report and returns structured next actions. It does not execute shell commands; apply mode only handles safe typed patch candidates.",
372
+ annotations: {
373
+ readOnlyHint: false,
374
+ },
375
+ inputSchema: {
376
+ type: "object",
377
+ properties: {
378
+ cwd: {
379
+ type: "string",
380
+ description: "Project directory. Defaults to the MCP project root.",
381
+ },
382
+ from: {
383
+ type: "string",
384
+ description: "Verify report path relative to cwd. Defaults to .mandu/agent-verify.json.",
385
+ },
386
+ apply: {
387
+ type: "boolean",
388
+ description: "Apply safe typed patch candidates only. Defaults to false.",
389
+ },
390
+ writeReport: {
391
+ type: "boolean",
392
+ description: "Write .mandu/agent-repair.json. Defaults to false.",
393
+ },
394
+ },
395
+ required: [],
396
+ },
397
+ },
398
+ {
399
+ name: "mandu.agent.sync",
400
+ description:
401
+ "Official agent sync helper. Writes or previews Codex, Claude Code, and Gemini CLI workflow artifacts under .mandu/agent-sync so each agent follows the same Mandu agent loop and MCP profile guidance.",
402
+ annotations: {
403
+ readOnlyHint: false,
404
+ },
405
+ inputSchema: {
406
+ type: "object",
407
+ properties: {
408
+ cwd: {
409
+ type: "string",
410
+ description: "Project directory. Defaults to the MCP project root.",
411
+ },
412
+ target: {
413
+ type: "string",
414
+ enum: ["codex", "claude", "gemini", "all"],
415
+ description: "Agent target to sync. Defaults to all.",
416
+ },
417
+ dryRun: {
418
+ type: "boolean",
419
+ description: "Preview files without writing. Defaults to false.",
420
+ },
421
+ },
422
+ required: [],
423
+ },
424
+ },
425
+ ];
426
+
427
+ export function agentTools(projectRoot: string) {
428
+ const handlers: Record<string, (args: Record<string, unknown>) => Promise<unknown>> = {
429
+ "mandu.agent.context": async (args) =>
430
+ runAgentContext(projectRoot, args as AgentContextInput),
431
+ "mandu.agent.plan": async (args) =>
432
+ runAgentPlan(projectRoot, args as AgentPlanInput),
433
+ "mandu.agent.apply": async (args) =>
434
+ runAgentApply(projectRoot, args as AgentApplyInput),
435
+ "mandu.agent.verify": async (args) =>
436
+ runAgentVerify(projectRoot, args as AgentVerifyInput),
437
+ "mandu.agent.repair": async (args) =>
438
+ runAgentRepair(projectRoot, args as AgentRepairInput),
439
+ "mandu.agent.sync": async (args) =>
440
+ runAgentSync(projectRoot, args as AgentSyncInput),
441
+ };
442
+ return handlers;
443
+ }