Polvenn MCP Server
Based on the provided schema, this local-first MCP server lets you search Vinmonopolet beer releases, check stock, find stores, manage a watchlist, configure settings, and validate integrations.
Search recently released beers from Vinmonopolet, an external release feed, or both, with filters like
since,style,releaseDate,storeId,includeUpcoming, andlimit.Search Vinmonopolet's "Kommende nyheter" for upcoming beer releases, optionally by style and limit.
Search new beers available in a specific store or your configured home/nearest store.
Check whether a specific article number is in stock at a Vinmonopolet store (defaults to your home store).
Find nearby Vinmonopolet stores by coordinates or home location, with distance and opening hours.
Manage a beer watchlist: add, remove, list, or check rules for brewery, style, series, or keyword.
Configure local settings: external release feed URL, Vinmonopolet API key, home store ID, and home coordinates.
Validate configuration and probe upstream services (release feed, Vinmonopolet product/store access, stock endpoint).
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Polvenn MCP Server search new imperial stouts from the last 30 days"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Polvenn MCP Server
A local-first MCP server for tracking beer releases on Vinmonopolet and an external release-feed API backed by your own collector/database.
npm package: @henrikogard/polvenn-mcp-server
CLI command: polvenn-mcp-server
It is designed to run as a local stdio MCP server:
no web app
no telemetry
no cloud sync
data stays on your machine in SQLite
What It Does
Polvenn exposes 13 MCP tools, 2 MCP resources plus 2 resource templates, and 3 MCP prompts. Every tool declares its structured output schema, so strict MCP clients get a contractually valid structuredContent payload alongside human-readable text.
Tool | Description | Writes data? |
| Search Vinmonopolet's current | No |
| Search Vinmonopolet's "Kommende nyheter" listing for upcoming beer releases | No |
| Search current | No |
| Search the full catalogue by name, article number, or EAN-13 barcode — works without an API key via vinmonopolet.no, with optional name/price sorting | No |
| Get full details for one product by article number: price, ABV, volume, availability, tasting notes, and image URLs | No |
| Check stock for a beer at a Vinmonopolet store, using the official API when possible and Vinmonopolet's web stock locator as fallback | No |
| Find the closest Vinmonopolet stores to a coordinate, with today's opening hours | No |
| Find stores that currently have a product in stock, ordered by distance (keyless, via the web stock locator) | No |
| List products changed since a date via the official API's | Yes (sync marker) |
| List available search filters (categories, countries, price ranges…) with result counts, from vinmonopolet.no | No |
| Add, remove, list, and check watch rules — text, ABV/price bounds, and per-article stock watches | Yes |
| Store API keys, home store, and home coordinates locally | Yes |
| Validate current config and probe upstream capabilities | No |
Resources
URI | Description |
| Your saved watchlist rules as JSON (subscribable — updated when rules change) |
| Current configuration as JSON (API key masked) |
| Resource template — one product as JSON, with image URL |
| Resource template — one store as JSON, with today's opening hours |
Prompts
Prompt | Description |
| Check the watchlist and summarize new matches |
| Find new releases, optionally filtered by |
| Check stock for an |
Typical use cases:
“Show me new imperial stouts from the last 30 days”
“Is article
20162402in stock near Stavanger?”“Find the nearest Vinmonopolet stores to my home”
“Alert me when Amundsen, Lervig, or pastry stouts show up”
If the official Vinmonopolet stock endpoint is not available, Polvenn falls back to Vinmonopolet's own web stock locator for store-level counts when possible. If neither source can verify the store, Polvenn reports store-level stock as unknown instead of incorrectly reporting zero stock or inferring "bestillingsutvalget" as a store-stock answer.
For polvenn_search_new_beers, the since filter is best-effort: Polvenn prefers external release dates when available, and otherwise falls back to Vinmonopolet's lastChanged timestamp.
If you pass storeId, only Vinmonopolet-backed results that are available in that store are included.
Related MCP server: trundler
Architecture
Any MCP client
(Codex, Claude Desktop, Inspector, others)
│
│ stdio
▼
polvenn-mcp-server
├── tools
├── zod schemas
├── Vinmonopolet service
├── External release feed client
└── SQLite storage via sql.js
│
▼
~/.polvenn/polvenn.dbProject structure:
src/
├── index.ts # MCP server entry point
├── constants.ts # URLs, defaults, retry/timeout settings
├── types.ts # Domain types
├── sql.js.d.ts # Local sql.js typings
├── tools/
│ ├── index.ts # MCP tool registration and handlers
│ └── server.test.ts # End-to-end tests over the SDK in-memory transport
├── resources/
│ └── index.ts # polvenn://watchlist and polvenn://config resources
├── prompts/
│ └── index.ts # MCP prompts
├── schemas/
│ ├── tools.ts # Zod input schemas
│ └── output.ts # Zod output schemas (structured content contracts)
├── services/
│ ├── release-feed.ts # External release feed client
│ ├── vinmonopolet.ts # Vinmonopolet API client
│ └── watchlist.ts # Watchlist matching logic
├── utils/
│ ├── concurrency.ts # Bounded-concurrency async mapping
│ ├── geo.ts
│ └── http.ts # Fetch with retry, backoff, and timeouts
├── db/
│ ├── database.ts # SQLite persistence, migrations, config
│ └── migrations.test.ts
└── test/
└── setup.ts # Per-file throwaway data dir for testsSetup
Prerequisites
Node.js 18 or newer
A Vinmonopolet API key from api.vinmonopolet.no
Install
npm install
npx tsc --noEmit
npm run buildPublished npm package:
npm install -g @henrikogard/polvenn-mcp-serverRun
npm startThis starts the MCP server on stdio, which is what local desktop/CLI MCP clients expect.
Using It From MCP Clients
Generic stdio client setup
If your MCP client supports local stdio servers, point it at:
command: node
args: ["/absolute/path/to/polvenn-mcp-server/dist/index.js"]If you installed the package globally from npm, you can also point the client directly at the CLI:
command: polvenn-mcp-server
args: []Claude Desktop
Add this to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"polvenn": {
"command": "node",
"args": ["/absolute/path/to/polvenn-mcp-server/dist/index.js"]
}
}
}After restarting Claude Desktop, configure your own collector from chat:
Configure polvenn with release feed URL https://releases.example.com.Codex
Codex supports MCP server definitions in ~/.codex/config.toml. Add:
[mcp_servers.polvenn]
command = "node"
args = ["/absolute/path/to/polvenn-mcp-server/dist/index.js"]Restart Codex after saving the config.
Then configure your own collector from a Codex chat:
Configure polvenn with release feed URL https://releases.example.com.ChatGPT
As of April 7, 2026, ChatGPT apps/custom MCP integrations use remote MCP servers over SSE or streaming HTTP, not local stdio servers.
That means this repo does not plug directly into ChatGPT in its current form.
To use Polvenn with ChatGPT, you would need to:
Wrap or rebuild it as a remote MCP server.
Expose it over HTTPS using SSE or streaming HTTP.
Add it in ChatGPT developer mode as an app/custom MCP integration.
In other words:
Codex and Claude Desktop can use this project directly as-is.
ChatGPT needs a remote deployment, not this local stdio process.
First-Time Configuration
Once connected from an MCP client, configure the local server with your keys and defaults.
External collector setup
Polvenn expects an external release collector that exposes:
GET /releases/latestYou can run your own collector from GitHub here:
Quick setup:
Clone the collector repo.
Run
npm install.Run
npm run build.Copy
polvenn-release-collector.config.example.jsontopolvenn-release-collector.config.json.Start it with
npm start.Verify
http://127.0.0.1:4100/health.Verify
http://127.0.0.1:4100/releases/latest?limit=3.
If you want to expose it publicly on a VPS, follow the deployment guide in the collector repo:
Once your collector is running, choose your own feed URL, for example:
releaseFeedUrl = http://127.0.0.1:4100or:
releaseFeedUrl = https://releases.example.comThat means the local MCP server will read from:
https://releases.example.com/releases/latest?limit=...Recommended order:
Set up your own
polvenn-release-collector.Verify its
/healthendpoint.Verify its
/releases/latest?limit=3endpoint.Start
polvenn-mcp-serverlocally in Codex or Claude Desktop.Configure Polvenn with the hosted
releaseFeedUrl.Validate the configuration from the MCP client.
Example prompts:
Configure polvenn with release feed URL https://releases.example.com.Configure polvenn with Vinmonopolet API key <key>.
Set home location to Stavanger (58.97, 5.73).
Set home store to 170.Validate my Polvenn configuration and tell me which integrations are working.Example Prompts
These work well in Codex, Claude Desktop, or another MCP client:
Search for new stouts from the last 30 days.Search for new beers available in store 116.Search for new beers from the 1. april 2026 release.Search for new beers and include upcoming Vinmonopolet web releases.Show upcoming beers from Vinmonopolet.Show upcoming sour beers from Vinmonopolet.Show new sour beers near my store.Check whether article 20162402 is in stock at store 170.Find the 5 closest Vinmonopolet stores to 58.97, 5.73.Add a watchlist rule for brewery Lervig.Check my watchlist against the latest release in my external feed.Watchlist Rules
The watchlist supports eight rule types:
Type | Matches against | Example |
| Producer name |
|
| Beer style |
|
| Beer name |
|
| Beer name and producer |
|
| Country of origin |
|
| ABV bounds ( |
|
| Price bounds ( |
|
| One article number's stock at your home store |
|
Text rules match by substring. abv and price rules take numeric bounds instead of value (which is derived, e.g. abv >= 10). Price rules are best-effort: prices are looked up via Vinmonopolet during a check, and beers whose price cannot be resolved are reported as not evaluated rather than silently skipped or guessed. stock rules are checked against live store stock at your home store during check; a beer that sells out and comes back is reported as new again.
Storage
All local state lives in:
~/.polvenn/polvenn.dbOverride the data directory with:
POLVENN_DATA_DIR=/some/pathStored data includes:
config values
watchlist rules
cached Vinmonopolet product lookups
API keys are stored locally and only sent to their respective upstream APIs.
Packaging
The package metadata is set up for npm publishing:
npm package name:
@henrikogard/polvenn-mcp-serverinstallable CLI entry:
polvenn-mcp-serverpackaged files limited to
dist/,README.md, andLICENSEprepackbuilds the TypeScript output before publishing
Data Sources
Vinmonopolet API
Base:
https://apis.vinmonopolet.noAuth:
Ocp-Apim-Subscription-KeyUsed for: products, stores, stock
Product lookups fall back to the public product page on
vinmonopolet.nowhen the API returns sparse article dataDocs: api.vinmonopolet.no
Vinmonopolet website (undocumented, no auth)
Search with free text, facets, and name/price sorting:
www.vinmonopolet.no/vmpws/v2/vmp/products/searchBarcode lookup:
www.vinmonopolet.no/vmpws/v2/vmp/products/barCodeSearch/{ean}Store stock locator (by proximity, paginated):
www.vinmonopolet.no/vmpws/v2/vmp/products/{id}/stockFacet tree:
www.vinmonopolet.no/api/search?fields=FULLProduct images (best-effort; placeholder for missing photos):
bilder.vinmonopolet.no/cache/{w}x{h}-0/{article}-1.jpg— see the product images post; CDN use is covered by the API terms of service
These endpoints are undocumented and can change without notice; responses are validated leniently and malformed entries are dropped with a warning rather than failing the call.
External Release Feed
Base: your configured
releaseFeedUrlEndpoint used by MCP:
GET /releases/latest?limit=NExpected response shape:
{
"releases": [
{
"id": "2026-04-01-main",
"title": "April 2026 main release",
"source": "vinmonopolet-monthly",
"publishedAt": "2026-04-01T08:00:00Z",
"url": "https://example.com/release/2026-04-01-main",
"items": [
{
"country": "Norge",
"articleNumber": "20162402",
"producer": "Amundsen Bryggeri",
"name": "Example Beer",
"style": "Imperial Stout",
"abv": 12,
"releaseDate": "1. april 2026"
}
]
}
]
}Development
npm run dev # tsc --watch
npm run typecheck # tsc --noEmit
npm run lint # biome check
npm test # vitest run (tests never touch your real ~/.polvenn data)
npm run build
npm run smoke # spawns dist/index.js and verifies the MCP handshake, tools, resources, prompts
npm run probe # opt-in live probe of every upstream source; records fixtures/live/ (gitignored)CI runs lint, typecheck, tests, build, and the smoke script on Node 20/22/24 via GitHub Actions.
Test With MCP Inspector
npx @modelcontextprotocol/inspector node dist/index.jsDependencies
Package | Purpose |
| MCP server framework |
| SQLite in pure JavaScript |
| HTML parsing |
| Input and output validation |
| Build tooling |
| Test runner |
| Linting and formatting |
Notes
The server is intentionally local-first and stdio-first.
Stock access may depend on the Vinmonopolet subscription tier you have.
The official API's product responses have been slimmed down upstream (basic + lastChanged only); Polvenn enriches them from product pages and prefers the richer website search.
Vinmonopolet removed the "Kommende nyheter" listing from vinmonopolet.no;
polvenn_search_upcoming_beersreports that honestly instead of returning empty results. The other website endpoints used here (search, barcode, stock locator, facet tree via search) were verified live in September 2026.ChatGPT support requires a remote MCP variant of this server.
License
MIT
Available Tools
8 toolspolvenn_check_store_stockCheck store stockARead-onlyIdempotent
Check if a specific beer is in stock at a Vinmonopolet store.
Args:
articleNumber (string): Vinmonopolet article number
storeId (string, optional): Store ID. Defaults to your configured home store.
Returns: Stock status and product details.
Inputs: articleNumber (required), storeId.
polvenn_configureConfigure PolvennAIdempotent
Set the release feed URL, API key, home store, and location for the Polvenn MCP server.
Args (all optional — only provided values are updated):
releaseFeedUrl: Base URL for your external release feed API
vinmonopoletApiKey: Subscription key from api.vinmonopolet.no
homeStoreId: Your preferred Vinmonopolet store ID
homeLatitude: Home latitude for nearby lookups
homeLongitude: Home longitude for nearby lookups
Returns: Current configuration (keys are masked).
Inputs: homeStoreId, homeLatitude, homeLongitude, releaseFeedUrl, +1 more.
polvenn_find_nearby_storesFind nearby Vinmonopolet storesARead-onlyIdempotent
Find the closest Vinmonopolet stores to a given location.
Args:
latitude (number, optional): Defaults to configured home location
longitude (number, optional): Defaults to configured home location
maxResults (number): How many stores to return (default: 5)
Returns: List of nearby stores with address, distance, category, and opening hours.
Inputs: latitude, longitude, maxResults.
polvenn_search_new_beersSearch new beersARead-onlyIdempotent
Search for recently released beers on Vinmonopolet via the official API and/or your external release feed.
Args:
source ('vinmonopolet' | 'external' | 'both'): Where to search (default: 'both')
since (string, optional): Best-effort date filter yyyy-MM-dd using external release dates, otherwise Vinmonopolet lastChanged
includeUpcoming (boolean): Also include beers from Vinmonopolet's "Kommende nyheter" web filter
style (string, optional): Filter by beer style, e.g. 'IPA', 'Stout'
releaseDate (string, optional): Exact release date filter
storeId (string, optional): Limit Vinmonopolet-backed results to beers available in one store
limit (number): Max results (default: 25)
Returns: List of new beers with name, producer, style, ABV, article number, and release date.
Inputs: limit, since, style, source, +3 more.
polvenn_search_new_beers_near_storeSearch new beers near your storeARead-onlyIdempotent
Search Vinmonopolet's current "Nyheter" listing for beers available in one store.
Args:
storeId (string, optional): Store ID. Falls back to your configured home store, then your nearest store from your home coordinates
style (string, optional): Filter by beer style, e.g. 'IPA', 'Stout'
releaseDate (string, optional): Exact release date filter
limit (number): Max results (default: 25)
Returns: New beers currently available in the selected store, enriched with external release dates when recent feed items match.
Inputs: limit, style, storeId, releaseDate.
polvenn_search_upcoming_beersSearch upcoming beersARead-onlyIdempotent
Search Vinmonopolet's "Kommende nyheter" web listing for upcoming beer releases.
Args:
style (string, optional): Filter by beer style, e.g. 'IPA', 'Stout'
limit (number): Max results (default: 25)
Returns: List of upcoming beers with name, producer, style, ABV, article number, and current website status.
Inputs: limit, style.
polvenn_validate_configValidate Polvenn configurationARead-onlyIdempotent
Validate current Polvenn configuration and run lightweight capability checks against upstream services.
Checks:
local config presence
external release feed access
Vinmonopolet product and store access
Vinmonopolet stock endpoint accessibility
Returns: A capability report with pass/warn/fail statuses.
Inputs: no named parameters.
polvenn_watchlistBeer watchlistA
Manage your beer watchlist. Track breweries, styles, series, or keywords to get notified about matching releases.
Args:
action ('add' | 'remove' | 'list' | 'check'): What to do
type ('brewery' | 'style' | 'series' | 'keyword'): Rule type (required for 'add')
value (string): What to watch for (required for 'add')
id (number): Entry ID to remove (required for 'remove')
Inputs: action (required), id, type, value.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 8 tools
Most tools are distinct, but the three search tools (search_upcoming_beers, search_new_beers, search_new_beers_near_store) have overlapping functionality, especially since search_new_beers can include upcoming results. Descriptions clarify differences, but there's a risk of selecting the wrong one.
Tool names follow a consistent pattern with the 'polvenn_' prefix and verb_noun format (e.g., check_store_stock, search_new_beers). The exception is 'polvenn_watchlist' which uses a noun instead of a verb action, but it's still clearly named.
With 8 tools, the server is well-scoped for its purpose: searching new/upcoming beers, checking stock, finding stores, managing a watchlist, and configuration. Each tool serves a distinct need without being excessive.
The domain of beer release tracking and store stock is well covered, including search, stock, store location, watchlist, and config. However, there's no general search for all beers, only new/upcoming, which may be a gap for users wanting to look up existing products.
Maintenance
Related MCP Connectors
MCP server for the Émile wine cellar — list, add, recommend, scan and search 100k+ wines.
Unlock the power of food transparency with our Open Food Facts MCP server. Easily look up any food
MCP server for OnceAsk, the AI-native current-address layer for people and agents.
Related MCP Servers
- AlicenseBqualityBmaintenanceA local-first nutrition MCP server for food search, barcode lookup, meal estimation, intake logging, hydration, and nutrition coaching workflows.46492 npm11MIT
- AlicenseAqualityBmaintenanceA local MCP server for grocery shopping, enabling product search, specials, and browsing across NZ supermarkets, with cart and order history for Countdown/Woolworths via browser-assisted login.141MIT
- AlicenseAqualityAmaintenanceAn MCP server that interfaces with Untappd's mobile API to search beers, breweries, venues, and user data, and to post check-ins, toasts, and comments using your own account.59528 npm1MIT
- AlicenseNot gradedqualityCmaintenanceMCP server for Untappd connectivity, enabling beer search with optional limit, offset, and sorting.MIT