Skip to content
ajan.io

Docs menu

On this page

File Input in MCP Tools

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

When an MCP tool declares an input field with format: "file", ajan 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//, or /mnt/data/), ajan'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:

typescript
{
  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 ajan is adding .meta({ format: "file" }) to your Zod schema field. When you save the MCP integration, ajan detects format: "file" in the JSON schema and stores the field as a FILE type. At execution time, ajan 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:

typescript
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 ajan 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 ajan calls your tool, it sends a fully resolved FileData object:

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

Your tool can then return metadata or processed results:

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

Example Project

The ajan\_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.

FAQ

Use file input when the external MCP tool needs to inspect or process a file that the user references in ajan. This is useful for tools that parse, transform, validate, or upload files to another system.

Check that the MCP tool declares a file input field, the user referenced an available file, the file type is supported by the tool, and the tool handles the file data format ajan sends.