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.
@@ -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,2 @@
1
+ [console_scripts]
2
+ hodgeguard-mcp = hodgeguard_mcp.client:main
@@ -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"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+