Sdílený Python runtime pro MCP konektory platformy OpenMCP.cz.
Konektor napsaný nad tímto SDK je jeden FastMCP server, který beze změny kódu běží ve třech režimech: lokálně přes stdio v Claude Desktopu, hostovaně na platformě OpenMCP, nebo self-hosted za vlastním OIDC. O identitu, přihlašovací údaje, politiku zápisu, pseudonymizaci osobních údajů a tvar odpovědí se stará SDK — konektor řeší jen svoje API.
- Verze: 0.4.2 · Python: 3.12+ (CI ověřuje 3.12, 3.13 a 3.14) · Licence: MIT
- Konektory postavené nad SDK: ares-mcp (veřejný rejstřík, běží bez jediného tajemství), upgates-com-mcp (e-shop, API klíč), dotykacka-mcp (pokladní systém, delegovaný OAuth)
SDK není na PyPI — jméno openmcp-sdk tam patří nesouvisejícímu projektu.
Instalujte přímo z GitHubu, ideálně připnuté na konkrétní commit:
pip install "openmcp-sdk @ git+https://github.com/mcp-open/openmcp-sdk@<commit-sha>"Konektory z organizace mcp-open navíc nosí ověřený snapshot SDK přímo
v repozitáři, takže se dají postavit i bez sítě:
python release/materialize_sdk.py --root . --output /tmp/openmcp-sdk
pip install /tmp/openmcp-sdk -e .Skript ověří SHA-256 archivu proti release/openmcp-sdk.sha256 a commit proti
.sdk-ref; nesoulad zastaví instalaci.
Konektor je adresář se třemi věcmi: connector.yaml (manifest), nástroje
zaregistrované do FastMCP a jeden run_connector().
# src/connector/__main__.py
from fastmcp import FastMCP
from mcp.types import ToolAnnotations
from openmcp_sdk import run_connector, current_context, UpstreamClient
mcp = FastMCP("muj-konektor")
@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
def get_faktura(cislo: str) -> dict:
ctx = current_context()
client = UpstreamClient(base_url="https://api.dodavatel.cz/v1",
headers={"X-Api-Key": ctx.secrets["api_key"]})
return client.get_json(f"/faktury/{client.seg(cislo)}")
run_connector("connector.yaml", mcp)Spuštění lokálně:
export OPENMCP_MODE=local-stdio # výchozí hodnota, dá se vynechat
export MUJKONEKTOR_API_KEY='...' # <SLUG>_<KLÍČ> velkými písmeny
python -m connectorPřipojení do MCP klienta (Claude Desktop, Claude Code):
{
"mcpServers": {
"muj-konektor": {
"command": "/cesta/k/.venv/bin/python",
"args": ["-m", "connector"],
"cwd": "/cesta/ke/konektoru",
"env": {
"OPENMCP_MODE": "local-stdio",
"MUJKONEKTOR_API_KEY": "..."
}
}
}
}Lokální režim nepotřebuje účet na OpenMCP ani žádnou běžící službu platformy.
Nástroj vrací obálku s daty a provenancí, aby model věděl, odkud údaj je a jak je čerstvý:
{
"data": {"ico": "27074358", "obchodniJmeno": "Asseco Central Europe, a.s."},
"provenance": {
"source_id": "ares",
"source_url": "https://ares.gov.cz/ekonomicke-subjekty-v-be/rest/ekonomicke-subjekty/27074358",
"retrieved_at": "2026-07-28T17:41:55Z",
"freshness": "live"
},
"warnings": []
}Provenance vynucuje HTTP(S) URL, bezpečný source_id a UTC časové razítko
s koncovkou Z.
Přesměrování se ve výchozím nastavení nenásleduje — klient s Basic auth by mohl odnést přihlašovací údaje na cizí origin. Když ho upstream potřebuje (typicky kanonizace URL záznamu), povolte ho výslovně a jen pro GET:
client.request("GET", "/faktury/ext:kod:FV-1", same_origin_redirects=1)Následuje se pouze Location se stejným scheme, hostem i portem; cokoli jiného
zůstane chybou.
Chyby jsou ConnectorError s uzavřenou množinou kódů — invalid_input,
forbidden, rate_limited, upstream_unavailable, upstream_error,
internal. Text upstream odpovědi se do zprávy nikdy nekopíruje: mohl by nést
obsah napsaný cizím uživatelem a putoval by rovnou do kontextu modelu. HTTP stav
zůstává dostupný v ConnectorError.status pro strukturované rozhodování.
Identita a přihlašovací údaje se nikdy nepředávají jako argument nástroje — model by je viděl a mohl si je vymyslet. Čtou se z kontextu, který transport založí pro každý request zvlášť:
from openmcp_sdk import current_context
ctx = current_context()
ctx.secrets["api_key"] # per-request kopie, neměnná
ctx.config["region"] # typovaná podle manifestu
ctx.principal.sub # ověřený subjekt
ctx.policy # co workspace dovoluje zapisovat
ctx.oauth # klient delegovaného OAuth, nebo NoneRežim vybírá OPENMCP_MODE; výchozí je local-stdio.
Jednouživatelský režim (sub=local). Hodnoty se čtou z proměnných prostředí
pojmenovaných <SLUG>_<KLÍČ> velkými písmeny a striktně se převádějí na typ
z manifestu (string, int, bool, enum). Booleany berou jen true,
false, 1, 0, yes, no, on, off — cokoli jiného zastaví start.
Chybějící povinný secret je chyba, ne varování.
Konektor běží na platformě za gatewayí. Ta posílá X-OpenMCP-Sub spolu
s X-OpenMCP-Gateway-Token; token se porovnává v konstantním čase ještě před
čtením jakéhokoli tajemství, takže samotná hlavička se subjektem není
bezpečnostní hranicí a přímé volání podu bez tokenu dostane 403.
Přihlašovací údaje se čtou z HashiCorp Vaultu (KV v2) z cesty
{mount}/{users|teams}/{owner_id}/{slug} a vždy v přesné verzi, kterou
určí control plane hlavičkou X-OpenMCP-Credential-Version. Verzi latest
runtime nikdy nečte — mohla by to být rozpracovaná rotace, která ještě neprošla
testem.
Povinné: OPENMCP_INTERNAL_TOKEN (nejméně 32 znaků), VAULT_ADDR (pokud
konektor má nějaké credentials).
Identita pochází výhradně z ověřeného OIDC access tokenu (FastMCP JWTVerifier
kontroluje podpis, issuer i audience); klientské hlavičky X-OpenMCP-* se
v tomto režimu jako záloha nepoužijí.
Povinné: OIDC_ISSUER, OIDC_JWKS_URI a VAULT_ADDR (má-li konektor
credentials).
| Proměnná | Režim | Výchozí | Význam |
|---|---|---|---|
OPENMCP_MODE |
vše | local-stdio |
local-stdio, hosted, self-hosted |
OPENMCP_PII_SALT |
vše | — | povinný, když manifest má runtime.pii_salt: true |
OPENMCP_LOG_LEVEL |
vše | INFO |
úroveň logu |
OPENMCP_LOG_FORMAT |
vše | json |
text přepne na čitelný formát |
OPENMCP_LOG_SETUP |
vše | true |
false ponechá logging na hostiteli |
OPENMCP_COMPONENT |
vše | slug konektoru | název komponenty v JSON logu |
OPENMCP_INTERNAL_TOKEN |
hosted, self-hosted | — | sdílené tajemství gatewaye, min. 32 znaků |
OPENMCP_ALLOWED_ORIGINS |
hosted, self-hosted | https://claude.ai,https://claude.com |
CORS allowlist |
PORT |
hosted, self-hosted | 8000 |
port HTTP serveru |
VAULT_ADDR |
hosted, self-hosted | — | adresa Vaultu |
VAULT_ROLE |
hosted, self-hosted | slug konektoru | Kubernetes auth role |
VAULT_MOUNT |
hosted, self-hosted | secret |
KV v2 mount |
VAULT_TTL |
hosted, self-hosted | 60 |
TTL cache přihlašovacích údajů (s) |
VAULT_TIMEOUT |
hosted, self-hosted | 10 |
timeout volání Vaultu (s) |
VAULT_CACERT |
hosted, self-hosted | — | PEM CA bundle pro interní TLS |
VAULT_REQUIRE_HTTPS |
hosted, self-hosted | false |
vynutí https:// adresu Vaultu |
VAULT_CACHE_MAX |
hosted, self-hosted | 1024 |
strop položek cache |
OIDC_ISSUER, OIDC_JWKS_URI |
self-hosted | — | ověření access tokenu |
OIDC_AUDIENCE |
self-hosted | slug konektoru | očekávaná audience |
SDK nemá přepínač, kterým by šlo vypnout ověřování TLS certifikátu Vaultu.
connector.yaml je striktní schéma (extra: forbid) — překlep v názvu pole
zastaví start, ne až první request. Validuje se mimo jiné DNS-safe slug, verze,
unikátnost klíčů, enum hodnoty a defaulty, zákaz tajemství zapsaných napevno
v YAML, egress pravidla (host, port, prefix cesty, HTTP metody) a kurátorovaný
blok display.
Klíč sdk_min_version je zároveň migrační přepínač: od 0.4.0 jsou startovací
kontroly tvrdé (nesoulad manifestu a zaregistrovaných nástrojů shodí start),
níže jen varují.
Read-only filtr je fail-closed. Když je instance read-only, přežijí jen nástroje
s výslovným ToolAnnotations(readOnlyHint=True); chybějící nebo nejednoznačná
anotace znamená „mutující", a nástroj se odstraní.
Kontrola bez spouštění serveru:
openmcp-sdk validate connector.yamlKonektory, které vracejí data o lidech, pseudonymizují citlivá pole ještě před
odesláním modelu. Token má tvar <KATEGORIE_a1b2c3d4e5f6> a je jednosměrný:
HMAC-SHA256 z "kategorie:hodnota" pod klíčem odvozeným z OPENMCP_PII_SALT
a rozsahu tenanta. Nikde nevzniká re-identifikační mapa.
Konektor dodává jen tabulku polí, logiku má SDK. Salt patří do secretu runtime prostředí — nikdy do manifestu ani do image, protože vstupy typu e-mail mají nízkou entropii a jeho únik by umožnil re-identifikaci hrubou silou.
Bez OPENMCP_PII_SALT konektor s runtime.pii_salt: true záměrně nenastartuje:
tichý fallback na náhodný salt by tokeny rozbil až po prvním restartu.
Konektor, který volá upstream jménem uživatele, deklaruje v manifestu:
auth:
type: oauth_delegated
provider: dotykacka
operator_fields:
- {key: client_id, label: "Client ID", type: string, required: true}
- {key: client_secret, label: "Client Secret", type: string, secret: true, required: true}
runtime_secrets: [refresh_token, cloud_id]operator_fields registruje provozovatel konektoru jednou. Platforma provede
uživatelský souhlas a uloží runtime_secrets do per-user Vault blobu. Nástroj
si pak vezme krátkodobý access token:
token = current_context().oauth.access_token() # líná výměna, cache do expiracePři upstream 401 zavolejte ctx.oauth.invalidate(), aby se token při dalším
volání vyměnil znovu. Klient je thread-safe a souběžná volání nespustí
lavinu výměn. Zabudovaný provider: dotykacka.
| Cesta | Ochrana | K čemu |
|---|---|---|
GET /healthz |
žádná | liveness a readiness |
GET,POST /mcp |
gateway token nebo OIDC | MCP protokol, bezstavový |
POST /internal/credential-test |
X-OpenMCP-Test-Token |
ověří přesnou verzi údajů z Vaultu; nepřijímá žádný vstup |
POST /internal/public-safe-test |
X-OpenMCP-Public-Safe-Test-Token |
syntetický test konektoru bez tajemství |
POST /test |
X-OpenMCP-Test-Token |
starší cesta s předaným {secrets, config}; s Vaultem se nemontuje |
MCP transport běží bezstavově (stateless_http), protože hostovaný konektor má
víc replik a následný request může dorazit na jiný pod.
Z jednoho release kontraktu umí SDK vyrenderovat balíčky pro Claude Desktop (MCPB 0.4), OpenAI a Gemini CLI:
openmcp-sdk render-adapters connector.yaml distribution.yaml --output /tmp/adaptery
openmcp-sdk verify-release release-gate.yaml --root . \
--source-commit "$GITHUB_SHA" --output release/release-evidence.jsonBrána je fail-closed: vyžaduje zamčené závislosti, přesný content manifest,
SPDX SBOM skutečného payloadu, výsledek scanu, keyless podpis a SLSA provenance.
Lokální a vzdálený režim se nemíchají — .mcpb vzniká jen pro lokální
distribuci, vzdálené konektory dostanou operátorský handoff, ne instalovatelný
balíček.
Podrobnosti a bezpečnostní invarianty: docs/DISTRIBUTION.md.
Další příkazy CLI: pack-mcpb, build-contents-manifest, bind-trivy-report,
build-provenance, withdraw-release.
uv venv -p 3.13 && . .venv/bin/activate
pip install -e '.[test]' ruff==0.15.22
ruff check openmcp_sdk tests
pytest -qBalík obsahuje py.typed. Verze má jediný zdroj pravdy v
openmcp_sdk/_version.py. Vyžaduje FastMCP >=3.2,<4; FastMCP 2.x se do
nového release locku nesmí dostat.
SDK řeší jen společný runtime. Klient konkrétního API, doménové modely a závislosti na nich patří do konektoru.
- Postup a nároky na změny: CONTRIBUTING.md
- Hlášení zranitelností: SECURITY.md — nikdy ne přes veřejné issue
- Historie změn: CHANGELOG.md