npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@chogwanghyung/codex-telegram-bridge-mcp

v1.0.3

Published

MCP bridge for Codex to communicate with allowlisted Telegram chats.

Downloads

478

Readme

Codex Telegram Bridge MCP

Reusable MCP server for allowlisted Telegram communication.

Korean documentation: README.ko.md

This bridge is an operator coordination tool for Codex sessions. It is not a general-purpose Telegram bot framework.

What It Provides

| Tool | Purpose | | --- | --- | | telegram_send | Send a message to an allowlisted Telegram chat. | | telegram_send_file | Send any file type from a local path, URL, or Telegram file ID. | | telegram_send_photo | Send a photo from a local path, URL, or Telegram file ID. | | telegram_send_document | Send a file/document from a local path, URL, or Telegram file ID. | | telegram_wait_reply | Wait for one reply from an allowlisted chat. | | telegram_ask | Send a message and wait for one reply. | | telegram_inbox_read | Read or consume messages captured by the receive monitor. | | telegram_monitor_status | Inspect monitor offset, inbox size, and monitor errors. | | telegram_relay_status | Inspect Telegram-to-Codex relay configuration and pending messages. | | telegram_approval_request | Ask Telegram for an explicit workflow approval. | | telegram_bridge_health | Check token, allowlist, and runtime health. |

The package also includes Codex hook commands:

| Command | Purpose | | --- | --- | | codex-telegram-permission-hook | Handle native Codex PermissionRequest approvals for Telegram-origin turns. | | codex-telegram-stop-hook | Send final replies for Telegram-origin turns from Codex Stop hooks. |

For telegram_send, telegram_wait_reply, telegram_ask, and media tools, chatId may be omitted when exactly one Telegram chat is allowlisted.

Requirements

  • Node.js 20 or newer.
  • A Telegram bot token from @BotFather.
  • A Telegram chat that has already sent /start or another message to the bot.
  • A Codex project configured to load this MCP server.
  • Codex hooks enabled when using native permission approval or automatic relay replies.
  • Core Telegram tools run anywhere Node.js runs. Console relay mode uses bundled Windows PowerShell helpers; use app-server mode or disable relay on other platforms.

Telegram bots cannot DM a user first. Pairing therefore starts with a user opening the bot or pressing a deep-link Start button.

Install

npm install -g @chogwanghyung/codex-telegram-bridge-mcp

The package exposes the codex-telegram-bridge-mcp MCP binary and the codex-telegram-permission-hook Codex hook binary.

Repository Layout

codex-telegram-bridge-mcp/
├─ src/                         # MCP server, Telegram monitor, relay modules
├─ scripts/                     # Pairing helper and Windows console relay helpers
├─ README.md
└─ README.ko.md

Codex Configuration

Add this server to the target project's .codex/config.toml:

[mcp_servers.codex-telegram-bridge]
command = "node"
args = ["<Codex-MCP>/codex-telegram-bridge-mcp/src/index.js"]

[mcp_servers.codex-telegram-bridge.env]
CODEX_TELEGRAM_BRIDGE_ENV_FILE = "<ProjectRoot>/.codex/config.toml.env"
CODEX_TELEGRAM_BRIDGE_ACCESS_FILE = "<ProjectRoot>/.codex/config.toml.access.json"
CODEX_TELEGRAM_BRIDGE_RUNTIME_DIR = "<ProjectRoot>/.codex/telegram-runtime"

Keep live secrets out of .codex/config.toml. Put project-specific runtime settings in .codex/config.toml.env and gitignore it:

CODEX_TELEGRAM_BRIDGE_ENABLED=1
TELEGRAM_BOT_TOKEN=<bot-token>
TELEGRAM_ALLOWED_CHAT_IDS=<chat-id>
CODEX_TELEGRAM_CODEX_RELAY_MODE=console
CODEX_TELEGRAM_CODEX_RELAY_IGNORE_EXISTING=1
CODEX_TELEGRAM_CODEX_SUBMIT_DELAY_MS=150
# Optional inbound media download settings:
# CODEX_TELEGRAM_BRIDGE_DOWNLOAD_DIR=<ProjectRoot>/.codex/telegram-runtime/downloads
# CODEX_TELEGRAM_DOWNLOAD_MAX_BYTES=20971520
# Telegram-origin requests are replied to by the bundled Stop hook.
# Optional native Codex permission approval:
# CODEX_TELEGRAM_APPROVAL_CHAT_IDS=<chat-id>
# CODEX_TELEGRAM_PERMISSION_TIMEOUT_MS=300000
# CODEX_TELEGRAM_PERMISSION_TIMEOUT_BEHAVIOR=ask
# CODEX_TELEGRAM_ALWAYS_APPROVAL_ENABLED=1
# CODEX_TELEGRAM_PERMISSION_HOOK_AUTO_INSTALL=1
# CODEX_TELEGRAM_PERMISSION_HOOK_SCOPE=global

Commit only a safe .codex/config.toml.env.example file.

If installed globally from npm, the MCP command can be the package binary:

[mcp_servers.codex-telegram-bridge]
command = "codex-telegram-bridge-mcp"

Pairing Flow

Clipboard setup:

node <Codex-MCP>/codex-telegram-bridge-mcp/scripts/telegram-configure.js token-clipboard

The command reads the BotFather token from the local clipboard, saves it without printing the token, and creates a short pairing code plus a Telegram deep link.

Open the printed pair_link, press Start in Telegram, then pair:

node <Codex-MCP>/codex-telegram-bridge-mcp/scripts/telegram-configure.js pair <code>

The script checks recent Telegram updates for /start <code> or the raw code, extracts message.chat.id, adds it to the allowlist, and removes the pending pairing code.

If exactly one pending code exists, pair can be run without an argument.

Configuration Commands

Use the configure script directly:

node <Codex-MCP>/codex-telegram-bridge-mcp/scripts/telegram-configure.js status
node <Codex-MCP>/codex-telegram-bridge-mcp/scripts/telegram-configure.js token-clipboard
node <Codex-MCP>/codex-telegram-bridge-mcp/scripts/telegram-configure.js pair <code>
node <Codex-MCP>/codex-telegram-bridge-mcp/scripts/telegram-configure.js discover
node <Codex-MCP>/codex-telegram-bridge-mcp/scripts/telegram-configure.js allow <chat-id>
node <Codex-MCP>/codex-telegram-bridge-mcp/scripts/telegram-configure.js remove <chat-id>
node <Codex-MCP>/codex-telegram-bridge-mcp/scripts/telegram-configure.js policy allowlist
node <Codex-MCP>/codex-telegram-bridge-mcp/scripts/telegram-configure.js policy disabled
node <Codex-MCP>/codex-telegram-bridge-mcp/scripts/telegram-configure.js hook-snippet
node <Codex-MCP>/codex-telegram-bridge-mcp/scripts/telegram-configure.js clear

After token or allowlist changes, restart or resume Codex so the MCP server reloads the saved environment and access files.

Automatic Receive Monitor

When enabled and configured, the server starts a Telegram getUpdates monitor. It stores allowlisted text messages in a capped runtime inbox, downloads allowlisted inbound photos/documents into the runtime download directory, advances a shared offset, and ignores non-allowlisted chats. Photo and file inbox entries include the local file path so Codex can inspect the downloaded file.

Read captured messages:

telegram_inbox_read

Read and consume messages:

{
  "chatId": "<chat-id>",
  "consume": true
}

Check monitor state:

telegram_monitor_status

Media Sending

Use telegram_send_file for format-agnostic file delivery. It sends through Telegram's document path, so extensions such as .apk, .md, .txt, .png, .jpeg, .zip, and logs are handled the same way and preserve the original file. telegram_send_document is kept as an equivalent explicit document tool.

Use telegram_send_photo only when you specifically want Telegram to render the image as a photo in chat. It shares the same local upload preparation logic, but uses Telegram's photo endpoint.

Each media tool accepts exactly one source:

  • path: upload a local file from the machine running the MCP server.
  • url: send a public HTTP(S) URL for Telegram to fetch.
  • fileId: resend an existing Telegram file_id.

When there is exactly one allowlisted chat, chatId may be omitted.

Send any local file:

{
  "path": "D:\\Projects\\app-release.apk",
  "caption": "Latest build"
}

Send a photo from a URL:

{
  "url": "https://example.com/screenshot.png",
  "caption": "Latest screenshot"
}

Result:

{
  "status": "sent",
  "type": "file",
  "source": "path",
  "chatId": "12345",
  "messageId": 77,
  "fileName": "app-release.apk",
  "fileSize": 123456,
  "timestamp": "2026-05-05T00:00:00.000Z"
}

Local uploads reject directories, missing files, and files over the bridge's conservative local upload cap before contacting Telegram.

Choice Questions

telegram_ask can send inline keyboard choices and wait for either a button click or a text fallback reply. This is useful for flows such as Claude fallback decisions:

{
  "message": "Claude review is unavailable. Choose the next action.",
  "choices": [
    { "label": "진행", "value": "proceed" },
    { "label": "대기", "value": "wait" },
    { "label": "중단", "value": "stop" }
  ],
  "timeoutMs": 300000
}

When there is exactly one allowlisted chat, chatId may be omitted. The default UX is button-based. If callback delivery fails or the client cannot use buttons, typing the label or value still works as a fallback.

Selection result:

{
  "status": "selected",
  "timeout": false,
  "selected_label": "진행",
  "selected_value": "proceed",
  "chatId": "12345",
  "messageId": 99,
  "userId": "777",
  "timestamp": "2026-04-26T00:00:00.000Z"
}

Timeout result:

{
  "status": "timeout",
  "timeout": true,
  "chatId": "12345",
  "messageId": 99
}

Telegram-To-Codex Relay

When the bridge is configured, allowlisted Telegram messages are relayed into the active Codex session by default. Console mode is the default on Windows:

CODEX_TELEGRAM_CODEX_RELAY_MODE=console

Supported relay modes:

| Mode | Use Case | | --- | --- | | console | Windows Codex TUI sessions. Injects text and Enter into the target console. Attachments are represented by local file paths. | | app-server | Codex app-server streams. Useful only when the client is connected to that stream. Downloaded images are sent as localImage inputs. |

Console relay details:

  • The bridge auto-detects a Codex console ancestor when possible.
  • CODEX_TELEGRAM_CODEX_CONSOLE_PID can explicitly select the target console.
  • CODEX_TELEGRAM_CODEX_SUBMIT_DELAY_MS delays the Enter key after text input.
  • Telegram-origin prompts are not modified with a telegram_send instruction. The bundled Stop hook sends the final assistant message back to the source Telegram chat after the turn completes.
  • CODEX_TELEGRAM_CODEX_RELAY_IGNORE_EXISTING=1 skips old inbox messages and pairing messages.
  • If Codex app-server status is available, the relay uses it as an idle gate and retries while the target thread is busy.

Relayed prompts contain the Telegram chatId marker, the user's message text, and downloaded attachment paths when present. Long Telegram file IDs and extra file metadata are kept out of the injected prompt so console submission stays reliable; the full metadata remains in the inbox attachment object. In app-server mode, downloaded image attachments are also included as native localImage inputs. When a relayed Telegram request is delivered, the bridge records a pending reply in the runtime state. The bundled Stop hook matches the completed turn and sends Codex's final assistant message back to Telegram.

Check relay state:

telegram_relay_status

Native Codex Permission Approval

Codex can call the bundled hook command whenever it is about to show a native approval prompt. The hook sends the request to Telegram and returns Codex's allow or deny decision from the Telegram reply.

When the MCP server starts and Telegram is fully configured, it automatically installs Codex PermissionRequest, PostToolUse, and Stop hooks. By default it uses the user-level Codex config at $CODEX_HOME/config.toml or %USERPROFILE%/.codex/config.toml, which makes the hook available to existing Codex projects without per-project setup.

Set CODEX_TELEGRAM_PERMISSION_HOOK_SCOPE=local to install the managed hook block into the current project's .codex/config.toml instead. Local scope is cleaner when you only want Telegram approval in projects that explicitly enable this MCP server.

If the current Codex process loaded config before the hook was installed, restart or resume Codex once. After that, MCP connection plus the user-level hook is enough for native permission requests to go through Telegram.

Set CODEX_TELEGRAM_PERMISSION_HOOK_AUTO_INSTALL=0 to disable automatic hook installation. The installer preserves Codex /hooks trust state when refreshing the managed block, so reviewing a hook should not be undone by MCP restart. To inspect or manually install the same hook, print the snippet:

node <Codex-MCP>/codex-telegram-bridge-mcp/scripts/telegram-configure.js hook-snippet

The command prints a TOML snippet like this:

[features]
hooks = true

[[hooks.PermissionRequest]]
matcher = "*"

[[hooks.PermissionRequest.hooks]]
type = "command"
command = "node <Codex-MCP>/codex-telegram-bridge-mcp/scripts/codex-permission-telegram.js"
timeout = 330
statusMessage = "Waiting for Telegram approval"

[[hooks.PostToolUse]]
matcher = "*"

[[hooks.PostToolUse.hooks]]
type = "command"
command = "node <Codex-MCP>/codex-telegram-bridge-mcp/scripts/codex-permission-telegram.js"
timeout = 30
statusMessage = "Updating Telegram approval state"

[[hooks.Stop]]
matcher = "*"

[[hooks.Stop.hooks]]
type = "command"
command = "node <Codex-MCP>/codex-telegram-bridge-mcp/scripts/codex-stop-telegram.js"
timeout = 30
statusMessage = "Sending Telegram reply"

If installed globally from npm, use the package binary:

[[hooks.PermissionRequest]]
matcher = "*"

[[hooks.PermissionRequest.hooks]]
type = "command"
command = "codex-telegram-permission-hook"
timeout = 330
statusMessage = "Waiting for Telegram approval"

[[hooks.PostToolUse]]
matcher = "*"

[[hooks.PostToolUse.hooks]]
type = "command"
command = "codex-telegram-permission-hook"
timeout = 30
statusMessage = "Updating Telegram approval state"

[[hooks.Stop]]
matcher = "*"

[[hooks.Stop.hooks]]
type = "command"
command = "codex-telegram-stop-hook"
timeout = 30
statusMessage = "Sending Telegram reply"

Behavior:

  • The approval prompt runs only while handling a request that originated from the Telegram relay. Matching is based on the pending relay turn/session stored in the Telegram runtime state.
  • Within a Telegram-origin turn, the hook can handle Codex PermissionRequest events such as shell escalation, managed-network approval, apply_patch, and MCP tool approvals.
  • CLI command prompts that look like Would you like to run the following command? are handled when Codex emits them as PermissionRequest events. The hook accepts both the standard tool_input.command payload and command-shaped payloads such as command, cmd, or argv.
  • When the MCP server starts with Telegram configured, it auto-installs the user-level hook by default. CLI-origin turns are ignored; only native permission requests raised during Telegram-origin turns are sent to Telegram.
  • Codex may require newly installed or changed hooks to be reviewed in /hooks before they run. The bridge installs the hook configuration but does not mark hooks reviewed on the user's behalf.
  • The bundled PostToolUse hook updates the Telegram message when a Telegram-origin permission request falls back to the CLI prompt and is later approved there. CLI denial is not observable from current Codex hook events because the tool does not run.
  • The bundled Stop hook replies only to requests that originated from the Telegram relay. Normal CLI-origin turns are ignored.
  • Telegram shows 승인, 항상 승인, and 거부 inline buttons. The internal request code is kept in the callback payload and is not shown in the message body. Buttons are removed after the first accepted response.
  • 항상 승인 stores a bridge-side approval for the same session, cwd, tool name, and exact tool input signature. It does not modify Codex's global permission configuration. Remove the Telegram runtime state file, or set CODEX_TELEGRAM_ALWAYS_APPROVAL_ENABLED=0, to stop using stored always approvals.
  • Text fallback still accepts approval words such as approve, 승인, deny, or 거부 from the same allowlisted chat. It also accepts always approve or 항상 승인 for the same bridge-side always-approval behavior.
  • If CODEX_TELEGRAM_APPROVAL_CHAT_IDS is set, requests go only to those allowlisted chats. Otherwise, requests go to all allowlisted chats.
  • If Telegram times out, the default behavior is ask, which falls back to the normal Codex approval prompt. Set CODEX_TELEGRAM_PERMISSION_TIMEOUT_BEHAVIOR=deny to fail closed.
  • Set CODEX_TELEGRAM_PERMISSION_APPROVAL_ENABLED=0 to disable the hook without removing hook config.

The hook uses the same token, allowlist, and runtime files as the MCP server. Set the Telegram env/access file paths in the Codex hook environment or in the project-local .codex/config.toml.env.

Workflow Approval Helper

For explicit agent workflows that need an approval step separate from native Codex permissions, call:

telegram_approval_request

The helper sends Telegram inline buttons for approve, always approve, and deny responses. Use it only in workflows that deliberately call the tool.

State Files

Project-local state:

<project>/.codex/
├─ config.toml
├─ config.toml.env
├─ config.toml.env.example
├─ config.toml.access.json
└─ telegram-runtime/

User-local fallback:

%USERPROFILE%/.codex/channels/telegram/
├─ .env
└─ access.json

Access JSON stores:

  • allowFrom: allowlisted Telegram chat IDs.
  • pending: temporary pairing codes.
  • dmPolicy: allowlist or disabled.

Multiple MCP Instances

Several Codex sessions can run this MCP server with the same bot token. The bridge uses a token-scoped cross-process lock around Telegram getUpdates, and a state-file lock around local state writes, so multiple monitors do not collide with Telegram long polling or corrupt the runtime state file.

A Telegram update is still consumed once per bot token. If separate Codex sessions use the same bot token but different runtime state files, only the instance that receives an update will relay that specific message. Use the same runtime state file for one shared relay target, or separate bot tokens/chats when each session needs independent routing.

Security Notes

  • The bridge is local-first and does not expose an inbound public service by default, but Telegram tokens and allowlisted chats still need protection.
  • Default access policy is allowlist.
  • Pairing codes expire after 10 minutes by default.
  • Pairing succeeds only when a recent Telegram update contains the matching code.
  • Telegram messages cannot approve their own chat IDs or mutate bridge policy.
  • MCP tools can send to or wait on allowlisted chats only.
  • Common token formats are sanitized from user-facing errors.
  • Prefer token-clipboard; pasting a token into chat may leave it in conversation history.
  • Never commit live bot tokens, chat IDs, access files, or runtime inbox files.

Validation

cd <Codex-MCP>/codex-telegram-bridge-mcp
npm run check
node scripts/telegram-configure.js status

Validation is recommended before publishing or after editing. It is not required for normal local runtime use.

In Codex, confirm these tools are available:

telegram_bridge_health
telegram_monitor_status
telegram_relay_status
telegram_send
telegram_send_file
telegram_send_photo
telegram_send_document
telegram_wait_reply
telegram_ask

License

MIT. See the repository root LICENSE.