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 featuresMDC 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.
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
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 UsageScope 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 .vdk/rules/react-patterns.md \
--output .cursor/rules/react-patterns.mdc
# Convert entire directory
vdk blueprints convert \
--from markdown \
--to mdc \
--input .vdk/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 .vdk/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