frame
Draw a decorative box around text with selectable border styles, padding, alignment, and an optional title. Supports single, double, rounded, bold, and ASCII borders.
Instructions
Draw a box/frame around text. Styles: single, double, rounded, bold, ascii.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | Text to frame (supports multi-line) | |
| style | No | Border style | single |
| padding | No | Inner padding (spaces) | |
| align | No | Text alignment | left |
| title | No | Optional title in the top border |
Implementation Reference
- src/frame.ts:33-58 (handler)The core handler function 'frame' that takes text and options (style, padding, align, title) and renders a bordered box around the text. It builds the top border (with optional title), pads and aligns each line, and outputs the bottom border.
export function frame(text: string, options: FrameOptions = {}): string { const { style = 'single', padding = 1, align = 'left', title } = options; const b = BORDERS[style]; const lines = text.split('\n'); const contentWidth = Math.max( ...lines.map((l) => l.length), title ? title.length + 2 : 0, ); const innerWidth = contentWidth + padding * 2; const hBar = b.h.repeat(innerWidth); const topBar = title ? b.h + ` ${title} ` + b.h.repeat(Math.max(0, innerWidth - title.length - 3)) : hBar; const out: string[] = []; out.push(b.tl + topBar + b.tr); for (const line of lines) { const padded = pad(line, contentWidth, align); out.push(b.v + ' '.repeat(padding) + padded + ' '.repeat(padding) + b.v); } out.push(b.bl + hBar + b.br); return out.join('\n'); } - src/frame.ts:26-31 (schema)The FrameOptions interface defining the input schema for the frame function: style (5 border styles), padding, alignment, and optional title.
export interface FrameOptions { style?: FrameStyle; padding?: number; align?: Alignment; title?: string; } - src/frame.ts:1-13 (schema)Type definitions: FrameStyle union type and FRAME_STYLES array listing the 5 border styles (single, double, rounded, bold, ascii).
export type FrameStyle = 'single' | 'double' | 'rounded' | 'bold' | 'ascii'; const BORDERS: Record<FrameStyle, { tl: string; tr: string; bl: string; br: string; h: string; v: string }> = { single: { tl: '┌', tr: '┐', bl: '└', br: '┘', h: '─', v: '│' }, double: { tl: '╔', tr: '╗', bl: '╚', br: '╝', h: '═', v: '║' }, rounded: { tl: '╭', tr: '╮', bl: '╰', br: '╯', h: '─', v: '│' }, bold: { tl: '┏', tr: '┓', bl: '┗', br: '┛', h: '━', v: '┃' }, ascii: { tl: '+', tr: '+', bl: '+', br: '+', h: '-', v: '|' }, }; export const FRAME_STYLES: FrameStyle[] = ['single', 'double', 'rounded', 'bold', 'ascii']; export type Alignment = 'left' | 'center' | 'right'; - src/mcp.ts:162-176 (registration)Tool registration in MCP server via server.tool('frame', ...) with Zod schema validation for text, style, padding, align, and title parameters. The handler calls the imported 'frame' function from frame.ts.
server.tool( 'frame', `Draw a box/frame around text. Styles: ${FRAME_STYLES.join(', ')}.`, { text: z.string().max(2000).describe('Text to frame (supports multi-line)'), style: z.enum(FRAME_STYLES as [string, ...string[]]).default('single').describe('Border style'), padding: z.number().min(0).max(10).default(1).describe('Inner padding (spaces)'), align: z.enum(['left', 'center', 'right']).default('left').describe('Text alignment'), title: z.string().max(50).optional().describe('Optional title in the top border'), }, async ({ text, style, padding, align, title }) => { const result = frame(text, { style: style as any, padding, align: align as any, title }); return { content: [{ type: 'text', text: result }] }; } ); - src/frame.ts:15-24 (helper)Helper function 'pad' used internally to handle left/center/right text alignment within the frame's content area.
function pad(text: string, width: number, align: Alignment): string { const gap = width - text.length; if (gap <= 0) return text; if (align === 'center') { const left = Math.floor(gap / 2); return ' '.repeat(left) + text + ' '.repeat(gap - left); } if (align === 'right') return ' '.repeat(gap) + text; return text + ' '.repeat(gap); }