Build an AI summarizer with background jobs: retries, signed webhooks and Postgres over one MCP connection A CloudHike developer published a walkthrough for building an AI summarizer that offloads slow model calls to background jobs with retries, signed webhooks and duplicate protection, all provisioned through a single MCP connection. The setup uses CloudHike's MCP tools to deploy Postgres and a jobs service, letting an AI coding agent configure the backend from one prompt instead of separate database, queue, worker and model-provider accounts. This is week 2 of Build with CloudHike , a weekly series where we build a small, real-world app with an AI coding agent and let the agent set up the backend. Disclosure: I built CloudHike https://cloudhike.dev?utm source=devto&utm medium=article&utm campaign=build series w2 , so keep that in mind. Every AI feature starts the same way: one await on a model call inside an API route. It works on your laptop. Then real users paste long documents, the model takes its time, the provider answers 429 now and then, and your request sits there waiting while the browser spinner keeps spinning. A failed call means the user clicks again, and you pay for the same work twice. The usual fix is a job queue: a queue service, a worker process somewhere to run it, retry logic, and a way to get the result back to your app. That's a small piece of infrastructure before you've improved anything for the user. This week we'll build an AI summarizer that moves the slow model call into a CloudHike background job , with retries, a signed webhook for the result, and duplicate protection. As always, the agent sets up the backend over one MCP connection , and every prompt is below. A "paste text, get a summary" app: queued and starts a background job run, so the user never waits on the model. x-cloudhike-signature header, skips run ids it has already handled, and saves the summary. Here's the flow: POST /api/summaries → a row in Postgres plus a new run, answered right away POST /api/jobs/summarize your worker → AI model → summary as JSON POST /api/jobs-webhook → signature check → duplicate check → summary saved GET /api/summaries/:id until the summary is there And here's how each piece maps to CloudHike, all in one project: DATABASE URL JOBS API URL , JOBS API KEY AI BASE URL , AI API KEY Normally that's a database host, a queue, a worker host and an AI provider account: four places to sign up and four sets of keys. Here it's one project, one .env and one credit balance. You don't need an OpenAI, Anthropic or Google account; you pick a model by name, such as openai/gpt-5-mini or anthropic/claude-sonnet-4.5 . If you did week 1, you're already connected; skip to Step 2. In the CloudHike dashboard, open Connect MCP in the sidebar, pick your editor and click Copy with key . That creates your workspace API key and gives you a snippet with the key already filled in. The server is remote Streamable HTTP , so there's nothing to install. Claude Code claude mcp add --transport http --scope user cloudhike https://cloudhike.dev/api/mcp \ --header "Authorization: Bearer icu your api key" Run /mcp inside Claude Code to check that it's connected. Cursor ~/.cursor/mcp.json { "mcpServers": { "cloudhike": { "url": "https://cloudhike.dev/api/mcp", "headers": { "Authorization": "Bearer icu your api key" } } } } Open Cursor Settings → MCP and look for the green dot. Snippets for the other editors are in the MCP docs https://cloudhike.dev/docs/mcp?utm source=devto&utm medium=article&utm campaign=build series w2 . Treat that key like a password. It lives in your home folder, not in the repo, and you can revoke it from the same page. npx create-next-app@latest summarizer cd summarizer Open the folder in Cursor, or run claude in it. Paste this prompt: Use the cloudhike MCP tools to set up the backend for this app. It's an AI summarizer that runs the model call in a background job. Create a CloudHike project called "summarizer" and deploy postgres and jobs. Wait until they're ready. Put the .env into .env.local, make sure it's git-ignored, and don't show me any secret values. Then read the jobs, postgres and ai docs with get docs so you know how to use them. Don't write app code yet. Just tell me which services are running and which variable names are in .env.local. Behind the scenes, the agent works through CloudHike's MCP tools: create project makes the project or list projects finds it if it already exists . deploy services deploys Postgres and Jobs, with the same plan and billing checks as the dashboard. wait for services waits until each one reports ready. get environment returns the project's .env , which the agent writes into .env.local . It can also ask for format: "names" to list just the variable names with no secrets. get docs pulls the Jobs, Postgres and AI pages as Markdown, so the code it writes next follows the real API instead of a guess. One click for the AI models. deploy services covers Postgres, Auth, Storage, Redis, Jobs and Email, so the AI service is the one you deploy yourself: open the project in the dashboard and click Deploy on the AI card. Then ask: Use the cloudhike get environment tool again and update .env.local, keeping any keys I added. Show me only the variable names and confirm AI BASE URL and AI API KEY are there. Read https://cloudhike.dev/docs/md/postgres https://cloudhike.dev/docs/md/postgres . Using node-postgres, add a migration script to this repo that creates two tables: - summaries: id uuid, default gen random uuid , input text, status 'queued', 'done' or 'failed' , summary nullable , run id nullable, unique , error nullable , created at and updated at. - handled runs: run id text primary key and handled at. Run the migration with DIRECT URL if .env.local has it, otherwise DATABASE URL. Create the app's pool once in lib/db.ts from DATABASE URL, keep it on globalThis so hot reloads reuse it, and use max 5 connections. Then use the cloudhike describe table tool to show me both tables. handled runs is our duplicate guard, and we'll come back to it in Step 7. The migration goes through DIRECT URL because DATABASE URL goes through a connection pooler PgBouncer , and the Postgres docs https://cloudhike.dev/docs/postgres?utm source=devto&utm medium=article&utm campaign=build series w2 recommend the direct address for migrations. Same safety model as week 1: CloudHike's query database tool always runs one statement in a READ ONLY transaction, execute sql for writes is Pro-only and your editor asks before running it, and no MCP tool can delete a project or service . Schema changes live in your repo as migrations. This is the route CloudHike Jobs will call. It holds the slow part, so nothing user-facing waits on it. Read https://cloudhike.dev/docs/md/jobs https://cloudhike.dev/docs/md/jobs and https://cloudhike.dev/docs/md/ai https://cloudhike.dev/docs/md/ai . Add lib/jobs-signature.ts with a verify rawBody, header function based on the x-cloudhike-signature example in the jobs docs: HMAC-SHA256 of "." with JOBS API KEY, compared with timingSafeEqual, refusing timestamps more than 300 seconds old. Then add POST /api/jobs/summarize: - Read the raw body with request.text and answer 401 if verify fails. - Parse { summaryId } and load that row's input text from summaries. - Call the AI service with the OpenAI SDK, baseURL AI BASE URL and apiKey AI API KEY, model "openai/gpt-5-mini", asking for a short summary in plain text. - Answer 200 with JSON { summary }. - If the AI call fails with a 429 or 5xx, or the network fails, answer 503 so the job retries. For any other error, answer 422 with a short message, so the run fails without retrying. Server code only. Never send JOBS API KEY or AI API KEY to the browser. A few details from the Jobs docs https://cloudhike.dev/docs/jobs?utm source=devto&utm medium=article&utm campaign=build series w2 shape this route: url and to your callbackUrl . The t=