Guia de Desenvolupament de Proveïdors
A Simple Vista
Què: Construir proveïdors d’evidència personalitzats per a Decision Gate Per què: Estendre les fonts d’evidència sense modificar el nucli Qui: Desenvolupadors de proveïdors, enginyers d’integració Requisits previs: provider_protocol.md, JSON-RPC 2.0
Arquitectura del Proveïdor
Un proveïdor és un servidor MCP que implementa una eina: evidence_query.
Provider
- Provider Contract (JSON)
- provider_id, name, description
- transport = "mcp"
- config_schema
- checks (params schema, result schema, comparators, examples)
- notes
- MCP Server
- tools/call -> evidence_query
Decision Gate
- Loads contract from capabilities_path
- Validates ScenarioSpec conditions against contract
- Calls evidence_query during scenario_next
La Decision Gate no utilitza tools/list en temps d’execució. Implementa-ho per a la compatibilitat amb MCP, però mantingues el fitxer de contracte com a autoritari.
Tipus de Proveïdors
| Tipus | Configuració | Transport | Cas d’ús |
|---|---|---|---|
| Integrat | type = "builtin" | In-process | time, env, json, http |
| MCP extern | type = "mcp" | stdio o HTTP | Proveïdors personalitzats |
Els proveïdors externs de MCP estan configurats amb o bé:
command = ["/path/to/provider", "arg"](stdio)url = "https://provider/rpc"(HTTP)
capabilities_path és requerit per a tots els proveïdors MCP. Els noms dels proveïdors han de ser únics; els identificadors integrats (time, env, json, http) estan reservats només per a type = "builtin".
Inici ràpid: Proveïdor mínim
Pas 1: Utilitza una plantilla SDK
Les plantilles viuen a decision-gate-provider-sdk/ (Python, TypeScript, Go). Implementen:
- Contingut-Longitud emmarcat (stdio)
tools/listitools/call- Anàlisi de JSON-RPC
Pas 2: Implementar evidence_query
El teu controlador ha de retornar un objecte EvidenceResult (no un error JSON-RPC) per a fallades normals.
El teu controlador ha de retornar un EvidenceResult objecte (no un error JSON-RPC) per a fallades normals.
def handle_evidence_query(query, context):
if query["check_id"] != "file_exists":
return {
"value": None,
"lane": "verified",
"error": {
"code": "unsupported_check",
"message": "unknown check",
"details": {"check_id": query["check_id"]}
},
"evidence_hash": None,
"evidence_ref": None,
"evidence_anchor": None,
"signature": None,
"content_type": None
}
rel_path = query.get("params", {}).get("path")
if not rel_path:
return {
"value": None,
"lane": "verified",
"error": {
"code": "params_missing",
"message": "missing path",
"details": {"param": "path"}
},
"evidence_hash": None,
"evidence_ref": None,
"evidence_anchor": None,
"signature": None,
"content_type": None
}
root = CONFIG["root"]
root_id = CONFIG["root_id"]
abs_path = os.path.normpath(os.path.join(root, rel_path))
exists = os.path.exists(abs_path)
return {
"value": {"kind": "json", "value": exists},
"lane": "verified",
"error": None,
"evidence_hash": None,
"evidence_ref": {"uri": f"dg+file://{root_id}/{rel_path}"},
"evidence_anchor": {
"anchor_type": "file_path_rooted",
"anchor_value": json.dumps({"root_id": root_id, "path": rel_path}, separators=(",", ":"), sort_keys=True)
},
"signature": None,
"content_type": "application/json"
}
Pas 3: Crear un Contracte de Proveïdor
Tots els camps a continuació són necessaris pel esquema del contracte.
{
"provider_id": "file-provider",
"name": "File Provider",
"description": "File existence checks",
"transport": "mcp",
"config_schema": {
"type": "object",
"additionalProperties": false,
"properties": {}
},
"checks": [
{
"check_id": "file_exists",
"description": "Check if a file exists",
"determinism": "external",
"params_required": true,
"params_schema": {
"type": "object",
"additionalProperties": false,
"properties": { "path": { "type": "string" } },
"required": ["path"]
},
"result_schema": { "type": "boolean" },
"allowed_comparators": ["equals", "not_equals"],
"anchor_types": ["file_path_rooted"],
"content_types": ["application/json"],
"examples": [
{
"description": "Check a report file",
"params": { "path": "report.json" },
"result": true
}
]
}
],
"notes": [
"External: depends on the local filesystem state."
]
}
Regles importants del contracte:
allowed_comparatorsha de ser no buit i en ordre canònic.params_requiredha de coincidir amb siparams_schemarequereix camps.transportha de ser"mcp"per a proveïdors externs.
Pas 4: Configurar la Decision Gate
[[providers]]
name = "file-provider"
type = "mcp"
command = ["python3", "/path/to/provider.py"]
capabilities_path = "contracts/file-provider.json"
Temps d’espera
La Decision Gate només aplica temps d’espera HTTP als proveïdors HTTP MCP:
[[providers]]
name = "cloud"
type = "mcp"
url = "https://provider.example.com/rpc"
capabilities_path = "contracts/cloud.json"
timeouts = { connect_timeout_ms = 2000, request_timeout_ms = 10000 }
No hi ha cap temps d’esgotament de la Decision Gate per als proveïdors MCP de stdio; mantingueu els seus controladors ràpids i deterministes.
Evidència de signatura
Quan trust.default_policy = { require_signature = { keys = [...] } }, els proveïdors han d’incloure signatures:
"signature": {
"scheme": "ed25519",
"key_id": "/etc/decision-gate/keys/provider.pub",
"signature": [1, 2, 3, 4]
}
Algorisme de signatura (exacte):
- Compute
evidence_hashfrom the evidence value.- valor JSON -> bytes JSON canònics -> sha256
- Valor de bytes -> sha256
- Serialitza l’objecte HashDigest com a JSON canònic.
- Signa aquests bytes amb Ed25519.
Decision Gate verifica que la signatura coincideixi amb el fitxer de clau pública configurat. Si evidence_hash falta, DG el calcula abans de la verificació. Si evidence_hash està present, ha de coincidir amb el hash canònic del valor de l’evidència o la resposta és rebutjada.
Gestió d’Errors
- Retorna EvidenceResult.error per a errors esperats.
- Utilitzeu errors JSON-RPC només per a fallades de protocol (JSON-RPC no vàlid, bloquejos interns). DG converteix els errors JSON-RPC en
provider_error.
Els codis d’error són definits pel proveïdor. Mantingueu-los estables i llegibles per a màquines (per exemple, params_missing, file_not_found).
Referència
- Esquema de contracte del proveïdor:
crates/decision-gate-contract/src/schemas.rs(provider_contract_schema) - Contractes de proveïdor integrats: providers.json
- Plantilles SDK:
decision-gate-provider-sdk/
Glossari
EvidenceQuery: Sol·licitud { provider_id, check_id, params }. EvidenceResult: Valor de resposta del proveïdor + metadades. Provider Contract: Document JSON que descriu comprovacions, esquemes, comparadors i exemples. Signature: Signatura Ed25519 sobre JSON canònic de evidence_hash.