trustmodel-agentcert-tag 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- trustmodel_agentcert_tag-0.1.0/PKG-INFO +49 -0
- trustmodel_agentcert_tag-0.1.0/README.md +33 -0
- trustmodel_agentcert_tag-0.1.0/pyproject.toml +27 -0
- trustmodel_agentcert_tag-0.1.0/setup.cfg +4 -0
- trustmodel_agentcert_tag-0.1.0/trustmodel_agentcert_tag/__init__.py +133 -0
- trustmodel_agentcert_tag-0.1.0/trustmodel_agentcert_tag.egg-info/PKG-INFO +49 -0
- trustmodel_agentcert_tag-0.1.0/trustmodel_agentcert_tag.egg-info/SOURCES.txt +7 -0
- trustmodel_agentcert_tag-0.1.0/trustmodel_agentcert_tag.egg-info/dependency_links.txt +1 -0
- trustmodel_agentcert_tag-0.1.0/trustmodel_agentcert_tag.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: trustmodel-agentcert-tag
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Verify an AgentCert + TrustScore inside a Python MCP server (shadow mode, opt-in, dependency-free).
|
|
5
|
+
Author: TrustModel.ai
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://trustmodel.ai/verify
|
|
8
|
+
Project-URL: Documentation, https://trustmodel.ai/wiki/agentcert/verify-gateway
|
|
9
|
+
Project-URL: Source, https://github.com/pdxlab/agentcert-tag
|
|
10
|
+
Keywords: mcp,agentcert,trustscore,verification,ai-agents,trustmodel
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# trustmodel-agentcert-tag
|
|
18
|
+
|
|
19
|
+
Verify an **AgentCert + TrustScore** inside a Python MCP server. Thin, dependency-free
|
|
20
|
+
client for a [TAG](https://trustmodel.ai/verify) verify endpoint — **off by default**,
|
|
21
|
+
**shadow mode** when on (logs, never blocks), safe to merge.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install trustmodel-agentcert-tag
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from trustmodel_agentcert_tag import verify_gate, extract_token
|
|
29
|
+
|
|
30
|
+
guard = verify_gate(mode="shadow") # shadow | enforce
|
|
31
|
+
|
|
32
|
+
async def handle_tool_call(request):
|
|
33
|
+
token = extract_token(request.headers) # X-AgentCert-Token (or mTLS-derived)
|
|
34
|
+
await guard(token) # logs (shadow) / raises VerifyError (enforce)
|
|
35
|
+
return await dispatch(request)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Enable per environment — nothing runs until you opt in:
|
|
39
|
+
|
|
40
|
+
| Env var | Meaning |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `TRUSTMODEL_VERIFY=1` | turn the gate on (otherwise `guard` is a no-op) |
|
|
43
|
+
| `TRUSTMODEL_VERIFY_URL` | TAG verify endpoint (default `http://localhost:8080/verify`) |
|
|
44
|
+
| `TRUSTMODEL_MODE=enforce` | switch to enforcement |
|
|
45
|
+
|
|
46
|
+
The gate never reads request payloads (metadata only) and never makes the allow/deny
|
|
47
|
+
decision on its own — it returns a structured verdict (`VERIFIED` / `REVOKED` /
|
|
48
|
+
`UNVERIFIED` / `ERROR`) your server acts on. MIT licensed. Part of
|
|
49
|
+
[pdxlab/agentcert-tag](https://github.com/pdxlab/agentcert-tag).
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# trustmodel-agentcert-tag
|
|
2
|
+
|
|
3
|
+
Verify an **AgentCert + TrustScore** inside a Python MCP server. Thin, dependency-free
|
|
4
|
+
client for a [TAG](https://trustmodel.ai/verify) verify endpoint — **off by default**,
|
|
5
|
+
**shadow mode** when on (logs, never blocks), safe to merge.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install trustmodel-agentcert-tag
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
from trustmodel_agentcert_tag import verify_gate, extract_token
|
|
13
|
+
|
|
14
|
+
guard = verify_gate(mode="shadow") # shadow | enforce
|
|
15
|
+
|
|
16
|
+
async def handle_tool_call(request):
|
|
17
|
+
token = extract_token(request.headers) # X-AgentCert-Token (or mTLS-derived)
|
|
18
|
+
await guard(token) # logs (shadow) / raises VerifyError (enforce)
|
|
19
|
+
return await dispatch(request)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Enable per environment — nothing runs until you opt in:
|
|
23
|
+
|
|
24
|
+
| Env var | Meaning |
|
|
25
|
+
|---|---|
|
|
26
|
+
| `TRUSTMODEL_VERIFY=1` | turn the gate on (otherwise `guard` is a no-op) |
|
|
27
|
+
| `TRUSTMODEL_VERIFY_URL` | TAG verify endpoint (default `http://localhost:8080/verify`) |
|
|
28
|
+
| `TRUSTMODEL_MODE=enforce` | switch to enforcement |
|
|
29
|
+
|
|
30
|
+
The gate never reads request payloads (metadata only) and never makes the allow/deny
|
|
31
|
+
decision on its own — it returns a structured verdict (`VERIFIED` / `REVOKED` /
|
|
32
|
+
`UNVERIFIED` / `ERROR`) your server acts on. MIT licensed. Part of
|
|
33
|
+
[pdxlab/agentcert-tag](https://github.com/pdxlab/agentcert-tag).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "trustmodel-agentcert-tag"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Verify an AgentCert + TrustScore inside a Python MCP server (shadow mode, opt-in, dependency-free)."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [{ name = "TrustModel.ai" }]
|
|
13
|
+
keywords = ["mcp", "agentcert", "trustscore", "verification", "ai-agents", "trustmodel"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
]
|
|
19
|
+
dependencies = []
|
|
20
|
+
|
|
21
|
+
[project.urls]
|
|
22
|
+
Homepage = "https://trustmodel.ai/verify"
|
|
23
|
+
Documentation = "https://trustmodel.ai/wiki/agentcert/verify-gateway"
|
|
24
|
+
Source = "https://github.com/pdxlab/agentcert-tag"
|
|
25
|
+
|
|
26
|
+
[tool.setuptools]
|
|
27
|
+
packages = ["trustmodel_agentcert_tag"]
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""trustmodel-agentcert-tag — verify an AgentCert + TrustScore inside a Python MCP server.
|
|
2
|
+
|
|
3
|
+
The verification decision itself is made by a TAG verify endpoint (a local sidecar or a
|
|
4
|
+
hosted endpoint); this package is a thin, dependency-free client + gate you drop in front
|
|
5
|
+
of your tool calls. It is a no-op unless verification is turned on, and defaults to shadow
|
|
6
|
+
mode (log, never block), so it is safe to merge.
|
|
7
|
+
|
|
8
|
+
Typical use inside an MCP server's tool-call path:
|
|
9
|
+
|
|
10
|
+
from trustmodel_agentcert_tag import verify_gate, extract_token
|
|
11
|
+
|
|
12
|
+
guard = verify_gate(mode="shadow") # shadow | enforce
|
|
13
|
+
|
|
14
|
+
async def handle_tool_call(request):
|
|
15
|
+
token = extract_token(request.headers) # X-AgentCert-Token or mTLS-derived
|
|
16
|
+
await guard(token) # logs (shadow) / raises (enforce) on bad verdict
|
|
17
|
+
return await dispatch(request)
|
|
18
|
+
|
|
19
|
+
Environment:
|
|
20
|
+
TRUSTMODEL_VERIFY=1 enable (otherwise verify_gate() is a no-op passthrough)
|
|
21
|
+
TRUSTMODEL_VERIFY_URL=... TAG verify endpoint (default http://localhost:8080/verify)
|
|
22
|
+
TRUSTMODEL_MODE=enforce override mode to enforce
|
|
23
|
+
"""
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import json
|
|
27
|
+
import logging
|
|
28
|
+
import os
|
|
29
|
+
import urllib.request
|
|
30
|
+
from typing import Awaitable, Callable, Iterable, Mapping, Optional
|
|
31
|
+
|
|
32
|
+
__version__ = "0.1.0"
|
|
33
|
+
__all__ = ["verify_gate", "verify", "extract_token", "VerificationResult", "VerifyError"]
|
|
34
|
+
|
|
35
|
+
log = logging.getLogger("agentcert-tag")
|
|
36
|
+
|
|
37
|
+
DEFAULT_HEADER = "x-agentcert-token"
|
|
38
|
+
DEFAULT_VERIFY_URL = "http://localhost:8080/verify"
|
|
39
|
+
DEFAULT_BLOCK_ON = ("REVOKED", "UNVERIFIED")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class VerificationResult(dict):
|
|
43
|
+
"""Structured TAG result. Keys: verification_status, agent_id, cert_valid,
|
|
44
|
+
trust_score{value,tier}, detail."""
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def status(self) -> str:
|
|
48
|
+
return self.get("verification_status", "ERROR")
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def score(self):
|
|
52
|
+
return (self.get("trust_score") or {}).get("value")
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def tier(self) -> str:
|
|
56
|
+
return (self.get("trust_score") or {}).get("tier", "Unknown")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class VerifyError(Exception):
|
|
60
|
+
"""Raised in enforce mode when a verdict is in block_on."""
|
|
61
|
+
|
|
62
|
+
def __init__(self, result: VerificationResult):
|
|
63
|
+
self.result = result
|
|
64
|
+
super().__init__(f"agentcert-tag blocked: {result.status} ({result.get('detail','')})")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _enabled() -> bool:
|
|
68
|
+
return os.environ.get("TRUSTMODEL_VERIFY") == "1"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def verify(token: Optional[str], *, verify_url: Optional[str] = None, timeout: float = 3.0) -> VerificationResult:
|
|
72
|
+
"""POST the presented credential to the TAG verify endpoint and return its result.
|
|
73
|
+
Never raises on transport error — returns an ERROR result so the caller's fail
|
|
74
|
+
policy decides."""
|
|
75
|
+
url = verify_url or os.environ.get("TRUSTMODEL_VERIFY_URL", DEFAULT_VERIFY_URL)
|
|
76
|
+
if not token:
|
|
77
|
+
return VerificationResult(verification_status="UNVERIFIED", cert_valid=False,
|
|
78
|
+
detail="no credential presented")
|
|
79
|
+
body = json.dumps({"credential": token}).encode()
|
|
80
|
+
req = urllib.request.Request(url, data=body, headers={"Content-Type": "application/json"})
|
|
81
|
+
try:
|
|
82
|
+
with urllib.request.urlopen(req, timeout=timeout) as r:
|
|
83
|
+
return VerificationResult(**json.loads(r.read().decode()))
|
|
84
|
+
except Exception as exc: # noqa: BLE001 - transport failures become an ERROR verdict
|
|
85
|
+
return VerificationResult(verification_status="ERROR", detail=f"verify unreachable: {exc}")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def extract_token(headers: Optional[Mapping[str, str]], header: str = DEFAULT_HEADER) -> Optional[str]:
|
|
89
|
+
"""Case-insensitive lookup of the AgentCert credential header."""
|
|
90
|
+
if not headers:
|
|
91
|
+
return None
|
|
92
|
+
for k, v in headers.items():
|
|
93
|
+
if k.lower() == header.lower():
|
|
94
|
+
return v
|
|
95
|
+
return None
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def verify_gate(
|
|
99
|
+
*,
|
|
100
|
+
mode: str = "shadow",
|
|
101
|
+
block_on: Iterable[str] = DEFAULT_BLOCK_ON,
|
|
102
|
+
verify_url: Optional[str] = None,
|
|
103
|
+
fail_mode: str = "closed",
|
|
104
|
+
on_result: Optional[Callable[[VerificationResult], None]] = None,
|
|
105
|
+
) -> Callable[[Optional[str]], Awaitable[VerificationResult]]:
|
|
106
|
+
"""Return an async guard(token) -> VerificationResult.
|
|
107
|
+
|
|
108
|
+
- Off entirely unless TRUSTMODEL_VERIFY=1 (guard returns immediately).
|
|
109
|
+
- shadow (default): logs the decision, never raises.
|
|
110
|
+
- enforce: raises VerifyError when the verdict is in block_on, or on ERROR when
|
|
111
|
+
fail_mode='closed'.
|
|
112
|
+
"""
|
|
113
|
+
effective_mode = "enforce" if os.environ.get("TRUSTMODEL_MODE") == "enforce" else mode
|
|
114
|
+
block = set(block_on)
|
|
115
|
+
|
|
116
|
+
async def guard(token: Optional[str]) -> VerificationResult:
|
|
117
|
+
if not _enabled():
|
|
118
|
+
return VerificationResult(verification_status="DISABLED")
|
|
119
|
+
result = verify(token, verify_url=verify_url)
|
|
120
|
+
log.info("[agentcert-tag] mode=%s status=%s score=%s tier=%s",
|
|
121
|
+
effective_mode, result.status, result.score, result.tier)
|
|
122
|
+
if on_result:
|
|
123
|
+
try:
|
|
124
|
+
on_result(result)
|
|
125
|
+
except Exception: # noqa: BLE001 - a callback must never break the request
|
|
126
|
+
log.exception("[agentcert-tag] on_result callback failed")
|
|
127
|
+
if effective_mode == "enforce":
|
|
128
|
+
bad = result.status in block or (result.status == "ERROR" and fail_mode == "closed")
|
|
129
|
+
if bad:
|
|
130
|
+
raise VerifyError(result)
|
|
131
|
+
return result
|
|
132
|
+
|
|
133
|
+
return guard
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: trustmodel-agentcert-tag
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Verify an AgentCert + TrustScore inside a Python MCP server (shadow mode, opt-in, dependency-free).
|
|
5
|
+
Author: TrustModel.ai
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://trustmodel.ai/verify
|
|
8
|
+
Project-URL: Documentation, https://trustmodel.ai/wiki/agentcert/verify-gateway
|
|
9
|
+
Project-URL: Source, https://github.com/pdxlab/agentcert-tag
|
|
10
|
+
Keywords: mcp,agentcert,trustscore,verification,ai-agents,trustmodel
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# trustmodel-agentcert-tag
|
|
18
|
+
|
|
19
|
+
Verify an **AgentCert + TrustScore** inside a Python MCP server. Thin, dependency-free
|
|
20
|
+
client for a [TAG](https://trustmodel.ai/verify) verify endpoint — **off by default**,
|
|
21
|
+
**shadow mode** when on (logs, never blocks), safe to merge.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install trustmodel-agentcert-tag
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from trustmodel_agentcert_tag import verify_gate, extract_token
|
|
29
|
+
|
|
30
|
+
guard = verify_gate(mode="shadow") # shadow | enforce
|
|
31
|
+
|
|
32
|
+
async def handle_tool_call(request):
|
|
33
|
+
token = extract_token(request.headers) # X-AgentCert-Token (or mTLS-derived)
|
|
34
|
+
await guard(token) # logs (shadow) / raises VerifyError (enforce)
|
|
35
|
+
return await dispatch(request)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Enable per environment — nothing runs until you opt in:
|
|
39
|
+
|
|
40
|
+
| Env var | Meaning |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `TRUSTMODEL_VERIFY=1` | turn the gate on (otherwise `guard` is a no-op) |
|
|
43
|
+
| `TRUSTMODEL_VERIFY_URL` | TAG verify endpoint (default `http://localhost:8080/verify`) |
|
|
44
|
+
| `TRUSTMODEL_MODE=enforce` | switch to enforcement |
|
|
45
|
+
|
|
46
|
+
The gate never reads request payloads (metadata only) and never makes the allow/deny
|
|
47
|
+
decision on its own — it returns a structured verdict (`VERIFIED` / `REVOKED` /
|
|
48
|
+
`UNVERIFIED` / `ERROR`) your server acts on. MIT licensed. Part of
|
|
49
|
+
[pdxlab/agentcert-tag](https://github.com/pdxlab/agentcert-tag).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
trustmodel_agentcert_tag
|