Inspiration

AI agents are becoming capable of acting directly on websites, but many useful workflows involve information that should not automatically become part of the agent's context.

A rental application is a simple example: an agent may need to know whether an applicant satisfies an income requirement, but it does not need the applicant's actual income. The same applies to identity data, age checks, financial values, health information, and many other private facts.

Sealed explores a simple idea:

The agent gets the decision — not the secret.

What it does

Sealed is a reusable WebMCP privacy boundary for agentic web applications.

The page exposes a small, state-aware set of WebMCP tools. Public information can move normally, while sensitive facts are evaluated locally inside the page and only allowlisted results are returned to the agent.

The primary rental demo shows the full pattern:

  • Public applicant information can be updated by the agent.
  • A private income_3x_rent predicate is evaluated locally.
  • The agent receives only satisfied or not satisfied; the income itself is returned as value: "withheld".
  • A passport verification requires explicit human approval.
  • Approval creates a random, session-bound opaque reference that does not encode the passport number.
  • Every private crossing is recorded in a visible Boundary Ledger.
  • Human review returns submitted: false; Sealed has no final-submission tool.
  • After review, the WebMCP capability surface contracts from five tools to only two safe read/flag operations.

A second Membership scenario reuses the same primitives to evaluate age_18_plus without exposing the user's date of birth.

Why WebMCP

WebMCP is load-bearing in Sealed.

Without structured site tools, an agent would have to infer meaning from DOM content, accessibility trees, or screenshots. That is especially problematic around sensitive data because the agent may end up observing more information than the task actually requires.

With WebMCP, the page defines the capability boundary explicitly.

Sealed registers tools through document.modelContext.registerTool(...), including:

  • get_application_context
  • set_public_fields
  • flag_uncertain
  • request_private_binding
  • evaluate_private_requirement
  • request_review

The available tool surface changes with workflow state. The agent can ask for a useful decision, but no tool exists that returns the underlying private value.

How I built it

Sealed is built with Next.js, React, TypeScript, and WebMCP and is deployed on Vercel.

The privacy boundary has several layers:

  1. Fixed private predicates
    The agent selects from predefined checks such as income_3x_rent or age_18_plus; it cannot construct arbitrary queries over private values.

  2. Local execution
    Private values are generated and retained page-locally. Predicate evaluation happens inside the application.

  3. Guarded egress
    Private operations pass through a single allowlisted response path that releases only approved fields such as status, requirement, and value: "withheld".

  4. Human-approved opaque bindings
    Consequential credential binding requires explicit user approval and returns only a random session-bound reference.

  5. Boundary Ledger
    Each private operation records the exact sanitized payload released across the boundary.

  6. State-dependent capabilities
    Once human review is requested, Sealed removes write/private tools and leaves only two safe operations.

Challenges I ran into

The hardest part was separating three different things that initially looked like the same problem: page registration, browser discovery, and agent invocation.

A page can successfully register WebMCP tools while the current ChatGPT browser session has not yet attached those tools to the conversation. I reproduced cases where the page showed five registered tools while the agent still reported that site tools were unavailable.

Testing against the official Chrome Labs WebMCP demo helped isolate the difference between application behavior and client-session discovery.

That led to an important UI correction: Sealed now says “Site tools registered”, rather than claiming that an agent is connected simply because local registration succeeded.

I also had to guard against stale sessions, repeat probing of private predicates, response/ledger drift, and accidental leakage through seemingly harmless response fields.

Accomplishments I am proud of

The final implementation demonstrates a complete human-agent privacy workflow rather than a single tool call.

The strongest result is that the same private operation produces both:

  • the agent-visible sanitized response, and
  • the visible Boundary Ledger entry

from the same guarded source of truth.

The rental flow demonstrates public writes, private decision-only evaluation, explicit human approval, opaque binding, human review without submission, and dynamic capability reduction.

The membership scenario shows that the pattern is reusable rather than hard-coded to one application.

What I learned

WebMCP is not only useful for making agents more capable. It can also make the boundary between a web application and an agent more explicit.

The most useful question became:

What is the minimum information the agent needs to complete this task?

For many workflows, the answer is not the private value itself. It is a decision, status, capability, or reference derived from that value.

I also learned that real browser behavior matters as much as implementing the API correctly. Registration, discovery, invocation, approvals, and session lifecycle all have to be tested end to end.

What's next

Sealed is intentionally narrow for this challenge.

Future work could explore additional private decision primitives, external verifier-backed references, and reusable SDK-level abstractions for application developers.

For now, the project focuses on one core principle:

Useful decisions can cross the boundary. Raw private values do not have to.

Built With

Share this project:

Updates

Submission history