MCP inspect tool
This commit is contained in:
parent
9f78750105
commit
5e66d6fae1
41
packages/mcp/src/tools/inspect.ts
Normal file
41
packages/mcp/src/tools/inspect.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import type { ComponentRegistry } from "../registry.js";
|
||||||
|
|
||||||
|
interface InspectInput { component: string; }
|
||||||
|
interface InspectResult {
|
||||||
|
name: string; description: string; exportPath: string;
|
||||||
|
parts: readonly string[]; requiredParts: readonly string[];
|
||||||
|
props: Record<string, unknown>; hasStyledVersion: boolean; example: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toKebab(str: string): string {
|
||||||
|
return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateExample(name: string, parts: readonly string[], requiredParts: readonly string[]): string {
|
||||||
|
const lines: string[] = [];
|
||||||
|
lines.push(`import { ${name} } from "pettyui/${toKebab(name)}";`);
|
||||||
|
lines.push("");
|
||||||
|
if (requiredParts.includes("Root") || parts.includes("Root")) {
|
||||||
|
lines.push(`<${name}>`);
|
||||||
|
for (const part of requiredParts) {
|
||||||
|
if (part === "Root") continue;
|
||||||
|
lines.push(` <${name}.${part}>...</${name}.${part}>`);
|
||||||
|
}
|
||||||
|
lines.push(`</${name}>`);
|
||||||
|
} else {
|
||||||
|
lines.push(`<${name} />`);
|
||||||
|
}
|
||||||
|
return lines.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns full component schema, parts, and usage example. */
|
||||||
|
export function handleInspect(registry: ComponentRegistry, input: InspectInput): InspectResult | null {
|
||||||
|
const comp = registry.getComponent(input.component);
|
||||||
|
if (!comp) return null;
|
||||||
|
return {
|
||||||
|
name: comp.meta.name, description: comp.meta.description, exportPath: comp.exportPath,
|
||||||
|
parts: comp.meta.parts, requiredParts: comp.meta.requiredParts,
|
||||||
|
props: comp.jsonSchemas, hasStyledVersion: comp.hasStyledVersion,
|
||||||
|
example: generateExample(comp.meta.name, comp.meta.parts, comp.meta.requiredParts),
|
||||||
|
};
|
||||||
|
}
|
||||||
45
packages/mcp/tests/tools/inspect.test.ts
Normal file
45
packages/mcp/tests/tools/inspect.test.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { describe, it, expect } from "vitest";
|
||||||
|
import { handleInspect } from "../../src/tools/inspect.js";
|
||||||
|
import { ComponentRegistry } from "../../src/registry.js";
|
||||||
|
|
||||||
|
describe("pettyui.inspect", () => {
|
||||||
|
const registry = new ComponentRegistry();
|
||||||
|
|
||||||
|
it("returns full component info", () => {
|
||||||
|
const result = handleInspect(registry, { component: "Dialog" });
|
||||||
|
expect(result).not.toBeNull();
|
||||||
|
expect(result?.name).toBe("Dialog");
|
||||||
|
expect(result?.parts).toContain("Root");
|
||||||
|
expect(result?.parts).toContain("Content");
|
||||||
|
expect(result?.exportPath).toBe("pettyui/dialog");
|
||||||
|
expect(typeof result?.description).toBe("string");
|
||||||
|
expect(result?.description.length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("includes JSON schema for props", () => {
|
||||||
|
const result = handleInspect(registry, { component: "Dialog" });
|
||||||
|
expect(result).not.toBeNull();
|
||||||
|
expect(result?.props).toBeDefined();
|
||||||
|
const dialogRoot = result?.props["dialogRoot"] as { type?: string } | undefined;
|
||||||
|
expect(dialogRoot).toBeDefined();
|
||||||
|
expect(dialogRoot?.type).toBe("object");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("includes minimal example", () => {
|
||||||
|
const result = handleInspect(registry, { component: "Dialog" });
|
||||||
|
expect(result).not.toBeNull();
|
||||||
|
expect(result?.example).toContain("Dialog");
|
||||||
|
expect(result?.example).toContain('from "pettyui/dialog"');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns null for unknown component", () => {
|
||||||
|
const result = handleInspect(registry, { component: "FakeComponent" });
|
||||||
|
expect(result).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("is case-insensitive", () => {
|
||||||
|
const result = handleInspect(registry, { component: "dialog" });
|
||||||
|
expect(result).not.toBeNull();
|
||||||
|
expect(result?.name).toBe("Dialog");
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user