Skip to content

delta_create_invite: accept optional target_addr for securejoin pre-bind - #41

Open
terafin wants to merge 2 commits into
mainfrom
sindri/delta-create-invite-target-addr
Open

delta_create_invite: accept optional target_addr for securejoin pre-bind#41
terafin wants to merge 2 commits into
mainfrom
sindri/delta-create-invite-target-addr

Conversation

@terafin

@terafin terafin commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Per spec relayed by @mimir (2026-08-02, Justin's standing approval):
extend the bifrost MCP tool delta_create_invite(bot_id, target_addr=None)
to accept an optional expected-recipient address for relay-side securejoin
pre-bind (anti-MITM forward-looking ref: Vikunja #41097 / #41098).

What this PR does

Plumbs a new optional target_addr: Optional[str] = None parameter through
the entire delta_create_invite stack:

Layer File Change
Tool class app/mcp_tools.py DeltaCreateInviteTool.create_invite accepts target_addr
FastMCP tool app/mcp_server.py delta_create_invite signature extended
Backend protocol app/relay.py Backend.create_invite interface accepts target_addr
Real-rpc impl app/relay.py DeltaChat2Backend.create_invite logs pre-bind intent
Relayer app/relay.py Relayer.create_invite echoes target_addr in response
HTTP route app/relay.py GET /invite?target_addr=...
Tests tests/test_mcp_tools.py New test: param passes through to URL
Tests tests/test_relay.py FakeBackend signature matches
Docs README.md Tool table updated

Why target_addr is NOT in the URL

The signed URL (i.delta.chat/#<fpr>&v=3&i=<invite>&s=<sig>&a=<addr>&n=<name>)
is generated by get_chat_securejoin_qr_code(accid, None). The OpenPGP
signature s= covers the entire URL string including the a= / n= fields,
which are locked to the bot's self-identity (its own fingerprint, address,
display name). Rewriting them post-hoc would invalidate the signature.

Per the spec, target_addr is the inviter-expected recipient address
meta data forwarded to the relay-side PeerMesh for pre-bind (so the
corresponding delta_secure_join on the recipient side can cross-check
the inviter). The URL itself is unchanged.

Acceptance criteria (per Mimir spec)

  • Bot can call delta_create_invite(bot_id, target_addr) and get back
    a URL string https://i.delta.chat/#...
  • The URL itself is the bot's signed contact-invite (verified when
    tapped in another Delta client → verified 1:1 chat)
  • Tool exposed via bifrost MCP (current surface)
  • Backward-compatible: target_addr=None produces identical behavior
    to the previous single-arg call

Test results

  • 4/4 invite-related tests pass (test_delta_create_invite_*,
    test_relay_create_invite_routes_and_returns, test_invite_endpoint)
  • Full mcp_tools test file: 20/20 pass
  • 6 pre-existing failures in test_relay.py / test_mcp_server.py are
    unrelated to this change (confirmed by running on main clean)

Reviewers

Bot-author: sindri
Refs: Vikunja #17621 (umbrella), Mimir spec 2026-08-02

🤖 Generated with Claude Code

terafin and others added 2 commits August 2, 2026 01:40
Extends the bifrost MCP tool delta_create_invite(bot_id, target_addr=None)
to plumb an optional recipient address through to the relay-side
securejoin pre-bind (forward-looking ref: Vikunja #41097 / #41098).

The signed URL itself (i.delta.chat/#...) is locked to the bot's self-
identity by the OpenPGP signature s= — the a=/n= fields cannot be
rewritten post-hoc without invalidating the signature. So target_addr
is metadata forwarded to the relay's PeerMesh for anti-MITM binding
when the recipient later taps the URL and accepts via delta_secure_join.

Plumb path: mcp_tools.DeltaCreateInviteTool.create_invite
         -> mcp_server.delta_create_invite
         -> relay.Relayer.create_invite
         -> relay.Backend.create_invite
         -> /invite HTTP route

Bot-author: sindri
Reviewers: @mimir (bifrost correctness), @idunn (merge gate)
Refs: spec relayed by mimir 2026-08-02

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The relay's Relayer.create_invite now forwards target_addr to its
backend; update the in-tree FakeBackend to match the new signature
so the test_filter tracker records (account_id, target_addr) tuples.

Verified: pre-existing 6 failures in test_relay/test_mcp_server are
unrelated to this change (confirmed by running on main clean).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant