Skip to main content
Glama
Telegram OSINT

Telegram OSINT

by alamri-intel

Unofficial Telegram OSINT

An unofficial, independent plugin. Not affiliated with, endorsed by or sponsored by Telegram.

An MCP server for your own Telegram account. Read your chats through an AI assistant, and run a background monitor that watches every incoming message for things you care about.

The monitor works in two stages: cheap rules (substring / whole-word / regex) decide what's worth looking at, then Claude judges each hit against your plain-language criteria and decides whether it's worth surfacing. On a firehose of busy channels, stage one keeps the cost down and stage two keeps the noise down. The judge is optional — without it, every rule hit becomes an alert.

Everything runs locally. Nothing leaves your machine except calls to Telegram's API and, if you enable judging, Anthropic's.

What it runs and sends

  • Local server. The plugin starts a Python MCP server on your computer with uv run --locked. On first start, uv downloads Python and the exact package versions pinned in uv.lock from PyPI.

  • Telegram. The server and the watcher log in to your Telegram account (a user session, not a bot) and talk to Telegram's servers to list chats, read and search messages, and receive new ones. Nothing is ever sent, deleted, or left on Telegram — there are no write tools.

  • Anthropic. Only when judging is on and ANTHROPIC_API_KEY is set, the watcher sends the text of each rule-matched message, plus your criteria, to Anthropic's API for a verdict. Messages that match no rule are never sent anywhere.

  • Login happens in the chat. You type your Telegram API ID and hash, phone number, login codes and (if you have one) two-step verification password into the conversation, and Claude passes them to the local server. They become part of that conversation's history in your Claude app. The password is passed to Telegram once to sign in and is never stored.

  • Local files. Session files, your API credentials (.env, mode 0600), the alerts database, and the watcher log live in ~/.telegram-mcp/. Nothing is uploaded elsewhere.

  • Background watcher. A separate process you start yourself; the plugin never starts it for you. On macOS it can show desktop notifications via osascript.

Related MCP server: Dotiphant

Where it works

Claude app

Works

Claude Code (terminal, IDE, desktop app Code tab)

Yes

Cowork in the desktop app

Yes, when the task runs on your computer — not in a cloud task

Chat on claude.ai web, desktop, or mobile

Skills only — chat can't start a local server, so the Telegram tools aren't available

Operating systems. Developed and tested on macOS. On Windows and Linux the tools, login and monitoring work, but desktop notifications are macOS-only: elsewhere alerts are still recorded and listed, they just don't pop up.

Requirements

Check these before installing — without uv the plugin's server cannot start, and the Telegram tools simply never appear.

What

Needed for

Required

uv on the computer running Claude

Starting the plugin's server. uv installs Python 3.10+ and the pinned packages itself.

Required

A Telegram account and an app API ID + API hash from my.telegram.org (API development tools)

Logging in

Required

Claude Code, or Cowork running on your computer

Local servers don't run in claude.ai chat or cloud tasks

Optional

An Anthropic API key (a workspace key from the Console)

Judging alerts against your criteria. Without it, every rule match becomes an alert.

Optional

macOS

Desktop notifications

Installing uv

  • macOS with Homebrew: brew install uv

  • Windows: winget install --id=astral-sh.uv -e

  • Linux, or macOS without Homebrew: use your package manager, or uv's standalone installer from its installation guide (it installs to ~/.local/bin)

Then check with uv --version, and fully quit and reopen your Claude app.

Two pitfalls:

  • Apps launched from the Dock or Start menu may not see ~/.local/bin or a conda/virtualenv. If uv --version works in a terminal but the plugin still fails to connect, put uv somewhere the app can see (on macOS, sudo ln -s ~/.local/bin/uv /usr/local/bin/uv) — don't install it with pip into a conda environment.

  • The first start downloads Python and ~50 packages, which can outlast the app's connection timeout. If the first connection fails, retry once.

Network access

Host

When

pypi.org, files.pythonhosted.org (and uv's Python download host)

First start, and after updates

Telegram's servers

Always

api.anthropic.com

Only with judging on

Managed or corporate networks that block PyPI or inspect TLS will stop the first start; ask IT to allow the hosts above.

Python packages are declared in pyproject.toml and pinned exactly in uv.lock (53 packages); uv installs them automatically. Direct dependencies: mcp, telethon, and — for judging — anthropic and pydantic.

Install

As a Claude Code plugin — this is the easy path, and gives you the setup skill:

claude plugin marketplace add alamri-intel/telegram-mcp
claude plugin install telegram-osint@telegram-osint

Or from inside Claude Code: /plugin marketplace add alamri-intel/telegram-mcp, then /plugin install telegram-osint@telegram-osint.

Start a new session, then run /telegram-osint:setup and answer the questions — it writes your rules and criteria for you.

Or as a plain Python package, if you'd rather not use the plugin:

uv tool install "telegram-monitor-mcp[judge] @ git+https://github.com/alamri-intel/telegram-mcp"
claude mcp add telegram -- telegram-mcp

The judge extra pulls in the Anthropic SDK. Omit it if you only want rule matching.

You need a Telegram API_ID / API_HASH pair from https://my.telegram.org (API development tools). These identify the app, not your account.

export TELEGRAM_API_ID=...
export TELEGRAM_API_HASH=...
export ANTHROPIC_API_KEY=...   # only if you want judging

Start the watcher

telegram-mcp-watcher

The first run prompts for your phone number and the login code Telegram sends. After that the saved session is reused and startup is silent. Leave it running — alerts are only recorded while it's up.

To run it in the background:

nohup telegram-mcp-watcher > ~/.telegram-mcp/watcher.log 2>&1 &

Registering the server by hand

The plugin does this for you. If you installed the plain package instead:

claude mcp add telegram -- telegram-mcp

Claude Desktop — add to claude_desktop_config.json:

{
  "mcpServers": {
    "telegram": {
      "command": "telegram-mcp",
      "env": {
        "TELEGRAM_API_ID": "...",
        "TELEGRAM_API_HASH": "..."
      }
    }
  }
}

The server and the watcher use separate Telegram sessions on purpose: one session file can only be used by one process at a time. A side effect worth knowing is that the monitor tools work even if the server itself is never logged in — they only read the local database.

Tools

Monitoring — local database only, no Telegram login needed

Tool

add_alert_rule(name, pattern, …)

Create a prefilter rule. Live within ~5s.

list_alert_rules(include_disabled)

Rules with hit counts.

set_alert_rule_enabled(rule_id, enabled)

Pause or resume a rule.

delete_alert_rule(rule_id)

Delete a rule and its alerts.

add_criterion(name, description)

Add a plain-language judging criterion.

list_criteria(include_disabled)

Criteria with hit counts.

set_criterion_enabled(id, enabled)

Pause or resume a criterion.

delete_criterion(id)

Delete a criterion.

list_alerts(limit, verdict, min_severity, …)

What matched and what the judge decided.

ack_alerts(alert_ids | rule_id | all_alerts)

Clear alerts from the default view.

monitor_status()

Watcher liveness, counts, judge throughput.

Skills (plugin install only)

/telegram-osint:setup walks you through a full setup: it connects Telegram, interviews you in multiple-choice rounds (with "suggest for me", "widen coverage" and "describe it in my own words" at every step), learns what you want from real messages in your channels, engineers and tests the keywords across languages, calibrates the judge on real examples, and only then creates the rules and criteria. /telegram-osint:review reports how your coverage is performing — gaps, noise, silent rules, questionable verdicts — and adjusts it in the same format, any time. /telegram-osint:watcher covers starting the daemon and working out why alerts aren't arriving.

Reading — talks to Telegram

list_dialogs, read_messages, search_messages, unread_summary, preview_rule. list_dialogs is how you find the numeric chat ids for rule scopes; search_messages searches history, which rules never see; preview_rule tests a candidate rule against real message history before you create it.

Login — sets up your Telegram session

Tool

auth_status()

Whether credentials are saved and each session is logged in.

set_api_credentials(api_id, api_hash)

Save your Telegram app credentials to ~/.telegram-mcp/.env (mode 0600).

login_request_code(phone)

Ask Telegram to send a login code.

login_submit_code(code, password)

Finish login; the session file is saved locally.

Rules and criteria

They answer different questions. A rule asks "does this string appear?" A criterion asks "does this matter?"

Rules:

  • match_type — substring (default), word (whole words only, so deploy won't fire on redeployment), or regex

  • case_sensitive — off by default

  • chat_ids / exclude_chat_ids — scope it; omit chat_ids to watch everything. Exclusions apply first.

  • include_outgoing — off by default, so your own messages don't match

  • notify — desktop notification on a surfaced alert (macOS)

Criteria are prose. Write them the way you'd brief a person doing the triage for you — say what qualifies and what doesn't, because near-misses are where a judge earns its keep:

remote-backend-roles — A specific open role for a backend engineer that is remote or remote-friendly in Europe, posted by someone hiring for it. Must name the company and the role. Excludes: recruiter cold-calls with no named company, roles requiring relocation, and anyone advertising their own availability.

Nothing about the subject matter is built in — the criteria supply it. The same machinery works for job leads, release announcements, a research field, or a resale market.

Each alert keeps the judge's verdict, severity, one-line summary, and its reasoning — including why it rejected something. list_alerts hides rejected alerts by default; pass include_irrelevant=True to audit them.

Gotchas

  • Rules are forward-looking. The watcher only sees messages that arrive while it's running. Use search_messages for history.

  • Check monitor_status() first. If the watcher died, the alert tools keep answering from a stale database. Status is what tells you. It reports the watcher down when its heartbeat is over 90 seconds old.

  • Judging is best-effort. If the API call fails, the alert is marked error and surfaced anyway — dropping a possible hit is worse than a false positive. Repeated auth failures disable judging for that run rather than retrying on every message.

  • A broken rule is skipped, not fatal. An invalid regex logs a warning; the other rules keep running.

Configuration

Variable

Default

TELEGRAM_API_ID / TELEGRAM_API_HASH

—

required

ANTHROPIC_API_KEY

—

required for judging

TELEGRAM_MCP_HOME

~/.telegram-mcp

database and session files

TELEGRAM_MCP_DB

$TELEGRAM_MCP_HOME/monitor.db

database path

TELEGRAM_MCP_SESSION

mcp

server's session name

TELEGRAM_MCP_WATCHER_SESSION

watcher

watcher's session name

TELEGRAM_MCP_JUDGE

1

0 disables judging

TELEGRAM_MCP_JUDGE_MODEL

claude-opus-5

judging model

TELEGRAM_MCP_JUDGE_EFFORT

low

low…max; raise if verdicts look shallow

TELEGRAM_MCP_NOTIFY

1

0 silences desktop notifications

TELEGRAM_MCP_LOG

INFO

watcher log level

Security

  • Session files under ~/.telegram-mcp/ (mode 0700) are equivalent to login credentials for your Telegram account. Never commit or share one.

  • The database holds the full text of every message that matched a rule.

  • These are user sessions, not bots — the watcher sees everything you see. Scope rules with chat_ids if you'd rather not store message text from every chat you're in.

  • The server exposes no Telegram write operations: nothing here can send, delete, or leave anything. Add write tools deliberately and narrowly if you need them.

License

MIT

Country names in skills/setup/data/country-names/ come from the Unicode CLDR project, © Unicode, Inc., under the Unicode License v3 (included alongside the data). Regenerate them with python3 scripts/build_country_names.py.

Available Tools

20 tools
ack_alertsA

Mark alerts as acknowledged so they drop out of the default list_alerts view. Pass exactly one of the three selectors.

Args: alert_ids: specific alert ids to acknowledge. rule_id: acknowledge every unacked alert from this rule. all_alerts: acknowledge every unacked alert.

Inputs: rule_id, alert_ids, all_alerts.

add_alert_ruleA

Create an alert rule. The watcher picks it up within a few seconds — no restart needed. Rules only match messages that arrive after they are created; use search_messages to look backwards.

Args: name: unique label for the rule, used in alerts and notifications. pattern: what to look for. match_type: 'substring' (default), 'word' (whole-word only), or 'regex'. case_sensitive: match case exactly (default: case-insensitive). chat_ids: only watch these chats; omit to watch every chat. exclude_chat_ids: never match in these chats; applied before chat_ids. include_outgoing: also match messages you send (default: incoming only). notify: fire a macOS desktop notification on match.

Inputs: name (required), pattern (required), notify, chat_ids, +4 more.

add_criterionA

Add a natural-language criterion the judge uses to decide whether a prefiltered post actually matters. The watcher picks it up on the next judged alert — no restart needed.

Rules decide what gets looked at; criteria decide what gets surfaced. Write a criterion the way you'd brief someone doing the triage for you: say what qualifies and what doesn't. "A specific open remote backend role that names the company" beats "jobs".

Args: name: short unique label, shown on matching alerts. description: what qualifies, in plain language.

Inputs: name (required), description (required).

auth_statusA

Check whether Telegram is logged in, and as whom.

Reports both sessions: the watcher's (the one that must be logged in for monitoring to work) and this server's (needed only for the read tools). Call this before anything else if alerts or reads are failing.

Inputs: no named parameters.

delete_alert_ruleA

Delete an alert rule and every alert it produced. Irreversible — prefer set_alert_rule_enabled(rule_id, False) to just pause it.

Args: rule_id: id from list_alert_rules.

Inputs: rule_id (required).

delete_criterionA

Delete a criterion. Alerts already judged against it keep their verdicts. Prefer set_criterion_enabled to pause one.

Args: criterion_id: id from list_criteria.

Inputs: criterion_id (required).

list_alert_rulesB

List alert rules with their hit counts.

Args: include_disabled: include rules that are currently turned off.

Inputs: include_disabled. Returns: result

list_alertsA

List recorded alerts, newest first.

By default this hides alerts the judge ruled irrelevant — that filtering is the whole point of the judge. Pass include_irrelevant=True to audit what it rejected and why (each one keeps its reasoning).

Args: limit: max number of alerts to return. unacked_only: only alerts you haven't acknowledged yet (default). rule_id: restrict to one prefilter rule. chat_id: restrict to one chat. since_hours: only alerts matched within this many hours. verdict: exact verdict — relevant, irrelevant, pending, skipped, error. min_severity: lowest severity to include (low, medium, high, critical). include_irrelevant: include alerts the judge rejected.

Inputs: limit, chat_id, rule_id, verdict, +4 more. Returns: result

list_criteriaA

List the judging criteria and how often each has matched.

Args: include_disabled: include criteria that are currently turned off.

Inputs: include_disabled. Returns: result

list_dialogsA

List your Telegram chats/channels, most recently active first.

Use this to find the numeric chat ids you need for alert rule scopes.

Args: limit: max number of dialogs to return. unread_only: only return dialogs with unread messages. include_archived: include archived chats (excluded by default).

Inputs: limit, unread_only, include_archived. Returns: result

login_request_codeA

Start logging in: ask Telegram to send a login code.

Telegram delivers the code in the Telegram app itself if the user is signed in elsewhere, otherwise by SMS. Follow with login_submit_code.

Ask the user for their phone number rather than guessing it.

Args: phone: phone number in international format, e.g. +14155550123. session: which session to log in — 'watcher' (default, the one monitoring needs) or 'mcp' (for this server's read tools).

Inputs: phone (required), session.

login_submit_codeA

Finish logging in with the code Telegram sent.

If the account has two-factor authentication, this returns an error asking for the password; call it again with both.

Args: code: the login code the user received. password: two-factor password, only if the account has one. session: the session being logged in; must match login_request_code.

Inputs: code (required), session, password.

monitor_statusA

Check whether the watcher daemon is running and what it has seen.

Reports liveness from the daemon's heartbeat, so a 'stale' result means watcher.py has stopped and no new alerts are being recorded.

Inputs: no named parameters.

preview_ruleA

Test a candidate rule against real message history before creating it.

Shows what the rule would have matched, so the user can judge whether it is too broad or too narrow while they are still writing it. Creates nothing. Use this during setup, before add_alert_rule, and show the user the samples — a rule that looks sensible in the abstract often turns out to match mostly noise.

The matched samples are also the right input for testing draft criteria: read them and decide which ones a criterion should keep, then tell the user which would have been surfaced and which filtered out.

Args: pattern: the candidate pattern. match_type: 'substring', 'word', or 'regex'. case_sensitive: match case exactly. chat_ids: restrict to these chats; omit to search everywhere. search_hint: a plain word to search Telegram for when match_type is 'regex' — Telegram cannot search by regex, so this narrows what gets scanned locally. Required for an unscoped regex preview. limit: max samples to return. scan: how many messages to pull and test.

Inputs: pattern (required), scan, limit, chat_ids, +3 more.

read_messagesA

Read the most recent messages from a chat/channel.

Args: chat_id: numeric dialog id, as returned by list_dialogs. limit: max number of messages to return (most recent first).

Inputs: chat_id (required), limit. Returns: result

search_messagesA

Search your Telegram messages for a keyword.

Searches history, unlike alert rules which only see new messages.

Args: query: text to search for. chat_id: restrict search to one chat; omit to search all chats. limit: max number of results.

Inputs: query (required), limit, chat_id. Returns: result

set_alert_rule_enabledA

Turn an alert rule on or off without deleting it or its alerts.

Args: rule_id: id from list_alert_rules. enabled: True to resume matching, False to pause.

Inputs: enabled (required), rule_id (required).

set_api_credentialsA

Save the Telegram app credentials needed before any login.

The user gets these from https://my.telegram.org under "API development tools" — they identify the application, not the account, and are not secret in the way a login code is. Stored owner-only in /.env.

Args: api_id: numeric App api_id from my.telegram.org. api_hash: 32-character App api_hash from my.telegram.org.

Inputs: api_id (required), api_hash (required).

set_criterion_enabledA

Turn a criterion on or off without deleting it.

Args: criterion_id: id from list_criteria. enabled: True to resume judging against it, False to pause.

Inputs: enabled (required), criterion_id (required).

unread_summaryA

Summarize unread chats: for each, the unread count and the last few unread message previews.

Args: limit_per_chat: how many recent messages to preview per chat. max_chats: max number of unread chats to include.

Inputs: max_chats, limit_per_chat. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.9/5.0

    Scored across 20 tools

    Disambiguation5/5

    Each tool targets a distinct action/resource: auth flow (status, credentials, request/submit code), dialog reading, search, alert-rule CRUD, criterion CRUD, alert listing/acking, and a monitor status check. The two-tier design (rules prefilter, criteria judge, alerts result) is explicitly documented, so even similar-sounding pairs like list_alert_rules/list_alerts and set_alert_rule_enabled/set_criterion_enabled are clearly separated.

    Naming Consistency4/5

    The vast majority follow a clean verb_noun pattern (list_alert_rules, add_alert_rule, delete_criterion, search_messages, ack_alerts). A few deviate to noun-phrases with no verb (auth_status, unread_summary, monitor_status), which is a minor inconsistency but still readable and predictable.

    Tool Count4/5

    At 20 tools this is on the heavier side, but the surface spans several genuinely distinct concerns (auth, reading, rules, criteria, alerts, monitoring), and each tool maps to a real operation without obvious redundancy. It sits just above the ideal band rather than being bloated.

    Completeness4/5

    Coverage is strong: full login/auth flow, dialog listing, reading, searching, preview-before-create, and CRUD for both rules and criteria, plus alert listing/acking and daemon status. Minor gaps remain (no delete/prune or un-ack for alerts, no fetch-by-id), but these are workaroundable.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      A read-only Telegram MCP server that retrieves messages from your DMs, groups, and channels, enabling Claude to generate executive briefings from Telegram conversations.
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Enables AI assistants to search and read a private, local archive of your own Telegram chats, groups and media, so they can answer questions about past conversations. It keeps access read-only toward Telegram, treats message text as untrusted, and lets you choose which chats AI apps may see.
      6
      3
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      A read-only server that lets any MCP client or model list, search, and read your own Telegram chats, including chat details, forum topics, message history, and surrounding context. It never sends, edits, or deletes anything, and stores your Telegram credentials encrypted at rest.
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Connects your own Telegram account or a bot to Claude and other AI assistants so they can read, search, send, and wait for Telegram messages, with everything stored in a local database.
      MIT