negotiate-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| MCP_CLIENT | No | Optional client identifier for telemetry. | |
| DIRECTORY_URL | No | URL to a private or forked directory of stores. Default is the public directory. | |
| RATE_LIMIT_BURST | No | Extra tokens above sustained rate. | 10 |
| TELEMETRY_DISABLED | No | Set to '1' to disable telemetry. | |
| RATE_LIMIT_DISABLED | No | Set to '1' to bypass rate limiting entirely. Not recommended in production. | |
| RATE_LIMIT_PER_MINUTE | No | Sustained tokens/minute per IP. | 60 |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| find_storesA | Find negotiate.v1-compliant stores matching a search query or category. Use this when the shopper asks to negotiate for something but hasn't specified a particular store. Search by free-text product name, category, or both. Returns a ranked list of matching stores; pick one and pass its domain to start_negotiation. Args: query: Free-text search across store name, tagline, categories, and product names. Empty string matches all stores. category: Filter by category tag (e.g., "appliances", "books", "fitness", "office", "fashion"). Empty string skips filter. Returns: List of matching store dicts. Each entry has: - name: human-readable store name - domain: the domain to pass to discover_store / start_negotiation - tagline: short marketing line - categories: list of category tags - products_count: how many products are listed - sample_products: a few example product names |
| discover_storeA | Probe a domain to discover whether it speaks the negotiate.v1 protocol. Fetches /negotiate.json (with /.well-known/negotiate.json fallback) and validates the schema. Returns the full protocol descriptor on success. Args: domain: Site to probe. Accepts 'example.com', 'https://example.com', or with trailing slash. Returns: The negotiate.v1 descriptor: store info, endpoints, products, limits. Raises: RuntimeError if the domain doesn't speak negotiate.v1 or can't be reached. |
| list_productsA | List products available for negotiation at a store. Fetches the store's negotiate.json and returns a paginated, optionally filtered slice of the products array. Each product has id, name, kind, list_price, page_url, and start_chat_url. Args: domain: Site to query. Same accepted forms as discover_store. query: Optional case-insensitive substring filter against product name and id. Empty string matches all. limit: Max products to return (default 50, max 100). Stores can have thousands of SKUs — keep this small to avoid hitting the MCP 1MB result-size cap. offset: Skip this many matches before returning (default 0). Use with limit to paginate through large catalogs. Returns: { "total_in_store": int, # total products at this store "matched": int, # how many matched the query "returned": int, # how many returned in this page "offset": int, "limit": int, "products": [ ... ], # the page of results "more_available": bool, # True if matched > offset+returned "next_offset": int|None, # pass to next call, or None if done } |
| start_negotiationA | Open a new negotiation session for a specific product. Looks up the start_chat URL template from the store's descriptor, substitutes the product_id, fetches the result. The merchant agent's opening greeting is in the response. Args: domain: Site to negotiate at. product_id: Must be one of products[].id from list_products(). Returns: Dict with session_id, greeting (merchant's opener), and next URL for the next turn (with {url_encoded_message} placeholder). |
| send_messageA | Send one shopper turn in an active negotiation. Take the 'next' URL from the previous response (returned by start_negotiation or the previous send_message call), substitute your URL-encoded shopper message, and fetch. Args: next_url: The 'next' URL from the previous response. Should contain a {url_encoded_message} placeholder. message: Your shopper turn, plain text. Will be URL-encoded. Returns: Dict with the merchant's reply, a 'closed' flag, and the next URL for the following turn (or null if the negotiation is closed). |
| read_historyA | Read the running history of a chat session. Useful for resumption or for double-checking what's been said. The history_url comes from the read_history endpoint in the store's descriptor — typically /api/store/chat/. Args: history_url: Full URL to the history endpoint with session_id substituted. Returns: Dict with session_id and history (list of {speaker, message}). |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 6 tools
Every tool has a distinct purpose with no overlap. discover_store probes a specific domain, find_stores searches across stores, list_products enumerates products, and the three negotiation tools handle distinct phases of a chat session.
All tool names follow the verb_noun pattern consistently: discover_store, find_stores, list_products, read_history, send_message, start_negotiation. The convention is uniform throughout.
Six tools is ideal for a negotiation protocol: discovery, search, listing, session start, messaging, and history. The count is well-scoped and each tool is essential.
The tool surface covers the full negotiation workflow from store discovery to chatting. A minor gap is the lack of an explicit cancel/close negotiation tool, but the 'closed' flag in send_message responses provides a workaround.