MDC Format
Cursor's enhanced rule format combining Markdown with XML-like directives
MDC Format Blueprint
MDC (Markdown with Directives) is Cursor's enhanced rule format that combines standard Markdown with XML-like directives for richer AI context and interactive features.
Format Specification
Basic Structure
---
title: "Rule Title"
description: "Brief description"
version: "2.0.1"
schema: "cursor-mdc-v1"
tags: ["tag1", "tag2"]
---
# Rule Title
```xml
<cursor:context>
High-level project context and overview
</cursor:context>
Standard Markdown Content
<cursor:patterns>
Code patterns and examples
</cursor:patterns>
<cursor:rules>
- Specific coding rules
- Guidelines and conventions
</cursor:rules>
YAML Frontmatter Schema
# Required fields
title: string # Rule title
description: string # Brief description
version: string # Semantic version
schema: "cursor-mdc-v1" # MDC schema version
# Standard fields (inherited from Markdown)
tags: array<string> # Technology tags
created: string # ISO 8601 timestamp
updated: string # ISO 8601 timestamp
# MDC-specific fields
priority: number # Rule priority (1-10)
scope: array<string> # File patterns where rule applies
enableDirectives: boolean # Enable/disable directive processing
validateOnSave: boolean # Validate when file is saved
# Cursor-specific fields
cursor:
version: string # Minimum Cursor version
features: array<string> # Required Cursor features
experimental: boolean # Uses experimental features
MDC Directives
Core Directives
<cursor:context>
Provides high-level project context for the AI assistant.
<cursor:context>
This is a Next.js 15 e-commerce application using TypeScript, Tailwind CSS, and Prisma.
The project follows a feature-based architecture with server components as the default
pattern and client components only for interactive features.
Key architectural decisions:
- App Router for file-based routing
- Server actions for form handling
- Zustand for client-side state management
- React Query for server state
</cursor:context>
Best Practices:
- Keep context concise but comprehensive
- Include architectural decisions and reasoning
- Mention key technologies and patterns
- Explain project-specific conventions
<cursor:patterns>
Defines coding patterns with examples.
API Route Pattern
All API routes follow this error handling pattern:
// app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
const createUserSchema = z.object({
name: z.string().min(1),
email: z.string().email()
});
export async function POST(request: NextRequest) {
try {
const body = await request.json();
const data = createUserSchema.parse(body);
const user = await createUser(data);
return NextResponse.json(user, { status: 201 });
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: 'Validation failed', details: error.errors },
{ status: 400 }
);
}
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}
Component Pattern
React components follow this structure:
interface ComponentProps {
// Props with JSDoc comments
/** User data object */
user: User;
/** Optional edit handler */
onEdit?: (user: User) => void;
}
export default function UserCard({ user, onEdit }: ComponentProps) {
return (
<div className="p-4 border rounded-lg">
<h3 className="font-semibold">{user.name}</h3>
<p className="text-gray-600">{user.email}</p>
{onEdit && (
<button
onClick={() => onEdit(user)}
className="mt-2 px-3 py-1 bg-blue-500 text-white rounded"
>
Edit
</button>
)}
</div>
);
}
Best Practices:
- Include complete, working examples
- Show the full pattern, not just snippets
- Explain the reasoning behind patterns
- Provide multiple related examples
<cursor:rules>
Specific coding rules and guidelines.
- Always use TypeScript with proper interface definitions
- Prefer server components over client components
- Use
'use client'
directive only when interactivity is required - Include proper error handling in all async operations
- Follow the repository pattern for data access
- Use absolute imports with
@/
prefix - Include JSDoc comments for complex functions
- Implement proper loading and error states
- Use Tailwind utility classes instead of custom CSS
- Follow the established naming conventions (PascalCase for components, camelCase for functions)
**Best Practices:**
- Be specific and actionable
- Order rules by importance
- Use consistent language
- Reference project-specific conventions
#### `<cursor:technologies>`
Technology stack information.
<cursor:technologies>
Frontend:
- Framework: Next.js 15 (App Router)
- Language: TypeScript 5.0+
- Styling: Tailwind CSS v3
- State: Zustand + React Query
- UI Components: Headless UI + Custom
Backend:
- Runtime: Node.js 18+
- Database: PostgreSQL 15
- ORM: Prisma 5.0+
- Authentication: NextAuth.js v4
- API: Next.js Route Handlers
Development:
- Package Manager: pnpm
- Linting: ESLint + Prettier
- Testing: Jest + React Testing Library
- Type Checking: TypeScript strict mode
</cursor:technologies>
Advanced Directives
<cursor:structure>
Project structure and organization.
app/ # Next.js App Router
├── (auth)/ # Authentication routes
│ ├── login/ # Login page
│ └── register/ # Registration page
├── (dashboard)/ # Protected dashboard routes
│ ├── users/ # User management
│ └── settings/ # Settings pages
├── api/ # API routes
│ ├── auth/ # Authentication endpoints
│ └── users/ # User CRUD operations
├── globals.css # Global styles
└── layout.tsx # Root layout
components/ # Reusable components
├── ui/ # Base UI components (Button, Input, etc.)
├── forms/ # Form components
├── layout/ # Layout components (Header, Sidebar)
└── features/ # Feature-specific components
lib/ # Utilities and configurations
├── auth.ts # Authentication configuration
├── db.ts # Database connection
├── utils.ts # Utility functions
└── validations.ts # Zod schemas
types/ # TypeScript type definitions
├── auth.ts # Authentication types
├── user.ts # User-related types
└── api.ts # API response types
<cursor:examples>
Extended examples with explanations.
Complete Feature Example: User Management
1. Database Schema (Prisma)
// prisma/schema.prisma
model User {
id String @id @default(cuid())
name String
email String @unique
avatar String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("users")
}
2. API Route
// app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { createUserSchema } from '@/lib/validations';
import { createUser, getUsers } from '@/lib/db/users';
export async function GET() {
try {
const users = await getUsers();
return NextResponse.json(users);
} catch (error) {
return NextResponse.json(
{ error: 'Failed to fetch users' },
{ status: 500 }
);
}
}
export async function POST(request: NextRequest) {
try {
const body = await request.json();
const data = createUserSchema.parse(body);
const user = await createUser(data);
return NextResponse.json(user, { status: 201 });
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: 'Validation failed', details: error.errors },
{ status: 400 }
);
}
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}
3. Server Component (List)
// app/users/page.tsx
import { getUsers } from '@/lib/db/users';
import { UserCard } from '@/components/features/UserCard';
import { AddUserButton } from '@/components/features/AddUserButton';
export default async function UsersPage() {
const users = await getUsers();
return (
<div className="container mx-auto py-8">
<div className="flex justify-between items-center mb-6">
<h1 className="text-2xl font-bold">Users</h1>
<AddUserButton />
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{users.map(user => (
<UserCard key={user.id} user={user} />
))}
</div>
</div>
);
}
4. Client Component (Interactive)
// components/features/AddUserButton.tsx
'use client'
import { useState } from 'react';
import { Button } from '@/components/ui/Button';
import { Modal } from '@/components/ui/Modal';
import { UserForm } from '@/components/forms/UserForm';
export function AddUserButton() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<Button onClick={() => setIsOpen(true)}>
Add User
</Button>
<Modal isOpen={isOpen} onClose={() => setIsOpen(false)}>
<UserForm
onSuccess={() => setIsOpen(false)}
onCancel={() => setIsOpen(false)}
/>
</Modal>
</>
);
}
MDC Processing
Directive Processing
Cursor processes MDC directives in this order:
- Parse YAML frontmatter - Extract metadata and configuration
- Identify directives - Find all
<cursor:*>
tags in content - Validate syntax - Check directive syntax and nesting
- Extract content - Parse content within directives
- Apply context - Use directive content to enhance AI understanding
Context Hierarchy
Directives create a hierarchy of context for the AI:
Project Context (cursor:context)
├── Technologies (cursor:technologies)
├── Structure (cursor:structure)
├── Patterns (cursor:patterns)
│ ├── Code Examples
│ └── Implementation Details
├── Rules (cursor:rules)
│ ├── Coding Standards
│ └── Best Practices
└── Examples (cursor:examples)
├── Complete Implementations
└── Real-world Usage
Scope Application
MDC rules can be scoped to specific files or directories:
---
scope:
- "app/**/*.tsx" # App Router pages only
- "components/**/*.tsx" # React components only
- "lib/**/*.ts" # Utility functions only
---
When working in scoped files, Cursor gives higher priority to matching rules.
Validation
Schema Validation
MDC files are validated against the schema:
# Validate MDC syntax
vdk validate --format mdc --file .cursor/rules/patterns.mdc
# Validate all MDC files
vdk validate --format mdc --directory .cursor/rules/
# Fix common MDC issues
vdk blueprints fix --format mdc .cursor/rules/
Directive Validation
Common validation rules:
- Proper nesting: Directives cannot be nested
- Valid syntax: XML-like tags must be properly closed
- Content requirements: Some directives require non-empty content
- Schema compliance: Content must match expected schema
Cursor Integration
Cursor validates MDC files automatically:
- On file save (if
validateOnSave: true
) - On project open
- When rules are updated
- Before AI context application
Conversion from Markdown
Automatic Conversion
VDK can convert standard Markdown rules to MDC format:
# Convert single file
vdk blueprints convert \
--from markdown \
--to mdc \
--input .ai/rules/react-patterns.md \
--output .cursor/rules/react-patterns.mdc
# Convert entire directory
vdk blueprints convert \
--from markdown \
--to mdc \
--input .ai/rules/ \
--output .cursor/rules/
Conversion Mapping
Markdown Section | MDC Directive | Notes |
---|---|---|
Project Context | <cursor:context> | High-level overview |
Technology Stack | <cursor:technologies> | Structured tech info |
Code Examples | <cursor:patterns> | Patterns with examples |
Best Practices | <cursor:rules> | Bullet-point rules |
File Structure | <cursor:structure> | Directory layout |
Manual Enhancement
After conversion, enhance with Cursor-specific features:
Before (Markdown):
## Component Pattern
Use TypeScript interfaces for props.
After (MDC):
Component Pattern
Always define TypeScript interfaces for component props:
interface UserCardProps {
user: User;
onEdit?: () => void;
}
export default function UserCard({ user, onEdit }: UserCardProps) {
return <UserCardComponent user={user} onEdit={onEdit} />;
}
Best Practices
Directive Usage
- Use appropriate directives - Choose the right directive for content type
- Keep content focused - Each directive should have a single purpose
- Provide complete examples - Include full, working code examples
- Maintain consistency - Use consistent terminology and patterns
- Update regularly - Keep directives current with project evolution
Content Organization
<!-- Good: Logical flow -->
<cursor:context>
Project overview and key decisions
</cursor:context>
<cursor:technologies>
Tech stack details
</cursor:technologies>
<cursor:patterns>
Implementation patterns with examples
</cursor:patterns>
<cursor:rules>
Specific coding guidelines
</cursor:rules>
<!-- Avoid: Mixed content in single directive -->
<cursor:patterns>
Project uses React and TypeScript.
Use interfaces for props.
Here's an example...
</cursor:patterns>
Performance Optimization
- Limit directive size - Keep individual directives under 5KB
- Use specific scopes - Apply rules only where relevant
- Avoid redundancy - Don't repeat information across directives
- Optimize examples - Include only essential code in examples
- Regular cleanup - Remove outdated or unused rules
Cursor-Specific Features
Real-time Updates
MDC files are monitored for changes:
---
# Enable real-time updates
autoUpdate: true
watchFiles: true
reloadOnChange: true
---
AI Context Enhancement
MDC directives enhance Cursor's AI in specific ways:
cursor:context
→ Provides project understandingcursor:patterns
→ Improves code generationcursor:rules
→ Enforces coding standardscursor:technologies
→ Enables tech-specific suggestionscursor:examples
→ Provides reference implementations
Integration with Cursor Features
- Code completion uses patterns and rules
- Chat context includes project context
- Code generation follows established patterns
- Refactoring suggestions respect project conventions
Migration to Other Formats
To Standard Markdown
# Extract content from MDC directives
vdk blueprints convert \
--from mdc \
--to markdown \
--input .cursor/rules/ \
--output .ai/rules/
To Windsurf XML
# Convert to XML-enhanced format
vdk blueprints convert \
--from mdc \
--to xml \
--input .cursor/rules/ \
--output .windsurf/rules/
Next Steps
- XML-Enhanced Format - Learn about Windsurf's format
- JSON Format - GitHub Copilot's structured format
- Cursor Integration - Complete Cursor setup guide
- Custom Directives - Create custom MDC directives