Offer Discovery MCP Server
Allows ChatGPT to call the get_offers tool to fetch live structured product offers in real time.
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., "@Offer Discovery MCP Serverfind me the latest offers on electronics"
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.
Offer Discovery MCP Server
A Model Context Protocol (MCP) server that connects AI agents to a live offers API and returns structured product offers in real time.
Table of Contents
Related MCP server: Godalo
What is MCP?
Model Context Protocol (MCP) is an open standard that lets AI models (like ChatGPT) call external tools and fetch live data — designed specifically for LLM tool use.
ChatGPT ──────── MCP Protocol ────────► MCP Server ────► Offers API
"call get_offers tool" (this repo) (live, 520+ offers)
◄────────────────────────────── ◄──────────
Returns structured JSONWhen a user asks ChatGPT "What home improvement deals are available?", ChatGPT automatically:
Recognizes it needs real data
Calls our
get_offerstool via MCPReceives a structured JSON list of live offers
Summarizes and presents them to the user
Architecture Overview
┌─────────────────────────────────────────────────────────────────────┐
│ CLIENT LAYER │
│ │
│ ChatGPT / AI Agent / MCP Inspector │
│ (Sends JSON-RPC tool call requests) │
└───────────────────────────┬─────────────────────────────────────────┘
│ MCP Protocol (JSON-RPC 2.0)
│
┌─────────────▼──────────────┐
│ TRANSPORT LAYER │
│ │
│ stdio (local/dev) │ ← src/index.ts
│ HTTP + SSE (remote/ngrok) │ ← src/server.ts
└─────────────┬──────────────┘
│
┌─────────────▼──────────────────────────┐
│ McpServer (SDK v1.x high-level API) │
│ │
│ registerTool("get_offers", { │
│ inputSchema: GetOffersInputZodShape, │ ← offerSchema.ts
│ description: "...", │
│ }, handler) │
│ │
│ • Serves tools/list automatically │
│ • Validates args via Zod automatically │
│ • Routes tools/call to handler │
└─────────────┬───────────────────────────┘
│ pre-validated GetOffersInput
┌─────────────▼──────────────┐
│ API CLIENT LAYER │
│ │
│ fetchOffers() │ ← src/api/offersClient.ts
│ Live API + mock fallback │
└─────────────┬──────────────┘
│ axios.get()
┌─────────────▼──────────────┐
│ OFFERS API │
│ api.example.com/offers │
│ /offers?campaignMappingId │
│ =ALL (live offers) │
└────────────────────────────┘Project Structure
offer-discovery-mcp/
│
├── src/
│ ├── index.ts # Entry point: stdio transport (local dev & MCP Inspector)
│ ├── server.ts # Entry point: HTTP/SSE transport (ngrok & remote clients)
│ │
│ ├── schemas/
│ │ └── offerSchema.ts # Zod schemas: input args + offer output shape
│ │
│ ├── api/
│ │ └── offersClient.ts # Live API client: calls the offers API, falls back to mock
│ │
│ └── tools/
│ └── getOffers.ts # Tool handler: validate → fetch → filter → format → respond
│
├── package.json # Dependencies + npm scripts
├── tsconfig.json # TypeScript: ES2022, NodeNext, strict mode
├── .gitignore
├── README.md # ← You are here
└── TESTING.md # Step-by-step testing guideData Flow
Exact journey of a single tool call from ChatGPT to a response:
1. ChatGPT sends:
{ "method": "tools/call", "params": { "name": "get_offers", "arguments": { "category": "furniture", "featured": true } } }
2. src/index.ts (or server.ts) — McpServer receives the tool call
└── SDK validates args against GetOffersInputZodShape (Zod)
├── FAIL → SDK returns validation error to ChatGPT (handler not called)
└── PASS → calls the registered handler with typed GetOffersInput args
3. src/tools/getOffers.ts :: handleGetOffers(args: GetOffersInput)
└── calls fetchOffers(args)
4. src/api/offersClient.ts :: fetchOffers()
├── axios.get("https://api.example.com/offers?campaignMappingId=ALL")
│ ├── SUCCESS → live offers returned
│ └── FAIL → falls back to MOCK_OFFERS (server stays functional)
└── Applies in-process filters:
industry → category (legacy) → offerType → region → network → brand → featured → pagination
└── Returns: Offer[]
5. src/tools/getOffers.ts :: formatOfferForChatGPT()
└── Strips raw image URLs + internal IDs
└── Surfaces: brand, offerType, links, keywords, expiryMsg, disclosure
└── Wraps in envelope: { totalOffers, appliedFilters, offers: [...] }
6. ChatGPT receives the JSON and presents live offers to the user.Transport Modes
Mode | File | Command | Use When |
stdio |
|
| Local MCP Inspector, Claude Desktop |
HTTP/SSE |
|
| Remote access via ngrok, ChatGPT Agents SDK |
Endpoints (HTTP mode)
Endpoint | Method | Purpose |
| Streamable HTTP | OpenAI Responses API (recommended) |
| Streamable HTTP | SSE streaming for long responses |
| SSE (legacy) | MCP Inspector |
| SSE (legacy) | MCP Inspector message routing |
| — | Health check |
OpenAI Integration
Source: OpenAI Apps SDK — Build your MCP server · MCP concept overview
Recommended Transport: Streamable HTTP
Per official OpenAI docs, Streamable HTTP is the recommended transport for production.
Transport | Status | Use When |
| ✅ Active | Local MCP Inspector, Claude Desktop |
| ⚠️ Legacy | Remote testing with MCP Inspector |
| ✅ Recommended | Production (ChatGPT, OpenAI Responses API) |
Both transports are implemented in this project. POST /mcp uses Streamable HTTP; GET /sse uses legacy SSE.
Tool Annotations (Required for ChatGPT App Store)
server.registerTool("get_offers", {
description: "...",
inputSchema: GetOffersInputZodShape,
annotations: {
readOnlyHint: true, // ✅ reads data only, never writes
openWorldHint: false, // ✅ scoped to the offers domain only
destructiveHint: false, // ✅ no deletes or irreversible actions
},
}, handler);Official References
Resource | Link |
OpenAI Apps SDK: Build MCP server | |
MCP concept overview | |
TypeScript SDK | |
MCP Specification | |
MCP Inspector |
Getting Started
Prerequisites
Node.js v18+
npm v9+
ngrok (only for remote/HTTP mode)
Installation
git clone https://github.com/siddharthkoundal/chatgpt-marketplace-app.git
cd offer-discovery-mcp
npm installRunning Locally (stdio — for MCP Inspector)
npm run devRunning for Remote Access (HTTP — for ChatGPT / ngrok)
# Terminal 1: Start HTTP server
npm run dev:http
# → 🚀 offer-discovery-mcp v1.0.0 running on port 3000
# → [offer-discovery-mcp] Offers API working! returned live offers.
# Terminal 2: Expose via ngrok
ngrok http 3000
# → Forwarding: https://abc123.ngrok-free.app → localhost:3000See TESTING.md for detailed testing steps.
Available Scripts
Command | Description |
| Start server with stdio transport (local MCP Inspector) |
| Start server with HTTP/SSE transport (ngrok / remote) |
| Compile TypeScript to |
| Run compiled JS from |
Environment Variables
Create a .env file in the project root (already listed in .gitignore — never commit it):
# Offers API
OFFERS_API_URL=https://api.example.com/offers
OFFERS_API_KEY=your-api-key-here
# Server
PORT=3000tsx (used by npm run dev and npm run dev:http) loads .env automatically — no extra packages needed.
If
OFFERS_API_KEYis missing or empty, the server falls back to theMOCK_OFFERSdataset automatically.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Tools
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/siddharthkoundal/mcp-offer-search'
If you have feedback or need assistance with the MCP directory API, please join our Discord server