Download m3d/module.py from jkorstad/m3d-core: direct link, hf CLI and curl.
- Browser
- Download file 1.84 kB
-
https://huggingface.co/jkorstad/m3d-core/resolve/main/m3d/module.py
- Command line
-
hf download hf://jkorstad/m3d-core/m3d/module.py
-
curl -L -o module.py https://huggingface.co/jkorstad/m3d-core/resolve/main/m3d/module.py
1.84 kB
| """M3D module SDK. | |
| A module = a module.json manifest + an MCP server exposing the same tools | |
| in-process (used by the DAG runner) and over stdio/HTTP (used by external | |
| agents and agentic harnesses). One class, one interface, every runtime. | |
| Built on MCP Python SDK v2 (pip install mcp==2.2.0): | |
| from mcp.server import MCPServer; @mcp.tool() registers a typed tool. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| from typing import Any | |
| from mcp.server import MCPServer | |
| class M3DModule: | |
| def __init__(self, manifest: dict): | |
| assert "id" in manifest and "version" in manifest, "manifest needs id + version" | |
| assert "license" in manifest, "every M3D module declares its license graph" | |
| self.manifest = manifest | |
| self.server = MCPServer(manifest["id"]) | |
| self._tools: dict[str, Any] = {} | |
| def tool(self, name: str | None = None): | |
| """Register a typed function as both an M3D tool and an MCP tool.""" | |
| def deco(fn): | |
| tool_name = name or fn.__name__ | |
| self._tools[tool_name] = fn | |
| self.server.add_tool(fn, name=tool_name) # MCP v2 registration | |
| return fn | |
| return deco | |
| def run_tool(self, name: str, args: dict) -> Any: | |
| """Direct in-process call used by the DAG runner (isolation principle).""" | |
| if name not in self._tools: | |
| raise KeyError( | |
| f"module {self.manifest['id']} has no tool {name!r}; " | |
| f"available: {sorted(self._tools)}" | |
| ) | |
| return self._tools[name](**args) | |
| def serve(self, transport: str = "stdio") -> None: | |
| """Serve over MCP — stdio/sse/streamable-http, any agentic harness can attach.""" | |
| self.server.run(transport=transport) | |
| def manifest_json(self) -> str: | |
| return json.dumps(self.manifest, indent=2) |