Skip to main content
Glama
test_messaging_semantics.py4.86 kB
from __future__ import annotations import pytest from fastmcp import Client from mcp_agent_mail.app import build_mcp_server @pytest.mark.asyncio async def test_reply_message_inherits_thread_and_subject_prefix(isolated_env): server = build_mcp_server() async with Client(server) as client: await client.call_tool("ensure_project", {"human_key": "/backend"}) await client.call_tool( "register_agent", {"project_key": "Backend", "program": "codex", "model": "gpt-5", "name": "BlueLake"}, ) m1 = await client.call_tool( "send_message", { "project_key": "Backend", "sender_name": "BlueLake", "to": ["BlueLake"], "subject": "Plan", "body_md": "body", }, ) msg = (m1.data.get("deliveries") or [{}])[0].get("payload", {}) orig_id = int(msg.get("id")) # Reply r = await client.call_tool( "reply_message", {"project_key": "Backend", "message_id": orig_id, "sender_name": "BlueLake", "body_md": "ack"}, ) rdata = r.data expected_thread = msg.get("thread_id") or str(orig_id) assert rdata.get("thread_id") == expected_thread assert str(rdata.get("reply_to")) == str(orig_id) # Subject on delivery payload should be prefixed deliveries = rdata.get("deliveries") or [] assert deliveries subj = deliveries[0].get("payload", {}).get("subject", "") assert subj.lower().startswith("re:") @pytest.mark.asyncio async def test_mark_read_then_ack_updates_state(isolated_env): server = build_mcp_server() async with Client(server) as client: await client.call_tool("ensure_project", {"human_key": "/backend"}) await client.call_tool( "register_agent", {"project_key": "Backend", "program": "codex", "model": "gpt-5", "name": "GreenCastle"}, ) await client.call_tool( "register_agent", {"project_key": "Backend", "program": "codex", "model": "gpt-5", "name": "RedStone"}, ) m1 = await client.call_tool( "send_message", { "project_key": "Backend", "sender_name": "GreenCastle", "to": ["RedStone"], "subject": "AckPlease", "body_md": "hello", "ack_required": True, }, ) msg = (m1.data.get("deliveries") or [{}])[0].get("payload", {}) mid = int(msg.get("id")) mr = await client.call_tool( "mark_message_read", {"project_key": "Backend", "agent_name": "RedStone", "message_id": mid}, ) assert mr.data.get("read") is True and isinstance(mr.data.get("read_at"), str) ack = await client.call_tool( "acknowledge_message", {"project_key": "Backend", "agent_name": "RedStone", "message_id": mid}, ) assert ack.data.get("acknowledged") is True assert isinstance(ack.data.get("acknowledged_at"), str) assert isinstance(ack.data.get("read_at"), str) @pytest.mark.asyncio async def test_acknowledge_idempotent_multiple_calls(isolated_env): server = build_mcp_server() async with Client(server) as client: await client.call_tool("ensure_project", {"human_key": "/backend"}) await client.call_tool( "register_agent", {"project_key": "Backend", "program": "codex", "model": "gpt-5", "name": "GreenCastle"}, ) await client.call_tool( "register_agent", {"project_key": "Backend", "program": "codex", "model": "gpt-5", "name": "RedStone"}, ) m1 = await client.call_tool( "send_message", { "project_key": "Backend", "sender_name": "GreenCastle", "to": ["RedStone"], "subject": "AckTwice", "body_md": "hello", "ack_required": True, }, ) msg = (m1.data.get("deliveries") or [{}])[0].get("payload", {}) mid = int(msg.get("id")) first = await client.call_tool( "acknowledge_message", {"project_key": "Backend", "agent_name": "RedStone", "message_id": mid}, ) first_ack_at = first.data.get("acknowledged_at") assert first.data.get("acknowledged") is True and isinstance(first_ack_at, str) second = await client.call_tool( "acknowledge_message", {"project_key": "Backend", "agent_name": "RedStone", "message_id": mid}, ) # Timestamps should remain the same (idempotent) assert second.data.get("acknowledged_at") == first_ack_at

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Dicklesworthstone/mcp_agent_mail'

If you have feedback or need assistance with the MCP directory API, please join our Discord server