Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 1x 1x 1x 1x 1x 5x 5x 1x 1x 1x 1x 1x 11x 11x 11x 3x 3x 8x 8x 8x 11x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 11x 1x 1x 1x 11x | /**
* MCP Resources - Static documentation accessible to MCP consumers
*
* Resources are read-only data that provide context to language models.
* This module exposes worksheet pedagogy documentation.
*/
import fs from 'fs'
import path from 'path'
export interface McpResource {
uri: string
name: string
description: string
mimeType: string
}
export interface McpResourceContent {
uri: string
mimeType: string
text: string
}
/**
* Registry of available resources
* URIs use the format: docs://worksheet/{topic}
*/
const RESOURCE_REGISTRY: McpResource[] = [
{
uri: 'docs://worksheet/regrouping',
name: 'Regrouping (Carrying/Borrowing)',
description:
'What regrouping means pedagogically, and how pAnyStart/pAllStart control problem difficulty',
mimeType: 'text/markdown',
},
{
uri: 'docs://worksheet/scaffolding',
name: 'Scaffolding Options',
description:
'Visual aids on worksheets: carryBoxes, answerBoxes, placeValueColors, tenFrames, and display rule values',
mimeType: 'text/markdown',
},
{
uri: 'docs://worksheet/difficulty-profiles',
name: 'Difficulty Profiles',
description:
'The six preset profiles (beginner → expert), when to use each, and progression philosophy',
mimeType: 'text/markdown',
},
{
uri: 'docs://worksheet/digit-range',
name: 'Digit Range',
description: 'How digitRange.min and digitRange.max affect problem complexity',
mimeType: 'text/markdown',
},
{
uri: 'docs://worksheet/operators',
name: 'Operators (Addition/Subtraction/Mixed)',
description: 'Difference between operators, pedagogical sequence, and scaffolding differences',
mimeType: 'text/markdown',
},
]
/**
* Map URIs to file paths
* Files are stored in docs/mcp/worksheet/
*/
function getFilePath(uri: string): string | null {
const prefix = 'docs://worksheet/'
if (!uri.startsWith(prefix)) {
return null
}
const topic = uri.slice(prefix.length)
// Validate topic to prevent directory traversal
if (!/^[a-z-]+$/.test(topic)) {
return null
}
// Construct path relative to the project root
// In Next.js, process.cwd() is the project root (apps/web)
return path.join(process.cwd(), 'docs', 'mcp', 'worksheet', `${topic}.md`)
}
/**
* List all available resources
*/
export function listResources(): { resources: McpResource[] } {
return { resources: RESOURCE_REGISTRY }
}
/**
* Read a specific resource by URI
*/
export function readResource(uri: string): { contents: McpResourceContent[] } | { error: string } {
// Find resource in registry
const resource = RESOURCE_REGISTRY.find((r) => r.uri === uri)
if (!resource) {
return { error: `Resource not found: ${uri}` }
}
// Get file path
const filePath = getFilePath(uri)
if (!filePath) {
return { error: `Invalid resource URI: ${uri}` }
}
// Read file content
try {
const text = fs.readFileSync(filePath, 'utf-8')
return {
contents: [
{
uri,
mimeType: resource.mimeType,
text,
},
],
}
} catch (err) {
console.error(`Failed to read resource ${uri}:`, err)
return { error: `Failed to read resource: ${uri}` }
}
}
|