71 lines
2.8 KiB
C#
71 lines
2.8 KiB
C#
using System.ComponentModel;
|
|
using ClaudeMailbox.Data.Repositories;
|
|
using ClaudeMailbox.Http;
|
|
using ModelContextProtocol.Server;
|
|
|
|
namespace ClaudeMailbox.Mcp;
|
|
|
|
public sealed record SendResult(long Id, DateTime QueuedAt);
|
|
public sealed record InboxMessage(long Id, string From, string Body, DateTime SentAt);
|
|
public sealed record InboxStatusDto(int Pending, DateTime? OldestAt);
|
|
public sealed record MailboxInfo(string Name, DateTime LastSeenAt, int PendingForYou);
|
|
|
|
[McpServerToolType]
|
|
public sealed class MailboxTools
|
|
{
|
|
private readonly MailboxContextAccessor _accessor;
|
|
private readonly MailboxRepository _mailboxes;
|
|
private readonly MessageRepository _messages;
|
|
|
|
public MailboxTools(
|
|
MailboxContextAccessor accessor,
|
|
MailboxRepository mailboxes,
|
|
MessageRepository messages)
|
|
{
|
|
_accessor = accessor;
|
|
_mailboxes = mailboxes;
|
|
_messages = messages;
|
|
}
|
|
|
|
[McpServerTool, Description("Send a message to another mailbox. The sender is the current session's X-Mailbox name.")]
|
|
public async Task<SendResult> Send(
|
|
[Description("Name of the recipient mailbox.")] string to,
|
|
[Description("Message body (plain text or markdown).")] string body,
|
|
CancellationToken ct)
|
|
{
|
|
var from = _accessor.Current;
|
|
var msg = await _messages.SendAsync(from, to, body, ct);
|
|
return new SendResult(msg.Id, msg.CreatedAt);
|
|
}
|
|
|
|
[McpServerTool, Description("Pull all undelivered messages for the current mailbox and mark them delivered. Returns an empty array when the inbox is empty.")]
|
|
public async Task<IReadOnlyList<InboxMessage>> CheckInbox(CancellationToken ct)
|
|
{
|
|
var name = _accessor.Current;
|
|
var pulled = await _messages.CheckInboxAsync(name, ct);
|
|
return pulled.Select(m => new InboxMessage(m.Id, m.FromMailbox, m.Body, m.CreatedAt)).ToList();
|
|
}
|
|
|
|
[McpServerTool, Description("Check whether the current mailbox has undelivered messages, without consuming them. Cheap; safe to call often.")]
|
|
public async Task<InboxStatusDto> PeekInbox(CancellationToken ct)
|
|
{
|
|
var name = _accessor.Current;
|
|
var status = await _messages.PeekAsync(name, ct);
|
|
return new InboxStatusDto(status.Pending, status.OldestAt);
|
|
}
|
|
|
|
[McpServerTool, Description("List all known mailboxes with their last-seen timestamp and how many messages each has queued for the current mailbox.")]
|
|
public async Task<IReadOnlyList<MailboxInfo>> ListMailboxes(CancellationToken ct)
|
|
{
|
|
var me = _accessor.Current;
|
|
var all = await _mailboxes.ListAsync(ct);
|
|
var result = new List<MailboxInfo>(all.Count);
|
|
foreach (var m in all)
|
|
{
|
|
var pending = await _messages.PendingCountForAsync(me, m.Name, ct);
|
|
result.Add(new MailboxInfo(m.Name, m.LastSeenAt, pending));
|
|
}
|
|
return result;
|
|
}
|
|
}
|