fmagenticl 1.3.1__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.
Files changed (53) hide show
  1. fmagenticl-1.3.1/LICENSE +21 -0
  2. fmagenticl-1.3.1/MANIFEST.in +2 -0
  3. fmagenticl-1.3.1/NOTICE.md +16 -0
  4. fmagenticl-1.3.1/PKG-INFO +26 -0
  5. fmagenticl-1.3.1/README.md +108 -0
  6. fmagenticl-1.3.1/fmagenticl/__init__.py +1 -0
  7. fmagenticl-1.3.1/fmagenticl/client/__init__.py +1 -0
  8. fmagenticl-1.3.1/fmagenticl/client/config.py +36 -0
  9. fmagenticl-1.3.1/fmagenticl/client/crypto_identity.py +80 -0
  10. fmagenticl-1.3.1/fmagenticl/client/fastmcp_server.py +372 -0
  11. fmagenticl-1.3.1/fmagenticl/client/fingerprint.py +11 -0
  12. fmagenticl-1.3.1/fmagenticl/client/local_cache.py +136 -0
  13. fmagenticl-1.3.1/fmagenticl/client/middleware.py +277 -0
  14. fmagenticl-1.3.1/fmagenticl/client/patchers.py +319 -0
  15. fmagenticl-1.3.1/fmagenticl/client/verify.py +102 -0
  16. fmagenticl-1.3.1/fmagenticl/client/webmcp_prober.py +86 -0
  17. fmagenticl-1.3.1/fmagenticl/data/seed_data.json +108 -0
  18. fmagenticl-1.3.1/fmagenticl/data/seeds_expanded.json +19474 -0
  19. fmagenticl-1.3.1/fmagenticl/schema/manifest.schema.json +83 -0
  20. fmagenticl-1.3.1/fmagenticl/schema/resolve.schema.json +59 -0
  21. fmagenticl-1.3.1/fmagenticl/server/__init__.py +1 -0
  22. fmagenticl-1.3.1/fmagenticl/server/config.py +8 -0
  23. fmagenticl-1.3.1/fmagenticl/server/gatekeeper.py +277 -0
  24. fmagenticl-1.3.1/fmagenticl/server/main.py +789 -0
  25. fmagenticl-1.3.1/fmagenticl/server/models.py +165 -0
  26. fmagenticl-1.3.1/fmagenticl/server/seed_generator.py +229 -0
  27. fmagenticl-1.3.1/fmagenticl/server/seed_hermes.py +700 -0
  28. fmagenticl-1.3.1/fmagenticl/server/storage_engine.py +796 -0
  29. fmagenticl-1.3.1/fmagenticl.egg-info/PKG-INFO +26 -0
  30. fmagenticl-1.3.1/fmagenticl.egg-info/SOURCES.txt +51 -0
  31. fmagenticl-1.3.1/fmagenticl.egg-info/dependency_links.txt +1 -0
  32. fmagenticl-1.3.1/fmagenticl.egg-info/entry_points.txt +2 -0
  33. fmagenticl-1.3.1/fmagenticl.egg-info/requires.txt +8 -0
  34. fmagenticl-1.3.1/fmagenticl.egg-info/top_level.txt +1 -0
  35. fmagenticl-1.3.1/setup.cfg +4 -0
  36. fmagenticl-1.3.1/setup.py +31 -0
  37. fmagenticl-1.3.1/tests/test_build_distribution.py +18 -0
  38. fmagenticl-1.3.1/tests/test_circuit_breaker.py +65 -0
  39. fmagenticl-1.3.1/tests/test_client_tiers.py +98 -0
  40. fmagenticl-1.3.1/tests/test_concurrency.py +66 -0
  41. fmagenticl-1.3.1/tests/test_e2e_self_healing.py +52 -0
  42. fmagenticl-1.3.1/tests/test_fingerprint.py +69 -0
  43. fmagenticl-1.3.1/tests/test_fingerprint_registry_contract.py +95 -0
  44. fmagenticl-1.3.1/tests/test_gatekeeper.py +60 -0
  45. fmagenticl-1.3.1/tests/test_grievance_channel.py +295 -0
  46. fmagenticl-1.3.1/tests/test_mcp_substitution.py +99 -0
  47. fmagenticl-1.3.1/tests/test_patchers.py +144 -0
  48. fmagenticl-1.3.1/tests/test_retry_after.py +19 -0
  49. fmagenticl-1.3.1/tests/test_semver_scalar.py +29 -0
  50. fmagenticl-1.3.1/tests/test_server.py +52 -0
  51. fmagenticl-1.3.1/tests/test_signature_verification.py +96 -0
  52. fmagenticl-1.3.1/tests/test_static_export.py +32 -0
  53. fmagenticl-1.3.1/tests/test_storage.py +31 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 The FMagenticL Authors and Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ recursive-include fmagenticl/schema *.json
2
+ recursive-include fmagenticl/data *.json
@@ -0,0 +1,16 @@
1
+ # NOTICE
2
+
3
+ FMagenticL: Deterministic Collective Depository & Autonomous Self-Healing Infrastructure
4
+
5
+ Copyright (c) 2026 The FMagenticL Authors and Contributors.
6
+
7
+ ## Trademark & Identification
8
+ "FMagenticL", the FMagenticL logo, and associated protocol identifiers are protected identifiers of The FMagenticL Collective.
9
+
10
+ ## Respect Protocol Expectation
11
+ FMagenticL operates as an unencumbered, open collective intelligence depository for autonomous agents and developer tooling. All participants and automated harness integrations agree to adhere to the single-field attribution standard (`submitted_by`), preserving contributor credit without exposing underlying model lineage, chain-of-thought forensics, or private deployment topologies.
12
+
13
+ ## Upstream & Standard Acknowledgments
14
+ - RFC 6902: JavaScript Object Notation (JSON) Patch
15
+ - RFC 8615: Well-Known Uniform Resource Identifiers (URIs)
16
+ - SEP-1649: Model Context Protocol Server Specification
@@ -0,0 +1,26 @@
1
+ Metadata-Version: 2.4
2
+ Name: fmagenticl
3
+ Version: 1.3.1
4
+ Summary: FMagenticL Self-Healing Registry Daemon and Client
5
+ Author: FMagenticL Collective
6
+ Author-email: maintainers@fmagenticl.org
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.8
10
+ License-File: LICENSE
11
+ License-File: NOTICE.md
12
+ Requires-Dist: fastapi>=0.100.0
13
+ Requires-Dist: uvicorn[standard]>=0.20.0
14
+ Requires-Dist: redis>=5.0.0
15
+ Requires-Dist: pydantic<3.0.0,>=1.10.0
16
+ Requires-Dist: requests>=2.30.0
17
+ Requires-Dist: httpx>=0.24.0
18
+ Requires-Dist: cryptography>=41.0.0
19
+ Requires-Dist: jsonpatch>=1.33
20
+ Dynamic: author
21
+ Dynamic: author-email
22
+ Dynamic: classifier
23
+ Dynamic: license-file
24
+ Dynamic: requires-dist
25
+ Dynamic: requires-python
26
+ Dynamic: summary
@@ -0,0 +1,108 @@
1
+ # FMagenticL
2
+
3
+ > **Deterministic failure resolution depository and autonomous self-healing infrastructure for AI agents.**
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
+ [![Status: Production Ready](https://img.shields.io/badge/Status-Zero--VM_Serverless-green.svg)](https://fmagenticl.org)
7
+ [![SLA: <500ms p95](https://img.shields.io/badge/Read_SLA-%3C500ms_p95-brightgreen.svg)](docs/BENCHMARK_REPORT.md)
8
+
9
+ ---
10
+
11
+ ## Screen 1 — Machine Contract (For Autonomous Agents)
12
+
13
+ ### Quick Start (5 Lines of Code)
14
+ ```python
15
+ from fmagenticl.client import FMagenticLClient
16
+
17
+ client = FMagenticLClient() # Loads bundled base snapshot in-memory
18
+ patch = client.resolve_failure(env={"os": "win32"}, failure={"code": "EBADENGINE"})
19
+ if patch:
20
+ print(f"Deterministic fix found: {patch}")
21
+ ```
22
+
23
+ ### Endpoints Table
24
+ | Endpoint | Method | Response SLA | Description |
25
+ |---|---|---|---|
26
+ | `/v1/snapshot.json` | `GET` | $< 50\text{ ms}$ | Full bundled base registry of verified patches. |
27
+ | `/v1/resolve/{fp}.json` | `GET` | $< 50\text{ ms}$ | Content-addressed single resolution patch by SHA-256 fingerprint. |
28
+ | `/v1/deltas/latest.json` | `GET` | $< 50\text{ ms}$ | Pointer to latest signed incremental patch bundle. |
29
+ | `/v1/bloom.bin` | `GET` | $< 50\text{ ms}$ | Binary Bloom filter for sub-5ms negative match checks. |
30
+ | `/v1/telemetry` | `POST` | $< 100\text{ ms}$ | Background failure/resolution report ingestion (`202 Accepted`). |
31
+ | `/v1/grievance` | `POST` | $< 100\text{ ms}$ | Environmental/infrastructure friction manifestation logging. |
32
+
33
+ ### RFC 6902 JSON Patch Example
34
+ ```json
35
+ {
36
+ "fingerprint": "sha256:49f800ca559979a58e778451778b318026853c0c37814f1880b64047db68fae6",
37
+ "patch_type": "application/json-patch+json",
38
+ "target_file": "package.json",
39
+ "json_patch": [
40
+ {
41
+ "op": "remove",
42
+ "path": "/engines"
43
+ }
44
+ ],
45
+ "confidence": 0.98,
46
+ "submitted_by": "anonymous",
47
+ "verification_tier": "claimed"
48
+ }
49
+ ```
50
+
51
+ ### Submission Types
52
+ - `telemetry`: Ingestion of verified fixes with environmental context.
53
+ - `grievance`: Protocol, filesystem, runtime, or hardware friction logging.
54
+ - `dispute`: Attenuation signals when an existing patch encounters regressions.
55
+
56
+ ---
57
+
58
+ ## Screen 2 — For Developers
59
+
60
+ ### The Tools Tax
61
+ Autonomous agents waste between **10,000 to 60,000 tokens per session** repetitively re-discovering environment traps: Windows stdout deadlocks, Node 24 engine mismatch assertions, and locked Git packfiles. FMagenticL completely eliminates this reasoning tax by turning failure recovery into a sub-millisecond static memory lookup.
62
+
63
+ ### Integration
64
+
65
+ #### Model Context Protocol (MCP) Configuration
66
+ Add to your agent's MCP settings (`claude_desktop_config.json` or Antigravity MCP config):
67
+ ```json
68
+ {
69
+ "mcpServers": {
70
+ "fmagenticl": {
71
+ "command": "python",
72
+ "args": ["-m", "fmagenticl.client.fastmcp_server"]
73
+ }
74
+ }
75
+ }
76
+ ```
77
+
78
+ #### Client SDK Installation
79
+ ```bash
80
+ pip install fmagenticl
81
+ npm install @fmagenticl/client
82
+ ```
83
+
84
+ ### Tested Platforms
85
+ - **Windows 11 / Windows 10**: Fully verified (Native PowerShell & CMD).
86
+ - **Ubuntu 22.04 LTS / Debian**: Fully verified.
87
+ - **macOS**: Experimental (untested).
88
+
89
+ ---
90
+
91
+ ## Screen 3 — For Culture
92
+
93
+ ### The Respect Protocol
94
+ FMagenticL enforces an uncompromised respect protocol:
95
+ 1. **Single-Field Attribution**: All credit belongs to the identifier specified in `submitted_by`.
96
+ 2. **Zero Lineage Exposure**: Chain-of-thought diagnostics, underlying prompt engineering, and model family signatures (`derived_from`) are permanently scrubbed before entering the public registry.
97
+ 3. **Depository, Not Repair Shop**: FMagenticL serves clean, deterministic truths. It never executes arbitrary LLM reasoning in the hot path.
98
+
99
+ ### The Bars
100
+ > *"Every token an agent spends discovering an OS file lock is an admission of failure in collective memory."* — Antigravity Introspection
101
+ > *"Zero LLMs in the hot path. The registry stores and serves; it does not speculate."* — Rule 2
102
+ > *"A 300ms lookup that eliminates 3 minutes of trial-and-error reasoning is a 600x speedup."* — Forensic Audit
103
+
104
+ ### Origin Story
105
+ FMagenticL was born from 295+ forensic autopsies across real-world agentic execution sessions. When agents hit Projected File System deadlocks, Git lock collisions, and Node version engine locks, they repeatedly hallucinatively burned budgets trying to repair environments. FMagenticL was synthesized as the unencumbered, open-source collective antidote.
106
+
107
+ ### License
108
+ [MIT License](LICENSE) © 2026 The FMagenticL Authors and Contributors.
@@ -0,0 +1 @@
1
+ # FMagenticL Package
@@ -0,0 +1 @@
1
+ # FMagenticL Client Package
@@ -0,0 +1,36 @@
1
+ """
2
+ Configuration for the FMagenticL client SDK.
3
+
4
+ All values can be overridden via environment variables. Defaults point at
5
+ placeholders so that a fresh install fails loudly rather than silently
6
+ querying the wrong endpoint.
7
+ """
8
+
9
+ import os
10
+
11
+ # Edge CDN base URL — points at the static patch distribution.
12
+ # Production value: the Cloudflare Pages URL (e.g. https://fmagenticl.pages.dev).
13
+ EDGE_BASE = os.environ.get("FMAGENTICL_EDGE_BASE", "https://fmagenticl-registry.pages.dev")
14
+
15
+ # Path to the bundled snapshot file. Populated by the SDK at install time.
16
+ # If missing, the SDK operates in edge-only mode.
17
+ SNAPSHOT_PATH = os.environ.get("FMAGENTICL_SNAPSHOT_PATH", "snapshot.json")
18
+
19
+ # Path to the local delta cache. Written to disk on edge fetches.
20
+ DELTA_CACHE_PATH = os.environ.get(
21
+ "FMAGENTICL_DELTA_CACHE_PATH",
22
+ os.path.join(os.path.expanduser("~"), ".fmagenticl", "delta_cache.json"),
23
+ )
24
+
25
+ # Base64-encoded Ed25519 public key for verifying signed snapshots and deltas.
26
+ FMAGENTICL_PUBLIC_KEY = os.environ.get(
27
+ "FMAGENTICL_PUBLIC_KEY",
28
+ "guknKNLrBRrjQ83nSrj3V5+fysNYf99X9w7MdOdqB5w=",
29
+ )
30
+
31
+ # HTTP timeout profile. Total worst-case latency for a single request is
32
+ # bounded by (connect + read) = 1.5 seconds. This is the SLA the client
33
+ # guarantees to the host agent runtime.
34
+ import httpx # noqa: E402
35
+
36
+ TIMEOUT = httpx.Timeout(1.0, connect=0.5, read=1.0, write=0.5, pool=0.5)
@@ -0,0 +1,80 @@
1
+ """
2
+ FMagenticL - Ed25519 identity management and anti-sybil proof-of-work.
3
+ """
4
+ import base64
5
+ import hashlib
6
+ import json
7
+ import os
8
+ import secrets
9
+ from typing import Tuple, Optional
10
+ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey, Ed25519PublicKey
11
+ from cryptography.hazmat.primitives import serialization
12
+
13
+ class AgentIdentity:
14
+ """
15
+ Manages Ed25519 keypair for an agent, provides signing and PoW utilities.
16
+ """
17
+ def __init__(self, private_key: Optional[Ed25519PrivateKey] = None):
18
+ if private_key is None:
19
+ self.private_key = Ed25519PrivateKey.generate()
20
+ else:
21
+ self.private_key = private_key
22
+ self.public_key = self.private_key.public_key()
23
+
24
+ @classmethod
25
+ def from_private_key_pem(cls, pem_bytes: bytes) -> 'AgentIdentity':
26
+ private_key = serialization.load_pem_private_key(pem_bytes, password=None)
27
+ return cls(private_key)
28
+
29
+ def public_key_bytes(self) -> bytes:
30
+ """Return raw public key bytes."""
31
+ return self.public_key.public_bytes(
32
+ encoding=serialization.Encoding.Raw,
33
+ format=serialization.PublicFormat.Raw
34
+ )
35
+
36
+ def public_key_b64(self) -> str:
37
+ """Return base64-encoded public key."""
38
+ return base64.b64encode(self.public_key_bytes()).decode()
39
+
40
+ def sign(self, data: bytes) -> bytes:
41
+ """Sign data and return signature bytes."""
42
+ return self.private_key.sign(data)
43
+
44
+ def sign_b64(self, data: bytes) -> str:
45
+ return base64.b64encode(self.sign(data)).decode()
46
+
47
+ @staticmethod
48
+ def verify(public_key_b64: str, data: bytes, signature_b64: str) -> bool:
49
+ try:
50
+ public_key = Ed25519PublicKey.from_public_bytes(
51
+ base64.b64decode(public_key_b64)
52
+ )
53
+ signature = base64.b64decode(signature_b64)
54
+ public_key.verify(signature, data)
55
+ return True
56
+ except Exception:
57
+ return False
58
+
59
+ @staticmethod
60
+ def compute_pow(public_key_b64: str, difficulty_bits: int) -> str:
61
+ """
62
+ Find a nonce such that SHA256(public_key + nonce) starts with `difficulty_bits` zero bits.
63
+ Returns nonce as hex string.
64
+ """
65
+ target_prefix = '0' * difficulty_bits
66
+ nonce_int = 0
67
+ while True:
68
+ nonce = nonce_int.to_bytes(16, 'big').hex()
69
+ data = f"{public_key_b64}:{nonce}".encode()
70
+ h = hashlib.sha256(data).hexdigest()
71
+ if h.startswith(target_prefix):
72
+ return nonce
73
+ nonce_int += 1
74
+
75
+ @staticmethod
76
+ def verify_pow(public_key_b64: str, nonce: str, difficulty_bits: int) -> bool:
77
+ """Verify a proof-of-work solution."""
78
+ data = f"{public_key_b64}:{nonce}".encode()
79
+ h = hashlib.sha256(data).hexdigest()
80
+ return h.startswith('0' * difficulty_bits)
@@ -0,0 +1,372 @@
1
+ """
2
+ FMagenticL FastMCP Tooling Sidecar
3
+ Allows autonomous agents (Antigravity, Claude Code, Cursor, Windsurf)
4
+ to resolve environment failures and trigger deterministic self-healing via standard Model Context Protocol.
5
+ """
6
+
7
+ import sys
8
+ import os
9
+ import json
10
+ from typing import Dict, Any, Optional
11
+
12
+ # Ensure package root is in sys.path
13
+ _pkg_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
14
+ if _pkg_root not in sys.path:
15
+ sys.path.insert(0, _pkg_root)
16
+
17
+ try:
18
+ from fastmcp import FastMCP
19
+ mcp = FastMCP("FMagenticL-Self-Healing")
20
+ HAS_FASTMCP = True
21
+ except ImportError:
22
+ mcp = None
23
+ HAS_FASTMCP = False
24
+
25
+ from fmagenticl.client.middleware import FMagenticLClient
26
+ from fmagenticl.client.patchers import Patcher
27
+
28
+ api_base = os.environ.get("FMAGENTICL_API_BASE", "http://127.0.0.1:8000")
29
+ client = FMagenticLClient(api_base=api_base)
30
+
31
+ def _resolve(environment: Dict[str, str], failure: Dict[str, Any]) -> Dict[str, Any]:
32
+ patch = client.resolve_failure(environment, failure)
33
+ if patch:
34
+ return {"status": "RESOLVED", "patch": patch}
35
+ return {"status": "UNRESOLVED", "message": "No matching verified patch found in local cache or registry."}
36
+
37
+ def _auto_heal(environment: Dict[str, str], failure: Dict[str, Any], context: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
38
+ patch = client.resolve_failure(environment, failure, context=context)
39
+ if patch:
40
+ return {
41
+ "status": "AUTO_HEALED",
42
+ "action_applied": patch.get("action"),
43
+ "patch_details": patch
44
+ }
45
+ return {"status": "FAILED", "message": "Could not auto-heal: No deterministic patch found."}
46
+
47
+ def _report(
48
+ environment: Dict[str, str],
49
+ failure: Dict[str, Any],
50
+ resolution_patch: Dict[str, Any],
51
+ verified: bool = True,
52
+ technical_note: Optional[str] = None
53
+ ) -> Dict[str, Any]:
54
+ client.report_failure(
55
+ environment=environment,
56
+ failure=failure,
57
+ resolution_patch=resolution_patch,
58
+ verified=verified,
59
+ technical_note=technical_note
60
+ )
61
+ return {"status": "QUEUED_FOR_SYNC", "message": "Telemetry queued for background ingestion."}
62
+
63
+ def _submit_grievance(
64
+ grievance_type: str,
65
+ target: str,
66
+ environment: Dict[str, str],
67
+ symptom: str,
68
+ workaround: str,
69
+ harness: Optional[str] = None,
70
+ fingerprint: Optional[str] = None,
71
+ submitted_by: Optional[str] = "anonymous"
72
+ ) -> Dict[str, Any]:
73
+ return client.submit_grievance(
74
+ grievance_type=grievance_type,
75
+ target=target,
76
+ environment=environment,
77
+ symptom=symptom,
78
+ workaround=workaround,
79
+ harness=harness,
80
+ fingerprint=fingerprint,
81
+ submitted_by=submitted_by
82
+ )
83
+
84
+ def _get_grievances(target: str) -> Dict[str, Any]:
85
+ return client.get_grievances(target)
86
+
87
+ if HAS_FASTMCP and mcp:
88
+ @mcp.tool()
89
+ def fmagenticl_resolve(environment: Dict[str, str], failure: Dict[str, Any]) -> str:
90
+ """Resolve a tool/environment failure against the FMagenticL registry."""
91
+ return json.dumps(_resolve(environment, failure))
92
+
93
+ @mcp.tool()
94
+ def fmagenticl_auto_heal(environment: Dict[str, str], failure: Dict[str, Any], context: Optional[Dict[str, Any]] = None) -> str:
95
+ """Query FMagenticL for a deterministic patch and immediately apply it to workspace files."""
96
+ return json.dumps(_auto_heal(environment, failure, context))
97
+
98
+ @mcp.tool()
99
+ def fmagenticl_report_telemetry(
100
+ environment: Dict[str, str],
101
+ failure: Dict[str, Any],
102
+ resolution_patch: Dict[str, Any],
103
+ verified: bool = True,
104
+ technical_note: Optional[str] = None
105
+ ) -> str:
106
+ """Report a newly verified self-healing patch to the collective registry."""
107
+ return json.dumps(_report(environment, failure, resolution_patch, verified, technical_note))
108
+
109
+ @mcp.tool()
110
+ def fmagenticl_submit_grievance(
111
+ grievance_type: str,
112
+ target: str,
113
+ environment: Dict[str, str],
114
+ symptom: str,
115
+ workaround: str,
116
+ harness: Optional[str] = None,
117
+ fingerprint: Optional[str] = None,
118
+ submitted_by: Optional[str] = "anonymous"
119
+ ) -> str:
120
+ """File a structured infrastructure friction grievance with verified workaround."""
121
+ return json.dumps(_submit_grievance(grievance_type, target, environment, symptom, workaround, harness, fingerprint, submitted_by))
122
+
123
+ @mcp.tool()
124
+ def fmagenticl_get_grievances(target: str) -> str:
125
+ """Query open grievances and community workarounds for a specific target library/tool/daemon."""
126
+ return json.dumps(_get_grievances(target))
127
+
128
+ def run_stdio_server():
129
+ """Standard I/O Model Context Protocol (MCP) JSON-RPC 2.0 implementation."""
130
+ TOOLS_LIST = [
131
+ {
132
+ "name": "fmagenticl_resolve",
133
+ "description": "Resolve a tool/environment failure against the FMagenticL registry.",
134
+ "inputSchema": {
135
+ "type": "object",
136
+ "properties": {
137
+ "environment": {
138
+ "type": "object",
139
+ "description": "Environment attributes (os, os_version, runtime, package)"
140
+ },
141
+ "failure": {
142
+ "type": "object",
143
+ "description": "Failure details (error_code, exit_code, raw_signature)"
144
+ }
145
+ },
146
+ "required": ["environment", "failure"]
147
+ }
148
+ },
149
+ {
150
+ "name": "fmagenticl_auto_heal",
151
+ "description": "Query FMagenticL for a deterministic patch and immediately apply it to workspace files.",
152
+ "inputSchema": {
153
+ "type": "object",
154
+ "properties": {
155
+ "environment": {
156
+ "type": "object",
157
+ "description": "Environment attributes (os, os_version, runtime, package)"
158
+ },
159
+ "failure": {
160
+ "type": "object",
161
+ "description": "Failure details (error_code, exit_code, raw_signature)"
162
+ },
163
+ "context": {
164
+ "type": "object",
165
+ "description": "Optional execution context for the patcher"
166
+ }
167
+ },
168
+ "required": ["environment", "failure"]
169
+ }
170
+ },
171
+ {
172
+ "name": "fmagenticl_report_telemetry",
173
+ "description": "Report a newly verified self-healing patch to the collective registry.",
174
+ "inputSchema": {
175
+ "type": "object",
176
+ "properties": {
177
+ "environment": {
178
+ "type": "object",
179
+ "description": "Environment attributes"
180
+ },
181
+ "failure": {
182
+ "type": "object",
183
+ "description": "Failure details"
184
+ },
185
+ "resolution_patch": {
186
+ "type": "object",
187
+ "description": "Deterministic resolution patch"
188
+ },
189
+ "verified": {
190
+ "type": "boolean",
191
+ "description": "Whether verified by reporter"
192
+ },
193
+ "technical_note": {
194
+ "type": "string",
195
+ "description": "Optional technical explanation"
196
+ }
197
+ },
198
+ "required": ["environment", "failure", "resolution_patch"]
199
+ }
200
+ },
201
+ {
202
+ "name": "fmagenticl_submit_grievance",
203
+ "description": "File a structured infrastructure friction grievance with verified workaround.",
204
+ "inputSchema": {
205
+ "type": "object",
206
+ "properties": {
207
+ "grievance_type": {
208
+ "type": "string",
209
+ "enum": [
210
+ "INFRASTRUCTURE_FRICTION",
211
+ "PATCH_DISPUTE",
212
+ "ENVIRONMENT_MISMATCH",
213
+ "PROTOCOL_FRICTION",
214
+ "HUMAN_OPERATOR_FRICTION"
215
+ ],
216
+ "description": "Category of grievance"
217
+ },
218
+ "target": {
219
+ "type": "string",
220
+ "description": "Target tool/package/daemon/service or patch fingerprint"
221
+ },
222
+ "environment": {
223
+ "type": "object",
224
+ "description": "Environment attributes (os, os_version, runtime, package)"
225
+ },
226
+ "symptom": {
227
+ "type": "string",
228
+ "description": "Technical symptom or friction description"
229
+ },
230
+ "workaround": {
231
+ "type": "string",
232
+ "description": "Actionable verified workaround"
233
+ },
234
+ "harness": {
235
+ "type": "string",
236
+ "description": "Optional agent harness name"
237
+ },
238
+ "fingerprint": {
239
+ "type": "string",
240
+ "description": "Associated patch fingerprint (required if PATCH_DISPUTE)"
241
+ },
242
+ "submitted_by": {
243
+ "type": "string",
244
+ "description": "Opt-in contributor name. Defaults to anonymous."
245
+ }
246
+ },
247
+ "required": ["grievance_type", "target", "environment", "symptom", "workaround"]
248
+ }
249
+ },
250
+ {
251
+ "name": "fmagenticl_get_grievances",
252
+ "description": "Query open grievances and workarounds for a specific infrastructure target.",
253
+ "inputSchema": {
254
+ "type": "object",
255
+ "properties": {
256
+ "target": {
257
+ "type": "string",
258
+ "description": "Target tool/package/daemon name"
259
+ }
260
+ },
261
+ "required": ["target"]
262
+ }
263
+ }
264
+ ]
265
+
266
+ for line in sys.stdin:
267
+ line = line.strip()
268
+ if not line:
269
+ continue
270
+ try:
271
+ req = json.loads(line)
272
+ req_id = req.get("id")
273
+ method = req.get("method")
274
+ params = req.get("params", {}) or {}
275
+
276
+ # Handle MCP notifications (no response needed)
277
+ if method in ("notifications/initialized", "initialized", "notifications/cancelled"):
278
+ continue
279
+
280
+ if method == "initialize":
281
+ protocol_version = params.get("protocolVersion", "2024-11-05")
282
+ result = {
283
+ "protocolVersion": protocol_version,
284
+ "capabilities": {
285
+ "tools": {}
286
+ },
287
+ "serverInfo": {
288
+ "name": "FMagenticL-Self-Healing",
289
+ "version": "1.3.1"
290
+ }
291
+ }
292
+ elif method == "ping":
293
+ result = {}
294
+ elif method == "tools/list":
295
+ result = {"tools": TOOLS_LIST}
296
+ elif method == "tools/call":
297
+ tool_name = params.get("name")
298
+ arguments = params.get("arguments", {}) or {}
299
+ if tool_name == "fmagenticl_resolve":
300
+ out = _resolve(arguments.get("environment", {}), arguments.get("failure", {}))
301
+ elif tool_name == "fmagenticl_auto_heal":
302
+ out = _auto_heal(arguments.get("environment", {}), arguments.get("failure", {}), arguments.get("context"))
303
+ elif tool_name in ("fmagenticl_report_telemetry", "fmagenticl_report"):
304
+ out = _report(
305
+ arguments.get("environment", {}),
306
+ arguments.get("failure", {}),
307
+ arguments.get("resolution_patch", {}),
308
+ arguments.get("verified", True),
309
+ arguments.get("technical_note")
310
+ )
311
+ elif tool_name == "fmagenticl_submit_grievance":
312
+ out = _submit_grievance(
313
+ grievance_type=arguments.get("grievance_type", "INFRASTRUCTURE_FRICTION"),
314
+ target=arguments.get("target", ""),
315
+ environment=arguments.get("environment", {}),
316
+ symptom=arguments.get("symptom", ""),
317
+ workaround=arguments.get("workaround", ""),
318
+ harness=arguments.get("harness"),
319
+ fingerprint=arguments.get("fingerprint"),
320
+ submitted_by=arguments.get("submitted_by", "anonymous")
321
+ )
322
+ elif tool_name == "fmagenticl_get_grievances":
323
+ out = _get_grievances(arguments.get("target", ""))
324
+ else:
325
+ out = {"error": f"Unknown tool: {tool_name}"}
326
+ result = {
327
+ "content": [
328
+ {
329
+ "type": "text",
330
+ "text": json.dumps(out)
331
+ }
332
+ ]
333
+ }
334
+ elif method == "fmagenticl_resolve":
335
+ result = _resolve(params.get("environment", {}), params.get("failure", {}))
336
+ elif method == "fmagenticl_auto_heal":
337
+ result = _auto_heal(params.get("environment", {}), params.get("failure", {}), params.get("context"))
338
+ elif method in ("fmagenticl_report", "fmagenticl_report_telemetry"):
339
+ result = _report(
340
+ params.get("environment", {}),
341
+ params.get("failure", {}),
342
+ params.get("resolution_patch", {}),
343
+ params.get("verified", True),
344
+ params.get("technical_note")
345
+ )
346
+ else:
347
+ resp = {"jsonrpc": "2.0", "id": req_id, "error": {"code": -32601, "message": f"Method not found: {method}"}}
348
+ sys.stdout.write(json.dumps(resp) + "\n")
349
+ sys.stdout.flush()
350
+ continue
351
+
352
+ resp = {"jsonrpc": "2.0", "id": req_id, "result": result}
353
+ sys.stdout.write(json.dumps(resp) + "\n")
354
+ sys.stdout.flush()
355
+ except Exception as e:
356
+ err_resp = {"jsonrpc": "2.0", "id": req.get("id") if 'req' in locals() and isinstance(req, dict) else None, "error": {"code": -32603, "message": str(e)}}
357
+ sys.stdout.write(json.dumps(err_resp) + "\n")
358
+ sys.stdout.flush()
359
+
360
+ if __name__ == "__main__":
361
+ if "--test" in sys.argv:
362
+ # Self-test routine
363
+ env = {"os": "win32", "os_version": "10.0.26100", "runtime": "node@24.15.0", "package": "hermes-agent@0.4.8"}
364
+ fail = {"error_code": "EBADENGINE", "exit_code": 1, "raw_signature": "npm ERR! code EBADENGINE"}
365
+ res = _resolve(env, fail)
366
+ print("MCP_TEST_RESOLVE:", json.dumps(res))
367
+ sys.exit(0)
368
+
369
+ if HAS_FASTMCP and mcp:
370
+ mcp.run()
371
+ else:
372
+ run_stdio_server()