mech.app

The mech.app newsletter

Agentic AI, minus the noise.

Get practical field notes on AI agents, automation, developer tools and security delivered to your inbox.

No spam. Unsubscribe anytime.

Financial

Pomerado's Self-Healing APIs: How Deterministic Web Scraping Turns Legacy Banking Sites Into Agent-Ready MCP Servers

How Pomerado converts brittle bank sites into reliable MCP servers with deterministic scraping, self-healing selectors, and session management for finan...

Source: news.ycombinator.com
Pomerado's Self-Healing APIs: How Deterministic Web Scraping Turns Legacy Banking Sites Into Agent-Ready MCP Servers

Agents need to interact with banks, airlines, and legacy portals that will never ship official APIs. Pomerado (YC F26) wraps these sites as MCP servers by recording a single manual workflow, then generating deterministic HTTP-based scrapers that self-heal when the DOM changes. The pitch is simple: describe a task in natural language, answer a few questions, and get a working MCP in under an hour. Future calls skip the browser and return results in 5-30 seconds.

This matters because computer use (Anthropic’s term for pixel-level browser automation) is too slow and brittle for repeated financial workflows. Most banks also ban headless browsers in their terms of service. Pomerado’s approach sidesteps both problems by converting the site into a structured API that agents can call like any other tool.

The Determinism Problem

Traditional web scraping breaks when a bank changes a CSS class or reorders form fields. Pomerado claims “deterministic” scrapers, which means the same input always produces the same output, even after site updates. Here’s how that works in practice:

  • Initial recording: An agent-controlled browser performs the task once (login, search flights, check balance). Pomerado captures HTTP requests, response payloads, and DOM structure.
  • Selector generation: Instead of brittle XPath or CSS selectors, the system generates multiple fallback strategies (element text, ARIA labels, position relative to stable landmarks).
  • State fingerprinting: Each page state gets a hash of its structure. When a future request hits a page with a different hash, the self-healing logic kicks in.

The key insight is that financial sites change their presentation layer frequently but rarely change their underlying form schemas or API contracts. Pomerado bets that HTTP-level scraping (not Selenium clicks) can remain stable if you track structural invariants instead of surface selectors.

Self-Healing in Practice

When a bank’s login page changes, Pomerado’s MCP server detects the mismatch and triggers a repair workflow:

  1. Diff detection: Compare the current DOM hash to the stored fingerprint.
  2. Selector search: Try each fallback selector strategy until one matches the expected element type (input field, submit button).
  3. Validation: Submit a test request and verify the response matches the expected schema (account balance is a number, flight results are a list).
  4. Commit: If validation passes, update the stored selectors and fingerprint. If it fails, mark the MCP as degraded and alert the developer.

This only works if the site’s underlying behavior is stable. If a bank redesigns its entire authentication flow (OAuth to SAML, for example), no amount of selector healing will help. Pomerado’s model assumes incremental UI changes, not architectural rewrites.

Session Management and Rate Limiting

Financial agents need to maintain authenticated sessions across multiple tool calls. Pomerado’s MCP servers handle this by:

  • Cookie jars: Each MCP instance stores session cookies in encrypted storage. When an agent calls check_balance() followed by transfer_funds(), both requests reuse the same session.
  • Token refresh: If a session expires mid-workflow, the MCP automatically re-authenticates using stored credentials (encrypted at rest, decrypted only in memory).
  • Rate limiting: Pomerado tracks request frequency per site and injects delays to avoid triggering anti-bot defenses. For high-volume workflows, it rotates IP addresses or uses residential proxies.

The authentication boundary is critical. Pomerado stores credentials on behalf of the agent, which means the MCP server becomes a privileged component. If an attacker compromises the MCP, they gain access to the underlying bank account. This is why Pomerado positions itself as infrastructure for internal agents (employee assistants, back-office automation) rather than consumer-facing bots.

Failure Modes and Error Surfaces

When an agent tries to execute a trade through a scraped brokerage interface, several things can go wrong:

Failure TypeDetection MethodAgent-Visible Error
DOM structure changedHash mismatch on page loadToolUnavailable: Site structure changed, healing in progress
Session expired401 or redirect to loginAuthenticationRequired: Re-run with fresh credentials
Rate limit hit429 or CAPTCHA challengeRateLimitExceeded: Retry after 60s
Transaction rejectedError message in response bodyTransactionFailed: Insufficient funds (parsed from site error)
Network timeoutNo response after 30sTimeout: Site unresponsive, retry or escalate

The worst failure mode is silent success. If Pomerado’s parser misreads a confirmation page and reports a trade as executed when it actually failed, the agent will proceed with incorrect state. To mitigate this, Pomerado validates every response against an expected schema. If the schema match confidence is below 90%, the MCP returns Uncertain instead of a false positive.

Architecture: From Browser Recording to MCP

Here’s the end-to-end flow for creating a new MCP:

  1. Developer provides task description: “Log into Chase, navigate to checking account, return current balance.”
  2. Pomerado’s agent performs task once: Opens a headless browser, follows the steps, records all HTTP traffic.
  3. Code generation: Converts the recorded session into a Python function that replays the HTTP requests without a browser.
  4. Schema extraction: Infers the output schema (balance is a float, account number is a string) from the response.
  5. MCP packaging: Wraps the function in an MCP server with tool metadata (name, description, parameters, return type).
  6. Deployment: Hosts the MCP on Pomerado’s infrastructure or exports it as a Docker container for self-hosting.

The generated code looks like this (simplified):

import httpx
from mcp.server import MCPServer

class ChaseBalanceTool:
    def __init__(self, session_store):
        self.session = session_store
        self.client = httpx.Client(cookies=self.session.cookies)
    
    async def get_balance(self, account_id: str) -> dict:
        # Step 1: Navigate to accounts page
        resp = self.client.get(
            "https://secure.chase.com/web/auth/dashboard",
            headers={"User-Agent": "Mozilla/5.0..."}
        )
        if resp.status_code == 401:
            raise AuthenticationRequired()
        
        # Step 2: Parse balance from response
        balance_elem = self._find_element(resp.text, [
            {"selector": "span.balance-amount"},
            {"text_contains": "Available Balance"},
            {"aria_label": "account balance"}
        ])
        
        if not balance_elem:
            raise ToolUnavailable("Balance element not found, site may have changed")
        
        return {
            "account_id": account_id,
            "balance": float(balance_elem.text.strip("$").replace(",", "")),
            "currency": "USD"
        }
    
    def _find_element(self, html: str, strategies: list) -> Optional[Element]:
        for strategy in strategies:
            elem = self._try_selector(html, strategy)
            if elem and self._validate_element(elem):
                return elem
        return None

# MCP server registration
server = MCPServer()
server.register_tool("chase_get_balance", ChaseBalanceTool.get_balance)

The _find_element method is where self-healing happens. Each strategy is tried in order until one succeeds. If all fail, the tool returns an error and logs the failure for manual review.

CI/CD for Scraped APIs

Testing an MCP built from a live bank site is tricky. You can’t mock the responses because the whole point is to interact with the real site. Pomerado’s testing strategy:

  • Smoke tests: Run each MCP tool once per day against the live site. If it returns a valid response, mark it as healthy.
  • Schema validation: Compare the response schema to the stored schema. If fields are missing or types changed, trigger an alert.
  • Canary deployments: When self-healing updates a selector, deploy the new version to 10% of requests first. If the error rate increases, roll back.
  • Manual review queue: When a tool fails smoke tests three times in a row, flag it for human review.

The CI/CD pipeline runs in a sandboxed environment with access to test credentials for each site. For production deployments, Pomerado recommends running MCP servers in a separate VPC with strict egress rules (only allow connections to the target site, no lateral movement).

Security Boundaries

Pomerado’s architecture introduces several trust boundaries:

  1. Agent to MCP: The agent calls the MCP server with parameters (account ID, transfer amount). The MCP validates inputs but trusts the agent to make correct decisions.
  2. MCP to site: The MCP server authenticates to the bank using stored credentials. The bank trusts the MCP because it looks like a normal user session.
  3. Developer to Pomerado: The developer provides credentials to Pomerado’s platform. Pomerado encrypts them at rest and only decrypts them when the MCP runs.

The weakest link is credential storage. If Pomerado’s key management is compromised, an attacker gains access to all stored credentials. Pomerado mitigates this by:

  • Using hardware security modules (HSMs) for key storage.
  • Rotating encryption keys every 90 days.
  • Requiring multi-factor authentication for credential uploads.
  • Logging every credential access with tamper-proof audit trails.

For high-security deployments, Pomerado supports self-hosted MCP servers where credentials never leave the customer’s infrastructure.

When to Use This

Pomerado makes sense when:

  • You need agents to interact with sites that will never ship APIs (government portals, regional banks, legacy insurance systems).
  • The site’s underlying behavior is stable, even if the UI changes frequently.
  • You control the agent’s execution environment and can enforce strict security policies.
  • The cost of manual data entry or screen scraping exceeds the cost of maintaining scraped APIs.

Avoid this approach when:

  • The site has an official API (even if it’s poorly documented). Scraping should be a last resort.
  • The site uses aggressive anti-bot defenses (CAPTCHAs on every page, device fingerprinting, behavioral analysis).
  • The workflow involves high-stakes transactions where silent failures could cause financial loss.
  • You need real-time data (scraping adds 5-30 seconds of latency per request).

Technical Verdict

Pomerado solves a real problem: agents need structured access to legacy systems, and computer use is too slow for repeated workflows. The deterministic scraping approach is clever because it sidesteps the brittleness of traditional selectors while avoiding the latency of browser automation.

The self-healing mechanism is the key innovation. If it works as advertised (automatic recovery from 80% of site changes), this could be the difference between a tool that breaks every week and one that runs for months without intervention.

The biggest risk is credential management. Storing bank passwords in a third-party service is a hard sell for enterprises. Self-hosted deployments mitigate this, but they also eliminate Pomerado’s ability to run centralized smoke tests and share healing updates across customers.

For internal agents (employee assistants, back-office automation), this is a pragmatic solution to the legacy integration problem. For consumer-facing agents, the security and compliance risks are too high. Use this when you own both the agent and the credentials, and when the alternative is paying humans to copy data between systems.