DEV Community

KazKN
KazKN

Posted on • Edited on

Vinted MCP Architecture: How It Works Under the Hood

You've seen what the Vinted MCP Server can do — search listings, analyze prices, provide market insights through AI. But how does it actually work? What happens between your natural language query and the structured data that comes back?

Let's pop the hood and explore the architecture of the Vinted MCP Server.

MCP: The Protocol

Model Context Protocol (MCP) is Anthropic's open standard for connecting AI models to external tools. It defines:

  • Tools: Functions the AI can call (like search_vinted)
  • Resources: Data the AI can read (like market stats)
  • Prompts: Pre-built prompt templates
  • Transport: How client and server communicate (stdio or HTTP)

The Vinted MCP Server implements the Tools spec — exposing Vinted operations as callable functions.

Architecture Overview

┌──────────────┐     stdio/SSE      ┌──────────────────┐
│ Claude /     │◄──────────────────►│ Vinted MCP       │
│ Cursor /     │   MCP Protocol     │ Server           │
│ Any Client   │                    │                  │
└──────────────┘                    │ ┌──────────────┐ │
                                    │ │ Tool Handler │ │
                                    │ │              │ │
                                    │ │ - search     │ │
                                    │ │ - getItem    │ │
                                    │ │ - getUser    │ │
                                    │ └──────┬───────┘ │
                                    │        │         │
                                    │ ┌──────▼───────┐ │
                                    │ │ Vinted API   │ │
                                    │ │ Adapter      │ │
                                    │ └──────┬───────┘ │
                                    └────────┼─────────┘
                                             │
                                    ┌────────▼─────────┐
                                    │ Vinted Website   │
                                    │ (Public Data)    │
                                    └──────────────────┘
Enter fullscreen mode Exit fullscreen mode

The Three Layers

Layer 1: MCP Transport

The server uses @modelcontextprotocol/sdk to handle the MCP protocol. When launched via npx vinted-mcp-server, it starts a stdio transport — communicating with the AI client through standard input/output.

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';

const server = new McpServer({
  name: 'vinted-mcp-server',
  version: '1.0.0',
});

const transport = new StdioServerTransport();
await server.connect(transport);
Enter fullscreen mode Exit fullscreen mode

The AI client (Claude Desktop, Cursor) spawns the server as a child process and sends JSON-RPC messages over stdio.

Layer 2: Tool Definitions

Each tool is registered with a name, description, and input schema. This is what the AI sees when deciding which tool to call.

server.tool(
  'search_vinted',
  'Search for items on Vinted marketplace',
  {
    query: z.string().describe('Search query'),
    country: z.string().optional().describe('Country code (fr, de, nl...)'),
    priceMin: z.number().optional(),
    priceMax: z.number().optional(),
    sortBy: z.enum(['relevance', 'price_low', 'price_high', 'newest']).optional(),
    limit: z.number().optional().default(20),
  },
  async (params) => {
    // Handler implementation
  }
);
Enter fullscreen mode Exit fullscreen mode

The AI reads these descriptions to understand when and how to use each tool. Good descriptions = better AI behavior.

Layer 3: Vinted Data Adapter

The adapter translates MCP tool calls into Vinted queries and formats the results. It handles:

  • URL construction: Building the right Vinted search URL with parameters
  • Country routing: vinted.fr, vinted.de, vinted.nl, etc.
  • Data parsing: Extracting listing data from responses
  • Error handling: Timeouts, rate limits, invalid queries
  • Response formatting: Structuring data for the AI to understand
async function searchVinted(params: SearchParams): Promise<VintedListing[]> {
  const baseUrl = `https://www.vinted.${params.country || 'fr'}`;
  const searchUrl = buildSearchUrl(baseUrl, params);

  const response = await fetch(searchUrl, {
    headers: getHeaders(baseUrl),
  });

  const data = await response.json();
  return data.items.map(formatListing);
}
Enter fullscreen mode Exit fullscreen mode

Data Flow: A Complete Request

Let's trace what happens when you ask Claude: "Find Nike shoes under €50 on Vinted France"

1. User → Claude: Natural language query

2. Claude → MCP Client: Claude decides to call the search_vinted tool with parameters:

{
  "query": "Nike shoes",
  "country": "fr",
  "priceMax": 50
}
Enter fullscreen mode Exit fullscreen mode

3. MCP Client → Server: JSON-RPC message over stdio:

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "search_vinted",
    "arguments": { "query": "Nike shoes", "country": "fr", "priceMax": 50 }
  },
  "id": 1
}
Enter fullscreen mode Exit fullscreen mode

4. Server → Vinted: HTTP request to Vinted's search endpoint

5. Vinted → Server: Raw listing data

6. Server → MCP Client: Formatted results as JSON-RPC response:

{
  "jsonrpc": "2.0",
  "result": {
    "content": [{
      "type": "text",
      "text": "Found 20 listings for Nike shoes under €50...\n1. Nike Air Max 90 - €35 - Size 42..."
    }]
  },
  "id": 1
}
Enter fullscreen mode Exit fullscreen mode

7. Claude → User: Natural language summary with insights

Key Design Decisions

Why stdio Transport?

Stdio is the simplest and most secure transport for local MCP servers. The AI client spawns the server as a child process — no network ports to open, no authentication to manage, no CORS to configure. It just works.

For remote/hosted scenarios, the server also supports SSE (Server-Sent Events) transport via the Apify Vinted MCP Server.

Why Zod for Validation?

The MCP SDK uses Zod schemas for tool input validation. This gives you:

  • Runtime type checking
  • Automatic JSON Schema generation (for the AI to read)
  • Clear error messages when the AI sends bad parameters

Why Country as Environment Variable?

The VINTED_COUNTRY env var sets the default country. This keeps the common case simple — most users focus on one market. The AI can still override it per-query.

Extending the Server

Want to add new tools? The pattern is simple:

server.tool(
  'get_price_stats',
  'Get price statistics for a search query',
  {
    query: z.string(),
    country: z.string().optional(),
  },
  async ({ query, country }) => {
    const listings = await searchVinted({ query, country, limit: 50 });
    const prices = listings.map(l => l.price).sort((a, b) => a - b);

    return {
      content: [{
        type: 'text',
        text: JSON.stringify({
          count: prices.length,
          min: prices[0],
          max: prices[prices.length - 1],
          median: prices[Math.floor(prices.length / 2)],
          average: prices.reduce((a, b) => a + b, 0) / prices.length,
        }, null, 2)
      }]
    };
  }
);
Enter fullscreen mode Exit fullscreen mode

Performance Considerations

  • Cold start: First query takes 1-2 seconds (npm package startup). Subsequent queries are instant.
  • Response time: Depends on Vinted's response time — typically 500ms-2s per search.
  • Memory: The server is stateless — minimal memory footprint (~30MB Node.js process).
  • Concurrency: One server instance handles one client. For multiple clients, spawn multiple instances.

Hosted vs Local

Feature Local (npm) Hosted (Apify)
Setup npm install Zero
Transport stdio SSE/HTTP
Scaling Single instance Auto-scaled
Cost Free Free tier available
Customization Full source access Configuration only
Best for Development Production

The Apify hosted version wraps the same core logic but adds scaling, monitoring, and a web API.

Contributing

The project is open-source on GitHub. Key areas for contribution:

  • New tool implementations (saved searches, seller analytics)
  • Additional country support
  • Caching layer for repeated queries
  • SSE transport improvements
  • Documentation and examples

FAQ

What version of MCP does it implement?

The server uses the latest MCP SDK (@modelcontextprotocol/sdk), supporting the current MCP specification.

Can I use this server with non-Anthropic AI models?

Yes. Any AI client that supports MCP can connect. The protocol is model-agnostic.

How does it handle Vinted rate limits?

The server includes basic rate limiting awareness. For heavy usage, the Apify hosted version handles this with proxy rotation and automatic retries.

Is the data cached?

By default, no — every query hits Vinted live. You can add caching by extending the adapter layer.

What Node.js version is required?

Node.js 18+ (for native fetch support).

Explore Further

👉 npm package
👉 GitHub source
👉 Apify Vinted MCP
👉 Vinted Smart Scraper
👉 Apify Store

Understanding the architecture helps you build better tools on top of it. Fork it, extend it, make it yours.

Top comments (0)