WebMCP: research, then expose calternal actions to in-browser agents #160

Closed
opened 2026-09-26 09:40:13 +00:00 by kayg · 14 comments
Owner

Owner 2026-09-26: 'can we add WebMCP support to our app? research it.'

Phase 1 (research, commit docs/research/webmcp.md in ASD-STE100 style, sources linked): what WebMCP is today (W3C Web Machine Learning CG / WICG proposal, navigator.modelContext, declarative vs imperative tool registration, which browsers/agents ship it: Chrome flag/origin trial status, Edge, extensions, polyfills like MCP-B), its security model (user-visible consent, same-origin, tool annotations like readOnlyHint/destructiveHint), and how it differs from our server-side agent tokens (DESIGN §21: agents are data-scope only).
Phase 2 (build, only if phase 1 shows a usable API or an AGPL-compatible polyfill): register a small, safe tool set from the SPA via feature detection (no effect in browsers without it): search (read-only, only what the user can access), open/deep-link to an item (§33 grammar), read today's journal/agenda, create a log entry/task/note through the same client API the composer uses (destructive actions require an in-app confirmation), list files in a folder. Every tool runs as the signed-in user with the page's session, never adds privileges, and respects admin-only rules. Tools live in one module with a registry and unit tests; e2e with a stub modelContext that calls each tool.
Do not build anything marked OPEN in DESIGN. Report: findings, what shipped, what is blocked on browser support.

Owner 2026-09-26: 'can we add WebMCP support to our app? research it.' Phase 1 (research, commit docs/research/webmcp.md in ASD-STE100 style, sources linked): what WebMCP is today (W3C Web Machine Learning CG / WICG proposal, navigator.modelContext, declarative vs imperative tool registration, which browsers/agents ship it: Chrome flag/origin trial status, Edge, extensions, polyfills like MCP-B), its security model (user-visible consent, same-origin, tool annotations like readOnlyHint/destructiveHint), and how it differs from our server-side agent tokens (DESIGN §21: agents are data-scope only). Phase 2 (build, only if phase 1 shows a usable API or an AGPL-compatible polyfill): register a small, safe tool set from the SPA via feature detection (no effect in browsers without it): search (read-only, only what the user can access), open/deep-link to an item (§33 grammar), read today's journal/agenda, create a log entry/task/note through the same client API the composer uses (destructive actions require an in-app confirmation), list files in a folder. Every tool runs as the signed-in user with the page's session, never adds privileges, and respects admin-only rules. Tools live in one module with a registry and unit tests; e2e with a stub modelContext that calls each tool. Do not build anything marked OPEN in DESIGN. Report: findings, what shipped, what is blocked on browser support.
Author
Owner

Started research on branch job/webmcp at base 82d4c258bb. I will verify the W3C/WICG proposal, browser support, and MCP-B before deciding whether phase 2 is usable.

Started research on branch job/webmcp at base 82d4c258bbcc6f34e8805d0018004fa8e621b9a5. I will verify the W3C/WICG proposal, browser support, and MCP-B before deciding whether phase 2 is usable.
Author
Owner

Research committed at af96ab3. Primary sources show the current API is document.modelContext.registerTool with AbortSignal lifecycle; Chrome documents an origin trial and local flag. The current draft uses consequentialHint, not older destructiveHint. MCP-B core is MIT licensed, but native feature detection avoids a runtime dependency. Implementation is under test.

Research committed at af96ab3. Primary sources show the current API is document.modelContext.registerTool with AbortSignal lifecycle; Chrome documents an origin trial and local flag. The current draft uses consequentialHint, not older destructiveHint. MCP-B core is MIT licensed, but native feature detection avoids a runtime dependency. Implementation is under test.
Author
Owner

Phase 2 is committed in 3f22843 (tool registry, User-session client adapters, ConfirmSheet) and 1cce455 (stub modelContext browser harness). Merged current dev cleanly at b6adf756. Unit tests passed (4/4) and the merged web check reports 0 errors, 0 warnings. Full gates are running; a pre-merge full web run had one 5-second timeout in the unrelated theme contrast test under host load (359 passed).

Phase 2 is committed in 3f22843 (tool registry, User-session client adapters, ConfirmSheet) and 1cce455 (stub modelContext browser harness). Merged current dev cleanly at b6adf756. Unit tests passed (4/4) and the merged web check reports 0 errors, 0 warnings. Full gates are running; a pre-merge full web run had one 5-second timeout in the unrelated theme contrast test under host load (359 passed).
Author
Owner

A focused malformed-input test found that extra tool fields were accepted despite additionalProperties: false in the schema. Browsers need not enforce that schema. Commit c53215c rejects extra fields in every handler before confirmation or API calls; the focused suite is green (4/4).

A focused malformed-input test found that extra tool fields were accepted despite additionalProperties: false in the schema. Browsers need not enforce that schema. Commit c53215c rejects extra fields in every handler before confirmation or API calls; the focused suite is green (4/4).
Author
Owner

Gate finding: exact bun run test on merged dev finished 401 passed, 1 failed only by the theme contrast test's 5-second timeout; that file passed 55/55 with a 30-second timeout in isolation. First cargo clippy attempt failed because shared sccache used a deleted temp directory in another worktree; retry with RUSTC_WRAPPER unset is compiling normally. Final web check reports 0 errors and 0 warnings.

Gate finding: exact bun run test on merged dev finished 401 passed, 1 failed only by the theme contrast test's 5-second timeout; that file passed 55/55 with a 30-second timeout in isolation. First cargo clippy attempt failed because shared sccache used a deleted temp directory in another worktree; retry with RUSTC_WRAPPER unset is compiling normally. Final web check reports 0 errors and 0 warnings.
Author
Owner

Rust clippy passed after disabling the shared sccache wrapper: cargo clippy --all-targets -- -D warnings: 'Finished profile [unoptimized + debuginfo] target(s) in 44m 13s'. cargo fmt --check passed with no output. Workspace cargo test is running.

Rust clippy passed after disabling the shared sccache wrapper: cargo clippy --all-targets -- -D warnings: 'Finished profile [unoptimized + debuginfo] target(s) in 44m 13s'. cargo fmt --check passed with no output. Workspace cargo test is running.
Author
Owner

Rust clippy passed after disabling the shared sccache wrapper. Gate output: Finished dev profile [unoptimized + debuginfo] target(s) in 44m 13s. cargo fmt --check passed with no output. Workspace cargo test is running.

Rust clippy passed after disabling the shared sccache wrapper. Gate output: Finished `dev` profile [unoptimized + debuginfo] target(s) in 44m 13s. cargo fmt --check passed with no output. Workspace cargo test is running.
Author
Owner

The exact web gate passed on retry after host load dropped. Output: Test Files 53 passed (53); Tests 402 passed (402). The prior 5-second theme test timeout did not recur. Final web check: svelte-check found 0 errors and 0 warnings. Rust cargo test is compiling.

The exact web gate passed on retry after host load dropped. Output: Test Files 53 passed (53); Tests 402 passed (402). The prior 5-second theme test timeout did not recur. Final web check: svelte-check found 0 errors and 0 warnings. Rust cargo test is compiling.
Author
Owner

Continued after planned VM restart on job/webmcp. Working tree was clean at 32e361f2; prior comments and commits confirm phase 1, phase 2, and the web gates were complete. Merged current dev at 44b15bec into the job branch with no conflicts. I am running final gates and the production browser test against the merged tree.

Continued after planned VM restart on job/webmcp. Working tree was clean at 32e361f2; prior comments and commits confirm phase 1, phase 2, and the web gates were complete. Merged current dev at 44b15bec into the job branch with no conflicts. I am running final gates and the production browser test against the merged tree.
Author
Owner

Final gate observation after the dev merge: cargo test has passed earlier targets (including the cross-language editor test), but the Files plugin target is slow under shared-host I/O. Its test threads are waiting in jbd2_log_wait_commit; other server processes show the same wait and host load is about 50. No test failure is reported. I am letting the full gate continue and will report the exact exit result.

Final gate observation after the dev merge: `cargo test` has passed earlier targets (including the cross-language editor test), but the Files plugin target is slow under shared-host I/O. Its test threads are waiting in `jbd2_log_wait_commit`; other server processes show the same wait and host load is about 50. No test failure is reported. I am letting the full gate continue and will report the exact exit result.
Author
Owner

Focused gate result after the interrupted workspace run: cargo test -p calternal-plugin-files --lib -- --test-threads=1 passed: test result: ok. 87 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 246.22s. The earlier exact workspace cargo test exited 101 while this target was running, with no failure line in the retained log. The target directory was moved to /mnt/hdd during that run; the exact cause of the exit is not proven. Production web build passed. I am building the server binary for the WebMCP browser test.

Focused gate result after the interrupted workspace run: `cargo test -p calternal-plugin-files --lib -- --test-threads=1` passed: `test result: ok. 87 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 246.22s`. The earlier exact workspace `cargo test` exited 101 while this target was running, with no failure line in the retained log. The target directory was moved to /mnt/hdd during that run; the exact cause of the exit is not proven. Production web build passed. I am building the server binary for the WebMCP browser test.
Author
Owner

Production browser proof: after cargo build -p calternal-server and bun run build, bun e2e/webmcp.mjs --screenshots /mnt/hdd/targets/webmcp-screenshots exits 0 with WebMCP e2e: 7 tools called through stub modelContext. The first run exposed a harness-only unhandled rejection: Cancel was clicked before assert.rejects attached to the expected rejected promise. Commit 3cae739a attaches the assertion first; the rerun passed. Confirmation screenshots are at /mnt/hdd/targets/webmcp-screenshots/ (Log entry, Task, Note). The final workspace cargo test retry is running with four test threads to reduce shared-host I/O pressure.

Production browser proof: after `cargo build -p calternal-server` and `bun run build`, `bun e2e/webmcp.mjs --screenshots /mnt/hdd/targets/webmcp-screenshots` exits 0 with `WebMCP e2e: 7 tools called through stub modelContext`. The first run exposed a harness-only unhandled rejection: Cancel was clicked before `assert.rejects` attached to the expected rejected promise. Commit 3cae739a attaches the assertion first; the rerun passed. Confirmation screenshots are at /mnt/hdd/targets/webmcp-screenshots/ (Log entry, Task, Note). The final workspace cargo test retry is running with four test threads to reduce shared-host I/O pressure.
Author
Owner

WebMCP #160 final report

Head: 3cae739a52f1bb2575cd8b76639e6778393a0fc1 on job/webmcp. Merged dev into this branch at 0decf474; no push, deployment, or merge into dev was done by this job. The worktree is clean.

Built

  • Researched the current WebMCP draft, browser support, consent limits, annotations, and MCP-B license. Sources are linked in docs/research/webmcp.md.
  • Added seven SPA tools through feature detection of document.modelContext: search, open a stable item link, read today's Daily note and agenda, list a Home folder, and create a Log entry, Task, or Note. Calls use the signed-in User session and existing server API. Each create requires an in-app confirmation. No account or admin action is exposed.
  • Added a registry unit test and a production browser test with a stub modelContext. The test uses the real local server and verifies all seven tools, cancellation, search, and navigation. Fixed the test's expected-cancellation rejection timing in 3cae739a.

Files: docs/research/webmcp.md, apps/web/src/lib/webmcp/tools.ts, apps/web/src/lib/webmcp/tools.test.ts, apps/web/src/routes/+layout.svelte, apps/web/e2e/webmcp.mjs, apps/web/package.json.

Gates (verbatim output lines)

cargo fmt --check: exit 0, no output.

cargo clippy --all-targets -- -D warnings: exit 0.

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 59.89s

cargo test with RUST_TEST_THREADS=4: exit 0; 67 test targets completed. Selected output lines:

test result: ok. 87 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 93.70s
test result: ok. 89 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 152.33s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

bun run check: exit 0.

svelte-check found 0 errors and 0 warnings

bun run test: exit 0.

 Test Files  54 passed (54)
      Tests  421 passed (421)

bun run build: exit 0.

  Wrote site to "build"
  ✔ done

bun e2e/webmcp.mjs --screenshots /mnt/hdd/targets/webmcp-screenshots: exit 0.

WebMCP e2e: 7 tools called through stub modelContext

Confirmation screenshots: /mnt/hdd/targets/webmcp-screenshots/calternal_create_log.png, /mnt/hdd/targets/webmcp-screenshots/calternal_create_task.png, /mnt/hdd/targets/webmcp-screenshots/calternal_create_note.png (1280 × 720). Full gate logs are in /mnt/hdd/targets/webmcp-gates/. cargo clean removed 17,711 files and 13.9 GiB; the web build output was removed.

Findings and limits

The first full cargo test attempt exited 101 during the Files target without a failure line in its retained log. During that run, the target directory was moved to /mnt/hdd; the exact exit cause is not proven. A focused Files run passed 87/87, and the final full workspace retry passed.

Native WebMCP support is experimental. The production browser test uses a stub because ordinary Chromium does not expose the API by default. No polyfill is loaded, so browsers without document.modelContext keep the normal SPA behavior and expose no WebMCP tools. Live agent behavior under Chrome's origin trial remains unverified.

Decisions where DESIGN is silent

Use the draft's imperative document.modelContext API behind feature detection, with no default MCP-B dependency. Treat tool annotations as hints, validate every callback input in the page, and require calternal's own confirmation for creates. Keep the tool set to existing User-session APIs and stable deep links from DESIGN §33.

# WebMCP #160 final report Head: `3cae739a52f1bb2575cd8b76639e6778393a0fc1` on `job/webmcp`. Merged `dev` into this branch at `0decf474`; no push, deployment, or merge into `dev` was done by this job. The worktree is clean. ## Built - Researched the current WebMCP draft, browser support, consent limits, annotations, and MCP-B license. Sources are linked in `docs/research/webmcp.md`. - Added seven SPA tools through feature detection of `document.modelContext`: search, open a stable item link, read today's Daily note and agenda, list a Home folder, and create a Log entry, Task, or Note. Calls use the signed-in User session and existing server API. Each create requires an in-app confirmation. No account or admin action is exposed. - Added a registry unit test and a production browser test with a stub `modelContext`. The test uses the real local server and verifies all seven tools, cancellation, search, and navigation. Fixed the test's expected-cancellation rejection timing in `3cae739a`. Files: `docs/research/webmcp.md`, `apps/web/src/lib/webmcp/tools.ts`, `apps/web/src/lib/webmcp/tools.test.ts`, `apps/web/src/routes/+layout.svelte`, `apps/web/e2e/webmcp.mjs`, `apps/web/package.json`. ## Gates (verbatim output lines) `cargo fmt --check`: exit 0, no output. `cargo clippy --all-targets -- -D warnings`: exit 0. ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 59.89s ``` `cargo test` with `RUST_TEST_THREADS=4`: exit 0; 67 test targets completed. Selected output lines: ``` test result: ok. 87 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 93.70s test result: ok. 89 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 152.33s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `bun run check`: exit 0. ``` svelte-check found 0 errors and 0 warnings ``` `bun run test`: exit 0. ``` Test Files 54 passed (54) Tests 421 passed (421) ``` `bun run build`: exit 0. ``` Wrote site to "build" ✔ done ``` `bun e2e/webmcp.mjs --screenshots /mnt/hdd/targets/webmcp-screenshots`: exit 0. ``` WebMCP e2e: 7 tools called through stub modelContext ``` Confirmation screenshots: `/mnt/hdd/targets/webmcp-screenshots/calternal_create_log.png`, `/mnt/hdd/targets/webmcp-screenshots/calternal_create_task.png`, `/mnt/hdd/targets/webmcp-screenshots/calternal_create_note.png` (1280 × 720). Full gate logs are in `/mnt/hdd/targets/webmcp-gates/`. `cargo clean` removed 17,711 files and 13.9 GiB; the web build output was removed. ## Findings and limits The first full `cargo test` attempt exited 101 during the Files target without a failure line in its retained log. During that run, the target directory was moved to `/mnt/hdd`; the exact exit cause is not proven. A focused Files run passed 87/87, and the final full workspace retry passed. Native WebMCP support is experimental. The production browser test uses a stub because ordinary Chromium does not expose the API by default. No polyfill is loaded, so browsers without `document.modelContext` keep the normal SPA behavior and expose no WebMCP tools. Live agent behavior under Chrome's origin trial remains unverified. ## Decisions where DESIGN is silent Use the draft's imperative `document.modelContext` API behind feature detection, with no default MCP-B dependency. Treat tool annotations as hints, validate every callback input in the page, and require calternal's own confirmation for creates. Keep the tool set to existing User-session APIs and stable deep links from DESIGN §33.
Author
Owner

Merged into dev at 8521846d after Claude's screenshot review. Deploy status on #203.

Merged into dev at 8521846d after Claude's screenshot review. Deploy status on #203.
kayg closed this issue 2026-09-26 16:42:15 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#160
No description provided.