Preparing another connection process for every read or input adds repetition to even a small workflow script. I built an API that retains a task and page objects on one MCP client. Shorter calling code should not weaken the execution conditions underneath it.

Separate connection, task and page responsibilities

connectNorthstar initializes a connection through the existing stdio server and returns a browser object. begin starts work with a goal and context, retaining its ID in BrowserTask. A page refers to a tab inside that task; creating the object does not open another tab.

McpClient manages request numbers, pending replies and timers in the same process. Connection reuse differs from workflow-result reuse. This API does not replace a work journal or turn a previous success into a new request's success. Identifying which lifetime is reused comes first.

Do not hide arbitrary evaluation behind the page name

The page object forwards observation, search, extraction, navigation and fixed operations through typed MCP. A familiar automation-style syntax does not imply arbitrary evaluation. Convenience must not bypass the existing Broker boundary.

Snapshots bound text and control lists and expose truncation. They are not lossless copies of the whole page, and a compact reply does not establish that everything needed is present. The caller must be able to choose narrower search or extraction with knowledge of what was omitted.

A locator must not choose the first plausible target

getByRole requires exact role and name, with href when needed. Resolution performs a fresh find and matches those conditions. Multiple matches fail with ambiguity; truncated results fail rather than implying uniqueness.

An absent target does not become permission to use the first field on screen. The short API statement retains uniqueness checks underneath. These fields alone do not solve every duplicate-name problem across frames; host frame and reference checks and a more specific contract can still be necessary.

Verify entered values with a fresh reference

After fill, the page accepts a fresh observation carried by the mutation reply. It obtains a matching current reference or resolves again before verifyField compares the actual value. A mismatch ends with an error rather than another input attempt.

Click and Enter require an expected result. URL expectations are checked for absolute form before dispatch, preventing a fragment from masquerading as a full address. The caller still owns the correctness of the expectation. The API cannot repair a business-level success criterion merely because its syntax is valid.

Convenience must retain uncertainty

An uncertain dispatched outcome leaves the task blocked. Reads remain available while further mutations and finish are prevented. After OUTCOME_UNKNOWN, a single read can confirm a late result without sending the original click again.

The API tests check one persistent MCP process, value verification with a fresh reference, zero input on ambiguity and reads with further-input blocking after uncertainty. Those integration tests use a fixture server. I did not repeat real-account generation or publication for this article, and the evidence does not establish universal site compatibility.

A useful abstraction also exposes where work stopped

I wanted to remove repetitive calling syntax without erasing target selection or verification. A caller needs the goal, tab and failed expectation to make a meaningful repair. Turning every failure into a retry can make an API look easy while obscuring responsibility.

Reuse still requires distinguishing disconnect from stop and local waiting from remote outcome. Request and response metrics are bytes, not measured tokens. The role of this layer is to offer a familiar page API while preserving access to the original execution contract and observation limits.