chowdown

io.github.mridang由 GitHub 帳號 mridang 發布v0.1.0更新於 Oct 24, 2026

Your recipes as plain files in your own Google Drive, searchable by your AI assistant.

已驗證Streamable HTTP可網頁執行位置與生活效率與工作流檔案與儲存

概覽

AI 產生的概覽

Chowdown 是遠端 MCP 伺服器,讓助理瀏覽、搜尋和編輯存放在你自己 Google Drive 中的 Cooklang 食譜。

可以做什麼
  • 依料理類型、飲食分類或時間瀏覽與搜尋食譜,並列出可用的篩選條件
  • 依手邊食材找出能做的菜,以及只差一兩樣食材的菜色
  • 新增、編輯、加標籤、收藏和加註食譜,支援唯讀或讀寫權限
  • 從連結匯入食譜,並列出相似食譜或建議
適用情境
適合把食譜以 Cooklang 檔案保存在 Google Drive 的人,讓助理回答今晚煮什麼、冰箱食材能做什麼,或把新找到的食譜歸檔。
執行需求
需要遠端端點 chowdown.apps.mrida.ng/mcp,透過 Google 的 OAuth 2.1 登入,不必複製密鑰。使用食譜工具前還須在應用程式內另外連接 Google Drive(drive.file 權限)。授權時可選擇唯讀或讀寫權限。
安裝前請注意
連線會讀取並可能寫入 Google Drive 中由應用程式管理的 Recipes 資料夾,讀寫權限允許新增、編輯和刪除食譜。匯入與呼叫模型的工具受每日額度限制,可能回傳限流錯誤。不再使用時可在 Connected apps 或 OAuth 撤銷端點中斷連線。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 chowdown,將其新增到工作區。
  2. 連接 所需的 憑證。它們會被私密儲存,絕不會在公開頁面上展示。
  3. 為需要使用其工具的對話啟用該服務。

Web executable,透過 Streamable HTTP。 遠端服務在工作區中設定後即可從網頁執行環境執行。

交給代理程式安裝

把這段提示詞貼上到 Claude Code、Codex、Cursor 等代理程式,或 SourceWeft 對話中。代理程式會讀取該伺服器的安裝指南,先向你展示發布者、端點和登入方式,經你同意後再把它新增到你的客戶端。金鑰不會寫進任何命令。

閱讀 https://sourceweft.com/mcp/io.github.mridang%2Fchowdown/install.md,並按其中說明把這個 MCP 伺服器接入我的客戶端。修改任何設定之前,先告訴我它的發布者、端點和登入方式,等我確認。不要把 API 金鑰寫進命令或我會提交的檔案;問我金鑰應從哪裡取得。

檢視代理程式所依據的安裝指南

其他 MCP 客戶端

把它新增到你客戶端的 mcpServers 設定中。 客戶端會在首次連接時完成 OAuth 登入。

{
  "mcpServers": {
    "chowdown": {
      "type": "http",
      "url": "https://chowdown.apps.mrida.ng/mcp"
    }
  }
}

README

🍳 Chowdown

A recipe app for Cooklang .cook files, kept in the person's own Google Drive. Built as a Next.js app on Cloudflare Workers (OpenNext).

The Cloudflare Worker does the real work: Google sign-in, a separate "Connect Google Drive" step, syncing the Recipes folder into a D1 cache, the REST API, the MCP server (with its OAuth 2.1 endpoints) and the model calls for tagging and "find similar" (Workers AI). Drive stays the source of truth; D1 is a cache so pages render in one round trip.

Stack

  • Next.js 16 (App Router), React 19 and Tailwind 4, on Cloudflare Workers via OpenNext (@opennextjs/cloudflare)
  • D1 with Drizzle, plus the Workers AI and Images bindings
  • devbox pins Node 24
  • Jest for unit tests, Cypress for end-to-end tests
  • @mridang/eslint-defaults for linting
  • @cooklang/cooklang-ts for parsing

Google setup

Signing in and connecting Google Drive are two separate steps, each with its own Google consent screen:

  1. Sign in asks for identity only (openid email profile). It creates the account and a signed session cookie, and nothing else.
  2. Connect Google Drive (the button in the header, the account menu, and on pages that need it; GET /auth/drive) adds the drive.file scope and an offline refresh token, then creates the app-managed "Recipes" folder. drive.file is non-sensitive and only reaches files Chowdown created, so there is no Google verification and nothing is published to the Marketplace.

Until Drive is connected a person can look around and see anything already cached, but anything that reads or writes their Drive files is refused (the REST API answers 409 /problems/drive-not-connected, MCP tools return an error result that says what to do).

Set up in Google Cloud:

  1. Enable the Google Drive API.
  2. OAuth consent screen: External, add the .../auth/drive.file scope, add your Gmail as a test user (or publish to production — still review-free).
  3. OAuth client ID (Web application) → Authorized redirect URIs:
    • http://localhost:3737/auth/callback (dev)
    • https://chowdown.apps.mrida.ng/auth/callback (prod)

Secrets, in .env locally and wrangler secret put <NAME> in production (see Deploy):

sh
GOOGLE_OAUTH_CLIENT_ID=....apps.googleusercontent.comGOOGLE_OAUTH_CLIENT_SECRET=...SESSION_SECRET=...          # openssl rand -base64 32 — signs the session cookieTOKEN_ENCRYPTION_KEY=...    # openssl rand -base64 32 — seals Drive refresh tokens

APP_URL is optional (the public origin, if it can't be read from the request).

Connecting an assistant (MCP)

Chowdown is an MCP server at https://<your-domain>/mcp, protected with OAuth 2.1 as the MCP authorization spec describes. Add that URL as a connector in ChatGPT, Claude or any MCP client, sign in with Google when asked, and approve. There is no secret to copy. The person needs to have connected Google Drive (see above); until then the assistant is told so instead of being shown an empty collection.

Chowdown is listed in the MCP Registry as io.github.mridang/chowdown; the listing is server.json in this repository.

  • Scopes: recipes:read (browse and search) and recipes:write (add, edit, tag, favourite, annotate). An assistant can be granted read only.
  • Asking what to cook: browse_recipes ("I feel like cooking Indian", "something vegetarian under 30 minutes"), recipes_from_ingredients ("I have 3 tomatoes and 400 g of pasta" returns what can be cooked now and what is a couple of ingredients short) and list_filters. Every recipe is classed as vegan, vegetarian, pescatarian or non-vegetarian from its ingredients, so results can be grouped and filtered by diet; existing recipes get this without being re-tagged.
  • Discovery: /.well-known/oauth-protected-resource/mcp (RFC 9728) and /.well-known/oauth-authorization-server (RFC 8414).
  • Client registration: Client ID Metadata Documents (preferred) and dynamic registration (/oauth/register, RFC 7591). Public clients only, PKCE S256 required.
  • Tokens: opaque, stored hashed. Access tokens last an hour; refresh tokens rotate on every use, and reusing an old one revokes the whole connection.
  • Disconnect: "Connected apps" in the app, or POST /oauth/revoke.

REST API

The app's data is available as a REST API under /api, designed to the Zalando RESTful API guidelines (plural nouns, snake_case JSON, RFC 9457 problem details, cursor pagination, JSON Merge Patch, ETag / If-Match, X-Flow-ID). The deliberate departures are the /api prefix and path segments without hyphens (recipes/imports, not recipe-imports).

ResourceMethods
/api/recipes, /api/recipes/{id}list, create · read, replace, patch, delete
/api/recipes/{id}/notes[/{note_id}]list, create · read, replace, delete
/api/recipes/{id}/similarlist
/api/recipes/suggestions?q=list
/api/recipes/imports[/{id}]list, create · read, delete
/api/users/selfread, patch, delete
/api/users/self/favourites[/{recipe_id}]list · read, put, delete
/api/users/self/connections[/{grant_id}]list · delete
/api/sessionsdelete (sign out everywhere)
/api/sessions/selfdelete (sign out)

Auth is the signed session cookie. Writes must come from the app's own pages (cross-site writes get 403). Signing in does not connect Google Drive: writes and /api/recipes/suggestions answer 409 /problems/drive-not-connected until the person has connected it in the browser. Everything that is not a resource stays out of the API: MCP (/mcp), OAuth (/oauth/*, /.well-known/*), the Google sign-in and Drive-connection redirects (/auth/*), the health check (/health), the image proxy (/img), CSP reports (/csp/reports).

OpenAPI

openapi.json at the root of the repository describes exactly the routes under src/app/api, nothing else. test/openapi.test.ts fails when the two drift: every exported METHOD /path must be an operation and the other way round, a public operation must answer without a session and a secured one must answer 401, bad input must answer a documented status as application/problem+json, and good answers must fit their schemas.

Testing the API with Schemathesis

Every operation can be called by one ordinary signed-in account; there is no administrator role. Sign in with Google in a browser, connect Google Drive once (until then the operations that read or write recipe files answer 409), and copy the value of the chowdown_session cookie from the browser's developer tools into an environment variable. Then run, against a local or deployed instance:

sh
export CHOWDOWN_SESSION='<the cookie value>'   # a credential: keep it out of logs and filesschemathesis run openapi.json --url https://your-instance.example \  --header "Cookie: chowdown_session=$CHOWDOWN_SESSION" \  --exclude-operation-id deleteCurrentUser \  --exclude-operation-id deleteSessions

Leave the last two operations out of a long run: they delete the account and end every session, so the account is gone after the first call. The requests Schemathesis generates carry no Sec-Fetch-Site or Origin header, which the cross-site check lets through; they count against the platform's rate limits and the daily allowances of importing and suggesting, so expect some 429s with Retry-After.

Local development

All commands go through devbox, which pins Node 24:

sh
devbox run -- npx wrangler login   # once: the AI binding is remote-only in devdevbox run -- npm run migrate      # apply D1 migrations to the local databasedevbox run -- npm run build:views  # once, and after changing src/views: the generated widget pagesdevbox run -- npm run dev          # next dev on http://localhost:3737devbox run -- npm test             # jest, including the MCP conformance suitedevbox run -- npm run lint         # eslintdevbox run -- npm run typecheck    # tsc --noEmitdevbox run -- npm run format       # prettier

Put the secrets listed under Google setup in .env (gitignored) before signing in. http://localhost:3737 needs no certificate, because Google OAuth allows http for localhost: add http://localhost:3737/auth/callback to the OAuth client's redirect URIs.

Deploy

sh
# one-time per environmentdevbox run -- npx wrangler d1 create chowdown-db          # paste the id into wrangler.jsoncdevbox run -- npx wrangler d1 migrations apply DB --remotedevbox run -- npx wrangler secret put GOOGLE_OAUTH_CLIENT_IDdevbox run -- npx wrangler secret put GOOGLE_OAUTH_CLIENT_SECRETdevbox run -- npx wrangler secret put SESSION_SECRETdevbox run -- npx wrangler secret put TOKEN_ENCRYPTION_KEY
# every releasedevbox run -- npm run deploy                              # opennextjs-cloudflare build && wrangler deploy

The custom domain chowdown.apps.mrida.ng requires the apps.mrida.ng zone on the Cloudflare account, and the Worker needs the AI and Images bindings (declared in wrangler.jsonc).

GitHub Actions (deploy.yml) applies the D1 migrations and deploys on pushes to master. It needs a CLOUDFLARE_API_TOKEN secret and a CLOUDFLARE_ACCOUNT_ID variable in the production environment.

Operations

Settings. SESSION_SECRET signs the session cookie and TOKEN_ENCRYPTION_KEY seals Drive refresh tokens; both are Worker secrets. APP_URL is the public origin: set it in production, because when it is missing the origin is read from the request's Host header. MCP_ALLOWED_ORIGINS (comma-separated, exact origins such as chrome-extension://abcdef) lets a browser-based or webview MCP client call /mcp; leave it unset for assistants that run on a server.

Rate limits. Three layers, cheapest first:

  1. Cloudflare Workers Rate Limiting bindings (ratelimits in wrangler.jsonc, thirteen of them), checked in the Worker before the app runs. Which request counts against which binding is in src/lib/core/http/edge-limits.ts, and a test keeps the two in step. They are per Cloudflare location and eventually consistent: a cost guard that refuses floods, not an accounting system. Optionally add one Cloudflare WAF rate-limiting rule on top (dashboard: Security, WAF, Rate limiting rules) to stop a flood before the Worker is invoked at all.
  2. Exact, durable counters in D1: OAuth client registration, token endpoint, per-user MCP calls, and the daily budgets for imports, suggestions and the assistant tools that call a model (src/lib/util/daily-budget.ts).
  3. Hard caps inside a request: ten links or recipes per import, body sizes, page and image byte caps, 5,000 Cooklang lines.

A refused call answers 429 with Retry-After.

Checks. devbox run -- npm test runs the official MCP conformance suite against the server's request handling for 2026-07-28 and 2025-11-25 (test/e2e/mcp.e2e.test.ts, which also lists the known gaps with their reasons). MCP 2024-11-05 clients work over streamable HTTP only (no HTTP+SSE transport is hosted).

Agent skills

Skills are folders an AI agent can load to carry out a task end to end. They follow the open Agent Skills format (a SKILL.md plus helper scripts), so they work in Claude Code, Cowork, GitHub Copilot and other agents that read it.

SkillWhat it does
import-bookmarked-recipesFinds recipe links in your browser bookmarks, imports them into Chowdown through your MCP connector, fixes missing cover photos, verifies the result, and offers to remove the imported bookmarks only after you say yes. Can also run on a schedule ("periodically import my recipes"), in which case it imports but never deletes.

To install one, copy or symlink its folder into your agent's skills folder:

sh
# Claude Code (all projects)ln -s "$PWD/skills/import-bookmarked-recipes" ~/.claude/skills/import-bookmarked-recipes
# GitHub Copilot (this repository)mkdir -p .github/skills && cp -R skills/import-bookmarked-recipes .github/skills/

In Cowork, upload the folder (zipped) as a custom skill. The skill also needs Chowdown added to the agent as an MCP connector: use the MCP server address on the home page or the app's "Cook with AI" page, then approve the connection.

來源:README.md,提交 a11b214

工具

0
該伺服器需要登入,因此 SourceWeft 無法在沒有帳號的情況下讀取其工具,也未收錄。已連接帳號所能看到的內容可能因帳號及其權限而異。

版本歷史

1
  1. v0.1.0最新Oct 24, 2026

評分

已滿足適用檢查項的 85%

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

  • 近 30 天內可連通必需25 分
  • 已宣告認證方式必需10 分
  • 已列出工具15 分

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

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