communications-access-broker
by nasserma
README.md
# communications-access-broker
Communications MCP access broker: tiered, human-gated chat access to
Matrix and Microsoft Teams, built on access-broker-core. Fourth broker
in the suite.
## Why access brokers
The Model Context Protocol connects AI agents to real infrastructure:
file stores, chat platforms, mail servers, a home. Its permission model
is static. An MCP server declares a list of tools; the client shows the
list to the user once, at install time; the user approves; from then on,
every tool call runs with the server's full credential.
The model cannot express what matters once the infrastructure is real.
- A grant is all-or-nothing at install time. There is no scoped, expiring
grant for one folder, one room, or one lock. Approving the server
approves everything it can reach.
- There is no per-operation review. After install, a destructive write
runs as freely as a harmless read.
- There is no audit of agent decisions. What the agent requested, what
was refused, and who approved what is recorded nowhere the owner
controls.
- There is no human gate for sensitive actions. The only approval
happened between the agent and the client, before any concrete
operation existed.
- The credential at the server carries everything the server can do.
Tool descriptions that promise restraint are advisory; the token is
not.
An access broker is an MCP server that closes these gaps for one domain.
It holds the real credential, exposes a deliberately small tool surface,
and turns access into an explicit object: a scoped, expiring, audited,
human-approved grant, evaluated per operation.
## The access broker model
The suite implements one model with seven properties. Every broker
carries all of them; the mechanics live in access-broker-core.
1. A tier model per domain. Every operation is classified before it can
be requested. T0/T1 are free-lane reads and reversible actions that
run without a grant. T2 operations are sensitive and require
per-operation human approval through an approval gateway on a chat
platform; the agent cannot self-approve, and batches do not exist.
T3 operations are always gated and, where the action is irreversible,
are never offered as tools at all.
2. Declared operations. Each tool names the operation it performs. The
wall, the broker's scope checker, validates the resource and the
operation against active grants before anything executes. The free
lane is defined by the domain tier table, not by what happens to be
exposed.
3. Write-before-operate, hash-chained audit. Every request, execution,
refusal, and human decision is an audit-class event written to a
hash-chained log before the operation runs. `verify_chain` detects
tampering, including truncation. The chain, not memory, is the record
of what the agent did and why.
4. Fail-closed everywhere. Any configuration or validation failure
refuses the boot. Unknown or malformed input denies. A restart never
widens capability and never promotes pending or suspended state.
5. Approval separation. The approval gateway account is never a brokered
account. A broker that could approve its own requests is a design
failure, and the configuration is refused at boot.
6. Custody declarations. The broker declares, machine-readably, what its
backend credentials can reach. An undeclared trust boundary refuses
to start, and the custody class rides every audit record.
7. The D5 two-surface model in the data domain. The agent surface
handles metadata and reasoning; bulk bytes move through a separate
transfer surface addressed only by a CLI holding its own token, with
SHA-256 verify-then-write. File content never enters LLM context.
## The suite
[access-broker-core](https://github.com/nasserma/access-broker-core)
carries the mechanics: the grant store (conditional-SQL CAS state
machine), policy wall evaluation, the hash-chained audit log, the
approval-gateway substrate, the custody registry, the baseline engine,
and transport authentication. Each broker is a thin domain layer: a
scope-checker wall, backend adapters, a tier table, and tool surfaces.
One repo per broker; no monorepo.
| Broker | Domain | Repository |
|---|---|---|
| data-access-broker | WebDAV and OneDrive file stores | https://github.com/nasserma/data-access-broker |
| communications-access-broker | Matrix and Microsoft Teams chat | to be published |
| groupware-access-broker | Mail, calendar, contacts, tasks over IMAP/SMTP, CalDAV/CardDAV, MS Graph | to be published |
| automation-access-broker | Physical automation: Home Assistant entities and services, extendable to any actuated device | to be published |
## What it is
One MCP server brokering an AI agent's access to chat platforms. The
broker holds a dedicated Matrix account's token and a Teams delegated
Graph token; the agent never sees either. It contributes the
communications wall (room scoping), the Matrix (matrix-nio) and Teams
(Graph delta-polling) backends, and the enforcement that gives
approval separation teeth for the first time in the suite: the
brokered Matrix account must never be its own approval gateway, and a
configuration where the two coincide refuses the boot
(`check_approval_separation`).
## The tier model for conversation
- **No free reads.** Conversation content is surveillance-grade; reads
are grant-scoped per room, full stop. A read without an active grant
naming the room is refused. This is the one broker in the suite with
no T0/T1 lane at all: the seventh suite property is data-domain, and
this domain's analogue goes the other way, everything is grant-scoped
because everything a room contains is private by default.
- **T2 gated, per operation (no batches):** send, reply, react,
edit-own. Messages have no version history and no trash; per-
operation approval is the compensating-control argument.
- **T3 gated, never offered:** redaction, deletion, bulk operations,
membership changes, moderation. No v1 tool form reaches them; a
moderation function that cannot be revoked after the fact does not
become a tool.
- **No wildcards.** Grants name rooms exactly; room aliases resolve at
the backend boundary, never in the wall.
- **E2EE fails closed.** Encrypted rooms are detected and refused at
the backend boundary; key custody is a fast-follow with its own
review.
- **One discovery exception: `list_spaces`.** The account-scoped
`@spaces` read (room ids, names, joined/invited state) is the
surface's single free read — audited like every executed op, never
content. Registered only when the deployment enables discovery
(`discovery: true`, the default; `false` removes the tool at
registration time). Everything else in the tier table is unchanged:
a grant-less content read is refused, never approvable by call.
Tool surface: `get_history`, `get_room_state`, `get_members` (reads,
grant-scoped per room; each preflighted — an invisible room refuses
with the real reason, never a silent empty payload), `send_message`,
`reply`, `react`, `edit_own` (each individually human-approved), plus
`request_access`, `check_access`, `revoke_access`, `list_accounts`,
and `list_spaces` (discovery; see the exception above).
## Production-alpha notes
Live-verified 2026-09-21/22 through the owner's native MCP client
(discovery → request → approval → grant → read/send → read-back).
- **Approval-plane shield.** `execute()` and `request_access` refuse
ANY operation on the gateway's own approval room, before the wall:
the brokered identity cannot request access to the room that
approves it. The shield beats active grants and rides
`protected_surfaces` from the gateway config.
- **Membership preflight.** Every content read (`get_history`,
`get_room_state`, `get_members`) verifies the caller's own
membership first: homeservers answer reads on invisible rooms with
an HTTP-200 empty payload, and the preflight turns that into a
refusal with the real reason.
- **T2 grant semantics (open, owner decision pending).** An approved
T2 grant currently carries a time window, while the historical
wording promises per-operation approval every time. No
consume-on-use path exists in v1. Resolution options on record:
execute-time self-revocation after a gated op fires (true one-shot)
or a docstring correction to match the window semantics. Until the
owner decides, treat an approved T2 grant as a time window and audit
it accordingly (grant-level revocation is available agent- and
owner-side).
- **Known cosmetic gaps (queued).** Pending-request dedupe (repeated
requests stack new numbers), the `ops` comma-string parameter shape,
and pre-approval validation of gated-op targets.
## What is NOT here (v1)
Email (never here; drafts and store-and-forward are the groupware
broker's domain), Telegram and Signal (v2), encrypted rooms, voice
(deferred hard: no draft artifact, no revision point), raw user-API
Telegram reads (ToS-sensitive). File storage is the data broker's
domain; PIM is groupware's; entities are the automation broker's.
## Status
Production alpha (owner-verified live 2026-09-22 through the native
MCP client; see the notes above). 327 tests across nine files, 100%
statement and branch on every module; the real-protocol battery runs
against a scratch Dendrite. See CHANGELOG.md and DEPLOYMENT.md
(including the user-space systemd supervision section). Repository
publication: Sourcehut canonical, owner-gated.
## Security
SECURITY.md carries the domain threat model: the primary adversary is
the conversation content itself (a planted prompt injection in any
granted room is inside the agent's trust boundary), the secondary is
the irreversibility of sent messages, the tertiary is the approval
plane. Custody classes are declared per backend (matrix: account-wide;
teams: scoped under the employer app registration). The suite
invariants are stated once in the core README and inherited here.
## Provenance
Author and maintainer: Nasser Mohieddin Abukhdeir. The primary
implementation model was GLM (glm-5.3), with glm-5.3-flash as the
delegated sub-agent model. See AUTHORS.md for the full provenance
record.
## License
GPL-3.0-or-later.This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues