mcp-paprika
Used as an upstream identity provider for OAuth 2.1 authentication, enabling users to sign in with Auth0.
Used as an upstream identity provider for OAuth 2.1 authentication, enabling users to sign in with their Google account.
Used as an upstream identity provider for OAuth 2.1 authentication, enabling users to sign in with Keycloak.
Used as an upstream identity provider for OAuth 2.1 authentication, enabling users to sign in with Okta.
Provides semantic search capabilities through OpenAI-compatible embedding providers, allowing natural language recipe discovery.
Click on "Install 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., "@mcp-paprikasearch for vegetarian pasta recipes"
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.
@bojanrajkovic/mcp-paprika
An MCP server for Paprika recipe manager. Search, browse, create, and manage your recipes from any MCP client.
Features
40 tools for recipe, pantry, grocery, meal-planner, and menu management — search, filter, CRUD, categories, pagination, pantry inventory, aisles, grocery lists and items, meal planning (history, meal types, dated planner entries), and menus (recipe collections, their items, and one-shot add-to-planner)
Semantic search via
discover_recipes— find recipes by natural language description using any OpenAI-compatible embedding providerBackground sync — keeps your local cache in sync with Paprika's cloud
MCP resources — expose recipes as
paprika://recipe/{uid}, grocery lists aspaprika://grocery-list/{uid}, and menus aspaprika://menu/{uid}resourcesTwo transports — stdio (default, for CLI clients) and Streamable HTTP (for mobile/web clients)
Container image —
Dockerfileships a distroless runtime ready for self-hosting
Transports
mcp-paprika can speak the MCP protocol over two transports, selected via MCP_TRANSPORT:
Transport | Default? | Use it for |
| yes | Local CLI clients: Claude Code, Claude Desktop, Cursor, mcp-cli |
| no | Streamable HTTP for Claude Mobile and other HTTP-based MCP clients, or self-hosting |
The HTTP transport ships with OAuth 2.1 (authorization code + PKCE, RFC 7591 dynamic client registration). See the HTTP transport quick start below.
Quick start — stdio (Claude Desktop / Claude Code / Cursor)
Add to your MCP client config:
{
"mcpServers": {
"paprika": {
"command": "npx",
"args": ["-y", "@bojanrajkovic/mcp-paprika"],
"env": {
"PAPRIKA_EMAIL": "you@example.com",
"PAPRIKA_PASSWORD": "your-password"
}
}
}
}Quick start — HTTP transport
The HTTP transport uses OAuth 2.1 with OIDC delegation: mcp-paprika acts as the OAuth authorization server toward MCP clients, and delegates authentication to an upstream identity provider (IdP) of your choice.
Step 1 — Choose an upstream IdP
Pick a preset or supply a raw discovery URL:
Preset value | IdP | Notes |
| Discovery URL built-in | |
| Microsoft Entra ID (Azure AD) | Tenant-bound — requires |
| Okta | Tenant-bound — requires |
| Auth0 | Tenant-bound — requires |
| Keycloak | Tenant-bound — requires |
(none) | Custom | Set |
Step 2 — Register one OAuth client in your IdP
In your IdP's developer console (e.g., Google Cloud Console → APIs & Services → Credentials → OAuth 2.0 Client IDs), create a single OAuth 2.0 client with:
Application type: Web application
Redirect URI:
https://<your-MCP_PUBLIC_URL>/oauth/callback
Copy the resulting client ID and client secret — these become MCP_OIDC_CLIENT_ID and MCP_OIDC_CLIENT_SECRET.
Tenant-bound presets (entra, okta, auth0, keycloak): also copy the tenant-specific discovery URL from your IdP. For Entra this is
https://login.microsoftonline.com/<tenant-id>/v2.0/.well-known/openid-configuration.
Step 3 — Configure and start the server
Full env-var reference:
Env var | Required? | Description |
| yes | Set to |
| yes | Canonical |
| one of preset or discoveryUrl |
|
| one of preset or discoveryUrl | Raw OIDC discovery URL; required for tenant-bound presets |
| yes | Client ID from upstream IdP |
| yes | Client secret from upstream IdP |
| one of emails or subs | Comma-separated list of allowed email addresses |
| one of emails or subs | Comma-separated list of allowed subject IDs |
| no | Override preset's scope list (comma-separated; default |
| no |
|
| no | Override preset's allowed id_token signing algorithms (comma-separated) |
| no |
|
Example startup command:
MCP_TRANSPORT=http \
MCP_PUBLIC_URL=https://mcp.example.com \
MCP_OIDC_PRESET=google \
MCP_OIDC_CLIENT_ID=123456789-abc.apps.googleusercontent.com \
MCP_OIDC_CLIENT_SECRET=GOCSPX-... \
MCP_ALLOWED_EMAILS=you@example.com \
PAPRIKA_EMAIL=you@example.com \
PAPRIKA_PASSWORD=your-password \
npx -y @bojanrajkovic/mcp-paprikaStep 4 — Configure the allowlist
The allowlist uses OR semantics: access is granted if the authenticated user's email is in MCP_ALLOWED_EMAILS OR their subject ID is in MCP_ALLOWED_SUBS. At least one list must be non-empty.
MCP_ALLOWED_EMAILS— comma-separated email addresses. Subject toMCP_OIDC_EMAIL_VERIFIED_POLICY:strict(default): email must be present andemail_verified = trueskip: email is accepted without checkingemail_verifiedif-present: ifemail_verifiedis in the id_token, it must betrue; if absent, the email is accepted
MCP_ALLOWED_SUBS— comma-separated subject IDs (stable per-user opaque identifiers from the IdP). Useful when you want to allow access regardless of email verification status.
Step 5 — Add as a Claude connector
Open claude.ai → Settings → Connectors
Click "Add custom connector"
Enter your server URL:
https://<MCP_PUBLIC_URL>/mcpClaude will redirect your browser to the upstream IdP for authentication
After sign-in, you are redirected back and the connector is authorized
Verify the OAuth metadata
curl -sf https://<MCP_PUBLIC_URL>/.well-known/oauth-authorization-server | jq .issuer
# → "https://<MCP_PUBLIC_URL>"The server also exposes:
POST /mcp— MCP JSON-RPC over Streamable HTTPGET /mcp— long-lived SSE channel for server→client notificationsDELETE /mcp— session terminationGET /healthz— liveness probe returning{ "ok": true, "sessions": <n> }
Quick start — container
The image defaults to MCP_TRANSPORT=http, so a container run needs the same
OAuth environment that the HTTP transport quick start
walks through — MCP_PUBLIC_URL, an OIDC preset (or discovery URL), upstream
client credentials, and a non-empty allowlist. Without those, the server exits
during config validation.
Pull the published image (multi-arch: linux/amd64, linux/arm64):
docker pull ghcr.io/bojanrajkovic/mcp-paprika:latest
docker run --rm \
-e PAPRIKA_EMAIL=you@example.com \
-e PAPRIKA_PASSWORD=your-password \
-e MCP_PUBLIC_URL=https://mcp.example.com \
-e MCP_OIDC_PRESET=google \
-e MCP_OIDC_CLIENT_ID=123456789-abc.apps.googleusercontent.com \
-e MCP_OIDC_CLIENT_SECRET=GOCSPX-... \
-e MCP_ALLOWED_EMAILS=you@example.com \
-v "$(pwd)/data:/data" \
-p 3000:3000 \
ghcr.io/bojanrajkovic/mcp-paprika:latestThe image is signed with sigstore/cosign keyless OIDC and ships SLSA build provenance + an SPDX SBOM as OCI attestations. Verify both before running in untrusted environments — gh attestation verify without --predicate-type only validates the default (provenance) attestation, so the SBOM needs its own verification:
# SLSA build provenance
gh attestation verify oci://ghcr.io/bojanrajkovic/mcp-paprika:latest \
--owner bojanrajkovic \
--predicate-type https://slsa.dev/provenance/v1
# SPDX SBOM
gh attestation verify oci://ghcr.io/bojanrajkovic/mcp-paprika:latest \
--owner bojanrajkovic \
--predicate-type https://spdx.dev/Document/v2.3Contributors building from source can use docker build -t mcp-paprika:dev . and substitute mcp-paprika:dev for the image reference below.
For a one-shot smoke test that just verifies the image launches (no OAuth, no
remote clients), override the transport to stdio — note that this turns the
container into a CLI process that speaks MCP on stdin/stdout, so the port
mapping isn't used:
docker run --rm -i \
-e MCP_TRANSPORT=stdio \
-e PAPRIKA_EMAIL=you@example.com \
-e PAPRIKA_PASSWORD=your-password \
-v "$(pwd)/data:/data" \
ghcr.io/bojanrajkovic/mcp-paprika:latestThe HTTP-mode image binds on 0.0.0.0:3000 and persists the disk cache and
vector index under /data (the documented mount point). Both /data
sub-directories (config/, cache/) are pre-created with nonroot (UID 65532)
ownership in the image so writes work the first time even on a fresh bind-mount.
If you bind-mount a host directory you created as root, pre-chown it:
mkdir -p ./data && sudo chown -R 65532:65532 ./dataOr use a named volume (Docker handles ownership automatically):
docker run --rm \
-e PAPRIKA_EMAIL=... -e PAPRIKA_PASSWORD=... \
-v mcp-paprika-data:/data \
-p 3000:3000 \
ghcr.io/bojanrajkovic/mcp-paprika:latestThe image also declares a HEALTHCHECK that hits GET /healthz; verify with:
docker inspect --format '{{.State.Health.Status}}' <container>
# → healthyDeployment patterns (HTTP transport)
The HTTP transport ships with OAuth 2.1 built in. The primary remaining concerns are TLS termination and, optionally, additional network-layer controls.
TLS termination is required — MCP_PUBLIC_URL must be https:// and OAuth requires encrypted connections end-to-end. Recommended options:
Reverse proxy with TLS (nginx / Caddy) — terminates TLS, passes
X-Forwarded-Forheaders (required for rate limiting), and forwards to the container on a private port.Cloudflare Tunnel — no inbound port exposed; Cloudflare terminates TLS. Works well with Cloudflare Access for an additional authentication layer if desired.
Tailscale HTTPS — Tailscale's built-in HTTPS cert provisioning; suitable for homelab setups where all clients are on your tailnet.
Container deployment with Docker Compose:
services:
mcp-paprika:
image: ghcr.io/bojanrajkovic/mcp-paprika:latest
environment:
MCP_TRANSPORT: http
MCP_PUBLIC_URL: https://mcp.example.com
MCP_OIDC_PRESET: google
MCP_OIDC_CLIENT_ID: "<your-client-id>"
MCP_OIDC_CLIENT_SECRET: "<your-client-secret>"
MCP_ALLOWED_EMAILS: "you@example.com"
PAPRIKA_EMAIL: "you@example.com"
PAPRIKA_PASSWORD: "<your-paprika-password>"
volumes:
- mcp-paprika-data:/data
ports:
- "127.0.0.1:3000:3000"
volumes:
mcp-paprika-data:OAuth provides authentication-level controls; the reverse proxy provides TLS, rate limiting, and any additional network-level restrictions the deployment requires.
Documentation
Configuration — env vars, config files, transport options, platform paths
Tools reference — every tool with parameters and examples
Embedding providers — set up semantic search with Ollama, OpenAI, OpenRouter, etc.
Architecture — how it works under the hood
Releasing — maintainer-facing release model, prerelease validation, attestation verification
License
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/bojanrajkovic/mcp-paprika'
If you have feedback or need assistance with the MCP directory API, please join our Discord server