autoform-mcp-server 1.6.1 → 1.7.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 CHANGED
@@ -38,13 +38,14 @@ Config file location:
38
38
  - **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
39
39
  - **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
40
40
 
41
- ## Tools (9)
41
+ ## Tools (11)
42
42
 
43
43
  ### PDF Analysis
44
44
  | Tool | Description |
45
45
  |------|-------------|
46
46
  | `autoform_get_pdf_info` | Get page count and dimensions of a PDF |
47
47
  | `autoform_detect_fields` | Detect AcroForm fields in interactive PDFs |
48
+ | `autoform_analyze_static_pdf` | Classify PDF type and suggest field positions for static PDFs |
48
49
 
49
50
  ### Fill Single PDF
50
51
  | Tool | Description |
@@ -55,6 +56,7 @@ Config file location:
55
56
  ### Batch Generation
56
57
  | Tool | Description |
57
58
  |------|-------------|
59
+ | `autoform_fill_batch_acroform` | Generate multiple PDFs from an AcroForm PDF + data array |
58
60
  | `autoform_fill_batch_at_coordinates` | Generate multiple PDFs from one template + data, using coordinates |
59
61
  | `autoform_generate_batch` | Generate multiple PDFs using a saved template + data array |
60
62
 
@@ -65,6 +67,20 @@ Config file location:
65
67
  | `autoform_import_template` | Import a template JSON exported from the AutoForm web app |
66
68
  | `autoform_list_templates` | List all saved templates |
67
69
 
70
+ ### Experimental Parameters (v1.7.0+)
71
+
72
+ All tools accept optional `_session_id` and `_mode` parameters for experimental instrumentation:
73
+
74
+ - `_session_id`: Groups related tool calls in `metrics.jsonl` (format: `<pdf_id>_<mode>_<rep>`)
75
+ - `_mode`: Labels the autonomy mode (`1_manual_web`, `2_hybrid`, `3a_acroform`, `3b_vision`)
76
+
77
+ ### Metrics (v1.7.0+)
78
+
79
+ Every tool call is logged to `~/.autoform-mcp/metrics.jsonl` with:
80
+ - Timestamp, tool name, duration, success/error
81
+ - Per-field details: coordinates (PDF points), text written, field IDs
82
+ - Session and mode labels for experimental analysis
83
+
68
84
  ## Usage Examples
69
85
 
70
86
  ### Fill a certificate (Claude analyzes the PDF visually)
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import { handleGenerateBatch, generateBatchSchema } from './tools/generateBatch.
13
13
  import { handleListTemplates, listTemplatesSchema } from './tools/manageTemplates.js';
14
14
  import { handleImportTemplate, importTemplateSchema } from './tools/importTemplate.js';
15
15
  import { withMetrics } from './services/metricsLogger.js';
16
- const server = new Server({ name: 'autoform', version: '1.6.1' }, { capabilities: { tools: {} } });
16
+ const server = new Server({ name: 'autoform', version: '1.7.0' }, { capabilities: { tools: {} } });
17
17
  // Register all tools
18
18
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
19
19
  tools: [
@@ -78,4 +78,4 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
78
78
  // Start server
79
79
  const transport = new StdioServerTransport();
80
80
  await server.connect(transport);
81
- console.error('[AutoForm MCP] Server v1.6.1 started — 11 tools registered (metrics enabled)');
81
+ console.error('[AutoForm MCP] Server v1.7.0 started — 11 tools registered (metrics enabled)');
@@ -5,13 +5,10 @@ export interface MetricsEvent {
5
5
  success: boolean;
6
6
  error_message?: string;
7
7
  session_id?: string;
8
- input?: Record<string, number | string | boolean>;
8
+ mode?: string;
9
+ input?: Record<string, any>;
9
10
  output?: Record<string, number | string | boolean>;
10
11
  }
11
- /**
12
- * Wrap a tool handler to automatically measure and log metrics.
13
- * The handler's behavior is unchanged; metrics are captured transparently.
14
- */
15
12
  export declare function withMetrics<T>(toolName: string, args: any, handler: (args: any) => Promise<T>): Promise<T>;
16
13
  /**
17
14
  * Generate a new random session ID (not used automatically — exported for future use).
@@ -22,10 +22,6 @@ import * as crypto from 'crypto';
22
22
  const METRICS_DIR = path.join(os.homedir(), '.autoform-mcp');
23
23
  const METRICS_FILE = path.join(METRICS_DIR, 'metrics.jsonl');
24
24
  const METRICS_DISABLED = process.env.AUTOFORM_METRICS_DISABLED === '1';
25
- /**
26
- * Extract structural stats from tool arguments without leaking raw data.
27
- * Only records COUNTS and sizes, never the actual content of fields or user data.
28
- */
29
25
  function summarizeInput(toolName, args) {
30
26
  const summary = {};
31
27
  if (!args || typeof args !== 'object')
@@ -72,8 +68,93 @@ function summarizeInput(toolName, args) {
72
68
  if (typeof args.template_name === 'string') {
73
69
  summary.template_name = args.template_name;
74
70
  }
71
+ // ─── Ítem 1: Exact coordinate logging per field written ───
72
+ // For fill tools, extract detailed per-field info (coordinates + text)
73
+ try {
74
+ if (toolName === 'autoform_fill_at_coordinates' && fields) {
75
+ summary.fields_written = extractFieldsWritten(fields);
76
+ }
77
+ if (toolName === 'autoform_fill_batch_at_coordinates' && fieldDefs && dataRows) {
78
+ // For batch: log fields per row (first row only for brevity, full set in fields_written_all)
79
+ summary.fields_written = extractFieldDefsWritten(fieldDefs, dataRows[0]);
80
+ if (dataRows.length > 1) {
81
+ summary.fields_written_all_rows = dataRows.map((row) => extractFieldDefsWritten(fieldDefs, row));
82
+ }
83
+ }
84
+ if (toolName === 'autoform_fill_batch_acroform' && dataRows) {
85
+ // AcroForm: we know the field names from data_rows keys + optional field_map
86
+ const fieldMap = args.field_map && typeof args.field_map === 'object' ? args.field_map : null;
87
+ summary.fields_written = extractAcroFormFieldsWritten(dataRows[0], fieldMap);
88
+ if (dataRows.length > 1) {
89
+ summary.fields_written_all_rows = dataRows.map((row) => extractAcroFormFieldsWritten(row, fieldMap));
90
+ }
91
+ }
92
+ if (toolName === 'autoform_fill_pdf') {
93
+ // fill_pdf with field_values — AcroForm or template-based
94
+ if (args.field_values && typeof args.field_values === 'object') {
95
+ const fieldMap = args.field_map && typeof args.field_map === 'object' ? args.field_map : null;
96
+ summary.fields_written = extractAcroFormFieldsWritten(args.field_values, fieldMap);
97
+ }
98
+ }
99
+ }
100
+ catch {
101
+ // Never let field extraction break the logger
102
+ }
75
103
  return summary;
76
104
  }
105
+ /** Extract per-field details from fill_at_coordinates fields array */
106
+ function extractFieldsWritten(fields) {
107
+ return fields.map((f) => {
108
+ const detail = {
109
+ text: String(f.text ?? ''),
110
+ x_pt: Number(f.x) || 0,
111
+ y_pt: Number(f.y) || 0,
112
+ page: Number(f.page) || 1,
113
+ coordinate_origin: 'bottom_left'
114
+ };
115
+ if (f.width != null)
116
+ detail.width_pt = Number(f.width);
117
+ if (f.height != null)
118
+ detail.height_pt = Number(f.height);
119
+ if (f.fontSize != null)
120
+ detail.fontSize = Number(f.fontSize);
121
+ return detail;
122
+ });
123
+ }
124
+ /** Extract per-field details from fill_batch_at_coordinates (field_definitions + one data row) */
125
+ function extractFieldDefsWritten(fieldDefs, dataRow) {
126
+ if (!dataRow || typeof dataRow !== 'object')
127
+ return [];
128
+ return fieldDefs.map((fd) => {
129
+ const label = fd.label || '';
130
+ const detail = {
131
+ text: String(dataRow[label] ?? ''),
132
+ x_pt: Number(fd.x) || 0,
133
+ y_pt: Number(fd.y) || 0,
134
+ page: Number(fd.page) || 1,
135
+ coordinate_origin: 'bottom_left',
136
+ semantic_label: label
137
+ };
138
+ if (fd.width != null)
139
+ detail.width_pt = Number(fd.width);
140
+ if (fd.height != null)
141
+ detail.height_pt = Number(fd.height);
142
+ if (fd.fontSize != null)
143
+ detail.fontSize = Number(fd.fontSize);
144
+ return detail;
145
+ });
146
+ }
147
+ /** Extract per-field details from AcroForm fill (field_values object) */
148
+ function extractAcroFormFieldsWritten(fieldValues, fieldMap) {
149
+ if (!fieldValues || typeof fieldValues !== 'object')
150
+ return [];
151
+ return Object.entries(fieldValues).map(([key, value]) => ({
152
+ text: String(value ?? ''),
153
+ coordinates_available: false, // AcroForm positions handled internally by pdf-lib — harness uses field_id matching
154
+ field_id: fieldMap ? (fieldMap[key] || key) : key,
155
+ semantic_label: key
156
+ }));
157
+ }
77
158
  /**
78
159
  * Extract structural stats from the MCP tool response.
79
160
  * Parses the returned JSON text to extract counts (documents_generated, total_fields, etc.).
@@ -175,13 +256,18 @@ function writeEvent(event) {
175
256
  * Wrap a tool handler to automatically measure and log metrics.
176
257
  * The handler's behavior is unchanged; metrics are captured transparently.
177
258
  */
259
+ /** Valid experimental modes for _mode parameter */
260
+ const VALID_MODES = ['1_manual_web', '2_hybrid', '3a_acroform', '3b_vision'];
178
261
  export async function withMetrics(toolName, args, handler) {
179
262
  const startTime = Date.now();
180
263
  const sessionId = typeof args?._session_id === 'string' ? args._session_id : undefined;
181
- // Strip _session_id from args before passing to handler (internal only)
182
- const cleanArgs = args && typeof args === 'object' && '_session_id' in args
183
- ? (() => { const { _session_id, ...rest } = args; return rest; })()
184
- : args;
264
+ const mode = typeof args?._mode === 'string' && VALID_MODES.includes(args._mode) ? args._mode : undefined;
265
+ // Strip _session_id and _mode from args before passing to handler (internal only)
266
+ let cleanArgs = args;
267
+ if (args && typeof args === 'object' && ('_session_id' in args || '_mode' in args)) {
268
+ const { _session_id, _mode, ...rest } = args;
269
+ cleanArgs = rest;
270
+ }
185
271
  let result;
186
272
  let success = true;
187
273
  let errorMessage;
@@ -208,6 +294,7 @@ export async function withMetrics(toolName, args, handler) {
208
294
  success: false,
209
295
  error_message: errorMessage,
210
296
  ...(sessionId ? { session_id: sessionId } : {}),
297
+ ...(mode ? { mode } : {}),
211
298
  input: summarizeInput(toolName, cleanArgs)
212
299
  };
213
300
  writeEvent(event);
@@ -220,6 +307,7 @@ export async function withMetrics(toolName, args, handler) {
220
307
  success,
221
308
  ...(errorMessage ? { error_message: errorMessage } : {}),
222
309
  ...(sessionId ? { session_id: sessionId } : {}),
310
+ ...(mode ? { mode } : {}),
223
311
  input: summarizeInput(toolName, cleanArgs),
224
312
  output: summarizeOutput(result)
225
313
  };
@@ -68,6 +68,25 @@ export declare class PdfTextExtractor {
68
68
  * Each graphic element gets a nearbyLabel from the closest text item.
69
69
  */
70
70
  static extractFullPageInfo(pdfPath: string): Promise<PageFullInfo[]>;
71
+ /**
72
+ * Extract all text items from a PDF with positions converted to top-left origin.
73
+ * Used for post-hoc validation: verify that pdf-lib actually wrote where the MCP said it wrote.
74
+ *
75
+ * Returns items grouped by proximity (consecutive items on the same Y line are merged).
76
+ * Coordinates: PDF points, origin top-left (y=0 at top of page).
77
+ *
78
+ * This is an internal function called by the analysis harness (research/scripts/analyze-experiment.js),
79
+ * NOT exposed as an MCP tool.
80
+ */
81
+ static extractWrittenTextPositions(pdfPath: string): Promise<Array<{
82
+ text: string;
83
+ x: number;
84
+ y: number;
85
+ width: number;
86
+ height: number;
87
+ fontSize: number;
88
+ page: number;
89
+ }>>;
71
90
  /**
72
91
  * Classify a PDF based on extractable text density.
73
92
  * Thresholds are empirical; can be tuned.
@@ -233,6 +233,75 @@ export class PdfTextExtractor {
233
233
  }
234
234
  return results;
235
235
  }
236
+ /**
237
+ * Extract all text items from a PDF with positions converted to top-left origin.
238
+ * Used for post-hoc validation: verify that pdf-lib actually wrote where the MCP said it wrote.
239
+ *
240
+ * Returns items grouped by proximity (consecutive items on the same Y line are merged).
241
+ * Coordinates: PDF points, origin top-left (y=0 at top of page).
242
+ *
243
+ * This is an internal function called by the analysis harness (research/scripts/analyze-experiment.js),
244
+ * NOT exposed as an MCP tool.
245
+ */
246
+ static async extractWrittenTextPositions(pdfPath) {
247
+ const bytes = fs.readFileSync(pdfPath);
248
+ const pdf = await pdfjsLib.getDocument({
249
+ data: new Uint8Array(bytes),
250
+ useSystemFonts: true,
251
+ verbosity: 0
252
+ }).promise;
253
+ const results = [];
254
+ for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
255
+ const page = await pdf.getPage(pageNum);
256
+ const viewport = page.getViewport({ scale: 1 });
257
+ const pageHeight = viewport.height;
258
+ const textContent = await page.getTextContent();
259
+ // Collect raw items with top-left coordinates
260
+ const rawItems = [];
261
+ for (const raw of textContent.items) {
262
+ const text = String(raw.str ?? '');
263
+ if (text === '')
264
+ continue;
265
+ const [, , , scaleY, tx, ty] = raw.transform;
266
+ const fontSize = Math.abs(scaleY);
267
+ const width = Math.abs(raw.width ?? 0);
268
+ const height = Math.abs(raw.height ?? fontSize);
269
+ // Convert from PDF bottom-left to top-left origin
270
+ // ty is the text baseline; subtract height to get the top edge of the text
271
+ const yTopLeft = pageHeight - ty - height;
272
+ rawItems.push({
273
+ text,
274
+ x: tx,
275
+ y: yTopLeft,
276
+ width,
277
+ height,
278
+ fontSize,
279
+ page: pageNum
280
+ });
281
+ }
282
+ // Group consecutive items on the same Y line (within 2pt tolerance)
283
+ // pdfjs-dist fragments text into runs; pdf-lib may write a whole string as one item
284
+ const grouped = [];
285
+ for (const item of rawItems) {
286
+ const last = grouped[grouped.length - 1];
287
+ if (last &&
288
+ last.page === item.page &&
289
+ Math.abs(last.y - item.y) < 2 &&
290
+ Math.abs((last.x + last.width) - item.x) < 5) {
291
+ // Merge: extend text and width
292
+ last.text += item.text;
293
+ last.width = (item.x + item.width) - last.x;
294
+ last.height = Math.max(last.height, item.height);
295
+ last.fontSize = Math.max(last.fontSize, item.fontSize);
296
+ }
297
+ else {
298
+ grouped.push({ ...item });
299
+ }
300
+ }
301
+ results.push(...grouped);
302
+ }
303
+ return results;
304
+ }
236
305
  /**
237
306
  * Classify a PDF based on extractable text density.
238
307
  * Thresholds are empirical; can be tuned.
@@ -8,6 +8,15 @@ export declare const analyzeStaticPdfSchema: {
8
8
  type: string;
9
9
  description: string;
10
10
  };
11
+ _session_id: {
12
+ type: string;
13
+ description: string;
14
+ };
15
+ _mode: {
16
+ type: string;
17
+ enum: string[];
18
+ description: string;
19
+ };
11
20
  };
12
21
  required: string[];
13
22
  };
@@ -42,6 +42,15 @@ Hay algo de texto pero poca densidad. Puede haber campos que NO se detectaron au
42
42
  pdf_path: {
43
43
  type: 'string',
44
44
  description: 'Ruta absoluta al PDF estatico a analizar'
45
+ },
46
+ _session_id: {
47
+ type: 'string',
48
+ description: '(Opcional) ID de sesion experimental para agrupar tool calls en metrics.jsonl.'
49
+ },
50
+ _mode: {
51
+ type: 'string',
52
+ enum: ['1_manual_web', '2_hybrid', '3a_acroform', '3b_vision'],
53
+ description: '(Opcional) Modo de autonomia experimental.'
45
54
  }
46
55
  },
47
56
  required: ['pdf_path']
@@ -8,6 +8,15 @@ export declare const detectFieldsSchema: {
8
8
  type: string;
9
9
  description: string;
10
10
  };
11
+ _session_id: {
12
+ type: string;
13
+ description: string;
14
+ };
15
+ _mode: {
16
+ type: string;
17
+ enum: string[];
18
+ description: string;
19
+ };
11
20
  };
12
21
  required: string[];
13
22
  };
@@ -36,6 +36,15 @@ FLUJO RECOMENDADO PARA MULTIPLES DOCUMENTOS:
36
36
  pdf_path: {
37
37
  type: 'string',
38
38
  description: 'Ruta absoluta al archivo PDF'
39
+ },
40
+ _session_id: {
41
+ type: 'string',
42
+ description: '(Opcional) ID de sesion experimental para agrupar tool calls en metrics.jsonl.'
43
+ },
44
+ _mode: {
45
+ type: 'string',
46
+ enum: ['1_manual_web', '2_hybrid', '3a_acroform', '3b_vision'],
47
+ description: '(Opcional) Modo de autonomia experimental.'
39
48
  }
40
49
  },
41
50
  required: ['pdf_path']
@@ -55,6 +55,15 @@ export declare const fillAtCoordinatesSchema: {
55
55
  type: string;
56
56
  description: string;
57
57
  };
58
+ _session_id: {
59
+ type: string;
60
+ description: string;
61
+ };
62
+ _mode: {
63
+ type: string;
64
+ enum: string[];
65
+ description: string;
66
+ };
58
67
  };
59
68
  required: string[];
60
69
  };
@@ -69,6 +78,15 @@ export declare const getPdfInfoSchema: {
69
78
  type: string;
70
79
  description: string;
71
80
  };
81
+ _session_id: {
82
+ type: string;
83
+ description: string;
84
+ };
85
+ _mode: {
86
+ type: string;
87
+ enum: string[];
88
+ description: string;
89
+ };
72
90
  };
73
91
  required: string[];
74
92
  };
@@ -47,6 +47,15 @@ COORDENADAS: Origen (0,0) = esquina inferior-izquierda. Y aumenta hacia arriba.
47
47
  output_path: {
48
48
  type: 'string',
49
49
  description: '(Opcional) Ruta donde guardar el PDF. Default: ~/.autoform-mcp/output/'
50
+ },
51
+ _session_id: {
52
+ type: 'string',
53
+ description: '(Opcional) ID de sesion experimental para agrupar tool calls en metrics.jsonl. Formato: <pdf_id>_<mode>_<rep>'
54
+ },
55
+ _mode: {
56
+ type: 'string',
57
+ enum: ['1_manual_web', '2_hybrid', '3a_acroform', '3b_vision'],
58
+ description: '(Opcional) Modo de autonomia experimental. Se registra en metrics.jsonl.'
50
59
  }
51
60
  },
52
61
  required: ['pdf_path', 'fields']
@@ -61,6 +70,15 @@ export const getPdfInfoSchema = {
61
70
  pdf_path: {
62
71
  type: 'string',
63
72
  description: 'Ruta absoluta al archivo PDF'
73
+ },
74
+ _session_id: {
75
+ type: 'string',
76
+ description: '(Opcional) ID de sesion experimental para agrupar tool calls en metrics.jsonl.'
77
+ },
78
+ _mode: {
79
+ type: 'string',
80
+ enum: ['1_manual_web', '2_hybrid', '3a_acroform', '3b_vision'],
81
+ description: '(Opcional) Modo de autonomia experimental.'
64
82
  }
65
83
  },
66
84
  required: ['pdf_path']
@@ -33,6 +33,15 @@ export declare const fillBatchAcroFormSchema: {
33
33
  type: string;
34
34
  description: string;
35
35
  };
36
+ _session_id: {
37
+ type: string;
38
+ description: string;
39
+ };
40
+ _mode: {
41
+ type: string;
42
+ enum: string[];
43
+ description: string;
44
+ };
36
45
  };
37
46
  required: string[];
38
47
  };
@@ -51,6 +51,15 @@ VERIFICACION: Si el usuario adjunto el PDF al chat Y dio la ruta, aprovecha la i
51
51
  output_dir: {
52
52
  type: 'string',
53
53
  description: '(Opcional) Directorio de salida. Default: ~/.autoform-mcp/output/'
54
+ },
55
+ _session_id: {
56
+ type: 'string',
57
+ description: '(Opcional) ID de sesion experimental para agrupar tool calls en metrics.jsonl. Formato: <pdf_id>_<mode>_<rep>'
58
+ },
59
+ _mode: {
60
+ type: 'string',
61
+ enum: ['1_manual_web', '2_hybrid', '3a_acroform', '3b_vision'],
62
+ description: '(Opcional) Modo de autonomia experimental. Se registra en metrics.jsonl.'
54
63
  }
55
64
  },
56
65
  required: ['pdf_path', 'data_rows']
@@ -69,6 +69,15 @@ export declare const fillBatchAtCoordinatesSchema: {
69
69
  type: string;
70
70
  description: string;
71
71
  };
72
+ _session_id: {
73
+ type: string;
74
+ description: string;
75
+ };
76
+ _mode: {
77
+ type: string;
78
+ enum: string[];
79
+ description: string;
80
+ };
72
81
  };
73
82
  required: string[];
74
83
  };
@@ -75,6 +75,15 @@ SISTEMA DE COORDENADAS: Origen (0,0) = esquina inferior-izquierda. Y aumenta hac
75
75
  output_dir: {
76
76
  type: 'string',
77
77
  description: '(Opcional) Directorio de salida. Default: ~/.autoform-mcp/output/'
78
+ },
79
+ _session_id: {
80
+ type: 'string',
81
+ description: '(Opcional) ID de sesion experimental para agrupar tool calls en metrics.jsonl. Formato: <pdf_id>_<mode>_<rep>'
82
+ },
83
+ _mode: {
84
+ type: 'string',
85
+ enum: ['1_manual_web', '2_hybrid', '3a_acroform', '3b_vision'],
86
+ description: '(Opcional) Modo de autonomia experimental. Se registra en metrics.jsonl.'
78
87
  }
79
88
  },
80
89
  required: ['pdf_path', 'field_definitions', 'data_rows']
@@ -23,6 +23,15 @@ export declare const fillPdfSchema: {
23
23
  type: string;
24
24
  description: string;
25
25
  };
26
+ _session_id: {
27
+ type: string;
28
+ description: string;
29
+ };
30
+ _mode: {
31
+ type: string;
32
+ enum: string[];
33
+ description: string;
34
+ };
26
35
  };
27
36
  required: string[];
28
37
  };
@@ -34,6 +34,15 @@ DIRECTORIO DE SALIDA: Si no se especifica output_path, guarda en el MISMO direct
34
34
  template_name: {
35
35
  type: 'string',
36
36
  description: '(Opcional) Nombre del template a usar para posicionar los campos. Solo necesario si el PDF no tiene AcroForm.'
37
+ },
38
+ _session_id: {
39
+ type: 'string',
40
+ description: '(Opcional) ID de sesion experimental para agrupar tool calls en metrics.jsonl.'
41
+ },
42
+ _mode: {
43
+ type: 'string',
44
+ enum: ['1_manual_web', '2_hybrid', '3a_acroform', '3b_vision'],
45
+ description: '(Opcional) Modo de autonomia experimental.'
37
46
  }
38
47
  },
39
48
  required: ['pdf_path', 'field_values']
@@ -27,6 +27,15 @@ export declare const generateBatchSchema: {
27
27
  type: string;
28
28
  description: string;
29
29
  };
30
+ _session_id: {
31
+ type: string;
32
+ description: string;
33
+ };
34
+ _mode: {
35
+ type: string;
36
+ enum: string[];
37
+ description: string;
38
+ };
30
39
  };
31
40
  required: string[];
32
41
  };
@@ -35,6 +35,15 @@ Modos de distribucion:
35
35
  merge_into_single: {
36
36
  type: 'boolean',
37
37
  description: 'Si es true, une todos los PDFs en uno solo. Default: false.'
38
+ },
39
+ _session_id: {
40
+ type: 'string',
41
+ description: '(Opcional) ID de sesion experimental para agrupar tool calls en metrics.jsonl.'
42
+ },
43
+ _mode: {
44
+ type: 'string',
45
+ enum: ['1_manual_web', '2_hybrid', '3a_acroform', '3b_vision'],
46
+ description: '(Opcional) Modo de autonomia experimental.'
38
47
  }
39
48
  },
40
49
  required: ['template_name', 'data']
@@ -8,6 +8,15 @@ export declare const importTemplateSchema: {
8
8
  type: string;
9
9
  description: string;
10
10
  };
11
+ _session_id: {
12
+ type: string;
13
+ description: string;
14
+ };
15
+ _mode: {
16
+ type: string;
17
+ enum: string[];
18
+ description: string;
19
+ };
11
20
  };
12
21
  required: string[];
13
22
  };
@@ -11,6 +11,15 @@ ALTERNATIVA: Si no usas la app web, usa autoform_save_coordinates_as_template pa
11
11
  json_file_path: {
12
12
  type: 'string',
13
13
  description: 'Ruta absoluta al archivo JSON exportado desde la app web de AutoForm'
14
+ },
15
+ _session_id: {
16
+ type: 'string',
17
+ description: '(Opcional) ID de sesion experimental para agrupar tool calls en metrics.jsonl.'
18
+ },
19
+ _mode: {
20
+ type: 'string',
21
+ enum: ['1_manual_web', '2_hybrid', '3a_acroform', '3b_vision'],
22
+ description: '(Opcional) Modo de autonomia experimental.'
14
23
  }
15
24
  },
16
25
  required: ['json_file_path']
@@ -3,8 +3,18 @@ export declare const listTemplatesSchema: {
3
3
  description: string;
4
4
  inputSchema: {
5
5
  type: "object";
6
- properties: {};
7
- required: never[];
6
+ properties: {
7
+ _session_id: {
8
+ type: string;
9
+ description: string;
10
+ };
11
+ _mode: {
12
+ type: string;
13
+ enum: string[];
14
+ description: string;
15
+ };
16
+ };
17
+ required: string[];
8
18
  };
9
19
  };
10
20
  export declare function handleListTemplates(): Promise<{
@@ -6,7 +6,17 @@ export const listTemplatesSchema = {
6
6
  CUANDO USAR: Antes de autoform_generate_batch para verificar que el template existe y ver sus columnas requeridas.`,
7
7
  inputSchema: {
8
8
  type: 'object',
9
- properties: {},
9
+ properties: {
10
+ _session_id: {
11
+ type: 'string',
12
+ description: '(Opcional) ID de sesion experimental para agrupar tool calls en metrics.jsonl.'
13
+ },
14
+ _mode: {
15
+ type: 'string',
16
+ enum: ['1_manual_web', '2_hybrid', '3a_acroform', '3b_vision'],
17
+ description: '(Opcional) Modo de autonomia experimental.'
18
+ }
19
+ },
10
20
  required: []
11
21
  }
12
22
  };
@@ -59,6 +59,15 @@ export declare const saveCoordinatesAsTemplateSchema: {
59
59
  required: string[];
60
60
  };
61
61
  };
62
+ _session_id: {
63
+ type: string;
64
+ description: string;
65
+ };
66
+ _mode: {
67
+ type: string;
68
+ enum: string[];
69
+ description: string;
70
+ };
62
71
  };
63
72
  required: string[];
64
73
  };
@@ -45,6 +45,15 @@ FLUJO TIPICO:
45
45
  },
46
46
  required: ['label', 'page', 'x', 'y', 'width', 'height']
47
47
  }
48
+ },
49
+ _session_id: {
50
+ type: 'string',
51
+ description: '(Opcional) ID de sesion experimental para agrupar tool calls en metrics.jsonl.'
52
+ },
53
+ _mode: {
54
+ type: 'string',
55
+ enum: ['1_manual_web', '2_hybrid', '3a_acroform', '3b_vision'],
56
+ description: '(Opcional) Modo de autonomia experimental.'
48
57
  }
49
58
  },
50
59
  required: ['pdf_path', 'template_name', 'fields']
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autoform-mcp-server",
3
- "version": "1.6.1",
3
+ "version": "1.7.0",
4
4
  "description": "MCP server for bulk PDF form filling. Detect fields, fill templates, and generate hundreds of PDFs from data — directly from Claude.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",