This companion project validates an Actor result after an AI agent calls it through the hosted Apify MCP server. It checks execution, requested-source coverage, and dataset invariants separately.
The example comes from a bounded commercial real estate workflow: Codex asked
one Actor for five office listings from Crexi and five from LoopNet in a Dallas
sale search. The first platform-successful run returned only the Crexi half.
The final run returned both halves. This verifier makes that difference
machine-readable instead of treating SUCCEEDED as the whole verdict.
The verifier reads four local JSON files:
examples/job.jsondefines the requested sources, filters, per-source target, and charge ceiling.run.jsonrecords the platform status, MCP origin, runtime configuration, and actual Apify usage cost.run-summary.jsonrecords the Actor's source-level outcomes.dataset.jsoncontains the final normalized rows.
It returns three independent checks:
execution: Did the run succeed through MCP and remain within the declared charge ceiling?coverage: Did every requested source succeed and contribute the requested bounded result count?data: Do the rows match the requested state, transaction, asset class, and source constraints, with unique listing IDs and URLs?
safeToUse becomes true only when all three checks pass. A platform status of
SUCCEEDED can therefore coexist with coverage: partial and
safeToUse: false.
The term coverage contract describes the method used in this project. It is not an official Apify or Model Context Protocol standard.
- Node.js 22 or newer
- npm
jqonly for the optional fixture syntax check- An MCP client that supports Streamable HTTP and OAuth if you want to connect to Apify yourself
The local verifier never contacts Apify and does not require an Apify account. The MCP connection is needed only if you reproduce the agent-side workflow with your own run and your own budget.
The portable example in mcp-config.example.json scopes the hosted server to a
single Actor plus the four run and storage tools used by the audit. The hosted
server automatically adds get-actor-output to Actor-related configurations:
{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com?tools=kazkn/commercial-real-estate-brokerage-intel,get-actor-run,get-actor-log,get-dataset-items,get-key-value-store-record"
}
}
}With Codex CLI, the equivalent commands are:
codex mcp add apify --url "https://mcp.apify.com?tools=kazkn/commercial-real-estate-brokerage-intel,get-actor-run,get-actor-log,get-dataset-items,get-key-value-store-record"
codex mcp login apifyThe second command opens the browser-based Apify authorization flow. This keeps credentials out of project files. Restart the client or open a fresh task if it does not refresh its tool list after authentication.
When reproducing the workflow, set a charge ceiling before calling the Actor, keep the requested result count small, and use the explicit audit tools to inspect the stored input, platform metadata, source summary, logs, and dataset. A successful OAuth login proves authentication, not result quality.
Install dependencies, run every test and privacy check, then build the CLI:
npm install
npm run verify
npm run build
node dist/src/cli.js examples/job.json fixtures/complete/run.json fixtures/complete/run-summary.json fixtures/complete/dataset.jsonTo inspect the platform-successful but incomplete example:
node dist/src/cli.js examples/job.json fixtures/partial/run.json fixtures/partial/run-summary.json fixtures/partial/dataset.jsonThe complete fixture exits with code 0. A valid but unsafe workflow verdict
exits with code 2. Invalid JSON or a schema violation exits with code 1, and
incorrect CLI usage exits with code 64.
The complete fixture prints:
{
"execution": "pass",
"coverage": "complete",
"data": "pass",
"safeToUse": true,
"reasons": []
}The partial fixture passes the execution and row checks but reports three coverage reasons: the Actor summary is partial, the LoopNet outcome timed out, and the dataset contains zero of the five requested LoopNet rows. The returned rows can still be a valid Crexi shortlist, but they cannot be described as a complete two-source result.
The checks are deliberately separate. A failed execution is a technical failure. A completed execution with a missing requested source is partial coverage. Rows outside the declared filters or duplicated identities are data failures. Keeping those states separate prevents an agent from turning a source outage into a market conclusion.
The counts, statuses, timeouts, and costs mirror a bounded six-run experiment performed through the Apify MCP server on August 5, 2026. Listing identifiers, URLs, locations below state level, and contacts are deterministic sanitized placeholders. These fixtures do not claim that the displayed properties are live or exhaustive.
The partial fixture mirrors the first two-source attempt: five final Crexi rows,
zero LoopNet rows, and a deadline_exceeded source outcome. The complete
fixture mirrors the final bounded run: fourteen raw rows, ten final rows, and
exactly five rows retained from each source.
The public fixtures preserve only the evidence needed to exercise the contract. They do not contain private Actor identifiers, internal storage identifiers, real listing URLs, street addresses, broker details, credentials, or local filesystem paths.
This repository does not call an Actor. It only validates local evidence files, so it cannot prove that a future run will behave like either fixture.
It does not guarantee LoopNet availability. In the underlying experiment, several LoopNet transports failed before a later bounded run succeeded through a browser fallback. The complete fixture proves one run, not continuous source reliability.
It does not replace investment due diligence. The Actor works with public listing data, which can be incomplete, stale, or different from closed-deal records. Verify material facts against primary property and transaction sources.
It does not publish the proprietary scraper implementation. The repository contains only the agent-side validation contract, tests, and sanitized evidence shapes needed to reproduce the decision logic.
- Prefer the hosted Apify MCP server with OAuth so project files contain no API credential.
- Scope the MCP URL to the Actor or tools required by the workflow.
- Set a strict per-run charge ceiling and a bounded result target before any execution.
- Never commit live run, build, dataset, key-value-store, cookie, contact, or local-path identifiers.
- Run
npm run check:secretsand inspectgit diff --cachedbefore every push. - Keep screenshots and unpublished editorial drafts outside this repository.
The privacy scanner rejects common credential and private-identifier patterns. It is a focused safeguard, not a replacement for a full security review.