The plumbing was a person: giving my G2 scraper a memory and a locked door with MCP connectors A developer integrated MCP connectors into a G2 software reviews scraper on Apify Store, enabling it to check a user's database for new reviews and write digests without holding credentials. The companion Actor uses a locked-door approach, limiting its access to only the tools it needs, and includes memory to avoid re-reporting seen reviews. I maintain a G2 Software Reviews Scraper https://apify.com/factden/g2-reviews-scraper on Apify Store. It has 124 users, mostly product and sales teams who watch what people say about their competitors on G2. For a long time it did one honest thing: you gave it a product URL, it gave you back a dataset of reviews. Clean, boring, useful. I know exactly how those 124 people use it, because I use it the same way. You run it for a handful of competitors, download the CSVs, open last week's CSVs, and eyeball the two side by side to find what is new. Then you paste the interesting ones into a Slack thread. That is not a data problem. That is a plumbing problem, and the plumbing is a person doing a diff by hand every Monday. When Apify shipped MCP connectors https://docs.apify.com/platform/integrations/mcp-connectors in July, I realized the plumbing could be the Actor instead. But wiring a scraper into someone's stack turned out to be the easy part. The actual work was two things a raw pipe does not give you: a memory , so the run only ever surfaces reviews you have not already seen, and a locked door , so the Actor can touch the user's database without me ever holding their password and without being able to do more than three things to it. This is the story of getting those two right, including the four things that broke, one of which was a database quietly asleep and one of which was my data showing up wrapped in a prompt-injection guard I did not expect. First, the thing everyone mixes up, because I did. Apify has two MCP features that point in opposite directions. The Apify MCP server https://docs.apify.com/platform/integrations/mcp exposes your Actors as tools to outside AI clients like Claude or Cursor. The Actor sits still and waits to be called. MCP connectors are the reverse: they let your Actor reach out and call someone else's service during its run. Your scraper becomes the client, not the tool. I wanted the second one. I wanted my scraper, mid-run, to read a watchlist from the user's Notion, check the user's own database so it only reports genuinely new reviews, and write a digest back. The whole time, without ever holding the user's Notion token or database password. I did not touch the live G2 scraper, and that was a deliberate production decision, not a shortcut. You do not bolt an experimental connector integration onto an Actor that 124 people are paying to run; if the new surface misbehaves, their scrapes are not what should break. So the connectors live in a small companion Actor that calls the live scraper over its normal interface and wraps the workflow around it. Ship the risky new thing as an opt-in companion first, fold it into the main Actor once it has earned trust. The companion does three things in one run: That third number is the one my users actually care about. G2 reviews carry a didSwitchFromCompetitor flag, so "two people switched to you from a rival last week" falls out for free. A connector is just an input field with resourceType: "mcpConnector" . Apify renders a picker in the run form, filtered to the connectors the user has authorized that match your rules. Here is that one field from my input schema: "dedupConnector": { "title": "Dedupe store Supabase connector ", "description": "Skips reviews already stored in your Supabase and saves new ones.", "type": "string", "resourceType": "mcpConnector", "editor": "resourcePicker", "nullable": true, "mcpServers": { "url": " ", "tools": { "required": "execute sql", "list projects", "apply migration" } } } This is the locked door, and it is the part I want people to notice. The mcpServers list is not just a filter for the picker. It is a ceiling the proxy enforces at runtime: my Actor can only see and call the tools I named here. The user's Supabase connector can drop tables and delete projects; my Actor cannot, because it never asked for those verbs and the proxy will not forward them. So a user is handing a stranger's scraper access to their production database, and can verify from my input schema that the worst it can do is run three SQL calls. That guarantee is not my good behavior, it is Apify's plumbing. I kept both connectors optional and off by default, so with no connector supplied the Actor just returns reviews and nothing about the old behavior changes. Every run gets two environment variables: ACTOR MCP CONNECTOR BASE URL and APIFY TOKEN . You point a standard MCP client at ${ACTOR MCP CONNECTOR BASE URL}/