ต้นแบบ · รุ่นทดลอง: มีทุก server ในทะเบียนทางการ อัปเดตทุก 30 นาที รีวิวและบัญชีผู้ใช้จะมาในขั้นถัดไป
PopNx MCPที่รวม MCP สำหรับคนใช้ AI · อธิบายเป็นภาษาคน

Swiss Procurement MCP

โดย malkreideรุ่น 0.19.0i★ –iรันบนเครื่อง
ชื่อใน registryio.github.malkreide/swiss-procurement-mcp

ติดตั้ง

ภาพรวม

คำอธิบายจากผู้ทำ (ภาษาอังกฤษตามต้นฉบับ)

Swiss public procurement (simap.ch): tenders, awards, CPV codes, all cantons + federal, read-only

สามเสาของ PopNx MCP

สามเรื่องนี้ไม่รวมเป็นคะแนนเดียว เพราะความเห็น การวัด และความนิยม เป็นคนละเรื่องกัน

ใช้ทำอะไรได้

ตัวนี้ยังไม่ได้เรียบเรียงเป็นภาษาไทย ด้านล่างคือข้อเท็จจริงที่เราอ่านจาก registry

  • การเชื่อมต่อ: รันบนเครื่อง
  • ช่องทาง (transport): stdio
  • หมวด: กฎหมายและข้อมูลภาครัฐ

ติดตั้ง

เลือกโปรแกรม AI ที่คุณใช้ แล้วคัดลอกค่าตั้งไปวาง

ก่อนติดตั้ง

ต้องเตรียมก่อน

  • PyPIติดตั้ง uv ของ Python (มีคำสั่ง uvx) ในเครื่อง

คุณใช้แอปไหน

เลือกแอปด้านบน เราจำไว้ให้ ครั้งหน้าปุ่มจะขึ้นว่า “ติดตั้งลง …”

เปิด Claude Desktop → Settings → Developer → Edit Config แล้ววางค่านี้ในไฟล์ claude_desktop_config.json

{
  "mcpServers": {
    "swiss-procurement": {
      "command": "uvx",
      "args": [
        "swiss-procurement-mcp"
      ]
    }
  }
}

พิมพ์คำสั่งนี้ใน Terminal

claude mcp add swiss-procurement -- uvx swiss-procurement-mcp

เปิดใน Cursor

หรือคัดลอกค่าตั้งเอง

วางในไฟล์ .cursor/mcp.json ของโปรเจกต์ หรือ ~/.cursor/mcp.json

{
  "mcpServers": {
    "swiss-procurement": {
      "command": "uvx",
      "args": [
        "swiss-procurement-mcp"
      ]
    }
  }
}

เบราว์เซอร์จะถามก่อนเปิดแอป จากนั้นแอปแสดงค่าตั้งให้ตรวจแล้วกดยืนยัน ช่อง key เว้นว่างไว้ให้คุณใส่เอง

เปิดใน VS Code

หรือคัดลอกค่าตั้งเอง

วางในไฟล์ .vscode/mcp.json ของโปรเจกต์

{
  "servers": {
    "swiss-procurement": {
      "type": "stdio",
      "command": "uvx",
      "args": [
        "swiss-procurement-mcp"
      ]
    }
  }
}

เบราว์เซอร์จะถามก่อนเปิดแอป จากนั้นแอปแสดงค่าตั้งให้ตรวจแล้วกดยืนยัน ช่อง key เว้นว่างไว้ให้คุณใส่เอง

ตัวนี้รันในเครื่องคุณ แต่ ChatGPT ต่อได้เฉพาะ server บนอินเทอร์เน็ต ลองเลือกแอปอื่น

ตัวเลือกเก็บในคุกกี้บนเครื่องนี้ ไม่ต้องมีบัญชี

ค่าตั้งนี้สร้างจากข้อมูลใน registry ของผู้ทำ ถ้าไม่ตรงกับ README ให้เชื่อ README

ทำอะไรได้บ้าง

รันในเครื่องคุณ รายการเครื่องมือจะขึ้นในแอป AI หลังติดตั้ง

ผลตรวจเบื้องต้นi

เราตรวจจากข้อมูลที่ใครก็เปิดดูได้ ยังไม่ได้อ่านโค้ด ข้อที่ไม่เกี่ยวกับตัวนี้ไม่นับในตัวหาร · ตรวจเมื่อ 8 พ.ย. 2569

  • ✓ ผ่าน

    ตัวตนผู้ทำตรงกับ repo

    ชื่อใน registry ยืนยันด้วยบัญชี GitHub malkreide ซึ่งเป็นเจ้าของ repo

  • … ยังไม่ตรวจ

    ยังมีคนดูแล

    ยังไม่ได้อ่านข้อมูล repo จาก GitHub

  • … ยังไม่ตรวจ

    มีสัญญาอนุญาต (license)

    ยังไม่ได้อ่านข้อมูล repo จาก GitHub

  • – ไม่เกี่ยว

    endpoint ตอบ

    ตัวนี้รันบนเครื่องคุณ ไม่มี endpoint บนอินเทอร์เน็ต

  • – ไม่เกี่ยว

    ล็อกอินแบบ OAuth

    ตัวนี้รันบนเครื่อง ใช้ค่าที่ตั้งในเครื่องแทน

  • … ยังไม่ตรวจ

    คำอธิบายเครื่องมือไม่มีคำสั่งแอบแฝง

    รันในเครื่องคุณ เราอ่านรายการเครื่องมือได้เฉพาะตัวที่มี endpoint บนอินเทอร์เน็ต

เทียบกับตัวอื่นในหมวด กฎหมายและข้อมูลภาครัฐi

  • ดาวมากกว่า 0% ของอีก 1758 ตัวในหมวดนี้
  • ส่งรุ่นใหม่เข้า registry ล่าสุดกว่า 43% ของอีก 1758 ตัวในหมวดนี้
  • ผลตรวจเบื้องต้นดีกว่าหรือเท่ากับ 100% ของอีก 1758 ตัวในหมวดนี้

เทียบกับทุก server ที่ยังใช้งานในหมวดนี้ทั้งทะเบียน ดาวนับเฉพาะเมื่อผู้ลงทะเบียนเป็นเจ้าของ repo

คำถามที่พบบ่อย

Swiss Procurement MCP ปลอดภัยไหม?

จากการตรวจเบื้องต้นของเรา ผ่าน 1 จาก 1 ข้อที่ตรวจได้ เรายังไม่ได้อ่านโค้ด ก่อนใส่กุญแจหรือ token ให้ดูว่า server ขอสิทธิ์อะไร และเลือกกุญแจที่ทำได้เท่าที่จำเป็น

ต้องใช้กุญแจหรือรหัสอะไรบ้าง?

registry ไม่ได้ระบุว่าต้องใช้กุญแจ แต่บางตัวจะขอให้ล็อกอินตอนใช้ครั้งแรก

ตัวนี้รันบนเครื่องหรือบนคลาวด์?

รันบนเครื่องของคุณ โปรแกรม AI จะเปิด server ขึ้นมาเองเมื่อใช้ ข้อมูลไม่ต้องผ่านเซิร์ฟเวอร์ของผู้ทำ (ยกเว้นตัวที่ไปเรียกบริการออนไลน์ต่อ)

ยังมีคนดูแลอยู่ไหม?

repo บน GitHub มีการแก้โค้ดล่าสุด – และส่งรุ่นล่าสุด (0.19.0) เข้า registry 42 วันที่ผ่านมา

ใช้กับโปรแกรมไหนได้บ้าง?

โปรแกรมที่รองรับ MCP เช่น Claude Desktop, Claude Code, Cursor และ VS Code ตัวนี้ต้องมี Python (uv) ในเครื่องด้วย

มีตัวไหนใช้แทนได้บ้าง?

ในหมวดเดียวกันมี Miramo, Private Law Wiki, Gerro: госзакупки для ИИ / Russian public procurement

ตัวที่ใช้แทนได้

server หมวดเดียวกันจากผู้ทำคนอื่น เรียงตามดาว

อ่านการ์ด:↓ ดาวน์โหลดต่อสัปดาห์i★ ดาว GitHubiสามเสา: รีวิว · ผลตรวจ · การใช้งานiอัปเดต = วันที่ส่งรุ่นล่าสุดเข้า registryi

Miramo

French rental law for tenants and landlords: rent caps, rental zones and unfurnished lease drafts.

โดย miramolabsเริ่มต้นอัปเดต วันนี้

รันบนคลาวด์✓ miramo.fr

Private Law Wiki

Sourced answers, search and bank-case assessment for wiki.private.law by the Mothership runtime.

โดย privatelawattorneysยังใหม่มากอัปเดต วันนี้

รันบนคลาวด์

README จากผู้ทำ

เปิดอ่าน README

ส่วนนี้คัดจาก repo ของผู้ทำตามต้นฉบับ PopNx MCP ไม่ได้ตรวจหรือรับรองเนื้อหา ตัด HTML รูปภาพ และสคริปต์ออกแล้ว ลิงก์จะพาออกนอกเว็บ

Part of the [Swiss Public Data MCP Portfolio](https://github.com/malkreide/swiss-public-data-mcp) — open-source MCP servers connecting AI agents to Swiss public and open data.

This is a private project. It is independent of any employer or institutional affiliation and represents no official position of any authority.

swiss-procurement-mcp

MCP server for Swiss public procurement — read access to the official simap.ch API, covering all cantons and the Confederation, updated intraday.


🎯 Anchor demo query

*«Which school-building tenders did the City of Zurich publish in 2026, which BKP construction categories do they concern, and who are the procuring offices?»*

A single search_procurements_detailed(query="Schulhaus", canton="ZH", published_from="2026-01-01") returns the leading tenders already expanded with their BKP construction codes and procuring offices — connecting procurement to school-building planning in one call (optionally paired with search_construction_codes to resolve a category).

Demo

Why this server exists

Swiss public procurement is published on simap.ch. The platform's web UI is searchable by hand, but the amtsblatt-mcp server only reaches the three cantons (AR, BS, TI) that still mirror tenders to the Amtsblattportal — Zurich among the missing.

simap closes that gap: it operates a documented OpenAPI 3 read API (v1.5.1) whose search and detail endpoints are marked security: None and are callable without authentication. This server wraps exactly those read endpoints.

Mnemonic: *The web UI is the front door; the API is the loading dock. Probe the dock.*


Architecture decision

Architecture A (live API only, short-lived cache).

  • The public search, detail and reference endpoints are unauthenticated and were confirmed working live (2026-07-26).
  • Publications change intraday, so the cache TTL is deliberately short (30 min).
  • The ~200 write / my/ / OIDC-protected endpoints (publishing tenders, submitting offers) are out of scope — this server never writes.

Every response carries source and provenance (live_api / cached / degraded). Upstream failure yields a degraded envelope, never a silent empty list.


Live-probe findings (2026-07-26)

EndpointAuthResult
/publications/v2/project/project-searchnone20 hits, canton filter, current-day
/publications/v1/.../publication-details/...nonefull record: criteria, deadlines, codes
/publications/v1/publication/{id}/past-publicationsnoneproject lifecycle
/codes/v1/cpv/searchnoneCPV full-text search
/codes/v1/{bkp,npk,ebkp-h,ebkp-t,oag,cpc}/searchnoneSwiss construction codes
/procoffices/v1/po/publicnone~1 MB office list (client-side filter)
/cantons/v1, /countries/v1nonereference data
Known findings
  1. Wrong host, wrong conclusion. The read API lives under www.simap.ch/api. The simap.ch/de web UI is a separate SSR app that exposes none of it — probing the UI produced an earlier, mistaken "no API" verdict.
  2. `lang` is mandatory on project-search. Omitting it is HTTP 400 (errorCode E0025), not an empty result. The client injects a default.
  3. Award is not "award". newestPubTypes=award returns HTTP 400. Awards are split by procedure: award_tender, award_study_contract, award_competition, direct_award. The search_awards tool queries all four.
  4. Canton ids are bare. ZH, not CH-ZH. Passing an ISO subdivision code silently matches nothing; this server rejects it with a clear error.
  5. A session cookie is required. The first request sets it; a persistent HTTP client handles this transparently.

Tools

ToolPurpose
search_procurementsSearch projects by canton, CPV, process type, date, text
search_procurements_detailedSearch + full detail for the top *n* hits in one call (aggregated)
search_awardsAwarded contracts only (all four award types at once)
get_procurement_detailsFull record for one publication
get_publication_historyEarlier publications of the same project (tender → award)
search_cpv_codesResolve keywords to CPV classification codes
search_construction_codesSwiss construction codes (BKP, NPK, eBKP, OAG, CPC)
find_procurement_officePublic procurement offices by partial name
source_statusReachability and latency of the simap.ch API

All tools carry readOnlyHint, idempotentHint and openWorldHint (they query the live simap.ch API).

Every tool takes a single validated argument object. Bounds, allow-lists and patterns are declared on the input models in inputs.py — so an out-of-range limit or an unknown canton is rejected before any upstream request, and the constraints are visible to the model in the tool schema rather than buried in the tool body:

search_procurements({"canton": "ZH", "query": "Schulhaus", "limit": 20})

The models set strict=True (no silent "10" → 10 coercion) and extra="forbid" (unknown fields are rejected, not ignored). The canton, process type, publication type, code system and language allow-lists are derived from constants.py, so they cannot drift from the probe-verified tables.

What canton= means

simap offers exactly one geographic filter, orderAddressCantons, and it selects by where the work is delivered — not by who is procuring. When a procuring office files a free-text address, the structured canton is null and the publication is invisible to that filter. Measured CH-wide over 500 projects published since 2026-07-01: 303 (60.6%) carry no canton, among them the Amt für Hochbauten Zürich, Grün Stadt Zürich, USZ, BBL and SBB.

canton_match therefore makes the question explicit:

ValueMatchesZurich, 2026-07-01…27
procuring_body *(default)*procured by that canton's public bodies, incl. communal and subordinate offices (issuedByOrganizations)410 projects
place_of_deliverythe work is delivered there (orderAddressCantons)263 projects
bothunion of the two; two upstream calls, no pagination441 projects

The 31 projects only place_of_delivery finds are federal bodies procuring in Zurich (ETH, Empa, Flughafen Zürich AG) — a different question, not a gap, which is why this is three explicit semantics rather than a silent union.

Every response states in note which semantics were applied.


Portfolio connections

  • A vendor's UID links to register-mcp.
  • BKP / eBKP construction codes on a tender connect procurement to school-building planning and to zh-education-mcp.
  • Complements amtsblatt-mcp with national coverage instead of three cantons.

Installation

uvx swiss-procurement-mcp
Claude Desktop
{

"mcpServers": { "swiss-procurement": { "command": "uvx", "args": ["swiss-procurement-mcp"] } } }

Cloud (Render / Railway)
MCP_TRANSPORT=sse HOST=0.0.0.0 PORT=8000 python -m swiss_procurement_mcp
Container
docker compose up --build        # SSE on :8000

The image is multi-stage and runs as a non-root system user. compose.yaml adds a read-only root filesystem, drops all capabilities, sets no-new-privileges, and caps memory, CPU and PIDs. No secret is needed at runtime — the wrapped simap.ch endpoints are public.

CI builds the image on every push and asserts both properties that matter: that the container does not run as uid 0, and that the server still imports under --read-only --cap-drop ALL.

Configuration
VariableDefaultPurpose
MCP_TRANSPORTstdiostdio \sse \streamable-http
MCP_HOST / HOST127.0.0.1HTTP binding (cloud transports only). Defaults to loopback; set 0.0.0.0 explicitly to expose all interfaces in a cloud deployment.
MCP_CORS_ORIGINS_(unset)_Comma-separated origins allowed to call the HTTP transports from a browser. Unset means no cross-origin browser access at all — stdio and non-browser clients are unaffected. Mcp-Session-Id is exposed and accepted for the listed origins, so a browser client can hold a session. * is honoured but logs a warning and disables credentials, because browsers reject a wildcard origin together with credentials.
MCP_STATELESS_(off)_Set to 1 to run the streamable-http transport with no session tracking. Removes session affinity as a concern for multi-instance deployments; gives up SSE stream resumption and server-initiated notifications. No effect on the legacy SSE transport, which logs a warning if asked. See docs/load-balancing.md.
PORT / MCP_PORT8000HTTP port (cloud transports only)
LOG_LEVELINFODEBUG \INFO \WARNING \ERROR. Structured JSON, one object per line, always on stderr — stdout carries the MCP protocol on a stdio transport.

No API keys — the wrapped simap.ch read endpoints are fully public.

Built on structlog. Every event emitted during a tool call carries that call's correlation_id, bound via contextvars — so a failure logged deep inside the HTTP client can be joined to the request that caused it without threading context through every function.

LevelEmitted when
DEBUGa tool call was entered (tool_call_started) — tells you whether a hung call ever started
INFOa tool call finished cleanly, with latency
WARNINGsimap.ch was unreachable or errored (upstream_degraded)
ERRORa tool call raised

Records carry the exception *type* only — never its message and never an upstream response body (OBS-002).

{"event":"tool_call_started","tool":"search_procurements","correlation_id":"23221af26ae640c7","level":"debug","timestamp":"2026-07-27T22:20:07.494276Z"}

{"status":"ok","latency_ms":312,"event":"tool_call","tool":"search_procurements","correlation_id":"23221af26ae640c7","level":"info","timestamp":"2026-07-27T22:20:07.806Z"}


MCP Protocol Version

Served via the `initialize` handshake2024-11-05 … `2025-11-25` — the handshake ceiling
Served via the per-request envelope`2026-07-28`
Who picksThe client's first request, once per connection. A request carrying the 2026-07-28 _meta envelope opens a modern connection; anything else opens a handshake connection.
Pinned inMCP_PROTOCOL_VERSION in server.py
SDKmcp>=2.0.0,<3

| Cache hints | tools/list,

ตัดมาแค่ช่วงต้น อ่านต่อใน repo

ถาม PopNx