@sema-agent/connector-browser 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/KNOWN-LIMITS.md +7 -3
- package/README.md +4 -0
- package/bin/sema-connector-browser.mjs +2 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,17 @@ All notable changes to this package are documented here. Released sections are
|
|
|
4
4
|
frozen: once a version is published its section is never edited again; new text
|
|
5
5
|
goes into the next version's section.
|
|
6
6
|
|
|
7
|
+
## 0.2.2 (2026-10-25)
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Re-pinned to `@sema-agent/connectors` 0.9.0, so `sema-connector-browser` gains the shared CLI kit's `unmount` and
|
|
12
|
+
`list` subcommands (CN-065), `mount`'s duals: `unmount` removes only the entry `mount` wrote for this connector
|
|
13
|
+
(no entry is idempotent; an entry under the name that is not `mount`'s own shape is refused and left alone) and
|
|
14
|
+
`list` prints the mounted connectors' names and configuration directories, never a credential. Nothing in this
|
|
15
|
+
package's own code changed. An entry a person extended with `toolAxes` is not listed and is refused by `unmount`
|
|
16
|
+
(`KNOWN-LIMITS.md`, KL-32).
|
|
17
|
+
|
|
7
18
|
## 0.2.1 (2026-10-24)
|
|
8
19
|
|
|
9
20
|
### Changed
|
package/KNOWN-LIMITS.md
CHANGED
|
@@ -7,7 +7,7 @@ contract, or a long-lived transitional path: those are defects and get a ticket
|
|
|
7
7
|
| ID | Symptom | Why it is not fixed | Trigger | Upgrade criterion |
|
|
8
8
|
|---|---|---|---|---|
|
|
9
9
|
| KL-01 | A standalone catalog entry names its configuration directory with an absolute `--config-dir`. After the directory is moved, or when the `mcp` domain is exported in a bundle to another machine, the entry still names the old path: the launcher finds no secrets there and reports `unauthorized`, and `mount` (and with it the seed) refuses the stale entry as a conflict until it is removed by hand. | The engine starts stdio connectors with a minimal environment, so the entry must carry the directory (CN-028); an absolute path is machine-local by nature, like the installed connector package the entry also depends on. The seed (CN-009) never overwrites an entry, so it does not repair one. | Moving the configuration directory; importing a bundle that carries connector entries. | The CLI wrapper (CN-012) rewriting entries on import, or an engine that hands its configuration directory to stdio connectors. |
|
|
10
|
-
| KL-02 | The end-to-end gate pins `@sema-agent/server` 7.
|
|
10
|
+
| KL-02 | The end-to-end gate pins `@sema-agent/server` 7.136.0 word for word in `test/negctl/CN-006.json`: the four helper invocations the server starts outside the egress probe (`ps`, two `git` commands and `/bin/bash`, each with its exact arguments) and the variables `MODEL_ID`, `MODEL_API_KEY` and `APPROVAL_GRANT` it needs for a local run. A server release that changes any of them turns the gate red until a person has reviewed the new invocations or variables and updated the fixture. The per-tool axes gate (CN-013) pins wording the same way in `test/negctl/CN-013.json`: the start of the line with which a local run of `@sema-agent/server` 7.136.0 reports a call it refused for want of a person, and the reason that line gives for each of the two refusals it expects (the engine's wording, `@sema-agent/core` 7.55.0). | The server documents neither its helper processes nor the minimal environment of a local run as a stable contract, nor the wording of a refused call (the engine gives no code per reason); the fixtures record what the pinned releases do, and a reviewed change is what the gates are for. | A new version of the `@sema-agent/server` development dependency. | The server documents these helpers and variables as a stable contract, or publishes a machine-readable minimal environment that the gate can read instead of the fixture; for the refusal wording, a refusal the server reports with a code per reason. |
|
|
11
11
|
| KL-03 | On the hosted http face, `GET /status` answers `503` until a client has opened a session and the connector has answered `initialize`; a health probe on a fresh launcher sees an error although the launcher is fine (the compose healthcheck probes for the `401` instead). | The status lists the tools the caller sees, which only a running connector can tell; a `200` before that would carry an invented empty list, and the contract has no way to say "unknown". | Reading `/status` on a hosted launcher before any session, or after the session ended. | A `connector-status-v1` change that can state the tools as unknown, or a hosted launcher that starts its connector at boot (M2, with the token vault). |
|
|
12
12
|
| KL-04 | A connector that takes none of its waiting input for 10 seconds is ended as "stalled" (`connector.internal` on every pending call; exit 5 on stdio), also when it is merely busy: a client that keeps sending more than the pipe holds while one tool runs synchronously for over 10 seconds loses its pending calls. A reader taking at least about 1 KiB per 10 seconds is not affected. | The launcher cannot tell "stopped reading" from "busy", and without the bound a connector that stops reading leaves the launcher and itself hanging when upstream only closes its pipe (CN-025). | A connector that blocks for more than 10 seconds while more input than the pipe buffer waits for it. | A connector protocol signal for "busy", or a measured need for a longer bound from a real connector (M1). |
|
|
13
13
|
| KL-05 | A connector directory whose `.auth.lock` was left behind (a process killed while holding it, a power loss during `auth`) stops every launch of that connector: the launcher waits 5 seconds, exits 2 and names the lock; `auth` and `status` wait and refuse the same way, until someone removes the lock file by hand. | The lock is never guessed stale (a live holder could be slow), the same rule as the mount lock; a liveness check by pid would be wrong across machines and containers. | A crash or kill while a write or a launch snapshot holds the lock. | A lock that carries a lease the holder renews, or an operator command that removes a lock after checking its holder. |
|
|
@@ -19,10 +19,10 @@ contract, or a long-lived transitional path: those are defects and get a ticket
|
|
|
19
19
|
| KL-11 | The GitHub connector hands its personal access token to github-mcp-server in the variable `GITHUB_PERSONAL_ACCESS_TOKEN`: while github-mcp-server runs, a process of the same user (or root) that reads other processes' environments reads the token, and so does a crash report or core dump that records the environment. The Gitea connector hands gitea-mcp only the path of its 0600 copy, so its token is only ever in a file (which the same user can read too). | github-mcp-server 2.0.2 takes a personal access token from that variable only: it has no file or descriptor input for it. An argument would be readable by every process, so the variable is the narrowest way in. | Running the GitHub connector where other processes of the same user are not trusted. | github-mcp-server gains a file or descriptor input for the token (the connector then hands it the per-launch copy's path, as for Gitea). |
|
|
20
20
|
| KL-12 | With a token that looks like a classic personal access token (it starts with `ghp_`), github-mcp-server 2.0.2 sends `HEAD https://api.github.com/` (with a stored host, `HEAD <host>/api/v3/`) with the token every time it starts, before any tool is called, to read the token's scopes: every start of the GitHub connector, `sema-connector-github status` included, contacts GitHub. With a token that starts like a fine-grained one (`github_pat_`) or with neither prefix it connects nowhere until a tool is called; other kinds of token (such as `gho_`) were not measured. | It is github-mcp-server's own start-up (it hides the tools a classic token cannot use) and no option of it turns the request off; the destination is the GitHub API the token belongs to, and the gate fails on any other. | Starting the GitHub connector with a classic personal access token. | github-mcp-server gains an option to skip the scope request, or a deployment needs a start without network (a fine-grained token avoids it today). |
|
|
21
21
|
| KL-13 | A standalone connector that needs no credentials never runs: with no secret handle the launcher parks the session (see "Parked session" in `ARCHITECTURE.md`), so such a connector shows `unauthorized`, lists no tools and has no `auth` to run; storing any secret handle for it starts it. | The state has one judgement (a secret handle is present or not) and no second fact such as a declaration by the connector that it needs none; the private stub and the gates' planted connectors store a handle first. | A connector package that takes no credential, mounted in a standalone directory. | A connector of this repository that genuinely needs no credential (the browser connector of M1 keeps its login state as a handle instead). |
|
|
22
|
-
| KL-14 | `statusCommand` and `seed` find the launcher and the connector packages through this package's own `package.json` (`import.meta.url`), so a copy of `@sema-agent/connectors` inlined into another program's bundle cannot run them (`mount`
|
|
22
|
+
| KL-14 | `statusCommand` and `seed` find the launcher and the connector packages through this package's own `package.json` (`import.meta.url`), so a copy of `@sema-agent/connectors` inlined into another program's bundle cannot run them (`mount`, `unmount`, `listMounted` and their CLI wrappers are unaffected: none of them resolves its own package); the package is consumed installed. | A bundled copy has no package directory to resolve from, and a second way of finding the launcher would be a second source. | A command-line tool that bundles its dependencies and calls `statusCommand` or `seed`. | A consumer that must bundle; then the launcher path and the resolution root become explicit inputs of those two functions. |
|
|
23
23
|
| KL-23 | A standalone browser connector that is mounted without a `tools.json` grants every tool, `browser_run_code_unsafe` and `browser_evaluate` among them (CN-054 gives the operator the allow list; nothing writes one by default). | A default policy would be a second source of what the operator decides, and the shared layer does not know one connector's tools from another's. | The browser connector mounted with no policy file. | A connector package that ships a default `tools.json` the operator can override, as one rule for every connector. |
|
|
24
24
|
| KL-24 | The GitHub connector authenticates with a personal access token only; github-mcp-server's own OAuth login never runs, because the parked session keeps the upstream from starting without a token (CN-052). | An OAuth flow needs a person at a browser and a place to keep the result; the connector's `auth` and the handle store are that place, and the flow is designed when a deployment needs it rather than guessed now. | A deployment that cannot issue personal access tokens. | A deployment that needs OAuth: then `auth` gains an OAuth form that stores the result as the token handle (the GitHub connector's next minor). |
|
|
25
|
-
| KL-17 | The standalone browser connector has no egress policy: the browser opens whatever URL a tool call names, follows redirects and loads what pages load. playwright-mcp's `--allowed-origins` is not a security boundary (playwright-mcp says so) and is not used. | Browsing what the engine asks for is the connector's purpose; an egress policy belongs to the hosted container (M2, M3), enforced outside the browser. | Any browsing. | The hosted deployment's egress proxy (M3), or a standalone policy with an enforcement point outside the browser. |
|
|
25
|
+
| KL-17 | The standalone browser connector has no egress policy: the browser opens whatever URL a tool call names, follows redirects and loads what pages load. playwright-mcp's `--allowed-origins` is not a security boundary (playwright-mcp says so) and is not used. | Browsing what the engine asks for is the connector's purpose; an egress policy belongs to the hosted container (M2, M3), enforced outside the browser. | Any browsing. | The hosted deployment's egress proxy (M3), whose only input is the engine's host floor entries, or a standalone policy with an enforcement point outside the browser. |
|
|
26
26
|
| KL-18 | On Linux, Chromium's sandbox needs unprivileged user namespaces (or a setuid sandbox helper): in a container without them Chromium does not start and every page tool fails. The browser connector always passes `--sandbox` (playwright-mcp leaves the sandbox off on Linux for Chrome for Testing otherwise) and never `--no-sandbox`. | Without the sandbox a compromised renderer acts as the user; the container's profile (user namespaces, seccomp) is the deployment's to provide, not the connector's to work around. | The browser connector on Linux where user namespaces are disabled, as in many container runtimes by default. | The hosted deployment declares a container profile with user namespaces (M2), or a measured deployment that cannot provide them. |
|
|
27
27
|
| KL-19 | Chrome for Testing 155 contacts Google on its own when it starts, although Playwright passes switches meant to keep it quiet: the browser gate's proxied run names `accounts.google.com`, `update.googleapis.com`, `www.google.com` and `android.clients.google.com` (port 443), and past a proxy Chromium also connects a UDP socket to `[2001:4860:4860::8888]:443`; without a proxy it goes through the system's proxy settings or directly. | The requests come from Chromium components no option of playwright-mcp turns off, and the connector passes Chromium no switch of its own; the gate contains them and fails on a host outside google.com and googleapis.com. | Every start of the browser. | A playwright-mcp option or a Chromium switch that stops them, an egress policy (KL-17), or a host outside those domains in the gate's reading. |
|
|
28
28
|
| KL-20 | Chrome for Testing is pinned for `darwin-arm64` and `linux-x64` only: on another platform `install` of the browser connector refuses (`pins no playwright-mcp build for <platform>`). | Chrome for Testing publishes no Linux arm64 build, and the macOS x64 build has not been fetched and checked. | Installing the browser connector on another platform. | A request for another platform, with its archive downloaded and its sha256 checked. |
|
|
@@ -33,3 +33,7 @@ contract, or a long-lived transitional path: those are defects and get a ticket
|
|
|
33
33
|
| KL-27 | A request line the launcher cannot read on stdio (over 4 MiB, a batch, a repeated key, an id that is neither a string nor a number) is answered with `id` null and `connector.request_unreadable` (CN-030), so an MCP client cannot match the answer to the request it sent: it sees an error it cannot place and waits for that request until its own timeout. Over the hosted http face the same refusal is the answer to its own http request (`400` or `413`), so nothing waits there. | Nothing of a line the launcher cannot read is read, its id included: a batch has no single id, a line over 4 MiB is never parsed, and an object with a repeated key may carry an id that parsers read differently, so reading an id out of it would judge a message the launcher has just refused to judge. JSON-RPC answers a request whose id it cannot detect with id null too. | A tool call whose arguments make its line longer than 4 MiB; a batch, a repeated key or an id of another type, which the MCP SDK clients do not send. | A client measured waiting on such a request in normal use, or one reading of the id that every parser shares agreed for these lines. |
|
|
34
34
|
| KL-28 | A host can stop delivering the sandbox reports of one executable while the sandbox goes on refusing (seen on 2026-10-22: for hours no report of a refused node connection, while bash was reported as before). The connector gates then cannot see what node processes try past the probe, the planted upstreams included: the attempts are refused (the gates' control processes read `EPERM`) but not observed, and the last line of each gate says so ("the host delivered no sandbox reports for node, so attempts by unprobed processes (...) were blocked but not observed"). Delivery is shown only for the executables of the gates' control processes (bash and node); for gitea-mcp, github-mcp-server and Chrome for Testing the gates read the reports that come and cannot tell a host that drops them. | The reports are the host's to deliver, and nothing in sandbox-exec or the system log asks for them; what keeps a connection from leaving is the refusal, which the control still proves on every run. Failing the gate would turn it red for something this repository cannot change. | A host that stops delivering the reports of an executable. | A check that needs the reports themselves, not the refusal, comes to depend on them (github-mcp-server's name lookups are read from its reports), or the reports of a pinned program are seen missing: then that program gets a control process of its own. |
|
|
35
35
|
| KL-29 | On the hosted http face a session that has had no request of its own for 10 minutes is released (CN-033): a client that holds a session, sends nothing for longer and then sends a request gets `404` for its session id and has to `initialize` again (MCP Streamable HTTP answers that `404` with a new session). A request in flight for longer than 10 minutes is not affected, and neither is its session while it waits. The 10 minutes are fixed: no deployment setting changes them. | The face opens no stream, so the launcher has no sign that a client is still there other than its requests; a session held until `DELETE` kept every other client at `409` until the launcher restarted, and one fixed time is one rule for every deployment. | A client idle for more than 10 minutes within one session. | A deployment measuring clients that are idle for longer in normal use, or the hosted session model of M2 (a session per client, or a stream that shows the client is there). |
|
|
36
|
+
| KL-30 | There is no media connector, and the media service's external contract list (its HTTP and console faces, and the refusal shape of its MCP tool face: an `isError: true` result whose text starts with `<code>: <text>`) is not consumed by anything in this repository. | The media connector is M4 work behind the hosted container (M2); until it is designed there is nothing to pin, and a ticket that only waits is not a debt. | Any media use case. | The M4 media connector design, which reads the service's list and takes its refusal shape into the contract review. |
|
|
37
|
+
| KL-31 | A connector that changes its tool list at runtime is not re-read by the engine: the launcher forwards `notifications/tools/list_changed`, but the engine does not consume it, so a tool declared after the handshake is refused until the session is reconnected. | The consumer side is the engine's, and the engine has closed its ticket as a known limit; there is nothing in this repository to pin until the engine reads the notification. | A connector whose tool list changes while a session is open. | The engine consuming `tools/list_changed`; this repository then adds the positive control (the pointer ticket CN-018 is closed into this entry). |
|
|
38
|
+
| KL-32 | After a person adds `toolAxes` (or any other member) to a connector's standalone entry in `config.d/mcp.json`, `mount` of that connector refuses with a conflict (exit 1) and leaves the entry as written, and a seed that has not yet recorded the connector reports it as `conflict` (exit 1). `list` no longer shows the connector as mounted (the entry is no longer exactly what `mount` would write) and `unmount` refuses to remove it (`unexpected_shape`, never deleting what it did not write): recovering the standalone catalog's own reading of the connector means removing the extended entry from `config.d/mcp.json` by hand. | `mount` compares the whole entry and never overwrites one; telling the deployment's members from its own would need a list of the catalog's members, which are the settings schema's (this repository defines no catalog types). | Running `mount`, `list` or `unmount`, or a first seed, after editing the entry by hand. | The CLI wrapper (CN-012) editing entries through `mount`, or a reader of the entry's deployment members exported by the settings schema. |
|
|
39
|
+
| KL-33 | One entry anywhere in `config.d/mcp.json`'s `servers` that is nested too deep to compare (deeper than the shape comparison follows) makes `mount` and `unmount` of every connector in that configuration directory refuse with `unexpected_shape`, and `listMounted` refuse the whole call, not only the one entry: the post-write verification compares the whole list, so one unreadable entry means no write can be verified. | Answering for the other entries while one cannot be read would report a list shorter than the truth, or write a file whose verification is partial; refusing the whole call keeps the file and the lock exactly as they were. The limit on width (an entry with very many members) and the cost of `listMounted` on a very long list are not measured and not pinned. | A hand-edited `config.d/mcp.json` with a deeply nested entry (a seed or `mount` never writes one). | A reader of the catalog that reports per-entry problems instead of refusing the whole file (a settings-schema export of the entry shape would make that reading one source). |
|
package/README.md
CHANGED
|
@@ -105,6 +105,10 @@ connector and answers itself (see "Parked session" in [`ARCHITECTURE.md`](../ARC
|
|
|
105
105
|
25 tools of playwright-mcp (26 with the export on, see "Exporting the login state"); reading them starts playwright-mcp
|
|
106
106
|
but not the browser, which starts at the first tool that needs a page.
|
|
107
107
|
|
|
108
|
+
`unmount` removes that entry again and `list` prints the connectors mounted in the configuration directory, through the
|
|
109
|
+
shared `unmount` and `listMounted` (`@sema-agent/connectors` 0.9.0, CN-065); an entry under this connector's name that
|
|
110
|
+
is not exactly what `mount` writes is refused and left alone, and never listed (`KNOWN-LIMITS.md`, KL-32).
|
|
111
|
+
|
|
108
112
|
## What runs
|
|
109
113
|
|
|
110
114
|
With no arguments, `sema-connector-browser` is the connector process the launcher starts. It refuses to start (exit 1,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// sema-connector-browser (CN-027): the browser connector's executable. With no arguments it runs the pinned Playwright
|
|
3
|
-
// MCP server as an MCP stdio server; a first argument dispatches install, auth, mount
|
|
4
|
-
// (docs/CONNECTORS/browser.md). Implementation: src/cli.ts, built to dist/cli.js.
|
|
3
|
+
// MCP server as an MCP stdio server; a first argument dispatches install, auth, mount, unmount, status
|
|
4
|
+
// and list (docs/CONNECTORS/browser.md). Implementation: src/cli.ts, built to dist/cli.js.
|
|
5
5
|
import { main } from '../dist/cli.js'
|
|
6
6
|
|
|
7
7
|
process.exitCode = await main(process.argv.slice(2), process.env)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/connector-browser",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Browser connector: runs the pinned Playwright MCP server and a pinned Chrome for Testing behind the sema-connector launcher, in an isolated, headless session whose login state is a secret handle.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"build": "tsc -p tsconfig.json"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@sema-agent/connectors": "0.
|
|
26
|
+
"@sema-agent/connectors": "0.9.0",
|
|
27
27
|
"@sema-agent/connectors-contract": "0.2.0"
|
|
28
28
|
},
|
|
29
29
|
"engines": {
|