We use cookies to enhance your experience and measure how the site performs. Choose "Essential Only" to disable analytics. Read our Privacy Policy.

    Odeus Docs

    File Input in MCP Tools

    Learn how to pass files to MCP tools in Odeus. When an MCP tool declares a file input field, Odeus resolves file references into structured FileData objects automatically.

    File Input in MCP Tools

    Learn how to pass files to MCP tools in Odeus. When an MCP tool declares a file input field, Odeus resolves file references into structured FileData objects automatically.

    When an MCP tool declares an input field with format: "file", Odeus automatically intercepts the LLM's file reference and resolves it into a structured FileData object before the MCP server ever receives the call.

    How It Works

    When a user attaches a file in chat and the LLM references it (as a filename like report.pdf, a storage path like attachment/<uuid>/<filename>, or /mnt/data/<filename>), Odeus's engine intercepts that reference and resolves it into a full FileData object before passing it to your MCP tool.

    The FileData Shape

    Your MCP tool receives the following object:

    {
      fileName: string;       // original filename, e.g. "report.pdf"
      mimeType: string;       // e.g. "image/jpeg", "application/pdf"
      base64: string;         // full file content, base64-encoded
      size: number;           // byte length
      lastModified: Date;
    }
    

    The .meta({ format: "file" }) Marker

    The key signal to Odeus is adding .meta({ format: "file" }) to your Zod schema field. When you save the MCP integration, Odeus detects format: "file" in the JSON schema and stores the field as a FILE type. At execution time, Odeus resolves the file reference into a full FileData object and passes it to your MCP server.

    Implementing File Input in Your MCP Server

    Declare the input field as a Zod object matching the FileData shape. Do not use z.string() — the MCP SDK validates inputs before calling the handler, so the schema must match what it actually receives:

    server.registerTool(
      "process-file",
      {
        inputSchema: {
          file: z
            .object({
              fileName: z.string(),
              mimeType: z.string(),
              base64: z.string(),
              size: z.number().optional(),
            })
            .describe("File to process")
            .meta({ format: "file" }), // tells Odeus to resolve the reference
        },
      },
      async ({ file }) => {
        const buffer = Buffer.from(file.base64, "base64");
        // use buffer, file.fileName, file.mimeType, etc.
        return {
          content: [{ type: "text", text: `Processed: ${file.fileName} (${file.size} bytes)` }],
        };
      },
    );
    

    Example Tool Input and Output

    When Odeus calls your tool, it sends a fully resolved FileData object:

    {
      "file": {
        "fileName": "example.txt",
        "mimeType": "text/plain",
        "base64": "SGVsbG8gd29ybGQ=",
        "size": 11
      }
    }
    

    Your tool can then return metadata or processed results:

    {
      "success": true,
      "filename": "example.txt",
      "mimeType": "text/plain",
      "sizeBytes": 11
    }
    

    Example Project

    The odeus_mcp_file_upload repository is a minimal working MCP server that demonstrates the full file input flow — from schema declaration to handling the resolved FileData in the tool handler.

    Related Documentation