MCP Server Setup
Connect cannabis market data directly to AI assistants using the CannMenus MCP server.
MCP tools make API calls on your behalf, and each tool call counts toward your API usage and billing. Monitor your usage on the API Dashboard.
What is MCP?
The Model Context Protocol (MCP) is an open standard that lets AI assistants access external data sources and tools. The CannMenus MCP server gives AI tools direct access to cannabis product data, brand analytics, pricing, stock status, and more — without writing any code.
Prerequisites
- A CannMenus Pro or API subscription
- An active API token (generate one from your API Dashboard)
- An MCP-compatible AI client (Claude, Cursor, Windsurf, etc.)
Setup
Claude Desktop
Add the following to your Claude Desktop configuration file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"cannmenus": {
"type": "url",
"url": "https://api.cannmenus.com/mcp/",
"headers": {
"Authorization": "Bearer YOUR_API_TOKEN"
}
}
}
}
Restart Claude Desktop after saving.
Claude Code (CLI)
Add to your project or global settings at .claude/settings.json:
{
"mcpServers": {
"cannmenus": {
"type": "url",
"url": "https://api.cannmenus.com/mcp/",
"headers": {
"Authorization": "Bearer YOUR_API_TOKEN"
}
}
}
}
Claude.ai (Web)
Claude.ai supports OAuth authentication. Simply add https://api.cannmenus.com/mcp/ as the URL — no token needed. You'll be redirected to log in and authorize access.
Step 1. Click your profile icon in the bottom-left corner, then click Settings.

Step 2. In the Settings sidebar, click Connectors.

Step 3. Click the + button and select Add custom connector.

Step 4. In the dialog, enter CannMenus as the name and paste the MCP server URL:
https://api.cannmenus.com/mcp/
Click Add. You'll be redirected to CannMenus to log in and authorize access.

Step 5. Once connected, CannMenus will appear in your connectors list and all tools will be available to Claude.

You can manage tool permissions from the Customize > Connectors page:

Cursor
Open Settings > MCP Servers and add a new server:
{
"name": "cannmenus",
"type": "url",
"url": "https://api.cannmenus.com/mcp/",
"headers": {
"Authorization": "Bearer YOUR_API_TOKEN"
}
}
Windsurf
Add to your Windsurf MCP configuration:
{
"mcpServers": {
"cannmenus": {
"serverUrl": "https://api.cannmenus.com/mcp/",
"headers": {
"Authorization": "Bearer YOUR_API_TOKEN"
}
}
}
}
Other MCP Clients
Any MCP-compatible client that supports the Streamable HTTP transport can connect. Use:
- Server URL:
https://api.cannmenus.com/mcp/— combined endpoint, auto-filtered to your entitlements - Authentication: Pass your API token via
Authorization: Bearer YOUR_API_TOKENheader or append?token=YOUR_API_TOKENas a query parameter
Product-scoped endpoints
If you want to narrow the LLM's tool surface to one product area, use a scoped URL instead of /mcp/:
| Endpoint | Tool set | Requires |
|---|---|---|
https://api.cannmenus.com/mcp/cannabis | Cannabis menu / stock / sales / company tools | cmp_permissions entitlement |
https://api.cannmenus.com/mcp/bevalc | Beverage / alcohol retail analytics | HEMP_BEVERAGE_DATA subscription |
https://api.cannmenus.com/mcp/wholesale | Wholesale account / order / pricing tools | WHOLESYNC subscription |
The combined /mcp/ endpoint already filters down to whatever you're entitled to, so a bevalc-only customer hitting /mcp/ and /mcp/bevalc see the same list. The scoped URLs are most useful for cross-sell customers who want a focused single-domain assistant.
Available Tools
The MCP server registers 37 tools across cannabis, beverage/alcohol, and wholesale market data. The list returned by tools/list is filtered to your entitlements — you'll see somewhere between 17 and 37 tools depending on your subscriptions.
Tool selection — pick the right tool, not a fan-out
Pick a single structured tool over loops or ad-hoc SQL. Common questions map to one tool:
| Question | Tool |
|---|---|
| "Top N brands / categories / retailers by sales" | sales_rankings (one call, NOT a per-brand loop) |
| "Sales / volume trend over time" | market_trends |
| "Where is brand X in stock right now?" | brand_stock_status |
| "Full scorecard for one brand" | brand_performance (NOT a chain of stock + trends + gap) |
| "White-space retailers (carry competitors but not me)" | brand_gap_analysis |
| "MSO ownership tree / subsidiary sales" | get_company_hierarchy |
| "Market concentration across MSOs" | get_company_market_share |
| Genuinely ad-hoc (everything above doesn't fit) | query_analytics (last resort) |
Looping brand_performance per brand to build a top-10 leaderboard is the most common
anti-pattern — sales_rankings returns the whole list in one call.
Product Discovery & Menu Analysis
| Tool | Description |
|---|---|
search_products | Search cannabis products by state, brand, category, price, potency |
get_retailer_menu | Full menu for a retailer. Pass include_all_menu_providers=true if the default count looks low (secondary providers like BreadStack/Leafly) |
search_retailers | Find dispensaries by location, name, services |
search_brands | Find brands and get brand IDs |
get_brand_stats | Brand portfolio and category mix |
get_brand_retailers | Which retailers carry a brand |
Cannabis Brand & Market Analytics
| Tool | Description |
|---|---|
brand_performance | NIQ-grade single-brand scorecard — weekly sales, L4W vs P4W comparison, distribution %, category breakdown in one call |
market_trends | Sales volume, pricing trends over time. Returns aggregates block with pre-truncation totals |
sales_rankings | Top brands, categories, products by sales |
brand_stock_status | Brand availability across retailers (ground truth) |
brand_gap_analysis | White-space distribution opportunities |
price_comparison | Product pricing across retailers |
get_product_events | Stock and price event history |
query_analytics | Natural-language ad-hoc analytics (full access orgs only) — last resort, prefer the structured tools above when they fit |
Company & MSO Analysis
| Tool | Description |
|---|---|
search_companies | Find MSOs, operators, brand houses |
get_company_hierarchy | Ownership trees with sales data |
get_company_market_share | Market concentration analysis |
Wholesale (requires WholeSync subscription)
| Tool | Description |
|---|---|
wholesale_accounts | Revenue by retail account |
wholesale_account_orders | Order line items |
wholesale_revenue_breakdown | Revenue by brand/sku/retailer/month |
wholesale_account_health | Recency, frequency, avg order value |
wholesale_top_products | Best-selling SKUs |
wholesale_discount_analysis | Discount and pricing concession analysis |
wholesale_account_pricing | Per-account pricing profile vs fleet average |
Bev/Alc Retail Analytics (requires subscription)
Panel: CannMenus BevAlc Panel v1 — Total Wine, Spec's, ABC Fine Wine, Binny's (677 stores / 31 states). Every response includes a universe block with panel boundaries.
| Tool | Description |
|---|---|
bevalc_brand_performance | NIQ-grade single-brand scorecard — weekly series, L4W/P4W, category share, velocity |
bevalc_category_landscape | Top brands in a category with dollar/unit share + velocity per store per week |
bevalc_distribution_trend | Weekly distribution gains/losses — stores_carrying / added / dropped |
retail_brand_rankings | Top brands by estimated sales |
retail_brand_distribution | Brand presence across retail chains |
retail_store_inventory | Store-level inventory with current_price, original_price, discount_pct |
retail_price_trends | Pricing trends with price change counts |
retail_sales_velocity | Stock depletion velocity |
retail_category_overview | Category-level market overview |
retail_geographic_analysis | Geographic distribution analysis |
All cannabis tools use full state names (e.g. "California", "Colorado"). Bevalc tools accept either full names or two-letter codes ("TX" or "Texas"). Use the reference resources to discover valid parameter values.
Pagination & Truncation
Listing tools return a pagination block. There are three modes — each tool uses one:
mode=page — page-numbered
Used by: search_brands, search_retailers, search_products, get_brand_retailers.
Pass page=N to fetch the next page when has_more=true. Per-page sizes are tool-specific (20–200 rows).
"pagination": {
"mode": "page",
"page": 1,
"per_page": 200,
"returned_count": 200,
"total_count": 1437,
"has_more": true
}
mode=cursor — keyset pagination
Used by: get_product_events, get_retailer_menu.
Pass the returned next_cursor back as the cursor argument to fetch the next page. Page sizes: 100 events, 200 menu rows.
"pagination": {
"mode": "cursor",
"returned_count": 200,
"has_more": true,
"next_cursor": "eyJwIjoxLCJ2IjpbIkZsb3dlciIsIk51Z3oiLC..."
}
Don't loop blindly — most questions are answered by a single page. Only paginate when you genuinely need every row.
Rate limit: cursor pagination is capped at 50 pages per hour per (token, tool). Hitting it returns:
{
"error": "pagination_rate_limit",
"message": "get_retailer_menu has fetched 51 pages this hour (limit: 50). Narrow your filters instead of paginating further...",
"tool": "get_retailer_menu",
"pages_fetched_this_hour": 51,
"max_pages_per_hour": 50
}
If you hit it, narrow your filters (add category, event_type, retailer_id, etc.) — don't retry the same call.
Per-page summaries in get_product_events: event_summary and total_events cover the current page only, not the full timeline. Don't sum them across cursor calls.
mode=split — capped rows + aggregates
Used by: market_trends, brand_stock_status, price_comparison, brand_gap_analysis.
These tools cap row output but return an aggregates block computed from the full un-truncated set. For market figures use aggregates.* — never sum rows[] when truncated=true. These tools do not (yet) support cursor pagination — narrow filters if you need more rows.
"pagination": {
"mode": "split",
"returned_count": 5000,
"has_more": false,
"truncated": true,
"total_count": 12453,
"cap_applied": 5000
},
"aggregates": {
"total_estimated_sales": 4823901.50,
"total_estimated_units": 142318,
...
}
query_analytics — special case
query_analytics runs Vanna-generated SQL with arbitrary ORDER BY (or none), so cursor pagination is not possible. Results capped at 1,000 rows; the first 50 are returned inline (data field). New fields:
sample_size: 50— how many rows came inlineomitted_inline: N— how many were fetched but not inlinedtotal_fetched: N— total rows after the captruncated: true— set when the cap was hit
If you hit the cap, narrow your question (add a state filter, date range, brand/category) and re-ask. For listing-style data, use get_product_events or get_retailer_menu (cursor pagination); for market totals, use sales_rankings / market_trends aggregates.
Pricing Fields
Product-level tools return current_price (shelf price) and original_price (list/MSRP, may be NULL if unavailable). When both are present and original_price > current_price, the product is on promotion — compute discount_pct = (original_price - current_price) / original_price * 100. Never assume a product is discounted when original_price is NULL — it means we don't know the list price.
Reference Resources
The MCP server also exposes reference resources that help AI assistants discover valid parameter values:
| Resource | URI | Description |
|---|---|---|
| States | cann://reference/states | List of all supported US states |
| Categories | cann://reference/categories | Valid product categories |
| Tags | cann://reference/tags | Available product tags (effects, flavors, etc.) |
| Brands by State | cann://reference/brands/{state} | All brand names and IDs in a state |
Usage and Billing
Each MCP tool call makes one or more API requests on your behalf. These requests count toward your normal API usage and billing tiers:
| Tier | Requests | Rate |
|---|---|---|
| Tier 1 | 1 — 30,000 | $0.04 / request |
| Tier 2 | 30,001 — 90,000 | $0.03 / request |
| Tier 3 | 90,001+ | $0.02 / request |
Monitor your usage on the API Dashboard. Per-token request counts and last-used dates are displayed so you can track MCP usage separately from direct API calls.
Tip: Use a dedicated API token for MCP so you can track its usage independently from your other integrations.
Example Conversations
Once connected, you can ask your AI assistant questions like:
- "What are the best-selling flower brands in California?" →
brand_performanceorsales_rankings - "How is STIIIZY doing in California?" →
brand_performance(weekly sales, distribution, L4W/P4W) - "Compare pricing for Jeeter products across dispensaries in Colorado" →
price_comparison - "Which dispensaries in Arizona don't carry Raw Garden but carry similar brands?" →
brand_gap_analysis - "What are the top spirits brands at Total Wine in Texas?" →
bevalc_category_landscape - "Show me Tito's distribution trend over the last 12 weeks" →
bevalc_distribution_trend - "How is Don Julio doing vs the spirits category?" →
bevalc_brand_performance
The AI assistant will automatically use the appropriate CannMenus tools to fetch real-time data and provide analysis.
Troubleshooting
"Authentication failed" — Verify your API token is active and correctly set in the Authorization: Bearer header (or ?token= query parameter). Generate a new token from the API Dashboard if needed.
"No results found" — Make sure you're using valid state codes and category names. Use the reference resources to discover valid values.
"Rate limited" — The MCP server respects standard API rate limits. If you're making many rapid queries, space them out or contact support for higher limits.
