Skip to main content
Glama
ismaileneskucuk

Electronic Markets TR

Electronic Markets TR — MCP Server (Rust)

A lightweight Model Context Protocol server that searches Turkish electronics e-commerce sites in parallel and returns normalized product, price (TRY) and stock data for AI agents.

Purpose

Give LLM agents one tool to compare prices and stock across Turkish electronics markets, without loading pages or scraping HTML themselves. The server returns raw page-one search hits; ranking and relevance judgment stay with the agent.

Related MCP server: Market Fiyatı MCP Server

Supported markets

Market

Method

Robotistan

Server-rendered search page (/arama?q=)

Robocombo

Ticimax storefront JSON API

Direnc.net

T-Soft v5 search page (data-toggle attributes)

Robo90

T-Soft AJAX product loader

Ceriyan

WooCommerce product search (/?s=&post_type=product)

Architecture

src/
  domain/        Product, Price/Money (kurus-backed integer), StockStatus, Market, SearchQuery
  parsing.rs     Turkish price/stock text parsing (pure functions, no I/O)
  http.rs        Shared reqwest client: pooling, timeouts, bounded retry
  scrapers/      One independent module per market (fetch + site-specific parser)
  search.rs      Concurrent orchestration: all 5 markets in parallel, per-market timeout,
                 partial results on failure
  pipeline.rs    Stock filter + URL-canonicalization dedup (pure functions)
  mcp_service.rs rmcp tool server + shared search execution
  main.rs        stdio entry point

Design notes:

  • Money: kurus (1/100 TRY) stored as i64; no floating point anywhere near prices. A missing price is Price::Unavailable, distinct from zero.

  • Concurrency: all markets are queried concurrently (bounded by the static market count). A 20 s per-market timeout turns a slow site into a per-market error without affecting other markets.

  • Errors: typed (HttpError, ScrapeError); market failures are reported in the response payload (marketErrors) instead of failing the whole search.

Setup

Requires Rust 1.85+ (edition 2024).

cargo build --release

Configuration

Environment variables:

  • RUST_LOG — log filter (default: no logs on stdout; logs go to stderr, e.g. RUST_LOG=warn)

HTTP behavior (timeouts, retries, pool size) is configured in src/http.rs::HttpClientConfig with sensible defaults: 5 s connect timeout, 15 s request timeout, 1 retry for transient failures (5xx/timeout/network) only.

MCP usage

Register in an MCP client (e.g. Claude Desktop):

{
  "mcpServers": {
    "electronic-markets-tr": {
      "command": "/absolute/path/to/mcp-electronicmarkets-tr/target/release/mcp-electronicmarkets-tr"
    }
  }
}

Tool: search_products

Argument

Type

Default

Description

query

string

Product name or keywords (1–128 chars)

only_in_stock

boolean

true

Return only products currently in stock

Response (JSON):

{
  "query": "esp32",
  "onlyInStock": true,
  "resultCount": 5,
  "products": [
    {
      "market": "robotistan",
      "name": "ESP32-CAM ...",
      "price": { "available": { "kurus": 92320 } },
      "stockStatus": "in_stock",
      "url": "https://www.robotistan.com/..."
    }
  ],
  "marketErrors": []
}

Development

cargo check          # fast type check
cargo test           # unit + fixture + MCP protocol tests (offline)
cargo clippy --all-targets --all-features -- -D warnings
cargo fmt --check

Testing

  • Unit tests (src/): Turkish price parsing, stock text parsing, URL building, filtering, deduplication, query validation.

  • Fixture tests (tests/scraper_fixtures.rs, tests/robocombo_fixture.rs): real HTML/JSON captured from the live sites; parser output verified against live-observed counts (e.g. Ceriyan esp32 -> 10 products, 5 in stock / 5 out of stock). Includes malformed-HTML and missing-field safety tests.

  • MCP protocol tests (tests/mcp_protocol.rs): full rmcp handshake over an in-memory duplex transport — tool registration, input schema shape, invalid-parameter rejection.

Live smoke testing

Hits the real sites; ignored by default so cargo test stays offline:

cargo test --test live_smoke -- --ignored --nocapture

Verifies all five markets with three queries: arduino uno, esp32, 220 ohm resistor. Each market is reported independently; one failing market does not hide others' results.

Performance comparison (concurrent vs sequential search) can be run with:

cargo run --release --example perf_search

Measured on a residential connection (2026-09-10): concurrent 2.4 s vs sequential 7.4 s for esp32 (~3.1x speedup); results vary with per-site latency. Working set during a search: ~14 MB.

Release build

cargo build --release
# binary: target/release/mcp-electronicmarkets-tr

Adding a new scraper

  1. Add a variant to Market (src/domain/market.rs) and include it in Market::ALL.

  2. Create src/scrapers/<market>.rs with pub async fn search(http: &HttpClient, query: &SearchQuery) plus a pure pub fn parse_search_page(&str) -> Vec<Product>.

  3. Wire the variant in search.rs::scrape_market.

  4. Capture a real fixture (e.g. curl -A "Mozilla/..." <search-url> > tests/fixtures/<market>_search.html) and add a fixture test.

  5. Verify with live smoke tests before shipping.

Related MCP Connectors

Related MCP Servers