Github Webhook Mcp

io.github.Liplus-Project由 GitHub 帳號 Liplus-Project 發布v0.8.2更新於 Oct 27, 2026

MCP server bridging GitHub webhooks via Cloudflare Worker for real-time event streaming

已驗證STDIO僅桌面開發者工具溝通與協作

概覽

AI 產生的概覽

本機 stdio 代理,讓助理讀取經 Cloudflare Worker 轉送的待處理 GitHub webhook 事件,並可選擇即時推送。

可以做什麼
  • 查看待處理 webhook 事件:數量、最新接收時間與事件類型
  • 以摘要列出待處理事件,含 id、類型、動作、儲存庫、傳送者、編號、標題、連結與接收時間
  • 依事件 id 取得單一事件的完整內容,或一次取得全部待處理事件的完整內容
  • 將事件標記為已處理,可單筆或每批最多 100 筆,以清空待處理佇列
  • 在 Claude Code 中以即時頻道通知接收新的 webhook 事件,不必輪詢
適用情境
適合希望助理回應已安裝 GitHub App 的儲存庫活動時使用,例如分流新 issue 或檢視新到事件,而不必自行架設 webhook 接收端。最適合 Claude Code 或其他能執行本機 npx 程序的 MCP 用戶端。
執行需求
需要 Node.js 18 以上版本與 npx。需要可連線的 github-webhook-mcp Cloudflare Worker,預設為公開預覽執行個體,也可透過 WEBHOOK_WORKER_URL 指向自架部署。需要瀏覽器完成一次 GitHub 登入與 OAuth 授權。需要在目標帳號或組織上安裝 GitHub App。權杖會快取在使用者家目錄下。
安裝前請注意
登入會授權 Worker 存取你的 GitHub 個人資料與安裝資訊,OAuth 權杖以檔案形式存放在 ~/.github-webhook-mcp/ 下。預設 Worker 位址為無 SLA 的預覽執行個體,除非自架,事件會經過第三方服務。mark_processed 會變更伺服器端狀態,且需呼叫以避免佇列無限成長;超過每位租戶配額會回傳 429。舊版代理與目前 Worker 不相容且失敗是無聲的,更新後需重新啟動用戶端。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Github Webhook Mcp,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

github-webhook-mcp

Stdio MCP proxy that bridges local MCP clients (Claude Desktop, Claude Code, Codex, etc.) to a remote github-webhook-mcp Cloudflare Worker. The Worker receives GitHub webhook deliveries, persists them in a per-tenant Durable Object (SQLite), and exposes them through MCP tools and a real-time WebSocket stream.

This package is the client-side proxy only. Webhook ingestion, tenant routing, persistence, and the MCP server itself run on the Worker. See the main repository for architecture and self-hosting instructions.

Breaking change: MCP protocol revision 2026-07-28

From this release the Worker serves MCP protocol revision 2026-07-28 only, with no compatibility lane for the previous revision.

  • Proxy versions older than this release stop working. They open a session with initialize, which the Worker no longer answers. The failure is quiet: the proxy does not crash, it returns the protocol error as tool output text.
  • Real-time channel notifications keep arriving, which hides the breakage. The /events WebSocket stream is not MCP and is unaffected, so a stale proxy still pushes event summaries while every tool call — including mark_processed — fails. The pending queue stops being cleared even though notifications look healthy.
  • Restart the MCP client to pick up the new proxy. npx resolves @latest at process start, so an already-running Claude Desktop, Claude Code, or Codex keeps the copy it launched with however new the published version is. Quit it fully and reopen.
  • Pinning the proxy version leaves you stuck. If your MCP client config pins a version older than this release, restarting does not help; remove the pin (or move it forward) first.

The proxy's two protocol faces are independent: it still speaks the 2025-era MCP revision to your client over stdio. Only the face toward the Worker moved.

What this proxy does

  • Speaks stdio MCP locally to your client.
  • Forwards tools/call to the Worker's Streamable HTTP MCP endpoint (/mcp).
  • Optionally maintains a WebSocket connection to the Worker's /events endpoint and re-emits incoming webhook events as Claude Code claude/channel notifications (real-time push, no polling).
  • Handles Worker-hosted web OAuth against the Worker. The proxy identifies itself with an OAuth Client ID Metadata Document served by the Worker, and falls back to Dynamic Client Registration (RFC 7591) against Workers that do not advertise support. No localhost callback port is used: GitHub's redirect_uri is pinned to the Worker itself, so the flow works reliably across process restarts and concurrent client instances.
  • Caches access and refresh tokens under ~/.github-webhook-mcp/ (mode 0600) and refreshes them silently before expiry. On invalid_grant during refresh, the proxy re-reads the tokens file to adopt any rotation performed by a sibling process before falling back to a full re-authorization.

Requirements

  • Node.js >= 18
  • A reachable github-webhook-mcp Worker (the public preview default is https://github-webhook.smgjp.com; you can also point at your own deployment)
  • A web browser (used once to sign in on GitHub via the authorize URL the proxy prints — can be on a different machine from where the MCP client runs)
  • A GitHub App installed on the accounts/organizations whose events you want to receive (the Worker resolves your accessible installations automatically after OAuth)

Install / Run

The proxy is published to npm and exposes a github-webhook-mcp binary.

Run directly with npx (no global install required):

bash
npx github-webhook-mcp

Or install globally:

bash
npm install -g github-webhook-mcpgithub-webhook-mcp

On first run the proxy prints an authorize URL to stderr and tries to open it in your default browser:

[github-webhook-mcp] OAuth authorization required.[github-webhook-mcp] Opening: https://github-webhook.smgjp.com/oauth/authorize?client_id=abc&state=xyz[github-webhook-mcp] Approve in the browser window; the tab can be closed when done.[github-webhook-mcp] Waiting for approval (state expires in 600s)...

Sign in on GitHub (2FA works as usual), approve access, and close the tab when the "Authorization complete" page appears. Tokens are stored under ~/.github-webhook-mcp/ and refreshed automatically before expiry.

Migrating from v0.10.x / v0.11.0. v0.10.x used a browser-based localhost callback flow; v0.11.0 used a GitHub device code flow. On first run with v0.11.1+, the proxy treats any tokens file whose flow marker does not match the new web flow as inactive and transparently starts the new authorization. One-time re-authentication is required; the legacy file is left in place but ignored.

Configure the Callback URL on self-hosted GitHub Apps. If you self-host the Worker with your own GitHub App, register https://<your-worker>/oauth/callback as the Callback URL. Without it, the Worker's /oauth/callback step fails with "Authorization failed" because GitHub will reject the redirect. Device Flow is not used and can stay off. See the self-hosting guide for step-by-step instructions.

Updating

npx resolves the package version once, at process start — including when the client config pins @latest. A client that is already running keeps the version it launched with, so a new npm release does not reach it until that process is replaced: restart the MCP client (Claude Desktop, Claude Code, Codex) to pick up a new version. The restart is what moves the client onto the new version.

This matters most for releases that change the tool schemas the proxy advertises, because those schemas are served from the proxy's own code rather than fetched from the Worker — until the process restarts, the client keeps seeing the old tool definitions.

Verify what the registry holds with --prefer-online. The npm CLI caches registry metadata, so a bare npm view can report the previous version shortly after a publish:

bash
npm view github-webhook-mcp version --prefer-online

Client configuration

Claude Desktop / Claude Code

Add the server to your MCP client configuration. Example for Claude Desktop (claude_desktop_config.json):

json
{  "mcpServers": {    "github-webhook": {      "command": "npx",      "args": ["-y", "github-webhook-mcp"],      "alwaysLoad": true    }  }}

To target a self-hosted Worker, set the WEBHOOK_WORKER_URL environment variable:

json
{  "mcpServers": {    "github-webhook": {      "command": "npx",      "args": ["-y", "github-webhook-mcp"],      "alwaysLoad": true,      "env": {        "WEBHOOK_WORKER_URL": "https://your-worker.example.workers.dev"      }    }  }}

alwaysLoad: true requires Claude Code v2.1.121 or later. It exempts this server's tools from tool-search deferral so they remain immediately callable every turn (recommended because the server is invoked every turn via the UserPromptSubmit hook).

Codex (config.toml)

toml
[mcp.github-webhook-mcp]command = "npx"args = ["-y", "github-webhook-mcp"]
[mcp.github-webhook-mcp.env]WEBHOOK_WORKER_URL = "https://your-worker.example.workers.dev"WEBHOOK_CHANNEL = "0"

WEBHOOK_CHANNEL=0 disables the WebSocket real-time channel. Set it to 0 for clients that do not support claude/channel notifications (Claude Desktop, Codex). Leave it at the default to enable real-time push for Claude Code.

Real-time channel notifications (Claude Code only)

When WEBHOOK_CHANNEL is enabled (the default), the proxy declares the claude/channel experimental capability and re-emits new webhook events as channel notifications. To make them visible in a Claude Code session, load the channel:

bash
claude --dangerously-load-development-channels server:github-webhook-mcp

Notifications are one-way: they include event type, repo, action, title, sender, and URL. There is no reply tool.

Configuration

VariableRequiredDefaultDescription
WEBHOOK_WORKER_URLNohttps://github-webhook.smgjp.comBase URL of the Cloudflare Worker that exposes the MCP endpoint, the WebSocket stream, and OAuth metadata.
WEBHOOK_OBSERVERNo0 (disabled)Set exactly to 1 for raw pending status and noninteractive authentication using an existing saved access token.
WEBHOOK_CHANNELNo1 (enabled)Set to 0 to disable the WebSocket connection and claude/channel notifications.

OAuth client registration and tokens are stored in:

  • ~/.github-webhook-mcp/oauth-client.json (dynamic client registration; only written when the Worker does not support Client ID Metadata Documents)
  • ~/.github-webhook-mcp/oauth-tokens.json (access + refresh tokens, and the client_id they were issued to)

Delete these files to force a fresh authorization flow.

Note on the default Worker URL. https://github-webhook.smgjp.com is a preview instance offered for evaluation. It has no SLA and may change or stop without notice. For production use, deploy your own Worker (see the main repository's installation guide) and set WEBHOOK_WORKER_URL accordingly.

Passive observer connections

Set WEBHOOK_OBSERVER=1 on a dedicated bridge process to observe pending status without starting authentication UI. Authenticate using a separate normal CLI process first. Observer calls read the saved token file once per credential acquisition, so an external login can recover the connection on the next call. Missing, malformed, expired, or rejected credentials return a tool error with isError: true and matching JSON text / structuredContent:

json
{"error":"auth_required","message":"Observer mode requires an existing valid token. Authenticate using a separate CLI process, then retry."}

Observer mode does not register a client, refresh tokens, open a browser, or start OAuth polling. A saved token with no expiry is accepted until rejected by the server. Authentication failures stop background WebSocket reconnection; after external login, the next successful tool call restarts it. WEBHOOK_CHANNEL still controls channel notifications, and get_event remains available.

Detect the contract using tools/list: only the observer get_pending_status entry advertises _meta: {"io.github.Liplus-Project/github-webhook-mcp/pending-status-observer": 1}. Its result preserves the Worker's raw JSON text and any structuredContent, including nonzero counts:

json
{"pending_count":3,"types":{"issues":3},"latest_received_at":"2026-10-19T00:00:00Z"}

types maps event names to counts. latest_received_at is a timestamp string or null, and covers the latest pending event, not the full history. Status reads do not consume events or call mark_processed. Authentication and network failures are errors, not zero counts. Normal mode does not advertise this metadata; its existing nonzero status hook decision JSON and zero-count raw response remain unchanged. Use a separate process for hook callers that need that normal behavior.

Tools exposed

All tools are read-only except mark_processed.

ToolDescription
get_pending_statusLightweight snapshot of pending (unprocessed) webhook events: pending count, latest received timestamp, and event types. Use this for periodic polling before requesting details.
list_pending_eventsSummary list of pending events (limit: 1-100, default 20). Returns metadata only — id, type, action, repo, sender, number, title, url, received_at — without the full payload.
get_eventFull payload for a single webhook event by event_id.
get_webhook_eventsPending events with full payloads. Prefer get_pending_status or list_pending_events for polling and only fall back to this when you really need everything.
mark_processedMark events as processed so they no longer appear in pending queries. Pass event_id for one event, or event_ids (1-100) to clear a whole batch in a single call. Required to keep the pending queue from growing unbounded.

Recommended polling flow

  1. Poll get_pending_status() periodically (e.g. every 60 seconds).
  2. If pending_count > 0, call list_pending_events() for summaries.
  3. Call get_event(event_id) only for events that need the full payload.
  4. Call mark_processed after handling the events — event_ids: [...] clears the whole set in one call, which is the normal case when a batch of events was handled together.

If real-time channel notifications are enabled (Claude Code), step 1 can be skipped — the proxy will push event summaries as soon as the Worker receives them. You still need to call mark_processed to clear the queue.

Event retention

The Worker purges stored events automatically so Durable Object storage stays bounded. A time-based sweep runs on a Durable Object Alarm (daily) and reschedules itself, so cleanup happens even when mark_processed is never called.

Event classRetention windowWorker env varDefault
Processed (mark_processed called)events older than the window are deletedPURGE_AFTER_DAYS3 days
Unprocessed (never marked)events older than the window are deletedUNPROCESSED_PURGE_AFTER_DAYS90 days
  • The longer window for unprocessed events is intentional — unprocessed means user-unseen, so the margin before dropping is wide (the 3-day vs 90-day asymmetry is by design).
  • Processed events are also purged immediately on mark_processed for promptness; the Alarm sweep is the guarantee that covers tenants that stop consuming.
  • Both windows are Worker-side configuration (worker/wrangler.toml [vars]); set a value to 0 to purge that class immediately on sweep. These env vars live on the Worker, not in this proxy.
  • Known limitation: the windows bound event age, not volume. A high-rate, never-consumed tenant can still hit Cloudflare's 1 GB-per-DO ceiling before the 90-day window applies.

Authentication flow

  1. On first tool call (or on startup if cached tokens exist), the proxy discovers OAuth metadata at ${WEBHOOK_WORKER_URL}/.well-known/oauth-authorization-server.
  2. It picks its client_id. If the metadata carries client_id_metadata_document_supported: true and an https issuer, the client_id is <issuer>/oauth/client-metadata.json — a Client ID Metadata Document the Worker serves for this proxy — and no registration request is made. Otherwise it performs Dynamic Client Registration (RFC 7591) if no client is cached, declaring support for the urn:ietf:params:oauth:grant-type:web_authorization_poll and refresh_token grant types. Either way it is a public client with no secret — the Worker itself uses its own GITHUB_CLIENT_SECRET to talk to GitHub. Refresh always presents the client_id the tokens were issued to, so tokens obtained through an earlier registration keep refreshing after the Worker gains CIMD support.
  3. It generates a random state and opens ${WEBHOOK_WORKER_URL}/oauth/authorize?client_id=<cid>&state=<state> in your default browser. The Worker stores a pending state record and 302-redirects to GitHub's standard https://github.com/login/oauth/authorize, with redirect_uri pinned to the Worker's own /oauth/callback (no localhost).
  4. You sign in on GitHub and approve. GitHub redirects back to ${WEBHOOK_WORKER_URL}/oauth/callback?code=<code>&state=<state>. The Worker exchanges the code for a GitHub access token (confidential client), fetches your GitHub profile + installations, and issues its own opaque access/refresh token pair bound to that grant. The browser tab shows "Authorization complete".
  5. Meanwhile the proxy polls ${WEBHOOK_WORKER_URL}/oauth/token with grant_type=urn:ietf:params:oauth:grant-type:web_authorization_poll against the same state. It receives authorization_pending until the callback completes, then receives the Worker-issued token pair on the next poll.
  6. The Worker resolves your accessible GitHub installations (your user account plus any organizations where the GitHub App is installed) and binds them to the OAuth session, so events from any of those tenants surface through the same MCP session.
  7. Subsequent calls reuse the access token and silently refresh it five minutes before expiry. On 401 from the Worker or invalid_grant during refresh, the proxy first re-reads its tokens file (in case a sibling process has already rotated) and only falls back to a fresh web flow when no newer refresh token is on disk.

Concurrent bridges for the same OS user, normalized Worker URL and real authentication directory share one web flow. Only its owner registers, opens a browser, polls and saves tokens; other bridges return the same pending URL and expiry, then validate the saved scope/generation before continuing. Tool calls keep the 15-second startup limit and do not wait for the 600-second approval window. Observer mode remains read-only; refresh recovery is unchanged.

The owner holds an exclusive listener on 127.0.0.1, on one port derived from that scope's hash. This is private coordination, while the OAuth callback remains on the Worker. Every IPC request requires a random capability from a restrictive ~/.github-webhook-mcp/web-auth-<scope>.json record. Neither OAuth credentials nor unauthorized URL/state metadata are returned over IPC. Owner exit releases the listener; expiry aborts and fences its writes. A healthy owner repairs a damaged record; a replacement cannot be deleted or overwritten by its predecessor. Unknown listeners, blocked loopback listening and hash-port collisions fail closed with a retryable coordination error, rather than opening another flow on a different port.

Existing global token/client files still lack issuer metadata; this does not provide general cross-Worker cache isolation.

Troubleshooting

  • OAuth coordination unavailable; retry the tool call. Another local service may occupy the scope-derived port, or local policy may block loopback listening. Retry after the conflicting service/flow ends. Do not delete credential files or expose the listener on another interface.
  • Authorize URL never appears in the log. Check the stderr stream of the MCP process (Claude Code surfaces it as the server's log). Look for the [github-webhook-mcp] OAuth authorization required. block.
  • OAuth state expired before approval. Re-run the client to retry. The state token expires after ~10 minutes. Trigger any tool call again to restart the flow.
  • Browser lands on "Authorization failed" (Worker 502). The Worker rejected the GitHub code exchange. On self-hosts this usually means the GitHub App's Callback URL does not include https://<your-worker>/oauth/callback, or GITHUB_CLIENT_SECRET is missing / wrong.
  • Failed to reach worker. Check that WEBHOOK_WORKER_URL is correct and reachable from your machine.
  • Every tool call returns a protocol error, but channel notifications still arrive. The running proxy predates the 2026-07-28 revision the Worker now serves. Restart the MCP client so npx fetches the current version; if your config pins an older version, move the pin forward first. See the breaking-change note at the top of this page.
  • Authentication failed after retry. Cached tokens were rejected and re-authentication did not succeed. Remove ~/.github-webhook-mcp/oauth-tokens.json and retry.
  • Upgrading from v0.10.x / v0.11.0. Existing tokens files are ignored (flow marker mismatch) and a fresh web-flow authorize URL is emitted on the next tool call. No manual cleanup is required.
  • No events arriving. Confirm that the GitHub App is installed on the target account/organization and that webhook deliveries are succeeding on the GitHub App's Advanced → Recent Deliveries page. The Worker only sees events for installations linked to your authenticated account.
  • 429 from the Worker. The per-tenant event quota (default 10,000) has been exceeded. Process the backlog with mark_processed to free space.
  • Real-time notifications not showing in Claude Code. Make sure WEBHOOK_CHANNEL is not set to 0 and that Claude Code was launched with --dangerously-load-development-channels server:github-webhook-mcp.
  • Stale credentials. Remove ~/.github-webhook-mcp/oauth-tokens.json (and optionally oauth-client.json) and retry.

Links

License

Apache-2.0. See the LICENSE and NOTICE files in the main repository.

來源:mcp-server/README.md,提交 740bc5d

工具

0
SourceWeft 尚未在沙箱中啟動過該軟體包,因此其工具未知。

版本歷史

1
  1. v0.8.2最新Sep 16, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分