Skip to main content
Glama

img2pdf

Built by Tamim · @tamimbuilds

A local MCP (Model Context Protocol) server that converts images to PDF and PDFs to images. Supports any AI agent via two transport modes:

  • Streamable HTTP — for Cursor, Claude Code, and any HTTP-capable MCP client

  • stdio — for Claude Desktop, VS Code MCP, Cline, Roo Code, Windsurf, Continue, and any stdio-spawning agent

What's inside

Tool

Description

convert_images_to_pdf

Convert local files, URLs, or base64 data into a single PDF

convert_pdf_to_images

Extract individual images from a PDF file

get_server_time

Sanity-check tool to confirm the connection is working

Related MCP server: img-convert MCP Server

File structure

tamim-mcp-server/
├── src/
│   ├── server.ts            # Fastify HTTP transport (Streamable HTTP)
│   ├── stdio-server.ts      # stdio transport
│   ├── mcp.ts               # createMcpServer() factory
│   ├── config.ts            # env vars (port, token)
│   └── tools/
│       ├── index.ts         # registerTools() - wires every tool in
│       ├── time.ts          # get_server_time
│       └── imagesToPdf.ts   # convert_images_to_pdf
├── .env.example
├── .gitignore
├── package.json
├── tsconfig.json
└── README.md

1. Install

npm install
cp .env.example .env
# open .env and set MCP_TOKEN (openssl rand -hex 24), or leave it blank for no auth

2. Run it

npm run dev      # tsx watch, auto-reloads on save
# or, for a built version:
npm run build && npm start

You should see:

MCP server ready on http://127.0.0.1:8787/mcp

3. Test it before touching any client

curl -i -X POST http://127.0.0.1:8787/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'

A 200 OK with a mcp-session-id header back means the server is healthy. Or use the official MCP Inspector for a UI instead of raw curl:

npx @modelcontextprotocol/inspector
# point it at http://127.0.0.1:8787/mcp

4. Connect any AI agent

HTTP agents (server must already be running)

Cursor

.cursor/mcp.json (project root) or ~/.cursor/mcp.json (global):

{
  "mcpServers": {
    "tamim-local-mcp": {
      "url": "http://127.0.0.1:8787/mcp",
      "headers": { "Authorization": "Bearer YOUR_TOKEN_HERE" }
    }
  }
}

Omit the headers block entirely if you left MCP_TOKEN blank.

Claude Code

claude mcp add --transport http tamim-local-mcp http://127.0.0.1:8787/mcp \
  --header "Authorization: Bearer YOUR_TOKEN_HERE"

stdio agents (auto-spawned, no manual server start needed)

Claude Desktop

claude_desktop_config.json:

{
  "mcpServers": {
    "tamim-local-mcp": {
      "command": "npx",
      "args": ["-y", "tamim-mcp-stdio"]
    }
  }
}

If you installed locally instead of publishing to npm:

{
  "mcpServers": {
    "tamim-local-mcp": {
      "command": "node",
      "args": ["dist/stdio-server.js"],
      "cwd": "/absolute/path/to/tamim-mcp-server"
    }
  }
}

VS Code / GitHub Copilot

.vscode/mcp.json (project root):

{
  "servers": {
    "tamim-local-mcp": {
      "command": "node",
      "args": ["dist/stdio-server.js"],
      "cwd": "${workspaceFolder}"
    }
  }
}

Cline / Roo Code

~/.cline/mcp.json or ~/.roo/mcp.json:

{
  "mcpServers": {
    "tamim-local-mcp": {
      "command": "node",
      "args": ["dist/stdio-server.js"],
      "cwd": "/absolute/path/to/tamim-mcp-server"
    }
  }
}

Windsurf

.windsurf/mcp.json:

{
  "mcpServers": {
    "tamim-local-mcp": {
      "command": "node",
      "args": ["dist/stdio-server.js"],
      "cwd": "/absolute/path/to/tamim-mcp-server"
    }
  }
}

Continue

.continue/config.yaml:

mcpServers:
  - name: tamim-local-mcp
    command: node
    args:
      - dist/stdio-server.js
    cwd: /absolute/path/to/tamim-mcp-server

Generic stdio config (works with any MCP client)

{
  "command": "node",
  "args": ["dist/stdio-server.js"],
  "cwd": "/absolute/path/to/tamim-mcp-server"
}

5. Tool usage

convert_images_to_pdf

Accepts images from three sources (at least one required):

// Local file paths
{
  "imagePaths": ["/path/to/photo1.jpg", "/path/to/photo2.png"],
  "outputPath": "/path/to/output.pdf"
}

// URLs
{
  "urls": ["https://example.com/image1.jpg", "https://example.com/image2.png"],
  "outputPath": "/path/to/output.pdf"
}

// Base64 data
{
  "base64Images": ["/9j/4AAQSkZJRg...", "iVBORw0KGgo..."],
  "outputPath": "/path/to/output.pdf"
}

// Mix of all three
{
  "imagePaths": ["/path/local.jpg"],
  "urls": ["https://example.com/photo.png"],
  "base64Images": ["iVBORw0KGgo..."],
  "outputPath": "/path/to/output.pdf"
}

Options:

  • pageSize: "fit" (default) — each page matches its image, or "a4" — centers on A4

  • marginPt: margin in points when using A4 (default: 24)

convert_pdf_to_images

Extracts individual pages from a PDF as images (JPEG or PNG). It creates a dedicated folder [PDF_NAME]_to_images within your specified output directory.

{
  "pdfPath": "/path/to/document.pdf",
  "outputDir": "/path/to/downloads"
}

Options:

  • format: "jpeg" (default) or "png"

  • scale: Rendering scale factor (default: 2, where 1 = 72 DPI)

  • pageNumbers: Array of specific 1-indexed pages to render (default: all pages)

  • quality: JPEG quality 1-100 (default: 90)

get_server_time

No parameters. Returns the current server time in ISO format.


Keeping it running (HTTP mode)

HTTP-based MCP servers don't get auto-started by the client the way stdio ones do - the server has to already be running when HTTP clients try to connect. Options, easiest first:

  • Leave npm run dev in a spare terminal tab

  • pm2 start dist/server.js --name mcp to survive terminal closes and auto-restart on crash

stdio mode does not need this — the agent spawns the process itself.

Adding a new tool

  1. Create src/tools/yourTool.ts exporting registerYourTool(server)

  2. Call it from src/tools/index.ts

  3. Keep the tool narrow - one job, a tight zod schema, a description that tells the model exactly when to use it and what format inputs should be in

Security notes

  • The HTTP server binds to 127.0.0.1 only - not reachable from outside this machine

  • DNS rebinding protection is applied automatically by @modelcontextprotocol/fastify

  • Set MCP_TOKEN to require a bearer token even for local HTTP calls

  • stdio transport is inherently authenticated by process spawn — no token needed

  • Keep total tools per server in the 6-10 range - Cursor caps out around 40 active tools across all connected servers combined

  • 127.0.0.1:8787/mcp

  • npx @modelcontextprotocol/inspector node dist/stdio-server.js

node dist/cli.js image.png

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    A local PDF manipulation server for AI agents that provides tools for merging, splitting, extracting info, and converting images to PDF, all without uploading files.
    -