get_design_context
Retrieve the resolved design system context to inspect tokens, components, and conflicts. Use this first to understand existing design rules before building UI.
Instructions
Get the resolved design system context before building UI. Read-only, no side effects. Default (no category) returns a JSON summary of token counts, component names, conflict counts, and contract metadata. Pass category: 'all' | 'tokens' | 'components' | 'conflicts' to get full detail. Pass tokenCategory to filter tokens: colors, spacing, typography, borderRadius, shadows. Use this as the first call to understand what exists. For lookups by name, use get_token or get_component instead.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| category | Yes | ||
| tokenCategory | Yes |
Implementation Reference
- src/mcp/server.ts:134-204 (handler)The main handler function for the 'get_design_context' tool. It reads the contract and returns design context based on category: 'summary' (default, returns token counts, component names, conflicts), 'all', 'tokens', 'components', or 'conflicts'. Also supports filtering tokens by tokenCategory.
async (args) => { if (!this.contract) return this.noContract() const category = args.category || "summary" if (category === "summary") { const tokenCounts: Record<string, number> = {} for (const [cat, tokens] of Object.entries(this.contract.tokens)) { tokenCounts[cat] = Object.keys(tokens).length } const ageMs = Date.now() - new Date(this.contract.generatedAt).getTime() const contractAgeHours = Math.floor(ageMs / (1000 * 60 * 60)) const warnings = this.getContractWarnings() return this.json({ ...(warnings.length > 0 ? { warnings } : {}), sourceRoot: this.contract.sourceRoot ?? "(unknown — rebuild with latest primitiv)", generatedAt: this.contract.generatedAt, contractAgeHours, sources: this.contract.sources, tokenCounts, componentNames: Object.keys(this.contract.components), componentCount: Object.keys(this.contract.components).length, conflictCount: this.contract.conflicts.length, pendingConflicts: this.contract.conflicts.filter((c) => c.resolution === "pending").length }) } const stripSource = ( tokens: Record<string, { name: string; value: string; references?: string[]; rationale?: Rationale }> ) => Object.fromEntries( Object.entries(tokens).map(([k, t]) => [ k, { name: t.name, value: t.value, ...(t.references ? { references: t.references } : {}), ...(t.rationale ? { rationale: t.rationale } : {}) } ]) ) const result: Record<string, unknown> = {} if (category === "all" || category === "tokens") { result.tokens = args.tokenCategory ? { [args.tokenCategory]: stripSource(this.contract.tokens[args.tokenCategory] || {}) } : Object.fromEntries( Object.entries(this.contract.tokens).map(([cat, tokens]) => [cat, stripSource(tokens)]) ) } if (category === "all" || category === "components") { result.components = Object.fromEntries( Object.entries(this.contract.components).map(([k, c]) => [ k, { name: c.name, source: c.source, propCount: Object.keys(c.props ?? {}).length, ...(c.rationale ? { rationale: c.rationale } : {}) } ]) ) } if (category === "all" || category === "conflicts") { result.conflicts = this.contract.conflicts result.conflictCount = this.contract.conflicts.length result.pendingConflicts = this.contract.conflicts.filter((c) => c.resolution === "pending").length } result.generatedAt = this.contract.generatedAt result.sources = this.contract.sources return this.json(result) } - src/mcp/server.ts:123-205 (registration)The registerTools method registers 'get_design_context' (and other tools) via this.server.registerTool(). The registration includes the name 'get_design_context', description, inputSchema, and the async handler callback.
private registerTools(): void { this.server.registerTool( "get_design_context", { description: "Get the resolved design system context before building UI. Read-only, no side effects. Default (no category) returns a JSON summary of token counts, component names, conflict counts, and contract metadata. Pass category: 'all' | 'tokens' | 'components' | 'conflicts' to get full detail. Pass tokenCategory to filter tokens: colors, spacing, typography, borderRadius, shadows. Use this as the first call to understand what exists. For lookups by name, use get_token or get_component instead.", inputSchema: { category: z.string(), tokenCategory: z.string() } }, async (args) => { if (!this.contract) return this.noContract() const category = args.category || "summary" if (category === "summary") { const tokenCounts: Record<string, number> = {} for (const [cat, tokens] of Object.entries(this.contract.tokens)) { tokenCounts[cat] = Object.keys(tokens).length } const ageMs = Date.now() - new Date(this.contract.generatedAt).getTime() const contractAgeHours = Math.floor(ageMs / (1000 * 60 * 60)) const warnings = this.getContractWarnings() return this.json({ ...(warnings.length > 0 ? { warnings } : {}), sourceRoot: this.contract.sourceRoot ?? "(unknown — rebuild with latest primitiv)", generatedAt: this.contract.generatedAt, contractAgeHours, sources: this.contract.sources, tokenCounts, componentNames: Object.keys(this.contract.components), componentCount: Object.keys(this.contract.components).length, conflictCount: this.contract.conflicts.length, pendingConflicts: this.contract.conflicts.filter((c) => c.resolution === "pending").length }) } const stripSource = ( tokens: Record<string, { name: string; value: string; references?: string[]; rationale?: Rationale }> ) => Object.fromEntries( Object.entries(tokens).map(([k, t]) => [ k, { name: t.name, value: t.value, ...(t.references ? { references: t.references } : {}), ...(t.rationale ? { rationale: t.rationale } : {}) } ]) ) const result: Record<string, unknown> = {} if (category === "all" || category === "tokens") { result.tokens = args.tokenCategory ? { [args.tokenCategory]: stripSource(this.contract.tokens[args.tokenCategory] || {}) } : Object.fromEntries( Object.entries(this.contract.tokens).map(([cat, tokens]) => [cat, stripSource(tokens)]) ) } if (category === "all" || category === "components") { result.components = Object.fromEntries( Object.entries(this.contract.components).map(([k, c]) => [ k, { name: c.name, source: c.source, propCount: Object.keys(c.props ?? {}).length, ...(c.rationale ? { rationale: c.rationale } : {}) } ]) ) } if (category === "all" || category === "conflicts") { result.conflicts = this.contract.conflicts result.conflictCount = this.contract.conflicts.length result.pendingConflicts = this.contract.conflicts.filter((c) => c.resolution === "pending").length } result.generatedAt = this.contract.generatedAt result.sources = this.contract.sources return this.json(result) } ) - src/mcp/server.ts:129-132 (schema)Input schema for the tool: accepts 'category' (string) and 'tokenCategory' (string), both using zod validation.
inputSchema: { category: z.string(), tokenCategory: z.string() } - src/mcp/server.ts:134-157 (helper)The 'summary' branch of the handler calls getContractWarnings() (line 145) to check for stale contracts and mismatches, and uses helper methods like this.json() and this.err() for formatting responses.
async (args) => { if (!this.contract) return this.noContract() const category = args.category || "summary" if (category === "summary") { const tokenCounts: Record<string, number> = {} for (const [cat, tokens] of Object.entries(this.contract.tokens)) { tokenCounts[cat] = Object.keys(tokens).length } const ageMs = Date.now() - new Date(this.contract.generatedAt).getTime() const contractAgeHours = Math.floor(ageMs / (1000 * 60 * 60)) const warnings = this.getContractWarnings() return this.json({ ...(warnings.length > 0 ? { warnings } : {}), sourceRoot: this.contract.sourceRoot ?? "(unknown — rebuild with latest primitiv)", generatedAt: this.contract.generatedAt, contractAgeHours, sources: this.contract.sources, tokenCounts, componentNames: Object.keys(this.contract.components), componentCount: Object.keys(this.contract.components).length, conflictCount: this.contract.conflicts.length, pendingConflicts: this.contract.conflicts.filter((c) => c.resolution === "pending").length })