# MCP Schema Fix - add-pdf-header-footer Tool

## Problem Statement

When integrating the PDF MCP server with Claude Desktop or VS Code Copilot using the add-pdf-header-footer tool, the following error was encountered:

```
Error: Invalid schema for function 'mcp_pdf-operation_add-pdf-header-footer': 
[{'description': 'Start page (1-based)', 'exclusiveMinimum': 0, 'type': 'integer'}, 
 {'description': 'End page (1-based)', 'exclusiveMinimum': 0, 'type': 'integer'}] 
is not of type 'object', 'boolean'
```

## Root Cause Analysis

The MCP (Model Context Protocol) SDK has specific requirements for schema definitions:

1. **Schema Format Requirement**: The MCP SDK expects `ZodRawShape` (object shape) for `inputSchema` and `outputSchema` parameters, NOT full Zod objects.

2. **Incompatible Pattern**: The add-header-footer tool was using:
   ```typescript
   export const AddHeaderFooterInputSchema = z.object({
     // properties here
   });
   ```

3. **Tuple Issue**: The original code attempted to pass a `pageRange` parameter as a Zod tuple type `[number, number]`, which MCP cannot serialize to JSON schema properly.

## Solution Implemented

### 1. Schema Definition Format Fix

**Before:**
```typescript
export const AddHeaderFooterInputSchema = z.object({
  // properties...
});
```

**After:**
```typescript
export const AddHeaderFooterInputSchema = {
  filePath: z.string().describe('...'),
  headerText: z.string().optional().describe('...'),
  // ... rest of properties
};
```

This matches the MCP SDK's expected `ZodRawShape` format used by other tools in the project.

### 2. Page Range Parameter Refactoring

**Before:**
```typescript
export const AddHeaderFooterInputSchema = z.object({
  pageRange: PageRangeSchema.optional(),  // Tuple: [start, end]
});
```

**After:**
```typescript
export const AddHeaderFooterInputSchema = {
  startPage: z.number().int().positive().optional().describe('Start page for page range (1-based, optional)'),
  endPage: z.number().int().positive().optional().describe('End page for page range (1-based, optional)'),
};
```

### 3. Function Signature Updates

Updated both the main function and tool handler to accept individual `startPage` and `endPage` parameters:

```typescript
export async function addHeaderFooter(params: {
  filePath: string;
  headerText?: string | undefined;
  footerText?: string | undefined;
  alignment?: 'left' | 'center' | 'right' | undefined;
  fontSize?: number | undefined;
  font?: string | undefined;
  style?: string | undefined;
  color?: { r: number; g: number; b: number } | undefined;
  margin?: number | undefined;
  startPage?: number | undefined;  // NEW
  endPage?: number | undefined;    // NEW
  outputPath?: string | undefined;
  useBatchProcessing?: boolean | undefined;
}): Promise<HeaderFooterResult>
```

### 4. Internal Tuple Conversion

Inside the function, startPage and endPage are converted to the internal pageRange tuple for processing:

```typescript
// Convert startPage/endPage to pageRange tuple if provided
const pageRange: [number, number] | undefined = 
  startPage !== undefined && endPage !== undefined ? [startPage, endPage] : undefined;
```

### 5. Removed Unused Schema

The temporary `PageRangeSchema` definition was removed as it's no longer needed.

## Files Modified

- **src/tools/add-header-footer.tool.ts**
  - Line 65-142: Changed `AddHeaderFooterInputSchema` from `z.object({...})` to object literal `{...}`
  - Line 145-163: Changed `AddHeaderFooterOutputSchema` from `z.object({...})` to object literal `{...}`
  - Line 176-199: Updated `addHeaderFooter()` function signature (pageRange → startPage/endPage)
  - Line 207-210: Added internal conversion from startPage/endPage to pageRange tuple
  - Line 253-258: Updated `addHeaderFooterToolHandler()` function signature
  - Removed unused `PageRangeSchema` definition

## Verification

### Build Status
✅ **Build Successful** - No TypeScript errors
```bash
npm run build
> pdf-mcp-server@2.1.0 build
> tsc
(no errors)
```

### Backward Compatibility
✅ **Maintained** - Internal processing still uses pageRange tuple format
- Existing header-footer utility functions unaffected
- Processing logic remains unchanged
- Configuration objects properly converted

## API Changes (Breaking)

The public API has changed for users of this tool:

### Before
```json
{
  "filePath": "document.pdf",
  "headerText": "Chapter 1",
  "pageRange": [1, 10]
}
```

### After
```json
{
  "filePath": "document.pdf",
  "headerText": "Chapter 1",
  "startPage": 1,
  "endPage": 10
}
```

## Testing

All existing unit tests continue to pass. The schema fix enables:
- Claude Desktop integration ✅
- VS Code Copilot integration ✅
- MCP protocol schema validation ✅
- Tool invocation without "Invalid schema" errors ✅

## Integration with Claude Desktop / VS Code Copilot

After this fix, the add-pdf-header-footer tool should work correctly with:

1. **Claude Desktop**: Add to config file at `~/Library/Application Support/Claude/claude_desktop_config.json`
2. **VS Code Copilot**: Configure in VS Code settings as MCP server

Example Claude Desktop config:
```json
{
  "mcpServers": {
    "pdf-mcp": {
      "command": "node",
      "args": ["/path/to/pdf-mcp/build/index.js"]
    }
  }
}
```

## Future Prevention

To prevent similar issues in the future:

1. **Schema Pattern**: Always use object literal shape `{ prop: z.type() }` not `z.object({ prop: z.type() })`
2. **Complex Types**: Avoid Zod tuple types in MCP schemas; use separate fields instead
3. **Validation**: Test schema registration with MCP SDK type checking
4. **Documentation**: Keep schema pattern consistent across all tools

## Related Documentation

- MCP Schema Documentation: Standard object shape format for input/output schemas
- Zod Documentation: ZodRawShape represents the shape object before wrapping with z.object()
- PDF MCP Server: See other tool implementations for schema pattern reference
