Skip to main content
Glama
sina-attarzadeh

PrijsProfeet MCP

prijsprofeet-mcp

A Dockerized MCP server for the PrijsProfeet API: live offers from 10 Dutch supermarket chains (Albert Heijn, Aldi, DekaMarkt, Dirk, Ekoplaza, Hoogvliet, Jumbo, Lidl, PLUS, Vomar) as one normalised JSON API.

The 26 tools are generated from the OpenAPI document at https://www.prijsprofeet.nl/openapi.json (a copy is bundled in the image, because the live one sits behind Cloudflare and is not reachable from a server). Argument schemas come from the spec; the tool names and descriptions are curated, because a good description is what stops a model from quoting a price nobody is charging.

Quick start

docker build -t prijsprofeet-mcp .
docker run -i --rm -e PRIJSPROFEET_API_KEY prijsprofeet-mcp

That speaks MCP over stdio, so it wants to be run by an MCP client rather than by hand.

Related MCP server: PriceAtlas MCP Server

Wiring it into a client

The key is read from the PRIJSPROFEET_API_KEY environment variable and sent as the X-API-Key header.

stdio — the client launches the container

This is the default, and the right choice for a local Docker tool: no port, no auth surface, no network listener.

docker run -i --rm -e PRIJSPROFEET_API_KEY prijsprofeet-mcp:latest

opencode

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "prijsprofeet": {
      "type": "local",
      "command": ["docker", "run", "-i", "--rm", "-e", "PRIJSPROFEET_API_KEY", "prijsprofeet-mcp:latest"],
      "environment": { "PRIJSPROFEET_API_KEY": "{env:PRIJSPROFEET_API_KEY}" },
      "enabled": true
    }
  }
}

opencode prefixes tool names with the server name, so the tools arrive as prijsprofeet_pp_search, prijsprofeet_pp_get_categories, and so on. Prompt with use the prijsprofeet tools to pull them in.

Claude Desktop / any stdio client

claude_desktop_config.json only accepts command-shaped servers, so the container is the entry point — Desktop launches it and talks to it over pipes:

OS

Path

macOS

~/Library/Application Support/Claude/claude_desktop_config.json

Windows

%APPDATA%\Claude\claude_desktop_config.json

Linux

~/.config/Claude/claude_desktop_config.json

Settings → Developer → Edit Config opens it. Build the image once first, then point the entry at it:

docker build -t prijsprofeet-mcp:latest .
{
  "mcpServers": {
    "prijsprofeet": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "--env-file", "/absolute/path/to/.env",
        "prijsprofeet-mcp:latest"
      ]
    }
  }
}

Desktop apps launched from a dock do not inherit your shell environment, so --env-file is the reliable way to get PRIJSPROFEET_API_KEY in; -e PRIJSPROFEET_API_KEY only works if the variable is already exported in the process that started the app. Use an absolute path — the app's working directory is not your shell's.

Then fully quit and relaunch. Closing the window leaves the previous container running; the config is read once at process start, so edits made while the app is open do nothing.

With stdio there is no port and therefore no MCP_AUTH_TOKEN — the client owns the container's lifetime and talks to it over pipes. The token only exists in the HTTP transport.

Never paste a url into claude_desktop_config.json. Desktop's config schema is stdio-only: an entry with url, type, or headers fails validation, and recent builds respond by rewriting the file with the whole mcpServers block removed — taking your working entries with it, silently (#37286). The url + headers + "type": "http" shape belongs to Claude Code's ~/.claude.json, which is a different client with a different parser. For a remote endpoint, use the mcp-remote bridge below.

HTTP — the client connects to a URL

Set PRIJSPROFEET_TRANSPORT=http and the same container serves Streamable HTTP instead:

docker run -d --rm -p 127.0.0.1:3000:3000 \
  -e PRIJSPROFEET_TRANSPORT=http \
  -e MCP_AUTH_TOKEN="$(openssl rand -base64 32)" \
  -e PRIJSPROFEET_API_KEY \
  prijsprofeet-mcp:latest

Endpoint

Auth

http://localhost:3000/mcp

Authorization: Bearer $MCP_AUTH_TOKEN

http://localhost:3000/healthz

none, so a platform health check can poll it

In opencode that is a remote server rather than a local one:

{
  "mcp": {
    "prijsprofeet": {
      "type": "remote",
      "url": "http://localhost:3000/mcp",
      "headers": { "Authorization": "Bearer YOUR_TOKEN" },
      "enabled": true
    }
  }
}

Or with compose, which keeps it bound to loopback:

cp .env.example .env   # then fill in the key
docker compose --profile http up -d prijsprofeet-mcp-http
Claude Desktop

Desktop has no schema for a remote endpoint, so a command entry is the only way in — mcp-remote is a stdio bridge that speaks Streamable HTTP on the other side, and it carries the Authorization header that Desktop's own remote path cannot:

{
  "mcpServers": {
    "prijsprofeet": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote",
        "https://prijsprofeet-mcp.onrender.com/mcp",
        "--transport", "http-only",
        "--header", "Authorization: Bearer YOUR_MCP_AUTH_TOKEN"
      ]
    }
  }
}

--transport http-only is not optional decoration: mcp-remote otherwise negotiates the SSE half of Streamable HTTP first, GETs this endpoint, gets a 405 back, and stalls through a backoff before retrying as POST. With it pinned, only the POST path is used.

Settings → Connectors → Add custom connector is not an alternative here. That flow is OAuth-only, and this server authenticates with a bearer token it has no OAuth endpoints for.

Desktop reads the config once at process start, so fully quit and relaunch after editing — closing the window is not enough. Check Settings → Developer for a connected entry with the tool count this server publishes.

That block works unchanged against the local http://localhost:3000/mcp from the compose service above, with Bearer $MCP_AUTH_TOKEN in the header.

A 401 from this server is a dead end, not a login prompt. Clients treat an unauthenticated 401 from an HTTP MCP server as a request to start an OAuth flow (Claude Desktop 1.24012.0+, and mcp-remote alike). This server has no OAuth endpoints, so the flow cannot complete: mcp-remote logs Dynamic Client Registration rejected (HTTP 404) and exits, and Desktop opens a browser to a sign-in page that can never succeed. Both mean the same thing — a typo in the token, a stale token after rotation, or a wrong url. The usual culprit is the literal string YOUR_MCP_AUTH_TOKEN still sitting in the file. A correctly configured client never sees a 401.

The token sits in plaintext in this file, so chmod 600 it and keep the file out of any repo. It is the MCP_AUTH_TOKEN value, not PRIJSPROFEET_API_KEY — never put the partner key in a client config.

The HTTP transport is stateless — no session id, nothing held between requests — so the endpoint survives restarts and needs no sticky sessions behind a load balancer. Requests must send Accept: application/json, text/event-stream and Content-Type: application/json; it answers 406 and 415 respectively when you get that wrong, which is what the MCP spec asks for.

The API key is server-side in this mode, so MCP_AUTH_TOKEN is the only thing standing between the public internet and your rate limit. It is optional in code — unset, the server still starts and logs a warning — but treat an unset token as a deployment mistake, not a local-dev convenience. See Security.

docker compose run --rm prijsprofeet-mcp is still the right command for the stdio service: a stdio server has no port, so the client has to own the container's lifetime.

Deploying to Render

render.yaml is a Render blueprint, so the deploy is New → Blueprint → point at the repo. It builds the Dockerfile as a web service in frankfurt with the health check on /healthz.

Two things in it are deliberate. One is a trade-off, the other is easy to "fix" in a way that breaks the deploy:

  • plan: free by default, which means the service sleeps. 512 MB at $0, but a Free web service spins down after 15 minutes without traffic and takes about a minute to wake. MCP clients fetch tools/list on connect with a timeout usually measured in seconds, so against a service that has been idle the client reports a timeout and gives up while the server is still booting — the server cannot distinguish that from being dead, and there is nothing to fix from the server side. Staying on free means picking one of:

    Option

    What it costs you

    Raise the client timeout to ~90s

    The first connect after every idle period eats the wait, or fails if the client caps out earlier

    GET /healthz a minute before you start

    A manual step per session, and it only helps if you remember it

    Do nothing

    Works while you are actively using it, times out on the first connect after a break

    None of that is a server problem, it is the plan. If the endpoint has to be up the moment a client opens a session, switch to plan: 0.5c-512mb (formerly starter, $7/month): it never sleeps, the cold start disappears, and the only cost is the bill. It is one line in render.yaml — the free one is left commented out beside it.

  • No PRIJSPROFEET_HTTP_PORT. Render injects PORT; the server reads that and falls back to 3000. Pinning the port in the blueprint or the Dockerfile shadows PORT, the container listens where nobody is looking, and Render reports the deploy as live while every request 502s.

Render prompts for PRIJSPROFEET_API_KEY on first deploy, so the partner key never enters the repo. It generates MCP_AUTH_TOKEN for you — read it from Dashboard → Environment, then put it in your client's headers.

The service is stateless and single-instance, so deploys are not zero-downtime: a redeploy drops in-flight requests and clients reconnect. maxShutdownDelaySeconds is left at the 30s default, which is more than the server's own 5s drain needs.

Security

The threat model is narrow and worth stating plainly: this server has no user accounts, no database, and no writes to your filesystem. What an attacker wants is your PrijsProfeet key's rate limit, or just the data you can query with it. Ordered by what actually helps:

1. Set MCP_AUTH_TOKEN. A 256-bit random string, compared in constant time via crypto.timingSafeEqual, and returned as a 401 with a WWW-Authenticate: Bearer challenge when missing or wrong. Every failed attempt is logged with the client IP, so scanning shows up in the Render log stream.

Rotation is comma-separated and overlap-friendly: set MCP_AUTH_TOKEN=new,old, deploy, move your client to new, then drop old. No window where both are down.

2. Remember what this is not. A static bearer token is a deliberate deviation from the MCP spec, which asks HTTP servers to implement OAuth 2.1. That is the right trade for a single-tenant tool with one operator, and the wrong one for a shared or multi-user deployment — if you need per-caller identity, per-caller revocation, or scoped access, put a real OAuth proxy in front of it rather than extending this.

3. Lock the plan down, not just the endpoint. PRIJSPROFEET_PLAN=free withholds the 6 Pro tools, so a leaked token cannot reach the matching and price-history endpoints even if the key is Pro.

4. Prefer a tunnel over a public hostname if you can. Cloudflare Tunnel or Tailscale put the endpoint on a URL nobody can scan, which removes the guessing game entirely. Render's own ipAllowList is not an option here — it requires a Scale or Enterprise workspace.

5. Do not set a suspicious User-Agent. bot, crawler, spider and slurp in PRIJSPROFEET_USER_AGENT get 403 from PrijsProfeet on keyless requests, which looks like an outage but is not one. The server warns at startup.

If the key or token ever leaks: rotate the PrijsProfeet key in their dashboard, then rotate MCP_AUTH_TOKEN as above. Rotating the token alone does not help if the key is what leaked, because the key is what the attacker was spending.

The tools

20 tools are exposed by default, which is everything the API serves on a free key. The remaining 6 need the Pro plan and are withheld — see Plans below.

Tool

What it does

pp_search

Search offers across all chains, filtered by retailer, category, status, price, savings, diet

pp_get_categories

The 18 category slugs with counts — call this before filtering by category

pp_get_filter_stats

Facet counts for a query, to see what a filter would still return

pp_list_products

Bulk list with retailer, folder, promo-group and validity-window filters

pp_get_product

Full detail for one product

pp_get_products_by_folder

Every product in one promotional folder

pp_get_products_by_retailer

Everything from one chain

pp_get_promotional_products

Everything currently on offer

pp_search_products_by_name

The older path-based product search; pp_search supersedes it

pp_get_top_deals / pp_get_brand_deals / pp_get_deals_by_type / pp_get_new_deals / pp_get_popular_deals / pp_get_deals_summary

Offer browsing and aggregates

pp_get_price_forecast

Backtested price forecast; returns null when there is none, which is not an error

pp_health_check

Liveness of the API and its backing services

pp_get_sla_summary

Availability per calendar month

pp_get_partner_usage

Rate-limit usage and account info for the configured key

pp_request_free_key

Emails a free API key to an address (has a real-world side effect)

Plans

PRIJSPROFEET_PLAN decides whether the Pro-gated tools are exposed. It defaults to free.

PRIJSPROFEET_PLAN

Tools

free (default)

20 — the set above

pro

26 — adds the 6 below

The withheld six, all of which answer 403 This endpoint requires the Pro plan on a free key:

Tool

Endpoint

pp_match_by_ean

GET /api/v1/match/ean/{ean}

pp_match_for_product

GET /api/v1/match/product/{product_id}

pp_compare_prices

GET /api/v1/match/compare/{ean}

pp_get_ean_stats

GET /api/v1/match/stats

pp_search_shelf_prices

GET /api/v1/shelf-prices

pp_get_price_history

GET /api/v1/products/{id}/price-history

That list was verified call by call against a live free key, not read off the published docs, which only mention /match/* and price history. Withholding is deliberate: a tool that always fails costs a round trip and invites the model to invent a workaround, so on the free plan it is not merely unused but invisible — calling it returns Unknown tool, and the server's instructions stop advertising the features. If you upgrade, set PRIJSPROFEET_PLAN=pro and restart; no rebuild needed.

Configuration

Variable

Default

Purpose

PRIJSPROFEET_API_KEY

(unset)

Partner key, sent as X-API-Key. Unset means the anonymous Gratis tier. PP_API_KEY and X_API_KEY are accepted as aliases.

PRIJSPROFEET_BASE_URL

https://www.prijsprofeet.nl

API origin

PRIJSPROFEET_PLAN

free

free exposes 20 tools, pro exposes all 26

PRIJSPROFEET_TRANSPORT

stdio

stdio (client launches the container) or http (serve a URL)

MCP_AUTH_TOKEN

(unset)

Comma-separated bearer tokens for the http transport. Unset means no auth — the server starts and warns, so this is only safe on loopback.

PORT

(unset)

Honoured when PRIJSPROFEET_HTTP_PORT is unset, which is what Render, Heroku and Fly inject

PRIJSPROFEET_HTTP_HOST

0.0.0.0

Interface for http mode

PRIJSPROFEET_HTTP_PORT

3000

Port for http mode

PRIJSPROFEET_HTTP_PATH

/mcp

Path for http mode

PRIJSPROFEET_TIMEOUT_MS

30000

Per-request timeout

PRIJSPROFEET_MAX_RETRIES

2

Retries on 429/5xx and network errors, with backoff honouring Retry-After

PRIJSPROFEET_MAX_RESPONSE_BYTES

250000

Responses above this are truncated with a note instead of returned whole

PRIJSPROFEET_USER_AGENT

prijsprofeet-mcp/1.0

Sent on every request

PRIJSPROFEET_REFRESH_SPEC

0

Fetch the OpenAPI document at startup instead of using the bundled copy

PRIJSPROFEET_SPEC_URL

https://www.prijsprofeet.nl/openapi.json

Where to refresh from

PRIJSPROFEET_TOOL_PREFIX

pp

Prefix on every tool name

DEBUG

0

Diagnostics on stderr

Things worth knowing before you trust a price

A price is not a price until you read promotion_status. Every row carries one of four values, and they mean different things: active (on offer now), upcoming (starts next week), shelf (the regular price — no promotion at all) and historical (the last price seen, up to 60 days old). Taking the lowest price across all four hands you a number that no retailer is charging. The tool descriptions and the server instructions push back on this, but it is the single easiest mistake to make with this API.

This is offers, not an assortment. Products that are not on promotion are absent, so a recipe app built on pp_search alone will find a fraction of its ingredients, and a different fraction each week. On the free plan there is no way around it: the only endpoint that exposes regular non-promotion prices, pp_search_shelf_prices, is Pro-gated along with the matching tools. On Pro you get both that and cross-retailer comparison.

Not every chain publishes an EAN. Aldi, Lidl, Hoogvliet and Vomar do not, so for those chains the cross-retailer match (Pro) falls back to name, brand and category. Those rows are indicative, not product identity.

Pro-gated tools are withheld, not broken. On the default free plan the six tools in Plans are absent from tools/list entirely, so the model never spends a call discovering they 403. If you call one by name you get Unknown tool. Set PRIJSPROFEET_PLAN=pro to get all 26.

Do not put bot, crawler, spider or slurp in the User-Agent. The API answers 403 to keyless requests that look like a scraper, which reads like an outage but is not one. The default User-Agent is clean; the server warns on stderr at startup if PRIJSPROFEET_USER_AGENT is set to something suspicious. Naming yourself is the courteous thing to do and is the only way the API operator can reach you before a breaking change.

Rate limits are per IP: 120/min on search and product detail and 30/min on the bulk endpoints with no key, 150/min with a free key, 300/min on Pro, 1000/min on Business. A key is therefore always a rate-limit upgrade, never a downgrade.

Development

npm install
npm run build       # tsc + copy the spec into dist/
npm start           # run over stdio
npm run typecheck
npm run inspect     # print the generated tool surface, no transport

npm run inspect -- --json dumps the full tool definitions, which is the quickest way to see what a model actually receives.

Layout

File

Role

src/spec.ts

OpenAPI types, endpoint collection, spec loading with fallback

src/schema.ts

Resolves $refs, collapses OpenAPI 3.1 nullable unions, drops doc-only keywords

src/tools.ts

The curated tool catalogue and the spec-to-tool generator

src/client.ts

HTTP: auth header, retries, timeout, bounded reads, error hints

src/server.ts

MCP server factory and the instructions handed to the model

src/index.ts

Transport selection: stdio, or Streamable HTTP plus /healthz

src/config.ts

Environment parsing

src/openapi.json

Bundled copy of the spec, pinned at image build time

To add a curated description for a new endpoint, add an entry to CATALOG in src/tools.ts keyed by "METHOD /path". Unlisted endpoints still appear, under a name derived from the path — the catalogue only overrides.

Available Tools

20 tools
pp_get_brand_dealsA
Read-onlyIdempotent

Every current deal for one brand, e.g. Coca-Cola or Ahold. Brand matching follows the capitalisation in the source data, so keep the brand as the user wrote it and do not normalise it.

ParametersJSON Schema
NameRequiredDescriptionDefault
brandYes
limitNoMax products to return
promotion_typeNoFilter by promotion type

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, openWorldHint and non-destructive behavior, so the safety profile is covered. The description adds a genuinely non-obvious behavioral trait: brand matching is case-sensitive against source data and must not be normalised. It doesn't mention pagination or result-size behavior, but the casing warning is real added value.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two front-loaded sentences with the core purpose stated first and the casing caveat second. Nearly every clause earns its place, though 'keep the brand as the user wrote it and do not normalise it' restates the same idea twice.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 3-parameter read tool with no output schema but rich annotations, the description covers the purpose and the trickiest parameter caveat. It omits the unknown valid values for promotion_type (no enums in the schema) and any indication of result ordering or pagination, leaving moderate gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67%: 'limit' and 'promotion_type' are described in the schema, but 'brand' is not. The description compensates for the undocumented 'brand' parameter with critical case-sensitivity semantics, which is more than the schema offers. However it says nothing about limit defaults or valid promotion_type values, so it only partially fills the gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Every current deal for one brand', with concrete examples (Coca-Cola, Ahold). It implicitly separates itself from pp_get_deals_by_type by scoping to a single brand, but never names or contrasts with its many siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the purpose — call it to retrieve deals for one brand — but there is no explicit when-to-use or when-not guidance relative to siblings like pp_get_new_deals, pp_get_popular_deals or pp_get_top_deals. The casing instruction is a usage hint for the parameter rather than tool-selection guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pp_get_categoriesA
Read-onlyIdempotent

The unified categories with Dutch display names, product counts and group. Call this before pp_search to turn a user's word ("zuivel", "brood") into a valid category slug. Cheap, and worth it before a search that would otherwise return nothing.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, openWorld and non-destructive, so the safety profile is covered structurally. The description adds non-obvious behavioral context beyond that: the call is cheap and its typical outcome is a mapping from natural-language terms to slug values, which tells the agent it is a cheap prerequisite lookup rather than a result-producing query.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with what the tool returns and then the usage instruction, with no repetition of the title or schema. The closing clause ('Cheap, and worth it before a search that would otherwise return nothing') is slightly persuasive rather than informational but still carries real decision value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description usefully enumerates the fields returned (Dutch display names, product counts, group) and the slug-oriented purpose, which is enough to call it correctly. It stops short of describing the response container or how to map a returned row to a `category` slug value.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters and the schema is a closed empty object, so there is nothing parameter-wise to document; the baseline for no-params tools applies. The description correctly implies no input is needed, though it never literally says callers pass nothing.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States the exact resource returned (unified categories with Dutch display names, product counts and group) and pairs it with a named sibling relationship ('Call this before `pp_search`'), so the agent can distinguish it from the many pp_get_* deal/list tools without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use: call this before pp_search to translate a user's informal word ('zuivel', 'brood') into a valid `category` slug. It also gives the failure condition it prevents (a search that would otherwise return nothing), which is exactly the routing guidance an agent needs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pp_get_deals_by_typeA
Read-onlyIdempotent

Deals for one promotion mechanic, passed as a keyword such as 1+1, 2+2 or korting. The type values used by promotion_type elsewhere are the internal names (percentage, multi_buy, one_plus_one, volume, limited, starting).

ParametersJSON Schema
NameRequiredDescriptionDefault
typeYesPromotion keyword, e.g. '1+1'
limitNoDefault when omitted: 10.

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, openWorldHint, and destructiveHint=false, so the safety profile is fully covered. The description adds no further behavioral context beyond the parameter mapping — nothing about result volume, ordering, or whether unknown keywords yield empty results versus an error.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the purpose and then immediately the parameter mapping. Every clause earns its place; density is high but nothing is padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a 100% schema coverage, a limit default documented in the schema, and annotations covering safety, the main gap the description had to fill was the keyword-to-internal-name translation, and it does so. The absence of an output schema means return shape is unexplained, but for a simple list tool this is a minor omission.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description adds real meaning beyond the schema: it explains that the 'type' input is a promotion keyword like '1+1' or 'korting', and supplies the mapping to the internal names (percentage, multi_buy, one_plus_one, volume, limited, starting) used by promotion_type elsewhere. That translation layer is genuinely useful input guidance, though 'korting' is not tied to a specific internal name.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a clear resource and filter: 'Deals for one promotion mechanic,' which tells an agent this returns deals scoped to a promotion type. It stops short of differentiating itself from siblings like pp_get_new_deals, pp_get_popular_deals, or pp_get_top_deals, which also return deals under different filters.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: the agent can infer this is the tool to call when it has a promotion keyword such as '1+1' or 'korting' rather than wanting new, popular, or top deals. There is no explicit when-to-use statement, no named alternative, and no exclusion criteria despite a crowded sibling set.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pp_get_deals_summaryA
Read-onlyIdempotent

Aggregate stats: total products, retailer count, biggest discount, last update. One cheap call to check that the data is fresh before reporting anything about "this week".

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive and open-world, so the safety profile is covered. The description adds genuinely new context: it is cheap, and it is intended as a freshness gate before reporting. It does not describe latency, rate limits, or the exact freshness semantics, keeping it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences with no filler. The return contents come first, then the operational use case, which is the right front-loading for an agent deciding whether to call it.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the burden of describing the return value, and it enumerates the four key aggregate fields. For a zero-parameter summary tool, nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is nothing for the description to disambiguate about inputs. Baseline for a no-parameter tool is 4, and the description introduces no misleading parameter behavior.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific resource ('Aggregate stats') and enumerates exactly what is returned: total products, retailer count, biggest discount, last update. This sets it apart from listing tools like pp_get_top_deals or pp_get_deals_by_type. It stops short of explicitly naming a sibling it replaces, so not quite a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states a concrete situation for calling it: a 'cheap call to check that the data is fresh before reporting anything about this week.' That is real when-to-use guidance tied to a workflow. No exclusions or named alternatives (e.g. pp_health_check) are given, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pp_get_filter_statsA
Read-onlyIdempotent

Facet counts per retailer, promotion status and category. Pass q (and optionally category) to get the counts for one specific search — useful to show what a filter would still return, or to check whether a category exists before searching it.

ParametersJSON Schema
NameRequiredDescriptionDefault
qNoSearch query to filter counts
dietaryNoComma-separated dietary tags: bio, glutenvrij, lactosevrij, vegan
categoryNoFilter by category
retailerNoFilter by retailer
private_labelNoFilter on house brand: true for huismerken, false for A-merken
promotion_statusNoFilter by status

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish readOnlyHint=true, idempotentHint=true, destructiveHint=false and openWorldHint=true, so safety is covered. The description adds the meaningful behavioral detail that counts are scoped to a query when `q` is supplied, but says nothing about the unscoped (no-q) behavior, result volume, or rate limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, purpose first and usage second, with no filler. The em-dash clause is slightly dense but it carries real routing information (previewing filters, existence checks), so it earns its space.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

All six parameters are optional and there is no output schema, so the description's job is to convey the calling pattern and it does: the primary facet-count result plus the query-scoped variant. It could state what an unfiltered call returns, but nothing critical to correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so each of the six parameters is already documented in the schema. The description only elaborates on `q` and `category`, leaving retailer, dietary, private_label and promotion_status to the schema — the baseline 3 for a fully-covered schema is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a concrete noun phrase ('Facet counts per retailer, promotion status and category') that names the resource and the dimensions returned, so the agent knows this is a statistics/facet endpoint rather than a product list. It does not explicitly distinguish itself from nearby siblings such as pp_get_categories or pp_get_deals_summary, which keeps it from a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The second sentence gives concrete when-to-use guidance: pass `q` (and optionally `category`) for a specific search, to preview what a filter would still return, or to validate that a category exists before searching it. It stops short of naming an alternative tool or stating when NOT to use this one.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pp_get_new_dealsC
Read-onlyIdempotent

The most recently started offers, capped at 30 rows.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoDefault when omitted: 10.

TDQS

C2.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, openWorldHint, and destructiveHint=false, so the safety profile is covered. The description adds the 30-row cap, a useful behavioral constraint, but it duplicates the schema's maximum:30 and says nothing about ordering, freshness window, or pagination.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single short sentence, front-loaded with the key qualifier. It earns its place but is arguably too terse for a tool with 19 siblings, leaving ordering and semantics underspecified.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only list tool with full annotation coverage and no output schema, the description is minimally adequate. It does not explain the return record shape or the ordering key ('recently started' by what metric), which would help an agent use the results correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% for the single limit parameter, so the schema fully documents it, including the default of 10 and the max of 30. The description adds nothing beyond what structured fields already provide, making the baseline 3 appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the resource (offers/deals) with a temporal qualifier, 'most recently started,' which gives some sense of the ordering. However it uses 'offers' while the tool and siblings use 'deals,' and it never distinguishes itself from close siblings like pp_get_top_deals or pp_get_popular_deals. An agent would have to guess which 'get deals' variant to pick.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no statement of when to use this tool versus the many sibling deal tools (by_type, popular, summary, top, brand). No prerequisites, no exclusions, no alternative routing. The agent is left to infer selection from the name alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pp_get_partner_usageA
Read-onlyIdempotent

Current rate-limit usage and account info for the configured API key. Requires a valid partner key, so it fails with 401 when the server is running without one.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover safety (readOnly, idempotent, non-destructive, openWorld), and the description adds useful behavioral detail: it requires a valid partner key and returns 401 when the server lacks one. This auth requirement and failure mode go beyond the structured annotations, though broader return behavior is not described.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tightly written sentences with the primary purpose stated first and the prerequisite second. There is no filler or redundant restatement of structured data.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, read-only tool with rich annotations and no output schema, the description provides what an agent needs: what it returns, the key prerequisite, and the failure condition. No critical context is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there are no parameter semantics to document. The baseline for zero-param tools is 4, and the description does not need to compensate for any schema coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific return payload (rate-limit usage and account info) scoped to the configured API key, which is clear enough for an agent to know what the tool retrieves. It does not explicitly differentiate from any sibling tool, but the resource is distinct enough in context.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives a prerequisite (requires a valid partner key) and a failure mode (401 without one), which implies the tool should only be called when a partner key is available. However, it does not state when to choose this tool over alternatives or provide broader usage context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pp_get_price_forecastA
Read-onlyIdempotent

Server-side backtested price forecast for one product ("Profeet voorspelt"). A product with no forecast is not an error: the call returns HTTP 200 with a null forecast, and the reason arrives in the X-Forecast-Reason header. Report it as "no forecast available" rather than retrying.

ParametersJSON Schema
NameRequiredDescriptionDefault
product_idYes

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive and open-world, so the safety profile is covered. The description adds genuinely non-obvious behavior: a missing forecast still returns HTTP 200 with a null body and the reason in the X-Forecast-Reason header. That is real value beyond the structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, each carrying distinct information: what the tool does, the null-not-error contract, and the anti-retry instruction. Front-loaded and free of filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, and the description covers the one surprising return case (null forecast plus reason header) that an agent would otherwise mishandle. It does not describe the shape of a successful forecast, which is a minor remaining gap for a read tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and the single parameter has no description in the schema. The description says the forecast is for 'one product', which maps loosely to product_id, but adds no format, ID namespace, or validity detail to compensate for the coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Server-side backtested price forecast for one product'. The domain (price forecasting) is clearly distinct from the deals/products/categories siblings, though the description never names an adjacent tool to differentiate against.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit when-to-use-vs-alternative guidance, but the description does give one actionable usage rule: a null forecast is not an error and should not be retried. That covers the edge case but leaves the general call context implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pp_get_productA
Read-onlyIdempotent

Full detail for one product, including EAN, folder, promo group and dietary labels. product_id is the product_id field from any search or list result.

ParametersJSON Schema
NameRequiredDescriptionDefault
product_idYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint, so the safety profile is covered. The description adds value beyond them by disclosing the shape of the returned detail (EAN, folder, promo group, dietary labels) for a tool with no output schema, though it says nothing about missing-product or rate-limit behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no filler, with the purpose front-loaded and the parameter-provenance note second. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter read tool whose annotations already carry the safety profile and whose only parameter is explained, the description is sufficient to call it correctly. Omitting full return-field enumeration is acceptable given the tool's simplicity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the single parameter is documented only as a bare string type, so the description must compensate. It does so by explaining the provenance of product_id ('the product_id field from any search or list result'), which tells the agent where to obtain a valid value, though not its format.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb and resource (full detail for one product) and enumerates the kind of content returned (EAN, folder, promo group, dietary labels). The singular 'one product' implicitly separates it from the plural list/search siblings such as pp_list_products and pp_search_products_by_name.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The second sentence establishes the precondition for calling it: product_id comes from any search or list result, which routes the agent from the search/list siblings into this detail tool. It stops short of explicitly naming alternatives or a when-not-to-use case, so it does not reach a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pp_get_products_by_folderA
Read-onlyIdempotent

Every product in one promotional folder (a single actie). folder_id is the folder_id field on a product. page_size may go up to 1000 here, but a big page is expensive in context and in rate limit — ask for what the question needs.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNoPage number
folder_idYes
page_sizeNoItems per page

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the safety profile is covered. The description contributes non-obvious behavioral context: the 1000-item page ceiling is expensive in context and rate limit, which is operational knowledge not present in the annotations or schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tightly written sentences, front-loaded with the purpose before the parameter advice; every clause earns its place. Slightly informal phrasing ('a big page is expensive in context and in rate limit') keeps it from being maximally crisp.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple 3-parameter read tool with annotations covering safety, this is largely sufficient. However, with no output schema there is no statement of what a product record contains, how pagination continuation is detected, or whether results are ordered, which a list tool should disclose.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67% (page and page_size have descriptions). The description adds real meaning beyond the schema: it explains that `folder_id` corresponds to the `folder_id` field on a product (i.e., where to obtain it) and warns that a large `page_size` costs context and rate-limit budget. Only `page` remains undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource (all products) scoped to a single promotional folder, and clarifies the domain term 'actie' as 'folder'. It does not explicitly contrast itself with close siblings such as pp_get_products_by_retailer or pp_list_products, so the differentiation is left to inference.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives practical sizing advice ('ask for what the question needs') but never states when to choose this tool over pp_get_products_by_retailer, pp_list_products, or pp_get_promotional_products. Usage is implied by the folder scope rather than spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pp_get_products_by_retailerA
Read-onlyIdempotent

Every product from one retailer, paginated. Takes a retailer slug (albert_heijn, jumbo, aldi, lidl, ekoplaza, plus, dekamarkt, hoogvliet, vomar, dirk), not a display name.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNoPage number
retailerYes
page_sizeNoItems per page

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, non-destructive, openWorld), so the description is freed to add the details annotations cannot: that results are paginated and that the key must be a slug. No rate limits or ordering behavior are disclosed, but the added correctness detail is real.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, zero filler, front-loaded with what the tool returns before the parameter caveat. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only paginated listing with no output schema, the description covers result scope, identifier format, and pagination. It lacks any indication of ordering or how this fits among the many other product/deal siblings, which keeps it from being fully complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 67%, and the required 'retailer' param has no schema description and no enum. The description compensates by enumerating the ten valid slugs and warning it is a slug, not a display name — meaning an agent could construct a valid call without guessing. This is exactly the value the schema omits.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource with scope: 'Every product from one retailer, paginated.' This is distinguishable from generic siblings like pp_list_products or pp_search_products_by_name because the retailer scoping is explicit. It stops short of naming which sibling to use instead when no retailer filter is wanted.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by 'from one retailer' — call it when you want everything for a single retailer — but there is no explicit when-to-use/when-not guidance and no alternative sibling is named (e.g., pp_list_products for a cross-retailer listing). Implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pp_get_promotional_productsA
Read-onlyIdempotent

Everything currently on offer, newest first. Use pp_list_products with is_promotional=true instead when you also need a filter.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNoPage number
retailerNoFilter by retailer
page_sizeNoItems per page
max_valid_fromNoAlleen acties die op of vóór deze dag beginnen (YYYY-MM-DD)
min_valid_fromNoAlleen acties die op of ná deze dag beginnen (YYYY-MM-DD)

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true and destructiveHint=false, so the safety profile is covered. The description adds one genuine behavioral trait beyond that: results are returned 'newest first' and unfiltered by default. It says nothing about pagination behavior or result size, so the added value is modest given the annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with zero filler; the scope and sort order are front-loaded, and the routing guidance follows immediately. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only listing tool backed by four annotations and a fully documented five-parameter schema, the description supplies what an agent needs to select and call it. The only omission is any hint of the result shape, which is not covered by an output schema, but that is a minor gap for a list endpoint.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all five parameters (page, page_size, retailer, min_valid_from, max_valid_from) are already documented in the schema, including date formats. The description adds no parameter-level semantics, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the resource and scope: 'Everything currently on offer, newest first,' which tells an agent this is an unfiltered listing of promotional products ordered by recency. It also explicitly distinguishes itself from the sibling pp_list_products for the filtered case. The main verb is implicit rather than stated, keeping it just short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It names a concrete alternative and the condition that selects it: use pp_list_products with is_promotional=true when you also need a filter. That is clear when-to-use-routing. However, it ignores the many other deal-oriented siblings (pp_get_new_deals, pp_get_top_deals, pp_get_brand_deals, pp_get_deals_by_type), so an agent must still guess how this differs from those.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pp_get_sla_summaryA
Read-onlyIdempotent

Availability per calendar month, newest first. Answers "was the API down last Tuesday?" with a number instead of a guess.

ParametersJSON Schema
NameRequiredDescriptionDefault
monthsNoDefault when omitted: 12.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, openWorld and non-destructive, so the safety profile is covered. The description adds real behavioral detail beyond that: ordering ('newest first') and the fact that the return is a quantitative availability figure rather than a qualitative status.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, purpose front-loaded, no wasted preamble. 'Instead of a guess' is slightly colorful but succinctly conveys the tool returns hard numbers, so it largely earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only tool with one fully-documented optional parameter and rich annotations, the description covers what it returns (monthly availability, newest first) adequately. Without an output schema there is minor ambiguity about exact return format, but nothing critical to correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single 'months' parameter is fully documented there, including its default. The description's 'per calendar month' hints at granularity but adds no new parameter meaning, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific resource and granularity: availability/SLA per calendar month, ordered newest first. It's clearly distinguishable from the deal/product siblings, which are all unrelated domains. The verb is implicit ('get SLA summary') but the intent is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The scenario 'was the API down last Tuesday?' implies the appropriate usage context. However, there is no explicit when-not guidance and no named alternative sibling, leaving usage to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pp_get_top_dealsA
Read-onlyIdempotent

Top deals grouped per brand, optionally narrowed to one or more retailers. min_savings defaults to 10%; raise it to cut the noise. Pass retailer as an array to scope the lists to specific chains.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoNumber of deals per list
retailerNoLimit the lists to one or more retailers. Repeat the parameter to pass several: `?retailer=albert_heijn&retailer=jumbo`. Hyphenated slugs (`albert-heijn`) are accepted too.
min_savingsNoMinimum savings percentage

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the safety profile is covered. The description adds one genuinely new behavioral fact — the min_savings default of 10%, which is absent from the schema — but says nothing about return format, ordering, or list size behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the core purpose and free of filler. The retailer-array sentence partially duplicates the schema text, slightly reducing density but not enough to hurt readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-required-parameter read tool with no output schema and full annotation coverage, the description is adequate: it defines scope, grouping, and the key default. It could say more about what a 'list' contains or how many lists are returned, but nothing essential to invoking it is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so limit, retailer, and min_savings are already documented in the schema. The description adds the non-schema default value for min_savings and reinforces the array semantics, but the passing syntax it describes is already spelled out in the schema's retailer description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Top deals grouped per brand') and a clear scope modifier (optionally narrowed to retailers). It is distinguishable from pp_get_new_deals and pp_get_popular_deals by the brand grouping, though it does not explicitly contrast itself with the similarly-named pp_get_brand_deals sibling.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives actionable tuning guidance ('raise min_savings to cut the noise') and how to scope by retailer, which is usable context. However, it never states when to prefer this over the many sibling deal-listing tools (new_deals, popular_deals, deals_by_type), so alternative selection is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pp_health_checkA
Read-onlyIdempotent

Check that the PrijsProfeet API is reachable. Call this when another tool returns 5xx to tell an outage apart from a bad request.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive and open-world, so the safety profile is covered. The description adds genuine behavioral context beyond that: it is a diagnostic probe whose meaning depends on other calls failing with 5xx. It does not state what a successful or failed check returns, a minor gap given there is no output schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, action first and trigger second, with no filler. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a parameterless read-only probe the description is nearly sufficient: purpose and trigger are both covered. The one omission is what the result looks like (reachable vs. unreachable signal), which matters slightly because no output schema exists.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Zero parameters, so the baseline is 4; there is nothing for the description to explain. Schema coverage is 100% and the empty object schema is self-evident.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Check that the PrijsProfeet API is reachable.' This cleanly separates it from all sibling tools, which are data-fetching operations, so an agent can identify it as the diagnostic probe without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly names the trigger condition ('when another tool returns 5xx') and the decision it informs ('tell an outage apart from a bad request'). This is a rare case of precise when-to-use routing rather than generic guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pp_list_productsA
Read-onlyIdempotent

List products with filters, newest extraction first. Use pp_search when the user named a product; use this when you need to enumerate by retailer, folder, promo group or validity window. promo_group_id returns every product in one shared action — read that field off a product to get the rest of its group. min_valid_from / max_valid_from (YYYY-MM-DD) bound the date the promotion starts.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNoPage number
sort_byNoSorteerveld. Toegestaan: extracted_at, price, name, product_id, valid_from
retailerNoFilter by retailer
folder_idNoFilter by folder ID
max_priceNoMaximum price filter
min_priceNoMinimum price filter
page_sizeNoItems per page
sort_orderNoSort order (asc, desc)
is_promotionalNoFilter promotional products
max_valid_fromNoAlleen acties die op of vóór deze dag beginnen (YYYY-MM-DD)
min_valid_fromNoAlleen acties die op of ná deze dag beginnen (YYYY-MM-DD)
promo_group_idNoAlleen producten uit deze actiegroep (zie `promo_group_id` op een product): alle deelnemers aan één gezamenlijke actie

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, openWorld and non-destructive, so the safety profile is covered. The description adds real behavioral context beyond them: the default sort order, and that promo_group_id returns every participant of one shared action and can be read off a product to expand its group. It does not mention pagination behavior, the one trait annotations leave untouched.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short paragraphs, front-loaded with the core action and default ordering, followed by routing and then the two non-obvious parameters. No filler sentences.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 12 optional filter parameters and no output schema, the description covers the non-obvious filters (promo group, validity window) and the default sort. Price, name and page filters are self-documented at 100% coverage, and return values need no explanation without an output schema, so this is nearly complete for a filtering list tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds semantics the schema alone does not convey in English: min_valid_from/max_valid_from bound the promotion start date, and promo_group_id is described as a cross-call linking key. That is meaningful added value rather than restatement.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("List products") plus the default ordering ("newest extraction first"), and explicitly names the sibling it is not (pp_search). An agent can distinguish it from the search tool without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit routing rule: use pp_search when the user named a product, use this tool to enumerate by retailer, folder, promo group or validity window. However, it never acknowledges the overlapping siblings pp_get_products_by_folder, pp_get_products_by_retailer, pp_get_promotional_products, leaving an agent unsure whether those are preferred for the same enumerations.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pp_request_free_keyA

Request a free API key for an email address. A one-click link is mailed out; the key itself is never in the response. The response is deliberately identical whether or not that address already has a key, so a success here never confirms someone is a customer. Capped at 5 requests per hour per IP. This has a real-world side effect — it emails a stranger. Only call it when the user has explicitly asked for it in this conversation.

ParametersJSON Schema
NameRequiredDescriptionDefault
emailYesWhere we send the key link
site_urlNoWhere the data will appear (optional)
project_nameYesWhat you are building

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond annotations (readOnlyHint=false, openWorldHint=true, idempotentHint=false) by disclosing that the key is never returned, that the response is deliberately identical regardless of prior key existence (anti-enumeration), the 5/hr/IP cap, and the real-world email side effect. Rich, non-obvious disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four tight sentences, each carrying distinct information, with the core purpose front-loaded and the safety caveat last. No filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and full param coverage, the description supplies everything else needed: return behavior (key absent, uniform response), rate limits, and the human-impact caveat. Nothing an agent needs to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all three parameters are already documented in the schema. The description adds no syntax or format detail beyond that, so the baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('request a free API key') and immediately clarifies the mechanism (a link is emailed, not the key). It is trivially distinguishable from all siblings, which are read-only deal/product lookup tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit precondition: 'Only call it when the user has explicitly asked for it in this conversation,' plus context about the rate cap and the real-world side effect. This is exactly the when-to-use guidance an agent needs for a side-effecting tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pp_search_products_by_nameA
Read-onlyIdempotent

Search products with the term inside the URL path. This is the older sibling of pp_search: same data, fewer filters, no sorting. Prefer pp_search for new work.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNoPage number
queryYes
retailerNoFilter by retailer
page_sizeNoItems per page

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the safety profile is covered. The description adds genuine capability context beyond them: fewer filters and no sorting relative to pp_search. It does not describe pagination behavior, but with annotations carrying the safety burden this is a solid addition.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, zero waste, with the core behavior front-loaded and the deprecation-style guidance following immediately.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple four-parameter read-only search with no output schema, the description covers purpose and routing adequately. It leaves pagination/return shape unstated, which is a minor gap given the schema fields are self-explanatory.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 75%, so page, page_size and retailer are already documented in the schema. The description's 'term inside the URL path' adds a hint about how query is used but nothing beyond what the schema provides for the other three parameters. Baseline 3 applies when the schema does most of the work.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (search) and resource (products), plus a precise mechanism ('term inside the URL path'). It also names the sibling pp_search and how this differs, so the agent can distinguish it without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent: 'Prefer `pp_search` for new work,' and characterizes this tool as the older sibling with fewer filters and no sorting. Both the when-to-use and the when-not-to-use conditions are stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 20 tool updatesv1.0.0
    • First observedpp_get_brand_deals
    • First observedpp_get_categories
    • First observedpp_get_deals_by_type
    • First observedpp_get_deals_summary
    • First observedpp_get_filter_stats
    • First observedpp_get_new_deals
    • First observedpp_get_partner_usage
    • First observedpp_get_popular_deals
    • First observedpp_get_price_forecast
    • First observedpp_get_product
    • First observedpp_get_products_by_folder
    • First observedpp_get_products_by_retailer
    • First observedpp_get_promotional_products
    • First observedpp_get_sla_summary
    • First observedpp_get_top_deals
    • First observedpp_health_check
    • First observedpp_list_products
    • First observedpp_request_free_key
    • First observedpp_search
    • First observedpp_search_products_by_name

TDQS

A3.7/5.0

Scored across 20 tools

Disambiguation4/5

Each tool targets a fairly distinct slice (newest, popular, top-by-brand, by-type, by-retailer), and descriptions explicitly differentiate them. However, there are documented redundancies that create real overlap: pp_get_promotional_products vs pp_list_products with is_promotional, and pp_search vs the 'older sibling' pp_search_products_by_name.

Naming Consistency4/5

Consistent pp_ prefix and snake_case verb_noun pattern (pp_get_*, pp_list_*, pp_search*). Minor deviation with pp_search / pp_search_products_by_name and the unprefixed-looking pp_health_check, but overall predictable.

Tool Count3/5

At 20 tools this sits in the heavy range for a read-mostly price API, with several near-duplicate listing/search tools that could be consolidated. Each tool has some justification, but the surface is larger than strictly needed.

Completeness4/5

Covers the domain well: search, list, product detail, categories, folders, retailers, price forecast, deal aggregations, health, SLA and account tools. Gaps are minor (no explicit comparison or basket tools), but core supermarket-data workflows are complete.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables users to compare prices, track budgets, and find promotional deals across major Dutch supermarkets and drugstores. It supports automated shopping list optimization, meal planning, and price history alerts for stores like Albert Heijn, Jumbo, and Kruidvat.
    16
    MIT
  • F
    license
    A
    quality
    D
    maintenance
    Enables AI assistants to track global food prices, search products by barcode or name, and compare costs across 27 countries. It provides tools for real-time price scraping and data aggregation from major international supermarket chains.
    8
    4
    -
  • A
    license
    A
    quality
    C
    maintenance
    A Model Context Protocol server for real-time Swiss grocery shopping that searches and compares products across 8 major Swiss retailers (Migros, Coop, Aldi, Denner, Lidl, Farmy, Volgshop, Otto’s), normalizes per-unit prices, surfaces promotions, computes optimal multi-store shopping plans, and works with any MCP-compatible client without API keys or accounts.
    7
    129 npm
    33
    AGPL 3.0
  • A
    license
    A
    quality
    A
    maintenance
    Enables searching products, comparing prices, and building optimal shopping lists across major Chilean supermarkets, using your local machine to access real-time prices and loyalty deals.
    14
    41 npm
    66
    MIT