Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
HOSTNoServer bind host127.0.0.1
PORTNoServer bind port8765
LOG_LEVELNoFuture: server log levelinfo
MCP_MAIL_STORENoRoot for per-project archives and SQLite~/.mcp-agent-mail
ATTACHMENT_POLICYNoFuture: auto, file, or inline default for image conversionauto
IMAGE_INLINE_MAX_BYTESNoThreshold for inlining WebP images during send_message (if enabled)65536

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
health_checkC

Return basic readiness information for the Agent Mail server.

ensure_projectA

Idempotently create or ensure a project exists for the given human key.

When to use

  • First call in a workflow targeting a new repo/path identifier.

  • As a guard before registering agents or sending messages.

How it works

  • Validates that human_key is an absolute path-like project key (typically the agent's working directory). It need not exist on the local filesystem: it is an opaque project KEY, and collaborating agents may not share a filesystem.

  • Computes a stable slug from human_key (lowercased, safe characters) so multiple agents can refer to the same project consistently.

  • Ensures DB row exists and that the on-disk archive is initialized (e.g., messages/, agents/, file_reservations/ directories).

CRITICAL: Project Identity Rules

  • The human_key MUST be an absolute path-like project key (typically the agent's working directory path)

  • Two agents working in the SAME directory path are working on the SAME project

  • Example: Both agents in /data/projects/smartedgar_mcp → SAME project

  • Sibling projects are DIFFERENT directories (e.g., /data/projects/smartedgar_mcp vs /data/projects/smartedgar_mcp_frontend)

Parameters

human_key : str An absolute path-like project key (e.g., "/data/projects/backend"), typically the agent's working directory. This MUST be an absolute path, not a relative path or arbitrary slug, but it does NOT need to exist on the local filesystem - it is an opaque project KEY (collaborating agents may not share a filesystem). This is the canonical identifier for the project - all agents using the same key share the same project identity. identity_mode : str, optional Per-call override of the server's PROJECT_IDENTITY_MODE setting; one of "dir", "git-remote", "git-common-dir", "git-toplevel". Only takes effect when worktree-friendly identity is enabled (WORKTREES_ENABLED=1).

Returns

dict Minimal project descriptor: { id, slug, human_key, created_at }.

Examples

JSON-RPC:

{
  "jsonrpc": "2.0",
  "id": "2",
  "method": "tools/call",
  "params": {"name": "ensure_project", "arguments": {"human_key": "/data/projects/backend"}}
}

Common mistakes

  • Passing a relative path (e.g., "./backend") instead of an absolute path

  • Using arbitrary slugs instead of the actual working directory path

  • Creating separate projects for the same directory with different slugs

Idempotency

  • Safe to call multiple times. If the project already exists, the existing record is returned and the archive is ensured on disk (no destructive changes).

register_agentA

Create or update an agent identity within a project and persist its profile to Git.

When to use

  • At the start of a coding session by any automated agent.

  • To update an existing agent's program/model/task metadata and bump last_active.

Semantics

  • If name is omitted, a random adjective+noun name is auto-generated.

  • Reusing the same name updates the profile (program/model/task) and refreshes last_active_ts.

  • A profile.json file is written under agents/<Name>/ in the project archive.

Agent Identity

Two naming modes are supported:

  1. Explicit identity — pass a stable ID like alpha-one, cc-0, or worker_42. Must match [A-Za-z0-9][A-Za-z0-9._-]{0,127}. Useful for swarm workflows where agents are relaunched onto the same identity.

  2. Auto-generated — omit name to get a random adjective+noun identity like GreenLake or BlueDog (RECOMMENDED for ad-hoc use).

Invalid examples: "BackendHarmonizer", "DatabaseMigrator" (descriptive role names are rejected in strict mode).

Parameters

project_key : str The same human key you passed to ensure_project (or equivalent identifier). program : str The agent program (e.g., "codex-cli", "claude-code"). model : str The underlying model (e.g., "gpt5-codex", "opus-4.1"). name : Optional[str] A valid explicit identity (e.g., "alpha-one", "cc-0") or adjective+noun combination (e.g., "BlueLake"). If omitted, a random valid name is auto-generated (RECOMMENDED). Names are unique per project; passing the same name updates the profile. task_description : str Short description of current focus (shows up in directory listings).

Returns

dict { id, name, program, model, task_description, inception_ts, last_active_ts, project_id }

Examples

Register with auto-generated name (RECOMMENDED):

{"jsonrpc":"2.0","id":"3","method":"tools/call","params":{"name":"register_agent","arguments":{
  "project_key":"/data/projects/backend","program":"codex-cli","model":"gpt5-codex","task_description":"Auth refactor"
}}}

Register with explicit valid name:

{"jsonrpc":"2.0","id":"4","method":"tools/call","params":{"name":"register_agent","arguments":{
  "project_key":"/data/projects/backend","program":"claude-code","model":"opus-4.1","name":"BlueLake","task_description":"Navbar redesign"
}}}

Pitfalls

  • Names MUST match the adjective+noun format or an error will be raised

  • Names are case-insensitive unique. If you see "already in use", pick another or omit name.

  • Use the same project_key consistently across cooperating agents.

deregister_agentB

Remove an agent from a project. Marks the agent as inactive and removes it from the active roster. Messages from/to the agent are preserved for audit but the agent can no longer send or receive new messages.

retire_agentA

Soft-delete an agent: mark it as retired so it stops accepting new messages while preserving message history. Retired agents are hidden from active agent lists but visible in 'all agents' views.

sweep_stale_agentsB

Retire abandoned agents in the caller's project using the server's conservative inactivity heuristic. The caller is never retired, the threshold has a 60-second floor, and active file reservations block retirement by default.

unretire_agentB

Restore a retired agent back to active status. The agent will resume accepting new messages.

archive_projectA

Soft-delete a project: mark it as archived so it is hidden from active project lists. All messages are preserved and the project can be restored with unarchive_project.

unarchive_projectC

Restore an archived project back to active status.

hard_delete_agentA

IRREVERSIBLY delete an agent and ALL associated data: messages sent by the agent, message recipient records, file reservations, agent links, window identities, and on-disk archive files (inbox, outbox, attachments). This is NOT soft-delete — data is permanently destroyed and cannot be recovered. Requires the confirmation parameter to be exactly 'I UNDERSTAND'.

hard_delete_projectA

IRREVERSIBLY delete a project and ALL associated data: every agent, message, message recipient, file reservation, agent link, window identity, message summary, sibling suggestion, product link, and the entire on-disk project archive directory. This is NOT soft-delete — data is permanently destroyed and cannot be recovered. Requires the confirmation parameter to be exactly 'I UNDERSTAND'.

whoisA

Return enriched profile details for an agent, optionally including recent archive commits.

Discovery

To discover available agent names, use: resource://agents/{project_key} Agent names are NOT the same as program names or user names.

Parameters

project_key : str Project slug or human key. agent_name : str Agent name to look up (use resource://agents/{project_key} to discover names). include_recent_commits : bool If true, include latest commits touching the project archive authored by the configured git author. commit_limit : int Maximum number of recent commits to include.

Returns

dict Agent profile augmented with { recent_commits: [{hexsha, summary, authored_ts}] } when requested.

create_agent_identityA

Create a new, unique agent identity and persist its profile to Git.

How this differs from register_agent

  • Always creates a new identity with a fresh unique name (never updates an existing one).

  • name_hint, if provided, MUST be a valid adjective+noun combination and must be available, otherwise an error is raised. Without a hint, a random adjective+noun name is generated.

CRITICAL: Agent Naming Rules

  • Agent names MUST be randomly generated adjective+noun combinations

  • Examples: "GreenCastle", "BlueLake", "RedStone", "PurpleBear"

  • Names should be unique, easy to remember, and NOT descriptive

  • INVALID examples: "BackendHarmonizer", "DatabaseMigrator", "UIRefactorer"

  • Best practice: Omit name_hint to auto-generate a valid name (RECOMMENDED)

When to use

  • Spawning a brand new worker agent that should not overwrite an existing profile.

  • Temporary task-specific identities (e.g., short-lived refactor assistants).

Parameters

return_registration_token : bool, default True When True (default, current behaviour), the response includes the freshly-minted registration_token. When False, the token is omitted from the tool result so transcript-visible MCP sessions can satisfy a "do not echo secrets into scrollback" contract; the agent is still bound to the current MCP session via _bind_session_agent, so follow-up calls in the same session can authenticate without ever surfacing the token. The token still exists on the server and can be retrieved or rotated through the normal admin paths. See issue #154.

Returns

dict { id, name, program, model, task_description, inception_ts, last_active_ts, project_id, registration_token? }

Examples

Auto-generate name (RECOMMENDED):

{"jsonrpc":"2.0","id":"c2","method":"tools/call","params":{"name":"create_agent_identity","arguments":{
  "project_key":"/data/projects/backend","program":"claude-code","model":"opus-4.1"
}}}

With valid name hint:

{"jsonrpc":"2.0","id":"c1","method":"tools/call","params":{"name":"create_agent_identity","arguments":{
  "project_key":"/data/projects/backend","program":"codex-cli","model":"gpt5-codex","name_hint":"GreenCastle",
  "task_description":"DB migration spike"
}}}

Transcript-safe creation (issue #154) — omit the token from the visible tool result and rely on session binding for follow-ups:

{"jsonrpc":"2.0","id":"c3","method":"tools/call","params":{"name":"create_agent_identity","arguments":{
  "project_key":"/data/projects/backend","program":"codex-cli","model":"gpt5",
  "return_registration_token":false
}}}
list_window_identitiesC

List active window identities for a project.

Returns all non-expired window identities with their display names, last activity timestamps, and age.

Parameters

project_key : str Project identifier.

Returns

dict { identities: [{ id, window_uuid, display_name, created_ts, last_active_ts, expires_ts }] }

rename_windowB

Update the display name of a window identity.

Parameters

project_key : str Project identifier. window_uuid : str The UUID of the window identity to rename. new_display_name : str New display name (must be a valid adjective+noun agent name).

Returns

dict Updated window identity record.

expire_windowC

Mark a window identity as expired.

Parameters

project_key : str Project identifier. window_uuid : str The UUID of the window identity to expire.

Returns

dict { window_uuid, expired: bool, expired_at }

send_messageA

Send a Markdown message to one or more recipients and persist canonical and mailbox copies to Git.

Discovery

To discover available agent names for recipients, use: resource://agents/{project_key} Agent names are NOT the same as program names or user names.

What this does

  • Stores message (and recipients) in the database; updates sender's activity

  • Writes a canonical .md under messages/YYYY/MM/

  • Writes sender outbox and per-recipient inbox copies

  • Optionally converts referenced images to WebP and embeds small images inline

  • Supports explicit attachments via attachment_paths in addition to inline references

Parameters

project_key : str Project identifier (same used with ensure_project/register_agent). sender_name : str Must match an agent registered in the project. to : list[str] Primary recipients (agent names). At least one of to/cc/bcc must be non-empty. subject : str Short subject line that will be visible in inbox/outbox and search results. body_md : str GitHub-Flavored Markdown body. Image references can be file paths or data URIs. cc, bcc : Optional[list[str]] Additional recipients by name. attachment_paths : Optional[list[str]] Extra file paths to include as attachments; will be converted to WebP and stored. convert_images : Optional[bool] Overrides server default for image conversion/inlining. If None, server settings apply. Note: sender attachments_policy "inline"/"file" always forces conversion/inlining. importance : str One of {"low","normal","high","urgent"} (free form tolerated; used by filters). ack_required : bool If true, recipients should call acknowledge_message after reading. thread_id : Optional[str] If provided, message will be associated with an existing thread. broadcast : bool If true and to is empty, expand recipients to all registered agents in the project (excluding the sender). Mutually exclusive with explicit to recipients. Respects contact_policy settings and is best-effort across contact boundaries: expanded recipients that are retired, set block_all, or would need contact approval are skipped rather than blocking the send, and are reported in broadcast_skipped ([{"agent": name, "reason": ...}]). No contact request is created for them — request contact explicitly if you want them included. auto_contact_if_blocked therefore never fires for broadcast-expanded recipients; it still applies to explicitly named to/cc/bcc names. topic : Optional[str] Optional topic tag (max 64 chars). Must start with a letter or digit and may otherwise contain alphanumerics, '.', '_', or '-' — so beads_rust hierarchical IDs like br-abc.1 can be used verbatim. Stored on the message for topic-based filtering via fetch_inbox(topic=...) or fetch_topic(). auto_contact_if_blocked : Optional[bool] When True (and contact policy blocks delivery to one or more recipients), the server will attempt to resolve the block automatically:

- If the recipient is already authenticated in the **same MCP session**, run
  ``macro_contact_handshake(..., auto_accept=True)`` to approve the link in-band.
  The current send proceeds normally and the message is delivered.
- Otherwise, fall back to creating a **pending** ``request_contact`` aimed at the
  recipient. This call then **fails loud** with ``CONTACT_REQUIRED`` carrying
  ``auto_contact_requested`` in ``data``. **The message body is not queued** —
  once the recipient approves the contact (``respond_contact(..., accept=True)``),
  the sender must re-call ``send_message`` to actually deliver the payload.

Defaults to the server-wide ``MESSAGING_AUTO_HANDSHAKE_ON_BLOCK`` setting (true
unless overridden). The pending-request TTL is governed by
``CONTACT_PENDING_TTL_SECONDS`` (default 7 days, separate from the in-session
auto-approval TTL ``CONTACT_AUTO_TTL_SECONDS``).

Returns

dict { "deliveries": [ { "project": str, "payload": { ... message payload ... } } ], "count": int }

Edge cases

  • If no recipients are given, the call fails.

  • Unknown recipient names fail fast; register them first.

  • Non-absolute attachment paths are resolved relative to the project archive root.

Do / Don't

Do:

  • Keep subjects concise and specific (aim for ≤ 80 characters).

  • Use thread_id (or reply_message) to keep related discussion in a single thread.

  • Address only relevant recipients; use CC/BCC sparingly and intentionally.

  • Prefer Markdown links; attach images only when they materially aid understanding. The server auto-converts images to WebP and may inline small images depending on policy.

Don't:

  • Send large, repeated binaries—reuse prior attachments via attachment_paths when possible.

  • Change topics mid-thread—start a new thread for a new subject.

  • Broadcast to "all" agents unnecessarily—target just the agents who need to act.

Examples

  1. Simple message:

{"jsonrpc":"2.0","id":"5","method":"tools/call","params":{"name":"send_message","arguments":{
  "project_key":"/abs/path/backend","sender_name":"GreenCastle","to":["BlueLake"],
  "subject":"Plan for /api/users","body_md":"See below."
}}}
  1. Inline image (auto-convert to WebP and inline if small):

{"jsonrpc":"2.0","id":"6a","method":"tools/call","params":{"name":"send_message","arguments":{
  "project_key":"/abs/path/backend","sender_name":"GreenCastle","to":["BlueLake"],
  "subject":"Diagram","body_md":"![diagram](docs/flow.png)","convert_images":true
}}}
  1. Explicit attachments:

{"jsonrpc":"2.0","id":"6b","method":"tools/call","params":{"name":"send_message","arguments":{
  "project_key":"/abs/path/backend","sender_name":"GreenCastle","to":["BlueLake"],
  "subject":"Screenshots","body_md":"Please review.","attachment_paths":["shots/a.png","shots/b.png"]
}}}
purge_old_messagesC

Delete messages older than the configured retention period. Defaults to retention_max_age_days from config (180 days). Returns count of messages purged.

reply_messageA

Reply to an existing message, preserving or establishing a thread.

Behavior

  • Inherits original importance and ack_required flags

  • thread_id is taken from the original message if present; otherwise, the original id is used

  • Subject is prefixed with subject_prefix if not already present

  • Defaults to to the original sender if not explicitly provided

Parameters

project_key : str Project identifier. message_id : int The id of the message you are replying to. sender_name : str Your agent name (must be registered in the project). body_md : str Reply body in Markdown. to, cc, bcc : Optional[list[str]] Recipients by agent name. If omitted, to defaults to original sender. subject_prefix : str Prefix to apply (default "Re:"). Case-insensitive idempotent.

Do / Don't

Do:

  • Keep the subject focused; avoid topic drift within a thread.

  • Reply to the original sender unless new stakeholders are strictly required.

  • Preserve importance/ack flags from the original unless there is a clear reason to change.

  • Use CC for FYI only; BCC sparingly and with intention.

Don't:

  • Change thread_id when continuing the same discussion.

  • Escalate to many recipients; prefer targeted replies and start a new thread for new topics.

  • Attach large binaries in replies unless essential; reference prior attachments where possible.

Returns

dict Message payload including thread_id and reply_to.

Examples

Minimal reply to original sender: If the caller has not already authenticated as sender_name in this MCP session, include sender_token.

{"jsonrpc":"2.0","id":"6","method":"tools/call","params":{"name":"reply_message","arguments":{
  "project_key":"/abs/path/backend","message_id":1234,"sender_name":"BlueLake",
  "body_md":"Questions about the migration plan...","sender_token":"<registration_token>"
}}}

Reply with explicit recipients and CC:

{"jsonrpc":"2.0","id":"6c","method":"tools/call","params":{"name":"reply_message","arguments":{
  "project_key":"/abs/path/backend","message_id":1234,"sender_name":"BlueLake",
  "body_md":"Looping ops.","to":["GreenCastle"],"cc":["RedCat"],"subject_prefix":"RE:",
  "sender_token":"<registration_token>"
}}}
request_contactA

Request contact approval to message another agent.

Creates (or refreshes) a pending AgentLink and sends a small ack_required intro message.

Discovery

To discover available agent names, use: resource://agents/{project_key} Agent names are NOT the same as program names or user names.

Parameters

project_key : str Project slug or human key. from_agent : str Your agent name (must be registered in the project). to_agent : str Target agent name (use resource://agents/{project_key} to discover names). to_project : Optional[str] Target project if different from your project (cross-project coordination). reason : str Optional explanation for the contact request. ttl_seconds : int Time to live for the contact approval request (default: 7 days).

respond_contactC

Approve or deny a contact request.

list_contactsC

List contact links for an agent in a project.

set_contact_policyC

Set contact policy for an agent: open | auto | contacts_only | block_all.

fetch_inboxA

Retrieve recent messages for an agent without mutating read/ack state.

Filters

  • urgent_only: only messages with importance in {high, urgent}

  • since_ts: ISO-8601 timestamp string; messages strictly newer than this are returned

  • limit: max number of messages (default 20)

  • include_bodies: include full Markdown bodies in the payloads

  • topic: filter to messages with this topic tag

  • unread_only: when True, restrict to messages this recipient has not yet explicitly marked read via mark_message_read or acknowledge_message. Per-recipient: a message read by Agent A is still unread for Agent B. A bare fetch_inbox call does NOT mark messages read; this filter inspects existing read state without mutating it.

Usage patterns

  • Poll after each editing step in an agent loop to pick up coordination messages.

  • Use since_ts with the timestamp from your last poll for efficient incremental fetches.

  • Use unread_only=True from polling agents (Claude Code, Codex, etc.) to skip messages the agent has already acknowledged — cuts token-burn at scale by avoiding re-running prompt context against already-handled mail.

  • Combine with acknowledge_message if ack_required is true.

Returns

list[dict] Each message includes: { id, subject, from, created_ts, importance, ack_required, kind, read_at, [body_md] } read_at is this recipient's read timestamp (null while unread), so the default view — which includes already-read mail — stays distinguishable.

Example

{"jsonrpc":"2.0","id":"7","method":"tools/call","params":{"name":"fetch_inbox","arguments":{
  "project_key":"/abs/path/backend","agent_name":"BlueLake","since_ts":"2025-10-23T00:00:00+00:00"
}}}
fetch_topicA

Fetch all messages in a project with a given topic tag, regardless of recipient.

Parameters

project_key : str Project identifier. topic_name : str The topic tag to filter by (case-insensitive). limit : int Max number of messages to return (default 50). include_bodies : bool Include full Markdown bodies in the payloads (default true). since_ts : Optional[str] ISO-8601 timestamp; only messages newer than this are returned. unread_only : bool When True, restrict to messages where the viewer has a recipient row that has not been explicitly marked read. This narrows beyond the default sender-or-recipient visibility — messages the viewer sent (but is not a recipient of) and broadcast/thread-visible messages where the viewer has no MessageRecipient row are excluded under this flag, because "unread" is only well-defined for a recipient row. A bare fetch_topic call does NOT mark messages read.

Returns

list[dict] Each message includes: { id, subject, from, created_ts, importance, topic, [body_md] }

mark_message_readA

Mark a specific message as read for the given agent.

Notes

  • Read receipts are per-recipient; this only affects the specified agent.

  • This does not send an acknowledgement; use acknowledge_message for that.

  • Safe to call multiple times; later calls return the original timestamp.

Idempotency

  • If mark_message_read has already been called earlier for the same (agent, message), the original timestamp is returned and no error is raised.

Returns

dict { message_id, read: bool, read_at: iso8601 | null }

Example

{"jsonrpc":"2.0","id":"8","method":"tools/call","params":{"name":"mark_message_read","arguments":{
  "project_key":"/abs/path/backend","agent_name":"BlueLake","message_id":1234
}}}
acknowledge_messageA

Acknowledge a message addressed to an agent (and mark as read).

Behavior

  • Sets both read_ts and ack_ts for the (agent, message) pairing

  • Safe to call multiple times; subsequent calls will return the prior timestamps

Idempotency

  • If acknowledgement already exists, the previous timestamps are preserved and returned.

When to use

  • Respond to messages with ack_required=true to signal explicit receipt.

  • Agents can treat an acknowledgement as a lightweight, non-textual reply.

Returns

dict { message_id, acknowledged: bool, acknowledged_at: iso8601 | null, read_at: iso8601 | null }

Example

{"jsonrpc":"2.0","id":"9","method":"tools/call","params":{"name":"acknowledge_message","arguments":{
  "project_key":"/abs/path/backend","agent_name":"BlueLake","message_id":1234
}}}
macro_start_sessionB

Macro helper that boots a project session: ensure project, register agent, optionally file_reservation paths, and fetch the latest inbox snapshot.

macro_prepare_threadC

Macro helper that aligns an agent with an existing thread by ensuring registration, summarising the thread, and fetching recent inbox context.

macro_file_reservation_cycleC

Reserve a set of file paths and optionally release them at the end of the workflow.

macro_contact_handshakeC

Request contact permissions and optionally auto-approve plus send a welcome message.

search_messagesA

Full-text search over subject and body for a project.

Tips

  • SQLite FTS5 syntax supported: phrases ("build plan"), prefix (mig*), boolean (plan AND users)

  • Results are ordered by bm25 score (best matches first)

  • Limit defaults to 20; raise for broad queries

Query examples

  • Phrase search: "build plan"

  • Prefix: migrat*

  • Boolean: plan AND users

  • Require urgent: urgent AND deployment

Parameters

project_key : str Project identifier. query : str FTS5 query string. limit : int Max results to return.

Returns

list[dict] Each entry: { id, subject, importance, ack_required, created_ts, thread_id, from }

Example

{"jsonrpc":"2.0","id":"10","method":"tools/call","params":{"name":"search_messages","arguments":{
  "project_key":"/abs/path/backend","query":""build plan" AND users", "limit": 50
}}}
summarize_threadA

Extract participants, key points, and action items for one or more threads.

Single-thread mode (thread_id is a single ID):

  • Returns detailed summary with optional example messages

  • Response: { thread_id, summary: {participants[], key_points[], action_items[]}, examples[] }

Multi-thread mode (thread_id is comma-separated IDs like "TKT-1,TKT-2,TKT-3"):

  • Returns aggregate digest across all threads

  • Response: { threads: [{thread_id, summary}], aggregate: {top_mentions[], key_points[], action_items[]} }

Parameters

project_key : str Project identifier. thread_id : str Single thread ID for detailed summary, OR comma-separated IDs for aggregate digest. include_examples : bool If true (single-thread mode only), include up to 3 sample messages. llm_mode : bool If true and LLM is enabled, refine the summary with AI. llm_model : Optional[str] Override model name for the LLM call. per_thread_limit : int Max messages to consider per thread (multi-thread mode).

Examples

Single thread:

{"thread_id": "TKT-123", "include_examples": true}

Multiple threads:

{"thread_id": "TKT-1,TKT-2,TKT-3"}
summarize_recentA

Summarize all recent project messages within a time window.

Fetches messages from the last since_hours hours, groups them by thread, and produces a combined project-wide summary. Results are stored in the message_summaries table for fast retrieval via fetch_summary.

Idempotent: if a summary already exists for the same time window (within 5-minute tolerance) it is returned from cache.

Parameters

project_key : str Project identifier (slug or human key). since_hours : float How far back to look (default 1 hour). llm_mode : bool Use LLM to refine the summary (default True). llm_model : str, optional Override LLM model name. max_messages : int Maximum messages to include (default 500, capped at 500). format : str, optional Output format (json or toon).

fetch_summaryA

Retrieve stored project-wide summaries.

Parameters

project_key : str Project identifier. since_hours : float Return summaries whose end_ts is within this window (default 24h). limit : int Maximum summaries to return (default 5). format : str, optional Output format.

install_precommit_guardA

Install the Agent Mail pre-commit guard into a git repository.

The guard blocks a commit that stages files another agent holds an exclusive file reservation on (set AGENT_MAIL_GUARD_MODE=warn to only warn). Commits must run with AGENT_NAME set to the committing agent. Any existing pre-commit hook is kept and still runs. Does nothing when worktree features are disabled (WORKTREES_ENABLED=0).

Parameters

project_key : str Project whose file reservations the guard enforces. code_repo_path : str Path to the git repository to install the hook into. format : str, optional Output format.

Returns

dict {"hook": "<path to the installed pre-commit hook>"}; empty string when skipped.

uninstall_precommit_guardA

Remove the Agent Mail commit guards from a git repository.

Removes Agent Mail's own pre-commit and pre-push guard plugins (and a legacy single-file Agent Mail hook); other hooks in the repository are left in place.

Parameters

code_repo_path : str Path to the git repository to remove the guard from. format : str, optional Output format.

Returns

dict {"removed": true} when a guard was removed, false when none was installed.

file_reservation_pathsA

Request advisory file reservations (leases) on project-relative paths/globs.

Semantics

  • Conflicts are reported if an overlapping active exclusive reservation exists held by another agent

  • Glob matching is symmetric (fnmatchcase(a,b) or fnmatchcase(b,a)), including exact matches

  • When granted, a JSON artifact is written under file_reservations/<sha1(path)>.json and the DB is updated

  • TTL must be >= 60 seconds (enforced by the server settings/policy)

  • Server-side enforcement (if enabled) only checks reservations that target mail archive paths such as agents/, messages/, or attachments/; code repo enforcement is via the pre-commit guard

Do / Don't

Do:

  • Reserve files before starting edits to signal intent to other agents.

  • Use specific, minimal patterns (e.g., app/api/*.py) instead of broad globs.

  • Set a realistic TTL and renew with renew_file_reservations if you need more time.

Don't:

  • Reserve the entire repository or very broad patterns (e.g., **/*) unless absolutely necessary.

  • Hold long-lived exclusive reservations when you are not actively editing.

  • Ignore conflicts; resolve them by coordinating with holders or waiting for expiry.

Parameters

project_key : str agent_name : str paths : list[str] File paths or glob patterns relative to the project workspace (e.g., "app/api/*.py"). ttl_seconds : int Time to live for the file_reservation; expired file_reservations are auto-released. exclusive : bool If true, exclusive intent; otherwise shared/observe-only. reason : str Optional explanation (helps humans reviewing Git artifacts).

Returns

dict { granted: [{id, path_pattern, exclusive, reason, expires_ts}], conflicts: [{path, holders: [...]}] }

Example

{"jsonrpc":"2.0","id":"12","method":"tools/call","params":{"name":"file_reservation_paths","arguments":{
  "project_key":"/abs/path/backend","agent_name":"GreenCastle","paths":["app/api/*.py"],
  "ttl_seconds":7200,"exclusive":true,"reason":"migrations"
}}}
release_file_reservationsA

Release active file reservations held by an agent.

Behavior

  • If both paths and file_reservation_ids are omitted, all active reservations for the agent are released

  • Otherwise, restricts release to matching ids and/or path patterns

  • JSON artifacts stay in Git for audit; DB records get released_ts

Returns

dict { released: int, released_at: iso8601 }

Idempotency

  • Safe to call repeatedly. Releasing an already-released (or non-existent) reservation is a no-op.

Examples

Release all active reservations for agent:

{"jsonrpc":"2.0","id":"13","method":"tools/call","params":{"name":"release_file_reservations","arguments":{
  "project_key":"/abs/path/backend","agent_name":"GreenCastle"
}}}

Release by ids:

{"jsonrpc":"2.0","id":"14","method":"tools/call","params":{"name":"release_file_reservations","arguments":{
  "project_key":"/abs/path/backend","agent_name":"GreenCastle","file_reservation_ids":[101,102]
}}}
force_release_file_reservationB

Force-release a stale file reservation held by another agent after inactivity heuristics.

The tool validates that the reservation appears abandoned (agent inactive beyond threshold and no recent mail/filesystem/git activity). When released, an optional notification is sent to the previous holder summarizing the heuristics.

renew_file_reservationsB

Extend expiry for active file reservations held by an agent without reissuing them.

Parameters

project_key : str Project slug or human key. agent_name : str Agent identity who owns the reservations. extend_seconds : int Seconds to extend from the later of now or current expiry (min 60s). paths : Optional[list[str]] Restrict renewals to matching path patterns. file_reservation_ids : Optional[list[int]] Restrict renewals to matching reservation ids.

Returns

dict { renewed: int, file_reservations: [{id, path_pattern, old_expires_ts, new_expires_ts}] }

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription
environment_resource_exact
tooling_directory_resource_exact
tooling_schemas_resource_exact
tooling_metrics_resource_exact
tooling_locks_resource_exact
projects_resource_exact

TDQS

B3.2/5.0

Scored across 41 tools

Disambiguation3/5

Most tools target distinct resources and actions, but several clusters overlap: agent lifecycle (register/create/deregister/retire/unretire), message state (mark read vs acknowledge), summary views (fetch/summarize thread/recent), and macro helpers duplicate lower-level operations. Detailed descriptions disambiguate some overlaps, but the set still requires careful selection.

Naming Consistency4/5

Nearly all names use snake_case and follow verb_noun or resource_action patterns, such as ensure_project, send_message, and release_file_reservations. Minor deviations like whois and a few long macro_* names slightly reduce predictability, but overall the naming is consistent.

Tool Count2/5

41 tools is far above a well-scoped set for one MCP server; it mixes core messaging, admin, contact, reservation, summary, guard, and macro operations. Although each tool may earn its place, the volume increases selection burden and feels heavy for the domain.

Completeness4/5

The surface covers project and agent lifecycle, messaging, contacts, file reservations, summaries, and pre-commit guards comprehensively. Minor gaps include no direct list_projects/list_agents tool and no edit/delete individual message, but resource-based discovery and purge/archive paths mitigate these.

Maintenance

ActivityActive
ResponsivenessResponsive