Upload Document
upload_documentUpload a document (PDF, Markdown, or text) to extract text for AI simulations. Returns a document ID used to create simulation scenarios.
Instructions
Upload a document for use in simulations. LIMITS: Max 10MB, PDF/MD/TXT only. The server extracts text server-side (PyMuPDF for PDFs). Returns a document_id to pass to create_simulation. NOTE: Only works with local file paths (stdio transport). For remote/hosted mode, the client skill uploads via HTTP instead.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| file_path | Yes | Absolute path to the file to upload. Supported: PDF, MD, TXT. Max 10MB. Rejects binary files and unsupported formats. |
Implementation Reference
- MCP tool registration and handler for 'upload_document'. Registers with Zod schema (file_path), calls client.uploadDocument(), returns document_id, filename, text_length, mime_type.
export function registerUploadDocument(server: McpServer, client: MirofishClient): void { server.registerTool( "upload_document", { title: "Upload Document", description: "Upload a document for use in simulations. " + "LIMITS: Max 10MB, PDF/MD/TXT only. " + "The server extracts text server-side (PyMuPDF for PDFs). " + "Returns a document_id to pass to create_simulation. " + "NOTE: Only works with local file paths (stdio transport). " + "For remote/hosted mode, the client skill uploads via HTTP instead.", inputSchema, annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }, }, async (args) => { try { const result = await client.uploadDocument(args.file_path); return { content: [ { type: "text" as const, text: JSON.stringify( { document_id: result.document_id, filename: result.filename, text_length: result.text_length, mime_type: result.mime_type, message: `Document uploaded and processed (${result.text_length} characters extracted). Use this document_id with create_simulation.`, }, null, 2, ), }, ], }; } catch (err) { throw toMcpError(err); } }, ); } - Zod input schema for upload_document: requires a single 'file_path' string (absolute path, PDF/MD/TXT, max 10MB).
const inputSchema = { file_path: z .string() .describe("Absolute path to the file to upload. Supported: PDF, MD, TXT. Max 10MB. Rejects binary files and unsupported formats."), }; - mcp-server/src/tools/index.ts:12-12 (registration)Import of registerUploadDocument from uploading-document.ts
import { registerUploadDocument } from "./upload-document.js"; - mcp-server/src/tools/index.ts:23-23 (registration)Registration call: registerUploadDocument(server, client) wired into the tool registry.
registerUploadDocument(server, client); - Client-side uploadDocument() method: reads file from disk, sends multipart/form-data POST to /api/documents/upload, returns DocumentUploadResult.
async uploadDocument(filePath: string): Promise<DocumentUploadResult> { const fs = await import("fs"); const path = await import("path"); const FormData = (await import("form-data")).default; const buffer = fs.readFileSync(filePath); const name = path.basename(filePath); const form = new FormData(); form.append("file", buffer, name); const resp = await this.http.post<MirofishApiResponse<DocumentUploadResult>>( "/api/documents/upload", form, { headers: form.getHeaders(), maxContentLength: Infinity, maxBodyLength: Infinity }, ); if (!resp.data?.success || !resp.data?.data) { throw new MirofishBackendError(resp.data?.error ?? "Upload failed", resp.status); } return resp.data.data; } - TypeScript interface DocumentUploadResult: document_id, filename, text_length, mime_type.
export interface DocumentUploadResult { document_id: string; filename: string; text_length: number; mime_type: string; } - engine/app/api/documents.py:16-67 (handler)Python Flask backend handler for POST /api/documents/upload. Validates file, calls DocumentManager.create_document(), returns JSON with document_id, filename, text_length, mime_type.
@documents_bp.route("/upload", methods=["POST"]) def upload_document(): """ Upload a document for use in simulations. Request: multipart/form-data with a single ``file`` field. Accepts PDF, Markdown, and plain-text files up to 10 MB. Returns:: { "success": true, "data": { "document_id": "doc_a1b2c3d4e5f6", "filename": "report.pdf", "text_length": 20862, "mime_type": "application/pdf" } } """ try: if "file" not in request.files: return jsonify({"success": False, "error": "No file provided"}), 400 file = request.files["file"] if not file.filename: return jsonify({"success": False, "error": "No filename"}), 400 user_id = getattr(g, "user_id", None) doc = DocumentManager.create_document(file, user_id=user_id) logger.info( "Document uploaded: %s (%s, %d bytes, %d chars text)", doc.document_id, doc.original_filename, doc.file_size, doc.text_length, ) return jsonify({ "success": True, "data": { "document_id": doc.document_id, "filename": doc.original_filename, "text_length": doc.text_length, "mime_type": doc.mime_type, }, }) except ValueError as e: return jsonify({"success": False, "error": str(e)}), 400 except Exception as e: logger.error("Document upload failed: %s\n%s", e, traceback.format_exc()) return jsonify({"success": False, "error": str(e)}), 500