mcp server
mcp-electronicmarkets-tr
High-performance Rust MCP server for real-time price and stock search across Turkish electronics markets.
Set up
Runs on your computer. Pick your agent and operating system.
This project does not publish an install method we can turn into a config. Follow the README instead.
README
synced Oct 26, 2026Electronic 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.
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 asi64; no floating point anywhere near prices. A missing price isPrice::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. Ceriyanesp32-> 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
- Add a variant to
Market(src/domain/market.rs) and include it inMarket::ALL. - Create
src/scrapers/<market>.rswithpub async fn search(http: &HttpClient, query: &SearchQuery)plus a purepub fn parse_search_page(&str) -> Vec<Product>. - Wire the variant in
search.rs::scrape_market. - Capture a real fixture (e.g.
curl -A "Mozilla/..." <search-url> > tests/fixtures/<market>_search.html) and add a fixture test. - Verify with live smoke tests before shipping.