Spec Driven Development
MCP Server that facilitates spec-driven development workflows, not just Vibe Coding.
제작자가 쓴 설명(영어 원문)
Remote MCP server for your Gaggiuino espresso machine's shots and profiles
이 세 가지는 절대 하나의 점수로 합치지 않아요. 의견, 측정, 인기는 서로 다른 것이니까요.
이 서버는 아직 쉬운 말로 된 요약을 쓰지 못했어요. 아래는 레지스트리에서 읽어 온 사실이에요.
쓰고 있는 AI 앱을 고른 다음 설정을 복사하세요.
GAGGIUINO_URL, PORT, HOST, MCP_PUBLIC_URL, MCP_OAUTH_SECRET, MCP_OAUTH_PASSPHRASE_HASH, MCP_OAUTH_ISSUER, MCP_ALLOWED_ORIGINS, MCP_ALLOWED_HOSTS, LOG_LEVEL비밀로 표시된 값은 내 계정의 열쇠예요. 절대 다른 사람과 공유하거나 채팅에 붙여 넣지 마세요.
필요한 것
어떤 앱을 쓰세요?
위에서 앱을 고르세요. 기억해 두었다가 다음부터는 버튼에 “…에 설치”라고 표시해요.
Claude Desktop → Settings → Developer → Edit Config를 열고 claude_desktop_config.json에 이 내용을 붙여 넣으세요
{
"mcpServers": {
"gaggiuino": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"GAGGIUINO_URL",
"-e",
"PORT",
"-e",
"HOST",
"-e",
"MCP_PUBLIC_URL",
"-e",
"MCP_OAUTH_SECRET",
"-e",
"MCP_OAUTH_PASSPHRASE_HASH",
"-e",
"MCP_OAUTH_ISSUER",
"-e",
"MCP_ALLOWED_ORIGINS",
"-e",
"MCP_ALLOWED_HOSTS",
"-e",
"LOG_LEVEL",
"ghcr.io/ljcl/gaggiuino-mcp:6.0.0"
],
"env": {
"GAGGIUINO_URL": "your-value",
"PORT": "your-value",
"HOST": "your-value",
"MCP_PUBLIC_URL": "your-value",
"MCP_OAUTH_SECRET": "your-value",
"MCP_OAUTH_PASSPHRASE_HASH": "your-value",
"MCP_OAUTH_ISSUER": "your-value",
"MCP_ALLOWED_ORIGINS": "your-value",
"MCP_ALLOWED_HOSTS": "your-value",
"LOG_LEVEL": "your-value"
}
}
}
}터미널에서 이 명령어를 실행하세요
claude mcp add gaggiuino --env GAGGIUINO_URL=your-value --env PORT=your-value --env HOST=your-value --env MCP_PUBLIC_URL=your-value --env MCP_OAUTH_SECRET=your-value --env MCP_OAUTH_PASSPHRASE_HASH=your-value --env MCP_OAUTH_ISSUER=your-value --env MCP_ALLOWED_ORIGINS=your-value --env MCP_ALLOWED_HOSTS=your-value --env LOG_LEVEL=your-value -- docker run -i --rm -e GAGGIUINO_URL -e PORT -e HOST -e MCP_PUBLIC_URL -e MCP_OAUTH_SECRET -e MCP_OAUTH_PASSPHRASE_HASH -e MCP_OAUTH_ISSUER -e MCP_ALLOWED_ORIGINS -e MCP_ALLOWED_HOSTS -e LOG_LEVEL ghcr.io/ljcl/gaggiuino-mcp:6.0.0실행하기 전에 빈 값을 채워 주세요.
프로젝트의 .cursor/mcp.json 또는 ~/.cursor/mcp.json에 붙여 넣으세요
{
"mcpServers": {
"gaggiuino": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"GAGGIUINO_URL",
"-e",
"PORT",
"-e",
"HOST",
"-e",
"MCP_PUBLIC_URL",
"-e",
"MCP_OAUTH_SECRET",
"-e",
"MCP_OAUTH_PASSPHRASE_HASH",
"-e",
"MCP_OAUTH_ISSUER",
"-e",
"MCP_ALLOWED_ORIGINS",
"-e",
"MCP_ALLOWED_HOSTS",
"-e",
"LOG_LEVEL",
"ghcr.io/ljcl/gaggiuino-mcp:6.0.0"
],
"env": {
"GAGGIUINO_URL": "your-value",
"PORT": "your-value",
"HOST": "your-value",
"MCP_PUBLIC_URL": "your-value",
"MCP_OAUTH_SECRET": "your-value",
"MCP_OAUTH_PASSPHRASE_HASH": "your-value",
"MCP_OAUTH_ISSUER": "your-value",
"MCP_ALLOWED_ORIGINS": "your-value",
"MCP_ALLOWED_HOSTS": "your-value",
"LOG_LEVEL": "your-value"
}
}
}
}브라우저가 앱을 열지 물어본 다음, 앱이 설정을 보여 주고 확인을 요청해요. 키 값은 비워 두니 직접 입력하세요.
프로젝트의 .vscode/mcp.json에 붙여 넣으세요
{
"servers": {
"gaggiuino": {
"type": "stdio",
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"GAGGIUINO_URL",
"-e",
"PORT",
"-e",
"HOST",
"-e",
"MCP_PUBLIC_URL",
"-e",
"MCP_OAUTH_SECRET",
"-e",
"MCP_OAUTH_PASSPHRASE_HASH",
"-e",
"MCP_OAUTH_ISSUER",
"-e",
"MCP_ALLOWED_ORIGINS",
"-e",
"MCP_ALLOWED_HOSTS",
"-e",
"LOG_LEVEL",
"ghcr.io/ljcl/gaggiuino-mcp:6.0.0"
],
"env": {
"GAGGIUINO_URL": "your-value",
"PORT": "your-value",
"HOST": "your-value",
"MCP_PUBLIC_URL": "your-value",
"MCP_OAUTH_SECRET": "your-value",
"MCP_OAUTH_PASSPHRASE_HASH": "your-value",
"MCP_OAUTH_ISSUER": "your-value",
"MCP_ALLOWED_ORIGINS": "your-value",
"MCP_ALLOWED_HOSTS": "your-value",
"LOG_LEVEL": "your-value"
}
}
}
}브라우저가 앱을 열지 물어본 다음, 앱이 설정을 보여 주고 확인을 요청해요. 키 값은 비워 두니 직접 입력하세요.
이 서버는 내 컴퓨터에서 실행되는데, ChatGPT는 인터넷에 있는 서버에만 연결할 수 있어요. 다른 앱을 고르세요.
선택한 앱은 이 기기의 쿠키에만 저장돼요. 계정은 필요 없어요.
GAGGIUINO_URL envPORT envHOST envMCP_PUBLIC_URL envMCP_OAUTH_ISSUER envMCP_ALLOWED_ORIGINS envMCP_ALLOWED_HOSTS envLOG_LEVEL env이 설정은 제작자의 레지스트리 정보로 만들었어요. README와 다르면 README를 따르세요.
내 컴퓨터에서 실행돼요. 설치하면 AI 앱에 도구 목록이 나타나요.
누구나 볼 수 있는 정보를 점검했고, 코드는 읽지 않았어요. 해당하지 않는 항목은 개수에서 뺐어요. · 2026년 11월 9일 점검
레지스트리 이름이 GitHub 계정 ljcl 기준으로 확인되었고, 이 계정이 저장소를 소유하고 있어요
아직 GitHub에서 이 저장소를 읽어 오지 않았어요
아직 GitHub에서 이 저장소를 읽어 오지 않았어요
내 컴퓨터에서 실행되는 서버라 인터넷 엔드포인트가 없어요
내 컴퓨터에서 실행되며, 대신 로컬 설정을 사용해요
내 컴퓨터에서 실행돼요. 도구 목록은 인터넷 엔드포인트가 있는 서버에서만 읽을 수 있어요
레지스트리에서 이 카테고리의 활성 서버 전체와 비교했어요. 스타는 게시자가 저장소를 소유한 경우에만 세요.
해당하는 기본 점검 1개 중 1개를 통과했어요. 코드는 읽지 않았어요. 키나 토큰을 넣기 전에 서버가 어떤 권한을 요구하는지 확인하고, 꼭 필요한 권한만 있는 키를 쓰세요.
입력해야 할 값: MCP_OAUTH_SECRET, MCP_OAUTH_PASSPHRASE_HASH
내 컴퓨터에서 실행돼요. AI 앱이 필요할 때 실행하고, 데이터는 제작자의 서버를 거치지 않아요(서버 자체가 온라인 서비스를 호출하는 경우는 제외).
GitHub 저장소는 마지막으로 – 변경됐고, 최신 버전(6.0.0)은 35일 전 레지스트리에 올라왔어요.
Claude Desktop, Claude Code, Cursor, VS Code처럼 MCP를 지원하는 앱에서 쓸 수 있어요. 내 컴퓨터에 Docker도 있어야 해요.
같은 카테고리에는: Spec Driven Development, Remote Desktop Commander, erateradar
같은 카테고리에서 다른 제작자가 만든 서버예요. 스타 순으로 정렬했어요.
카드 보는 법:↓ 주간 다운로드i★ GitHub 스타i세 기둥: 리뷰 · 점검 · 사용 정도i업데이트 = 최신 버전을 레지스트리에 공개한 날i
MCP Server that facilitates spec-driven development workflows, not just Vibe Coding.
Remote Desktop Commander: use files, terminal and processes on your own computers from any AI app.
Open E-rate network bids (Form 470s) from USAC public data, near a ZIP or in a state.
제작자의 저장소에서 쓰인 그대로 가져왔어요. PopNx MCP가 검토하거나 보증한 내용이 아니에요. HTML, 이미지, 스크립트는 제거했어요. 링크를 누르면 이 사이트를 벗어나요.
A Remote MCP server for integrating a Gaggiuino espresso machine with AI tools. Ask your AI assistant to check machine status, analyze shot data, and get dial-in guidance.
Shot Analysis
get_status - Current machine status (temperature, pressure, weight, water level)get_latest_shot_id - Most recent shot, id and headline numbers in one calllist_recent_shots - The last few shots summarised, for trends over a sessionget_shot_data - Structured shot summary with metricsget_shot_raw_data - Complete time-series dataview_shot_graph - Interactive shot graph, shown in hosts that support MCP Apps (other hosts get the text summary only) (pressure, flow, weight over time with target overlays and optional shot comparison)Profiles and Settings
list_profiles - Profiles on the machine, merged with this server's documentationget_profile_info - Everything known about one profileget_machine_settings - Boiler, steam, and scale configuration as the machine reports itget_maintenance_status - Descale and backflush history the machine tracks itself, with shots since eachget_dial_in_guidance - Expert guidance for analyzing espresso shotsselect_profile - Switch the active profile (changes the machine; requires an authenticated server)upload_profile - Save a new brew profile to the machine (changes the machine; requires an authenticated server). Creates only — it never updates, and the machine assigns a fresh id every time, so uploading twice leaves two profilesdelete_profile - Delete a profile from the machine (destructive and irreversible; requires an authenticated server). It demands the profile's exact name back as confirmation, refuses to delete the currently selected profile, and always prompts for approval in the host — even under a stored "always allow"MCP Prompts - workflow templates your host surfaces as slash commands or menu items:
dial_in_new_bag - first shots on a coffee you have not pulled before (bean, and optionally roast level, dose, and what you want in the cup)diagnose_last_shot - read the shot you just pulled against how it tasted (what was wrong, and optionally what you changed)choose_profile - pick a profile the machine actually holds for a coffee (roast level, and optionally drink and notes)espresso_shot_analyst - the dial-in guidance as a system prompt (same content as get_dial_in_guidance)Each workflow prompt lays out the tools to call in order, so the analysis starts from the machine's own data rather than a guess.
MCP Resources - gaggiuino://profiles and gaggiuino://profiles/{id} for profile data
The server is published as a multi-arch image (linux/amd64, linux/arm64) at ghcr.io/ljcl/gaggiuino-mcp, so there is nothing to clone or build. It is also listed in the MCP Registry as io.github.ljcl/gaggiuino-mcp.
mkdir gaggiuino-mcp && cd gaggiuino-mcp
curl -O https://raw.githubusercontent.com/ljcl/gaggiuino-mcp/main/docker-compose.yml curl -o .env https://raw.githubusercontent.com/ljcl/gaggiuino-mcp/main/.env.example
Edit .env with your Gaggiuino machine's address:
# Use the IP directly (recommended)
GAGGIUINO_URL=http://192.168.1.100
GAGGIUINO_URL=http://gaggiuino.local
docker compose up -d
curl http://localhost:8000/health
The server is available at http:// :8000/mcp.
The compose file tracks latest, which is always the newest release. To pin one instead, set GAGGIUINO_MCP_TAG in .env:
GAGGIUINO_MCP_TAG=5.0 # newest 5.0.x patch
GAGGIUINO_MCP_TAG=5.0.0 # exact release
Builds of unreleased main are published as edge (and main- ). They can carry a breaking change that no release has announced yet, so use them only to try a fix before it ships.
Upgrade with:
docker compose pull && docker compose up -d
| Variable | Default | Description |
|---|---|---|
GAGGIUINO_URL | http://gaggiuino.local | URL of your Gaggiuino machine |
PORT | 8000 | Port for the MCP server |
HOST | 0.0.0.0 | Host to bind to |
MCP_PUBLIC_URL | _(unset)_ | Public https origin clients reach this server on, with no path (e.g. https://box.tailnet.ts.net). Set together with MCP_OAUTH_SECRET to enable OAuth. It is advertised as the OAuth resource, so it must match the URL you enter in the client exactly. |
MCP_OAUTH_SECRET | _(unset)_ | Signing key for self-issued OAuth tokens, at least 32 characters (openssl rand -hex 32). Keep it stable across restarts so clients stay signed in. Setting only one of these two fails at startup. |
MCP_OAUTH_PASSPHRASE_HASH | _(unset)_ | scrypt hash of the passphrase you type on the consent page when connecting a client. Required whenever the built-in authorization server is on — without it the consent page would grant a token to anyone who reached it, so the server refuses to start. Generate with cd apps/server && bun run hash-passphrase; never store the passphrase itself. |
MCP_OAUTH_ISSUER | _(unset)_ | Delegate token issuing to an identity provider you already run (Authentik, Keycloak, Authelia, Zitadel, Kanidm, tsidp). Set it and this server serves no OAuth endpoints of its own, verifying RS256/ES256 tokens against the issuer's JWKS instead. Requires MCP_PUBLIC_URL; refuses to start alongside MCP_OAUTH_SECRET or MCP_OAUTH_PASSPHRASE_HASH. See Using an external identity provider. |
MCP_ALLOWED_ORIGINS | _(empty)_ | Comma-separated browser origins allowed to call /mcp. * allows any (unsafe). |
MCP_ALLOWED_HOSTS | _(empty)_ | Comma-separated Host header values to accept. Empty disables the check. |
LOG_LEVEL | info | debug, info, warn, error, or silent. Logs are one JSON object per line on stderr. |
GET /health returns JSON:
{
"status": "ok", "version": "3.2.0", "uptimeSec": 3412, "machine": { "url": "http://gaggiuino.local", "state": "unreachable", "lastCheckedAt": "2026-07-27T21:11:15.274Z", "lastError": "Unable to connect. Is the computer able to access the url?", "versions": { "coreVersion": "a06f97fd", "frontVersion": "a06f97fd", "staticVersion": "a06f97fd" } } }
It answers 200 whenever the process is alive, including while the machine is unreachable — your espresso machine is off most of the day, and the container healthcheck reads the status code. machine.state is ok, unreachable, or unknown, observed from the requests the server already makes rather than from a probe, so /health puts no extra load on the machine. machine.versions is observed the same way — remembered the first time anything reads the machine's settings (get_machine_settings), never fetched by /health itself — so null there means "this server has not read the settings yet", not "the machine reports no version". Only those three documented fields are published: /health is unauthenticated, so anything a future firmware adds under versions stays out of it until someone decides otherwise.
Logs are one JSON object per line, so you can pick out what you need:
docker compose logs -f | jq -c 'select(.event == "tool.call" and .outcome != "ok")'
Turn on OAuth before exposing this server beyond your LAN. Every tunnel option below puts /mcp on the public internet, and without authentication anyone who learns the URL gets the full tool surface against a machine in your kitchen. The server prints a warning at startup while nothing is configured.
Three variables, all required together:
# 1. The public origin clients will reach the server on — no path, https only.
resource, so it must match the URL youMCP_PUBLIC_URL=https://your-machine.tail-scale.ts.net
openssl rand -hex 32
cd apps/server && bun run hash-passphrase >> ../../.env
Then recreate the container — a plain restart is not enough:
docker compose up -d --force-recreate
Compose tracks the *list* of env_file paths, not their contents, so editing .env and running docker compose up -d (or restart) can reuse the existing container along with the environment it was created with. The new variables never reach the process and the server comes up unauthenticated exactly as if you had not set them — with no error, because from its point of view nothing is configured. Check what actually arrived:
docker inspect gaggiuino-mcp --format '{{range .Config.Env}}{{println .}}{{end}}' | grep MCP_
Setting only some of them fails at startup and names the missing one. That is deliberate: silently falling back to an open endpoint is how somebody exposes a tunnel believing it is protected. The corollary is worth knowing when diagnosing: a server that is *running* and unauthenticated has seen none of the three — if you believe you set them, the container is stale, not the config wrong.
OAuth is the only credential this server accepts, because it is the only one a Claude connector can present. A connector is added at the account level so one entry has to work on claude.ai, Claude Desktop and iOS, and on a personal plan the "Add custom connector" dialog offers an OAuth Client ID and Secret and no request-header field. A local stdio bridge is not a way around it either — it cannot run on iOS. A shared-secret header would sit in .env with no client able to send it, leaving the write tools permanently refused on exactly the deployment this project is built for. (If a long-lived .env still carries MCP_AUTH_TOKEN from a pre-2.0 install, delete the line: nothing reads it, and it does not gate /mcp.)
When you connect, Claude discovers the endpoint, sends you to a consent page served by this server, and you type the passphrase. There is nothing to register and no client secret to store.
/health and the /.well-known/* discovery documents are deliberately unauthenticated — the container's healthcheck presents no credential, and a document a client fetches *in order to* authenticate cannot itself require authentication.
select_profile, upload_profile and delete_profile — the tools that change the machine — need the espresso:write scope. A token without it gets a 403 that prompts Claude to ask you for the extra permission rather than failing silently. With nothing configured at all they refuse to run and say so, which is why an open server is a defensible default for a LAN and a machine-control tool on one is not.
Requests carrying an Origin header are rejected unless the origin is listed in MCP_ALLOWED_ORIGINS. This is what stops any web page you happen to visit from POSTing to a server running on your own network — a token does not help there, because the browser sends it for you. Requests with no Origin (Claude Desktop, curl, anything that is not a browser) are unaffected, so the default empty list is the right setting for almost everyone.
Listing an origin also makes /mcp answer
앞부분만 보여 드려요. 나머지는 저장소에서 읽어 보세요