Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,7 @@ bin/
log.txt
mcp.log
dist/

# Local binaries
telegram-mcp
telegram-mcp-out
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ The Model Context Protocol (MCP) is a system that lets AI apps, like Claude Desk
- [x] List dialogs with optional unread filter (`tool: tg_dialogs`)
- [x] Mark dialog as read (`tool: tg_read`)
- [x] Retrieve messages from specific dialog (`tool: tg_dialog`)
- [x] Send draft messages to any dialog (`tool: tg_send`)
- [x] Send draft messages to any dialog (`tool: tg_draft`)
- [x] Send messages to any dialog immediately (`tool: tg_send`)

### Prompt examples

Expand Down
4 changes: 2 additions & 2 deletions internal/tg/draft.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ func (c *Client) SendDraft(args DraftArguments) (*mcp.ToolResponse, error) {
Message: args.Text,
})
if err != nil {
return fmt.Errorf("failed to get history: %w", err)
return fmt.Errorf("save draft: %w", err)
}

return nil
}); err != nil {
return nil, errors.Wrap(err, "failed to get history")
return nil, errors.Wrap(err, "failed to save draft")
}

jsonData, err := json.Marshal(DraftResponse{Success: ok})
Expand Down
48 changes: 48 additions & 0 deletions internal/tg/send.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package tg

import (
"context"
"encoding/json"
"fmt"

"github.com/gotd/td/telegram/message"
mcp "github.com/metoro-io/mcp-golang"
"github.com/pkg/errors"
)

type SendArguments struct {
Name string `json:"name" jsonschema:"required,description=Name of the dialog"`
Text string `json:"text" jsonschema:"required,description=Plain text of the message"`
}

type SendResponse struct {
Success bool `json:"success"`
}

func (c *Client) SendMessage(args SendArguments) (*mcp.ToolResponse, error) {
client := c.T()
if err := client.Run(context.Background(), func(ctx context.Context) (err error) {
api := client.API()

inputPeer, err := getInputPeerFromName(ctx, api, args.Name)
if err != nil {
return fmt.Errorf("get inputPeer from name: %w", err)
}

sender := message.NewSender(api)
if _, err = sender.To(inputPeer).Text(ctx, args.Text); err != nil {
return fmt.Errorf("send message: %w", err)
}

return nil
}); err != nil {
return nil, errors.Wrap(err, "failed to send message")
}

jsonData, err := json.Marshal(SendResponse{Success: true})
if err != nil {
return nil, errors.Wrap(err, "failed to marshal response")
}

return mcp.NewToolResponse(mcp.NewTextContent(string(jsonData))), nil
}
7 changes: 6 additions & 1 deletion serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,16 @@ func serve(ctx context.Context, cmd *cli.Command) error {
return fmt.Errorf("register dialogs tool: %w", err)
}

err = server.RegisterTool("tg_send", "Send draft message to dialog", client.SendDraft)
err = server.RegisterTool("tg_draft", "Send draft message to dialog", client.SendDraft)
if err != nil {
return fmt.Errorf("register dialogs tool: %w", err)
}

err = server.RegisterTool("tg_send", "Send message to dialog immediately", client.SendMessage)
if err != nil {
return fmt.Errorf("register send tool: %w", err)
}

err = server.RegisterTool("tg_read", "Mark dialog messages as read", client.ReadHistory)
if err != nil {
return fmt.Errorf("register read tool: %w", err)
Expand Down