WEBMCP TECHNICAL ARCHITECTURE

Ten tools, one contract, zero hidden state.

Tether exposes four memory tools of its own. Each participating site adds tools that do something real in that product and route through the same shared layer.

TOOL CATALOG

Every tool registered across the three surfaces.

Constrained input schemas, predictable structured output, and a genuine product purpose behind each one.

store_contextTether

Persist a structured memory so any participating site can retrieve it later.

in
{ content, category?, tags?, source?, confidence? }
out
{ memory, duplicate }
retrieve_contextTether

Return the memories most relevant to a query, ranked, with the reason each matched.

in
{ query, source_filter?, limit? }
out
{ memories: [{ ...memory, relevance, matchedOn }] }
update_contextTether

Correct or refine a memory Tether already holds, by id or by matching text.

in
{ id? , match?, content?, category?, tags?, confidence? }
out
{ memory }
delete_contextTether

Permanently remove a memory so no site can retrieve it again.

in
{ id? , match? }
out
{ deleted }
save_preferenceDesignLab

Apply a design preference locally and write it to Tether in one call.

in
{ theme?, density?, language? }
out
{ preferences, stored }
remember_preferenceDesignLab

Remember an arbitrary preference stated in the user's own words — anything the built-in toggles cannot express.

in
{ content, category?, tags?, confidence? }
out
{ memory, duplicate }
get_preferencesDesignLab

Read what DesignLab has applied plus what Tether already knows.

in
{}
out
{ applied, remembered }
get_user_contextDevForge

Fetch project-relevant preferences from Tether without generating anything yet.

in
{ query? }
out
{ memories }
create_projectDevForge

Scaffold a project configured from stored preferences: language, theme, density, framework, package manager, styling.

in
{ name?, use_stored_context? }
out
{ project, config, sourceMemories }
apply_preferencesDevForge

Apply or drop Tether context on the open project, so provenance is visible.

in
{ use_stored_context }
out
{ config }
REGISTRATION

How a page hands an agent a real capability.

Excerpts from the files that ship in this repository.

src/lib/webmcp.tsverbatim from the repo
1// Locate the page's model context across every shape currently in the wild.
2export function discoverModelContext(): ModelContextHandle | null {
3 const candidates = [
4 ["navigator.modelContext", navigator.modelContext],
5 ["window.modelContext", window.modelContext],
6 ["document.modelContext", document.modelContext],
7 ];
8
9 for (const [host, candidate] of candidates) {
10 if (typeof candidate?.registerTool === "function")
11 return { context: candidate, host, api: "registerTool" };
12 if (typeof candidate?.provideContext === "function")
13 return { context: candidate, host, api: "provideContext" };
14 }
15
16 return null; // No agent present. The UI says so; it never fakes a call.
17}
18
19export function registerTools(handle, tools) {
20 for (const tool of tools) handle.context.registerTool(tool);
21}

The adapter probes navigator.modelContext, window.modelContext, and document.modelContext, and supports both the imperative registerTool() and declarative provideContext() shapes, because different WebMCP builds expose different ones. When none is present, the UI reports that plainly rather than simulating an agent.

API CONTRACT

The shared backplane.

POST/api/memoryCreate one structured memory. Idempotent on content.
GET/api/memoryList every memory for the session. Optional source/category filters.
GET/api/memory/search?q=Ranked retrieval with per-memory match reasons.
GET/api/memory/:idFetch one memory by id.
PATCH/api/memory/:idRefine content, category, tags, or confidence.
DELETE/api/memory/:idPermanent removal. The human control path.
GET/api/activityServer-persisted WebMCP event log, shared across tabs.
GET/api/healthStore driver and liveness for the status pill.
PRIVACY MODEL

An MVP architecture, described honestly.

This is a hackathon demo, not a production data platform. Here is exactly what it does and does not do.

No secrets in the browser

The Supabase service-role key is read only inside server-only modules. The client never sees a database credential; it talks to same-origin route handlers.

Session-scoped memories

Each visitor gets an opaque random id in an httpOnly first-party cookie. There are no accounts and no personal data: one visitor's demo can never appear in another's feed.

Every input validated

Tool arguments and API bodies pass through Zod schemas before reaching the store: length caps, category enums, tag limits, and a bounded confidence score.

Deletion is real

DELETE removes the row. There is no archive table and no soft-delete flag. Once removed, retrieve_context cannot return it to any site.

What this is not: Tether does not claim production-grade privacy or security. There is no authentication, no encryption at rest beyond what the database provides, and no multi-user isolation past the session cookie. Do not store sensitive personal data in it.