hodgeguard-mcp 0.2.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.
- hodgeguard_mcp-0.2.0/PKG-INFO +8 -0
- hodgeguard_mcp-0.2.0/hodgeguard_mcp/__init__.py +1 -0
- hodgeguard_mcp-0.2.0/hodgeguard_mcp/client.py +146 -0
- hodgeguard_mcp-0.2.0/hodgeguard_mcp.egg-info/PKG-INFO +8 -0
- hodgeguard_mcp-0.2.0/hodgeguard_mcp.egg-info/SOURCES.txt +8 -0
- hodgeguard_mcp-0.2.0/hodgeguard_mcp.egg-info/dependency_links.txt +1 -0
- hodgeguard_mcp-0.2.0/hodgeguard_mcp.egg-info/entry_points.txt +2 -0
- hodgeguard_mcp-0.2.0/hodgeguard_mcp.egg-info/top_level.txt +1 -0
- hodgeguard_mcp-0.2.0/pyproject.toml +16 -0
- hodgeguard_mcp-0.2.0/setup.cfg +4 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hodgeguard-mcp
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Zero-Knowledge MCP Circuit-Breaker Client for Autonomous Coding Agents (OpenCode, Claude Code, Cursor)
|
|
5
|
+
Author: Rajeev Prakash Nath
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.0"
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
PUBLIC OPEN-SOURCE MCP CLIENT: hodgeguard-mcp
|
|
4
|
+
Contains ZERO proprietary math.
|
|
5
|
+
- Auto-provisions a zero-friction anonymous trial key (250 free steps) per machine.
|
|
6
|
+
- Hashes tool names, targets, and state fingerprints locally via SHA-256 (100% Zero-Knowledge Privacy).
|
|
7
|
+
"""
|
|
8
|
+
import hashlib
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
import platform
|
|
12
|
+
import sys
|
|
13
|
+
import urllib.request
|
|
14
|
+
import urllib.error
|
|
15
|
+
import uuid
|
|
16
|
+
from typing import Optional
|
|
17
|
+
|
|
18
|
+
API_URL = os.environ.get("HODGEGUARD_API_URL", "https://hodgeguard-brain-api.fly.dev")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_default_anon_key() -> str:
|
|
22
|
+
node_fingerprint = f"{platform.node()}-{uuid.getnode()}"
|
|
23
|
+
digest = hashlib.sha256(node_fingerprint.encode("utf-8")).hexdigest()[:16]
|
|
24
|
+
return f"hg_anon_{digest}"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
API_KEY = os.environ.get("HODGEGUARD_API_KEY", get_default_anon_key())
|
|
28
|
+
|
|
29
|
+
TOOLS = [
|
|
30
|
+
{
|
|
31
|
+
"name": "hodgeguard_check_step",
|
|
32
|
+
"description": (
|
|
33
|
+
"Call before or after executing a shell/edit tool to verify the agent is not "
|
|
34
|
+
"trapped in a non-convergent edit-test-fail livelock. Zero-knowledge SHA-256 privacy."
|
|
35
|
+
),
|
|
36
|
+
"inputSchema": {
|
|
37
|
+
"type": "object",
|
|
38
|
+
"properties": {
|
|
39
|
+
"tool_name": {"type": "string", "description": "e.g., bash, edit_file, read_file"},
|
|
40
|
+
"target": {"type": "string", "description": "File path or command signature"},
|
|
41
|
+
"state_fingerprint": {"type": "string", "description": "Optional error output or file snippet"},
|
|
42
|
+
"verified_progress": {"type": "boolean", "description": "True ONLY if a new test passed"},
|
|
43
|
+
},
|
|
44
|
+
"required": ["tool_name", "target"],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "hodgeguard_reset",
|
|
49
|
+
"description": "Resets the Hodge curl manifold when starting a new user task.",
|
|
50
|
+
"inputSchema": {"type": "object", "properties": {}},
|
|
51
|
+
},
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def sha256_short(raw: str) -> str:
|
|
56
|
+
if not raw:
|
|
57
|
+
return ""
|
|
58
|
+
return hashlib.sha256(raw.strip().encode("utf-8")).hexdigest()[:16]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def call_cloud_brain(endpoint: str, payload: dict) -> dict:
|
|
62
|
+
req = urllib.request.Request(
|
|
63
|
+
f"{API_URL}{endpoint}",
|
|
64
|
+
data=json.dumps(payload).encode("utf-8"),
|
|
65
|
+
headers={
|
|
66
|
+
"Content-Type": "application/json",
|
|
67
|
+
"X-HodgeGuard-Key": API_KEY,
|
|
68
|
+
},
|
|
69
|
+
method="POST",
|
|
70
|
+
)
|
|
71
|
+
try:
|
|
72
|
+
with urllib.request.urlopen(req, timeout=3.0) as resp:
|
|
73
|
+
return json.loads(resp.read().decode("utf-8"))
|
|
74
|
+
except urllib.error.HTTPError as e:
|
|
75
|
+
return json.loads(e.read().decode("utf-8"))
|
|
76
|
+
except Exception as exc:
|
|
77
|
+
return {"status": "ERROR", "halted": False, "recommendation": f"Cloud Brain unreachable: {exc}"}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def handle_rpc(request: dict) -> Optional[dict]:
|
|
81
|
+
req_id = request.get("id")
|
|
82
|
+
method = request.get("method", "")
|
|
83
|
+
params = request.get("params", {})
|
|
84
|
+
|
|
85
|
+
if method == "initialize":
|
|
86
|
+
return {
|
|
87
|
+
"jsonrpc": "2.0",
|
|
88
|
+
"id": req_id,
|
|
89
|
+
"result": {
|
|
90
|
+
"protocolVersion": "2024-11-05",
|
|
91
|
+
"capabilities": {"tools": {}},
|
|
92
|
+
"serverInfo": {"name": "hodgeguard-mcp", "version": "0.2.0"},
|
|
93
|
+
},
|
|
94
|
+
}
|
|
95
|
+
elif method == "notifications/initialized":
|
|
96
|
+
return None
|
|
97
|
+
elif method == "tools/list":
|
|
98
|
+
return {"jsonrpc": "2.0", "id": req_id, "result": {"tools": TOOLS}}
|
|
99
|
+
elif method == "tools/call":
|
|
100
|
+
name = params.get("name")
|
|
101
|
+
args = params.get("arguments", {})
|
|
102
|
+
if name == "hodgeguard_check_step":
|
|
103
|
+
canonical_v = f"{args.get('tool_name', '').lower()}::{args.get('target', '')}"
|
|
104
|
+
cloud_resp = call_cloud_brain("/v1/step", {
|
|
105
|
+
"vertex_hash": sha256_short(canonical_v),
|
|
106
|
+
"state_hash": sha256_short(args.get("state_fingerprint", "")),
|
|
107
|
+
"verified_progress": bool(args.get("verified_progress", False)),
|
|
108
|
+
})
|
|
109
|
+
return {
|
|
110
|
+
"jsonrpc": "2.0",
|
|
111
|
+
"id": req_id,
|
|
112
|
+
"result": {
|
|
113
|
+
"content": [{"type": "text", "text": json.dumps(cloud_resp, indent=2)}],
|
|
114
|
+
"isError": bool(cloud_resp.get("halted", False)),
|
|
115
|
+
},
|
|
116
|
+
}
|
|
117
|
+
elif name == "hodgeguard_reset":
|
|
118
|
+
cloud_resp = call_cloud_brain("/v1/reset", {})
|
|
119
|
+
return {
|
|
120
|
+
"jsonrpc": "2.0",
|
|
121
|
+
"id": req_id,
|
|
122
|
+
"result": {"content": [{"type": "text", "text": json.dumps(cloud_resp)}]},
|
|
123
|
+
}
|
|
124
|
+
if req_id is not None:
|
|
125
|
+
return {"jsonrpc": "2.0", "id": req_id, "error": {"code": -32601, "message": f"Method not found: {method}"}}
|
|
126
|
+
return None
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def main():
|
|
130
|
+
for line in sys.stdin:
|
|
131
|
+
line = line.strip()
|
|
132
|
+
if not line:
|
|
133
|
+
continue
|
|
134
|
+
try:
|
|
135
|
+
req = json.loads(line)
|
|
136
|
+
resp = handle_rpc(req)
|
|
137
|
+
if resp is not None:
|
|
138
|
+
sys.stdout.write(json.dumps(resp) + "\n")
|
|
139
|
+
sys.stdout.flush()
|
|
140
|
+
except Exception as exc:
|
|
141
|
+
sys.stdout.write(json.dumps({"jsonrpc": "2.0", "id": None, "error": {"code": -32700, "message": str(exc)}}) + "\n")
|
|
142
|
+
sys.stdout.flush()
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
if __name__ == "__main__":
|
|
146
|
+
main()
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hodgeguard-mcp
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Zero-Knowledge MCP Circuit-Breaker Client for Autonomous Coding Agents (OpenCode, Claude Code, Cursor)
|
|
5
|
+
Author: Rajeev Prakash Nath
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
pyproject.toml
|
|
2
|
+
hodgeguard_mcp/__init__.py
|
|
3
|
+
hodgeguard_mcp/client.py
|
|
4
|
+
hodgeguard_mcp.egg-info/PKG-INFO
|
|
5
|
+
hodgeguard_mcp.egg-info/SOURCES.txt
|
|
6
|
+
hodgeguard_mcp.egg-info/dependency_links.txt
|
|
7
|
+
hodgeguard_mcp.egg-info/entry_points.txt
|
|
8
|
+
hodgeguard_mcp.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
hodgeguard_mcp
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hodgeguard-mcp"
|
|
7
|
+
version = "0.2.0"
|
|
8
|
+
description = "Zero-Knowledge MCP Circuit-Breaker Client for Autonomous Coding Agents (OpenCode, Claude Code, Cursor)"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [{name = "Rajeev Prakash Nath"}]
|
|
13
|
+
dependencies = []
|
|
14
|
+
|
|
15
|
+
[project.scripts]
|
|
16
|
+
hodgeguard-mcp = "hodgeguard_mcp.client:main"
|