@formepdf/mcp 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +102 -0
- package/dist/schemas/invoice.d.ts +139 -0
- package/dist/schemas/invoice.js +80 -0
- package/dist/schemas/letter.d.ts +103 -0
- package/dist/schemas/letter.js +65 -0
- package/dist/schemas/receipt.d.ts +80 -0
- package/dist/schemas/receipt.js +52 -0
- package/dist/schemas/report.d.ts +158 -0
- package/dist/schemas/report.js +94 -0
- package/dist/schemas/shipping-label.d.ts +75 -0
- package/dist/schemas/shipping-label.js +47 -0
- package/dist/templates/index.d.ts +10 -0
- package/dist/templates/index.js +47 -0
- package/dist/templates/invoice.d.ts +2 -0
- package/dist/templates/invoice.js +14 -0
- package/dist/templates/letter.d.ts +2 -0
- package/dist/templates/letter.js +5 -0
- package/dist/templates/receipt.d.ts +2 -0
- package/dist/templates/receipt.js +9 -0
- package/dist/templates/report.d.ts +2 -0
- package/dist/templates/report.js +179 -0
- package/dist/templates/shipping-label.d.ts +2 -0
- package/dist/templates/shipping-label.js +5 -0
- package/dist/tools/get-schema.d.ts +6 -0
- package/dist/tools/get-schema.js +15 -0
- package/dist/tools/list-templates.d.ts +5 -0
- package/dist/tools/list-templates.js +8 -0
- package/dist/tools/render-custom.d.ts +4 -0
- package/dist/tools/render-custom.js +70 -0
- package/dist/tools/render-pdf.d.ts +4 -0
- package/dist/tools/render-pdf.js +20 -0
- package/dist/zod-to-json-schema.d.ts +2 -0
- package/dist/zod-to-json-schema.js +84 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# @formepdf/mcp
|
|
2
|
+
|
|
3
|
+
MCP server that lets AI tools generate PDFs. Add one line to your config, then ask Claude, Cursor, or Windsurf to generate invoices, receipts, reports, and more.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
Add to your MCP config:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"mcpServers": {
|
|
12
|
+
"forme": {
|
|
13
|
+
"command": "npx",
|
|
14
|
+
"args": ["@formepdf/mcp"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Restart your AI tool. Done.
|
|
21
|
+
|
|
22
|
+
## What you can say
|
|
23
|
+
|
|
24
|
+
- "Generate an invoice for Acme Corp, 10 hours of consulting at $150/hour"
|
|
25
|
+
- "Create a shipping label from Seattle to NYC, 3 lbs, fragile"
|
|
26
|
+
- "Make a receipt for 2 lattes and a muffin"
|
|
27
|
+
- "Write a business letter to Jane Smith about our partnership proposal"
|
|
28
|
+
- "Create a custom PDF with a big centered title that says Hello World"
|
|
29
|
+
|
|
30
|
+
The agent figures out the data shape from the tool schema. You don't need to know the template fields.
|
|
31
|
+
|
|
32
|
+
## Tools
|
|
33
|
+
|
|
34
|
+
### `list_templates`
|
|
35
|
+
|
|
36
|
+
Returns all available templates with descriptions and field summaries.
|
|
37
|
+
|
|
38
|
+
### `get_template_schema`
|
|
39
|
+
|
|
40
|
+
Returns the full JSON Schema and example data for a specific template. This is how the agent knows what data to construct from your request.
|
|
41
|
+
|
|
42
|
+
### `render_pdf`
|
|
43
|
+
|
|
44
|
+
Renders a built-in template with data and writes the PDF to disk.
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
Input: { template: "invoice", data: { ... }, output: "invoice.pdf" }
|
|
48
|
+
Output: PDF file at the specified path
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### `render_custom_pdf`
|
|
52
|
+
|
|
53
|
+
Renders arbitrary JSX to PDF. The agent writes Forme JSX on the fly, the server transpiles it with esbuild and renders it.
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
Input: { jsx: "<Document><Page>...</Page></Document>", output: "custom.pdf" }
|
|
57
|
+
Output: PDF file at the specified path
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Built-in Templates
|
|
61
|
+
|
|
62
|
+
| Template | Description |
|
|
63
|
+
|----------|-------------|
|
|
64
|
+
| `invoice` | Line items, tax, totals, company/customer info |
|
|
65
|
+
| `receipt` | Payment confirmation, items, total, payment method |
|
|
66
|
+
| `report` | Multi-section document with title, headings, body text |
|
|
67
|
+
| `letter` | Business letter with letterhead, date, recipient, body |
|
|
68
|
+
| `shipping-label` | From/to addresses, weight, 4x6 format |
|
|
69
|
+
|
|
70
|
+
## How it works
|
|
71
|
+
|
|
72
|
+
The MCP server runs locally. PDF rendering happens in-process via Forme's Rust/WASM engine. No network calls, no API keys, no browser. The agent calls the tool, gets a file path back.
|
|
73
|
+
|
|
74
|
+
## Works with
|
|
75
|
+
|
|
76
|
+
- Claude Code
|
|
77
|
+
- Cursor
|
|
78
|
+
- Windsurf
|
|
79
|
+
- Any tool supporting the Model Context Protocol
|
|
80
|
+
|
|
81
|
+
## Links
|
|
82
|
+
|
|
83
|
+
- [Forme](https://github.com/formepdf/forme) -- PDF generation with JSX
|
|
84
|
+
- [Docs](https://docs.formepdf.com)
|
|
85
|
+
- [MCP Specification](https://modelcontextprotocol.io)
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { listTemplates } from './tools/list-templates.js';
|
|
6
|
+
import { getSchema } from './tools/get-schema.js';
|
|
7
|
+
import { renderPdf } from './tools/render-pdf.js';
|
|
8
|
+
import { renderCustom } from './tools/render-custom.js';
|
|
9
|
+
const server = new McpServer({
|
|
10
|
+
name: 'forme',
|
|
11
|
+
version: '0.4.4',
|
|
12
|
+
});
|
|
13
|
+
// ── list_templates ──────────────────────────────────────────────────
|
|
14
|
+
server.tool('list_templates', 'List available built-in PDF templates with descriptions and field summaries', {}, async () => {
|
|
15
|
+
const result = listTemplates();
|
|
16
|
+
return {
|
|
17
|
+
content: [{
|
|
18
|
+
type: 'text',
|
|
19
|
+
text: JSON.stringify(result, null, 2),
|
|
20
|
+
}],
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
// ── get_template_schema ─────────────────────────────────────────────
|
|
24
|
+
server.tool('get_template_schema', 'Get full JSON Schema and example data for a specific template', { template: z.string().describe('Template name (e.g. "invoice", "receipt", "report", "shipping-label", "letter")') }, async ({ template }) => {
|
|
25
|
+
try {
|
|
26
|
+
const result = getSchema(template);
|
|
27
|
+
return {
|
|
28
|
+
content: [{
|
|
29
|
+
type: 'text',
|
|
30
|
+
text: JSON.stringify(result, null, 2),
|
|
31
|
+
}],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
return {
|
|
36
|
+
isError: true,
|
|
37
|
+
content: [{
|
|
38
|
+
type: 'text',
|
|
39
|
+
text: err.message,
|
|
40
|
+
}],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
// ── render_pdf ──────────────────────────────────────────────────────
|
|
45
|
+
server.tool('render_pdf', 'Render a built-in template with data and write PDF to disk', {
|
|
46
|
+
template: z.string().describe('Template name (e.g. "invoice", "receipt", "report", "shipping-label", "letter")'),
|
|
47
|
+
data: z.record(z.unknown()).describe('Template data matching the template schema'),
|
|
48
|
+
output: z.string().optional().describe('Output file path (defaults to ./{template}.pdf)'),
|
|
49
|
+
}, async ({ template, data, output }) => {
|
|
50
|
+
try {
|
|
51
|
+
const result = await renderPdf(template, data, output);
|
|
52
|
+
return {
|
|
53
|
+
content: [{
|
|
54
|
+
type: 'text',
|
|
55
|
+
text: `PDF rendered successfully.\nPath: ${result.path}\nSize: ${(result.size / 1024).toFixed(1)} KB`,
|
|
56
|
+
}],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
return {
|
|
61
|
+
isError: true,
|
|
62
|
+
content: [{
|
|
63
|
+
type: 'text',
|
|
64
|
+
text: `Failed to render PDF: ${err.message}`,
|
|
65
|
+
}],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
// ── render_custom_pdf ───────────────────────────────────────────────
|
|
70
|
+
server.tool('render_custom_pdf', 'Render arbitrary JSX to PDF. Use Forme components: Document, Page, View, Text, Image, Table, Row, Cell, Fixed, Svg, PageBreak, StyleSheet, Font', {
|
|
71
|
+
jsx: z.string().describe('JSX/TSX source code using Forme components (Document, Page, View, Text, etc.)'),
|
|
72
|
+
output: z.string().optional().describe('Output file path (defaults to ./custom.pdf)'),
|
|
73
|
+
}, async ({ jsx, output }) => {
|
|
74
|
+
try {
|
|
75
|
+
const result = await renderCustom(jsx, output);
|
|
76
|
+
return {
|
|
77
|
+
content: [{
|
|
78
|
+
type: 'text',
|
|
79
|
+
text: `PDF rendered successfully.\nPath: ${result.path}\nSize: ${(result.size / 1024).toFixed(1)} KB`,
|
|
80
|
+
}],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
return {
|
|
85
|
+
isError: true,
|
|
86
|
+
content: [{
|
|
87
|
+
type: 'text',
|
|
88
|
+
text: `Failed to render custom PDF: ${err.message}`,
|
|
89
|
+
}],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
// ── Start server ────────────────────────────────────────────────────
|
|
94
|
+
async function main() {
|
|
95
|
+
const transport = new StdioServerTransport();
|
|
96
|
+
await server.connect(transport);
|
|
97
|
+
console.error('Forme MCP server running on stdio');
|
|
98
|
+
}
|
|
99
|
+
main().catch((err) => {
|
|
100
|
+
console.error('Fatal error:', err);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
});
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const invoiceSchema: z.ZodObject<{
|
|
3
|
+
invoiceNumber: z.ZodString;
|
|
4
|
+
date: z.ZodString;
|
|
5
|
+
dueDate: z.ZodString;
|
|
6
|
+
taxRate: z.ZodNumber;
|
|
7
|
+
company: z.ZodObject<{
|
|
8
|
+
name: z.ZodString;
|
|
9
|
+
initials: z.ZodString;
|
|
10
|
+
address: z.ZodString;
|
|
11
|
+
cityStateZip: z.ZodString;
|
|
12
|
+
email: z.ZodString;
|
|
13
|
+
}, "strip", z.ZodTypeAny, {
|
|
14
|
+
name: string;
|
|
15
|
+
initials: string;
|
|
16
|
+
address: string;
|
|
17
|
+
cityStateZip: string;
|
|
18
|
+
email: string;
|
|
19
|
+
}, {
|
|
20
|
+
name: string;
|
|
21
|
+
initials: string;
|
|
22
|
+
address: string;
|
|
23
|
+
cityStateZip: string;
|
|
24
|
+
email: string;
|
|
25
|
+
}>;
|
|
26
|
+
billTo: z.ZodObject<{
|
|
27
|
+
name: z.ZodString;
|
|
28
|
+
company: z.ZodString;
|
|
29
|
+
address: z.ZodString;
|
|
30
|
+
cityStateZip: z.ZodString;
|
|
31
|
+
email: z.ZodString;
|
|
32
|
+
}, "strip", z.ZodTypeAny, {
|
|
33
|
+
name: string;
|
|
34
|
+
address: string;
|
|
35
|
+
cityStateZip: string;
|
|
36
|
+
email: string;
|
|
37
|
+
company: string;
|
|
38
|
+
}, {
|
|
39
|
+
name: string;
|
|
40
|
+
address: string;
|
|
41
|
+
cityStateZip: string;
|
|
42
|
+
email: string;
|
|
43
|
+
company: string;
|
|
44
|
+
}>;
|
|
45
|
+
shipTo: z.ZodObject<{
|
|
46
|
+
name: z.ZodString;
|
|
47
|
+
address: z.ZodString;
|
|
48
|
+
cityStateZip: z.ZodString;
|
|
49
|
+
}, "strip", z.ZodTypeAny, {
|
|
50
|
+
name: string;
|
|
51
|
+
address: string;
|
|
52
|
+
cityStateZip: string;
|
|
53
|
+
}, {
|
|
54
|
+
name: string;
|
|
55
|
+
address: string;
|
|
56
|
+
cityStateZip: string;
|
|
57
|
+
}>;
|
|
58
|
+
items: z.ZodArray<z.ZodObject<{
|
|
59
|
+
description: z.ZodString;
|
|
60
|
+
quantity: z.ZodNumber;
|
|
61
|
+
unitPrice: z.ZodNumber;
|
|
62
|
+
}, "strip", z.ZodTypeAny, {
|
|
63
|
+
description: string;
|
|
64
|
+
quantity: number;
|
|
65
|
+
unitPrice: number;
|
|
66
|
+
}, {
|
|
67
|
+
description: string;
|
|
68
|
+
quantity: number;
|
|
69
|
+
unitPrice: number;
|
|
70
|
+
}>, "many">;
|
|
71
|
+
paymentTerms: z.ZodString;
|
|
72
|
+
notes: z.ZodOptional<z.ZodString>;
|
|
73
|
+
}, "strip", z.ZodTypeAny, {
|
|
74
|
+
invoiceNumber: string;
|
|
75
|
+
date: string;
|
|
76
|
+
dueDate: string;
|
|
77
|
+
taxRate: number;
|
|
78
|
+
company: {
|
|
79
|
+
name: string;
|
|
80
|
+
initials: string;
|
|
81
|
+
address: string;
|
|
82
|
+
cityStateZip: string;
|
|
83
|
+
email: string;
|
|
84
|
+
};
|
|
85
|
+
billTo: {
|
|
86
|
+
name: string;
|
|
87
|
+
address: string;
|
|
88
|
+
cityStateZip: string;
|
|
89
|
+
email: string;
|
|
90
|
+
company: string;
|
|
91
|
+
};
|
|
92
|
+
shipTo: {
|
|
93
|
+
name: string;
|
|
94
|
+
address: string;
|
|
95
|
+
cityStateZip: string;
|
|
96
|
+
};
|
|
97
|
+
items: {
|
|
98
|
+
description: string;
|
|
99
|
+
quantity: number;
|
|
100
|
+
unitPrice: number;
|
|
101
|
+
}[];
|
|
102
|
+
paymentTerms: string;
|
|
103
|
+
notes?: string | undefined;
|
|
104
|
+
}, {
|
|
105
|
+
invoiceNumber: string;
|
|
106
|
+
date: string;
|
|
107
|
+
dueDate: string;
|
|
108
|
+
taxRate: number;
|
|
109
|
+
company: {
|
|
110
|
+
name: string;
|
|
111
|
+
initials: string;
|
|
112
|
+
address: string;
|
|
113
|
+
cityStateZip: string;
|
|
114
|
+
email: string;
|
|
115
|
+
};
|
|
116
|
+
billTo: {
|
|
117
|
+
name: string;
|
|
118
|
+
address: string;
|
|
119
|
+
cityStateZip: string;
|
|
120
|
+
email: string;
|
|
121
|
+
company: string;
|
|
122
|
+
};
|
|
123
|
+
shipTo: {
|
|
124
|
+
name: string;
|
|
125
|
+
address: string;
|
|
126
|
+
cityStateZip: string;
|
|
127
|
+
};
|
|
128
|
+
items: {
|
|
129
|
+
description: string;
|
|
130
|
+
quantity: number;
|
|
131
|
+
unitPrice: number;
|
|
132
|
+
}[];
|
|
133
|
+
paymentTerms: string;
|
|
134
|
+
notes?: string | undefined;
|
|
135
|
+
}>;
|
|
136
|
+
export type InvoiceData = z.infer<typeof invoiceSchema>;
|
|
137
|
+
export declare const invoiceDescription = "Professional invoice with company header, billing/shipping addresses, itemized line items table, tax calculation, and payment terms.";
|
|
138
|
+
export declare const invoiceFields: Record<string, string>;
|
|
139
|
+
export declare const invoiceExample: InvoiceData;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const invoiceSchema = z.object({
|
|
3
|
+
invoiceNumber: z.string().describe('Invoice identifier, e.g. "INV-2026-0142"'),
|
|
4
|
+
date: z.string().describe('Invoice date, e.g. "February 10, 2026"'),
|
|
5
|
+
dueDate: z.string().describe('Payment due date'),
|
|
6
|
+
taxRate: z.number().describe('Tax rate as decimal, e.g. 0.08 for 8%'),
|
|
7
|
+
company: z.object({
|
|
8
|
+
name: z.string(),
|
|
9
|
+
initials: z.string().describe('1-3 letter initials for logo badge'),
|
|
10
|
+
address: z.string(),
|
|
11
|
+
cityStateZip: z.string(),
|
|
12
|
+
email: z.string(),
|
|
13
|
+
}).describe('Your company details'),
|
|
14
|
+
billTo: z.object({
|
|
15
|
+
name: z.string(),
|
|
16
|
+
company: z.string(),
|
|
17
|
+
address: z.string(),
|
|
18
|
+
cityStateZip: z.string(),
|
|
19
|
+
email: z.string(),
|
|
20
|
+
}).describe('Customer billing address'),
|
|
21
|
+
shipTo: z.object({
|
|
22
|
+
name: z.string(),
|
|
23
|
+
address: z.string(),
|
|
24
|
+
cityStateZip: z.string(),
|
|
25
|
+
}).describe('Shipping address'),
|
|
26
|
+
items: z.array(z.object({
|
|
27
|
+
description: z.string(),
|
|
28
|
+
quantity: z.number(),
|
|
29
|
+
unitPrice: z.number(),
|
|
30
|
+
})).describe('Line items'),
|
|
31
|
+
paymentTerms: z.string().describe('Payment terms paragraph'),
|
|
32
|
+
notes: z.string().optional().describe('Optional notes'),
|
|
33
|
+
});
|
|
34
|
+
export const invoiceDescription = 'Professional invoice with company header, billing/shipping addresses, itemized line items table, tax calculation, and payment terms.';
|
|
35
|
+
export const invoiceFields = {
|
|
36
|
+
invoiceNumber: 'string - invoice identifier',
|
|
37
|
+
date: 'string - invoice date',
|
|
38
|
+
dueDate: 'string - payment due date',
|
|
39
|
+
taxRate: 'number - tax rate as decimal (e.g. 0.08)',
|
|
40
|
+
company: 'object - your company name, initials, address, email',
|
|
41
|
+
billTo: 'object - customer name, company, address, email',
|
|
42
|
+
shipTo: 'object - shipping name, address',
|
|
43
|
+
items: 'array - line items with description, quantity, unitPrice',
|
|
44
|
+
paymentTerms: 'string - payment terms text',
|
|
45
|
+
notes: 'string? - optional notes',
|
|
46
|
+
};
|
|
47
|
+
export const invoiceExample = {
|
|
48
|
+
invoiceNumber: 'INV-2026-0142',
|
|
49
|
+
date: 'February 10, 2026',
|
|
50
|
+
dueDate: 'March 12, 2026',
|
|
51
|
+
taxRate: 0.08,
|
|
52
|
+
company: {
|
|
53
|
+
name: 'Northwind Design Co.',
|
|
54
|
+
initials: 'ND',
|
|
55
|
+
address: '1847 Lakewood Boulevard, Suite 300',
|
|
56
|
+
cityStateZip: 'Portland, OR 97205',
|
|
57
|
+
email: 'billing@northwinddesign.co',
|
|
58
|
+
},
|
|
59
|
+
billTo: {
|
|
60
|
+
name: 'Sarah Chen',
|
|
61
|
+
company: 'Meridian Architecture Group',
|
|
62
|
+
address: '520 Market Street, Floor 14',
|
|
63
|
+
cityStateZip: 'San Francisco, CA 94105',
|
|
64
|
+
email: 'sarah.chen@meridianarch.com',
|
|
65
|
+
},
|
|
66
|
+
shipTo: {
|
|
67
|
+
name: 'Meridian Architecture Group',
|
|
68
|
+
address: '520 Market Street, Floor 14',
|
|
69
|
+
cityStateZip: 'San Francisco, CA 94105',
|
|
70
|
+
},
|
|
71
|
+
items: [
|
|
72
|
+
{ description: 'Brand Identity Package - logo design, color palette, typography system', quantity: 1, unitPrice: 4500.00 },
|
|
73
|
+
{ description: 'Website Design - homepage, about, services, contact (desktop + mobile)', quantity: 1, unitPrice: 6200.00 },
|
|
74
|
+
{ description: 'Business Card Design - front and back, print-ready files', quantity: 1, unitPrice: 350.00 },
|
|
75
|
+
{ description: 'Social Media Templates - Instagram, LinkedIn, Twitter (12 templates)', quantity: 12, unitPrice: 125.00 },
|
|
76
|
+
{ description: 'Brand Guidelines Document - 24-page PDF with usage rules', quantity: 1, unitPrice: 1800.00 },
|
|
77
|
+
],
|
|
78
|
+
paymentTerms: 'Net 30. Payment due within 30 days of invoice date. A late fee of 1.5% per month will be applied to overdue balances.',
|
|
79
|
+
notes: 'Thank you for choosing Northwind Design.',
|
|
80
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const letterSchema: z.ZodObject<{
|
|
3
|
+
sender: z.ZodObject<{
|
|
4
|
+
name: z.ZodString;
|
|
5
|
+
title: z.ZodOptional<z.ZodString>;
|
|
6
|
+
company: z.ZodString;
|
|
7
|
+
address: z.ZodString;
|
|
8
|
+
cityStateZip: z.ZodString;
|
|
9
|
+
phone: z.ZodOptional<z.ZodString>;
|
|
10
|
+
email: z.ZodOptional<z.ZodString>;
|
|
11
|
+
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
name: string;
|
|
13
|
+
address: string;
|
|
14
|
+
cityStateZip: string;
|
|
15
|
+
company: string;
|
|
16
|
+
email?: string | undefined;
|
|
17
|
+
title?: string | undefined;
|
|
18
|
+
phone?: string | undefined;
|
|
19
|
+
}, {
|
|
20
|
+
name: string;
|
|
21
|
+
address: string;
|
|
22
|
+
cityStateZip: string;
|
|
23
|
+
company: string;
|
|
24
|
+
email?: string | undefined;
|
|
25
|
+
title?: string | undefined;
|
|
26
|
+
phone?: string | undefined;
|
|
27
|
+
}>;
|
|
28
|
+
date: z.ZodString;
|
|
29
|
+
recipient: z.ZodObject<{
|
|
30
|
+
name: z.ZodString;
|
|
31
|
+
title: z.ZodOptional<z.ZodString>;
|
|
32
|
+
company: z.ZodOptional<z.ZodString>;
|
|
33
|
+
address: z.ZodString;
|
|
34
|
+
cityStateZip: z.ZodString;
|
|
35
|
+
}, "strip", z.ZodTypeAny, {
|
|
36
|
+
name: string;
|
|
37
|
+
address: string;
|
|
38
|
+
cityStateZip: string;
|
|
39
|
+
company?: string | undefined;
|
|
40
|
+
title?: string | undefined;
|
|
41
|
+
}, {
|
|
42
|
+
name: string;
|
|
43
|
+
address: string;
|
|
44
|
+
cityStateZip: string;
|
|
45
|
+
company?: string | undefined;
|
|
46
|
+
title?: string | undefined;
|
|
47
|
+
}>;
|
|
48
|
+
salutation: z.ZodString;
|
|
49
|
+
body: z.ZodArray<z.ZodString, "many">;
|
|
50
|
+
closing: z.ZodString;
|
|
51
|
+
signatureName: z.ZodString;
|
|
52
|
+
signatureTitle: z.ZodOptional<z.ZodString>;
|
|
53
|
+
}, "strip", z.ZodTypeAny, {
|
|
54
|
+
date: string;
|
|
55
|
+
sender: {
|
|
56
|
+
name: string;
|
|
57
|
+
address: string;
|
|
58
|
+
cityStateZip: string;
|
|
59
|
+
company: string;
|
|
60
|
+
email?: string | undefined;
|
|
61
|
+
title?: string | undefined;
|
|
62
|
+
phone?: string | undefined;
|
|
63
|
+
};
|
|
64
|
+
recipient: {
|
|
65
|
+
name: string;
|
|
66
|
+
address: string;
|
|
67
|
+
cityStateZip: string;
|
|
68
|
+
company?: string | undefined;
|
|
69
|
+
title?: string | undefined;
|
|
70
|
+
};
|
|
71
|
+
salutation: string;
|
|
72
|
+
body: string[];
|
|
73
|
+
closing: string;
|
|
74
|
+
signatureName: string;
|
|
75
|
+
signatureTitle?: string | undefined;
|
|
76
|
+
}, {
|
|
77
|
+
date: string;
|
|
78
|
+
sender: {
|
|
79
|
+
name: string;
|
|
80
|
+
address: string;
|
|
81
|
+
cityStateZip: string;
|
|
82
|
+
company: string;
|
|
83
|
+
email?: string | undefined;
|
|
84
|
+
title?: string | undefined;
|
|
85
|
+
phone?: string | undefined;
|
|
86
|
+
};
|
|
87
|
+
recipient: {
|
|
88
|
+
name: string;
|
|
89
|
+
address: string;
|
|
90
|
+
cityStateZip: string;
|
|
91
|
+
company?: string | undefined;
|
|
92
|
+
title?: string | undefined;
|
|
93
|
+
};
|
|
94
|
+
salutation: string;
|
|
95
|
+
body: string[];
|
|
96
|
+
closing: string;
|
|
97
|
+
signatureName: string;
|
|
98
|
+
signatureTitle?: string | undefined;
|
|
99
|
+
}>;
|
|
100
|
+
export type LetterData = z.infer<typeof letterSchema>;
|
|
101
|
+
export declare const letterDescription = "Formal business letter with letterhead, recipient address, body paragraphs, and closing signature.";
|
|
102
|
+
export declare const letterFields: Record<string, string>;
|
|
103
|
+
export declare const letterExample: LetterData;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const letterSchema = z.object({
|
|
3
|
+
sender: z.object({
|
|
4
|
+
name: z.string(),
|
|
5
|
+
title: z.string().optional(),
|
|
6
|
+
company: z.string(),
|
|
7
|
+
address: z.string(),
|
|
8
|
+
cityStateZip: z.string(),
|
|
9
|
+
phone: z.string().optional(),
|
|
10
|
+
email: z.string().optional(),
|
|
11
|
+
}).describe('Sender/letterhead details'),
|
|
12
|
+
date: z.string().describe('Letter date'),
|
|
13
|
+
recipient: z.object({
|
|
14
|
+
name: z.string(),
|
|
15
|
+
title: z.string().optional(),
|
|
16
|
+
company: z.string().optional(),
|
|
17
|
+
address: z.string(),
|
|
18
|
+
cityStateZip: z.string(),
|
|
19
|
+
}).describe('Recipient address'),
|
|
20
|
+
salutation: z.string().describe('Greeting, e.g. "Dear Ms. Chen,"'),
|
|
21
|
+
body: z.array(z.string()).describe('Body paragraphs'),
|
|
22
|
+
closing: z.string().describe('Closing phrase, e.g. "Sincerely,"'),
|
|
23
|
+
signatureName: z.string().describe('Printed name under signature'),
|
|
24
|
+
signatureTitle: z.string().optional().describe('Title under signature'),
|
|
25
|
+
});
|
|
26
|
+
export const letterDescription = 'Formal business letter with letterhead, recipient address, body paragraphs, and closing signature.';
|
|
27
|
+
export const letterFields = {
|
|
28
|
+
sender: 'object - name, title?, company, address, cityStateZip, phone?, email?',
|
|
29
|
+
date: 'string - letter date',
|
|
30
|
+
recipient: 'object - name, title?, company?, address, cityStateZip',
|
|
31
|
+
salutation: 'string - greeting line',
|
|
32
|
+
body: 'array - body paragraphs as strings',
|
|
33
|
+
closing: 'string - closing phrase',
|
|
34
|
+
signatureName: 'string - printed name',
|
|
35
|
+
signatureTitle: 'string? - title under name',
|
|
36
|
+
};
|
|
37
|
+
export const letterExample = {
|
|
38
|
+
sender: {
|
|
39
|
+
name: 'James Mitchell',
|
|
40
|
+
title: 'Director of Partnerships',
|
|
41
|
+
company: 'Northwind Design Co.',
|
|
42
|
+
address: '1847 Lakewood Boulevard, Suite 300',
|
|
43
|
+
cityStateZip: 'Portland, OR 97205',
|
|
44
|
+
phone: '(503) 555-0147',
|
|
45
|
+
email: 'james.mitchell@northwinddesign.co',
|
|
46
|
+
},
|
|
47
|
+
date: 'February 24, 2026',
|
|
48
|
+
recipient: {
|
|
49
|
+
name: 'Sarah Chen',
|
|
50
|
+
title: 'VP of Operations',
|
|
51
|
+
company: 'Meridian Architecture Group',
|
|
52
|
+
address: '520 Market Street, Floor 14',
|
|
53
|
+
cityStateZip: 'San Francisco, CA 94105',
|
|
54
|
+
},
|
|
55
|
+
salutation: 'Dear Ms. Chen,',
|
|
56
|
+
body: [
|
|
57
|
+
'Thank you for our productive meeting last Thursday to discuss the upcoming Meridian rebrand initiative. We are excited about the opportunity to partner with your team on this project.',
|
|
58
|
+
'As discussed, our proposal includes a comprehensive brand identity package, website redesign, and full suite of marketing collateral. The enclosed statement of work outlines the project timeline, deliverables, and investment summary for your review.',
|
|
59
|
+
'We believe our experience with architectural and design firms positions us uniquely to capture the essence of Meridian\'s vision. Our team is prepared to begin discovery sessions as early as next month.',
|
|
60
|
+
'Please don\'t hesitate to reach out if you have any questions. We look forward to hearing from you.',
|
|
61
|
+
],
|
|
62
|
+
closing: 'Sincerely,',
|
|
63
|
+
signatureName: 'James Mitchell',
|
|
64
|
+
signatureTitle: 'Director of Partnerships',
|
|
65
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const receiptSchema: z.ZodObject<{
|
|
3
|
+
receiptNumber: z.ZodString;
|
|
4
|
+
date: z.ZodString;
|
|
5
|
+
taxRate: z.ZodNumber;
|
|
6
|
+
store: z.ZodObject<{
|
|
7
|
+
name: z.ZodString;
|
|
8
|
+
address: z.ZodString;
|
|
9
|
+
cityStateZip: z.ZodString;
|
|
10
|
+
phone: z.ZodString;
|
|
11
|
+
website: z.ZodString;
|
|
12
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
|
+
name: string;
|
|
14
|
+
address: string;
|
|
15
|
+
cityStateZip: string;
|
|
16
|
+
phone: string;
|
|
17
|
+
website: string;
|
|
18
|
+
}, {
|
|
19
|
+
name: string;
|
|
20
|
+
address: string;
|
|
21
|
+
cityStateZip: string;
|
|
22
|
+
phone: string;
|
|
23
|
+
website: string;
|
|
24
|
+
}>;
|
|
25
|
+
items: z.ZodArray<z.ZodObject<{
|
|
26
|
+
name: z.ZodString;
|
|
27
|
+
price: z.ZodNumber;
|
|
28
|
+
quantity: z.ZodOptional<z.ZodNumber>;
|
|
29
|
+
}, "strip", z.ZodTypeAny, {
|
|
30
|
+
name: string;
|
|
31
|
+
price: number;
|
|
32
|
+
quantity?: number | undefined;
|
|
33
|
+
}, {
|
|
34
|
+
name: string;
|
|
35
|
+
price: number;
|
|
36
|
+
quantity?: number | undefined;
|
|
37
|
+
}>, "many">;
|
|
38
|
+
paymentMethod: z.ZodString;
|
|
39
|
+
cardLastFour: z.ZodOptional<z.ZodString>;
|
|
40
|
+
}, "strip", z.ZodTypeAny, {
|
|
41
|
+
date: string;
|
|
42
|
+
taxRate: number;
|
|
43
|
+
items: {
|
|
44
|
+
name: string;
|
|
45
|
+
price: number;
|
|
46
|
+
quantity?: number | undefined;
|
|
47
|
+
}[];
|
|
48
|
+
receiptNumber: string;
|
|
49
|
+
store: {
|
|
50
|
+
name: string;
|
|
51
|
+
address: string;
|
|
52
|
+
cityStateZip: string;
|
|
53
|
+
phone: string;
|
|
54
|
+
website: string;
|
|
55
|
+
};
|
|
56
|
+
paymentMethod: string;
|
|
57
|
+
cardLastFour?: string | undefined;
|
|
58
|
+
}, {
|
|
59
|
+
date: string;
|
|
60
|
+
taxRate: number;
|
|
61
|
+
items: {
|
|
62
|
+
name: string;
|
|
63
|
+
price: number;
|
|
64
|
+
quantity?: number | undefined;
|
|
65
|
+
}[];
|
|
66
|
+
receiptNumber: string;
|
|
67
|
+
store: {
|
|
68
|
+
name: string;
|
|
69
|
+
address: string;
|
|
70
|
+
cityStateZip: string;
|
|
71
|
+
phone: string;
|
|
72
|
+
website: string;
|
|
73
|
+
};
|
|
74
|
+
paymentMethod: string;
|
|
75
|
+
cardLastFour?: string | undefined;
|
|
76
|
+
}>;
|
|
77
|
+
export type ReceiptData = z.infer<typeof receiptSchema>;
|
|
78
|
+
export declare const receiptDescription = "Simple retail receipt with store header, itemized purchases, tax calculation, and payment method.";
|
|
79
|
+
export declare const receiptFields: Record<string, string>;
|
|
80
|
+
export declare const receiptExample: ReceiptData;
|