Skip to content

jchoi2x/cf-rendercv

Repository files navigation

cf-rendercv

cf-rendercv is an HTTP API + MCP server for generating resume PDFs using the rendercv CLI.

rendercv is a CLI tool and is not readily portable to run inside Cloudflare workerd. To work around this, the repo uses Cloudflare Containers to run a Docker container that has the rendercv CLI available. A Node.js server wraps the CLI and exposes an HTTP endpoint; the Cloudflare Worker proxies requests to it.

Projects

The apps are:

  • ./apps/http
    • Cloudflare Worker (Hono)
    • MCPAgent (MCP tool/agent wiring)
    • hosts an MCP server that registers the rendercv tool, plus a prompt and a JSON schema resource (see ./apps/http/src/mcp/rendercv.mcp.ts)
    • handles MCP tool calls by routing them to the container-backed PDF generator
    • Cloudflare Container (docker run) (starts/manages the Docker container lifecycle)
  • ./apps/rendercv-app (lives inside the Docker container)
    • Node.js HTTP server
    • Hono + Swagger routes
    • Executes rendercv to generate the returned application/pdf

Architecture

  • Cloudflare Worker (./apps/http)

    • Boots a Docker container when needed.
    • Proxies incoming HTTP traffic to the Node.js app running inside the container.
  • Node.js API (./apps/rendercv-app)

    • Endpoint: POST /api/v1/generate
    • Request Body: RenderCV configuration provided as JSON or yaml (a JSON equivalent of the rendercv YAML file).
    • Response:
      • Content-Type: application/pdf
      • Body is the generated PDF.

Rendering via HTTP and MCP

This Worker supports using RenderCV in two ways:

  • HTTP API: POST /api/v1/generate (RenderCV configuration as JSON) returns a generated PDF.
  • MCP tool: the Worker registers an MCP tool named rendercv that accepts { content, format } and returns a generated PDF URL (or base64 when format: "base64").

The Worker also registers:

  • a prompt named rendercv
  • a resource at rendercv://schema-and-prompt containing the RenderCV JSON schema

See ./apps/rendercv-app/README.md for detailed API docs and examples.

Development

At a high level, you will:

Prerequisites

  • docker
  • node >= 20
  • pnpm >= 10.30.3

Google OAuth (required for local MCP)

The HTTP/MCP server uses Google OAuth for authentication.

To run locally, you must set up a Google OAuth client application in the Google Cloud console: https://console.cloud.google.com/auth/clients/create After creating the app, configure the resulting GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET for the worker.

Steps

  1. Install dependencies at the repo root:

    pnpm install
  2. Start the cloudflare worker and api locally from the repo root:

    pnpm run dev:http
  3. Start the Node.js API locally from the repo root:

    pnpm run dev:api
  4. Send a POST request to http://localhost:<port>/api/v1/generate with your RenderCV JSON payload and save the application/pdf response.

You must have rendercv installed on your local machine for PDF generation to work. See the official RenderCV “Get Started” guide for installation instructions: Get Started - RenderCV.

To develop or deploy the Cloudflare Worker in ./apps/http, refer to that app’s own configuration and scripts (e.g., wrangler.toml, package.json) for the precise commands.

Testing

  • Unit tests live next to source under apps/**/src/**/__tests__/ (see .cursor/rules/unit-testing.mdc).
  • Worker integration tests live in the repo-root ./integration/ directory. They use Cloudflare’s Workers Vitest integration (@cloudflare/vitest-pool-workers): tests run inside workerd against the same apps/http/wrangler.jsonc as local dev, and call the Worker via exports.default.fetch() from cloudflare:workers (see Cloudflare Test APIs).

From the repo root:

pnpm run test:integration

Watch mode:

pnpm run test:integration:watch

These tests do not replace container-backed PDF smoke checks; they validate routing and request handling in the Worker isolate without requiring wrangler dev in a separate terminal. The Vitest pool does not emulate Cloudflare Containers—paths that need a live container (for example a successful POST /api/v1/generate with a full RenderCV document) still require pnpm run dev:http / Docker or a deployed environment.

Debugging

Use the @modelcontextprotocol/inspector tool to debug the MCP server.

npx @modelcontextprotocol/inspector@latest

Diagrams

Sequence Diagram (HTTP)

Sequence (HTTP)

Rendering a resume via HTTP request

sequenceDiagram
  participant C as HTTP Client
  participant W as Cloudflare Worker (Hono)
  box Blue Durable Objects
    participant D as RendercvDo (MCPAgent durable object)
    participant K as DockerRendercvApp (Container)
  end
  box Purple Container
    participant A as rendercv-app (Node.js + Hono)
    participant R as rendercv CLI
  end


  C->>W: POST /api/v1/generate (RenderCV JSON)
  W->>D: stub.fetch(request)
  D->>K: callContainerService(path, method, body)
  K->>A: HTTP POST /api/v1/generate
  A->>R: rendercv (generate PDF)
  R-->>A: PDF binary
  A-->>K: application/pdf response
  K-->>D: proxy response
  D-->>W: proxy response
  W-->>C: application/pdf
Loading
Sequence Diagram (MCP)

Sequence (MCP)

MCP is the Model Context Protocol, a protocol for building agents that can interact with other agents and tools.

sequenceDiagram
  participant M as MCP Client (agent)
  participant R2 as R2 Bucket
  box Blue Durable Objects
    participant D as RendercvDo (MCPAgent durable object)
    participant T as MCP tool: rendercv
    participant K as DockerRendercvApp (Container)
  end
  box Purple Container
    participant A as rendercv-app (Node.js + Hono)
    participant R as rendercv CLI
  end


  M->>D: MCP request to RendercvDo (/mcp)
  D->>T: invoke tool rendercv (content, format)
  T->>K: callContainerService('/api/v1/generate', body)
  K->>A: HTTP POST /api/v1/generate
  A->>R: rendercv (generate PDF)
  R-->>A: PDF binary
  A-->>K: application/pdf

  rect rgba(33, 66, 99, 0.12)
    K-->>T: proxy response (PDF)
    T-->>R2: upload to R2 bucket
  end

  T-->>D: tool result (PDF URL)
  D-->>M: MCP response (PDF URL)
Loading
Sequence Diagram (MCP Discovery)

MCP Discovery (tools/resources/prompts)

Discovery is the process of the MCP client (agent) discovering the tools, resources, and prompts available on the MCP server.

sequenceDiagram
  participant M as MCP Client (agent)
  participant D as RendercvDo (MCPAgent durable object)
  participant G as GitHub: rendercv/schema.json

  M->>D: MCP initialize

  M->>D: tools/list
  D-->>M: tools include rendercv (input schema: RenderCV JSON)

  M->>D: resources/list
  D-->>M: resources include rendercv://schema-and-prompt

  M->>D: resources/read(rendercv://schema-and-prompt)
  D->>G: fetch schema.json
  G-->>D: schema.json (raw JSON)
  D->>D: parse JSON + JSON.stringify(schema, 2)
  D-->>M: resource text (application/json) containing the RenderCV schema

  M->>D: prompts/list
  D-->>M: prompts include rendercv

  M->>D: prompts/get('rendercv')
  D-->>M: prompt text with examples/instructions to build content (see rendercv://schema-and-prompt for the full schema)
  Note over M,D: Using the tool list + prompt examples + the schema resource, <br/>the LLM knows how to build a valid `content` payload, then calls the MCP tool when the user asks to generate a resume.
  M->>D: tool call rendercv { content, format: "url" }
Loading

About

rendercv on cloudflare workers

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors