docs: serve a model in "Your own mesh", cover the three service types - #447
Conversation
The walkthrough declared a static file server as `type: mcp` and fetched it through the raw proxy path, teaching the mesh as an HTTP passthrough. The type is a contract: the node verifies the backend speaks the declared protocol (model list, MCP initialize, agent card) before advertising it. - your-own-mesh: publish Ollama as an inference service and call it with curl from the second node's /v1 endpoint; add a section on MCP and A2A that links to their guides and use cases. - quickstart: note the three types and list the testnet's models. - node-api: curl examples for inference and the A2A card, next to MCP's. - sandboxed-agents: the boundary resolves <service>.<type>.sam.alt for every type, not only mcp. standalone.bats mirrored the old passthrough example. It now serves a fake OpenAI backend as inference across the dataplane and asserts that the same server mislabelled as mcp is never advertised.
There was a problem hiding this comment.
Code Review
This pull request updates the documentation and end-to-end tests to transition from a generic HTTP smoke service to an OpenAI-compatible inference service type, utilizing a new fake_openai.py mock backend. It also documents the a2a and mcp service types. Feedback is provided on the mock server's request parsing logic to prevent potential crashes or hangs from malformed requests.
| length = int(self.headers.get("Content-Length") or 0) | ||
| try: | ||
| req = json.loads(self.rfile.read(length) or b"{}") | ||
| except ValueError: | ||
| req = {} |
There was a problem hiding this comment.
Parsing Content-Length directly using int(self.headers.get("Content-Length") or 0) can raise a ValueError if the header is present but invalid (e.g., contains non-numeric characters). Additionally, if a negative value is supplied, self.rfile.read() will block indefinitely waiting for EOF. Finally, if the request body is not a JSON object (e.g., a list or a primitive), req.get will raise an AttributeError and crash the handler.\n\nUsing a robust try-except block with max(0, ...) and validating that req is a dictionary ensures the server does not crash or hang due to malformed requests.
try:\n length = max(0, int(self.headers.get("Content-Length", 0)))\n except ValueError:\n length = 0\n try:\n req = json.loads(self.rfile.read(length) or b"{}")\n except ValueError:\n req = {}\n if not isinstance(req, dict):\n req = {}
What
The "Your own mesh" walkthrough declared a static file server as
type: mcpand fetched it through the raw proxy path, which taught the mesh as a generic HTTP passthrough. The type is a contract: the node verifies that the backend speaks the declared protocol (model list, MCPinitialize, agent card) before advertising it, and the docs should say so and show a real service.inferenceservice; node B calls it withcurlover its socket (/v1/models, then/v1/chat/completions). The section explains what the node checks for each type and why a plain web server is never advertised. A new "MCP servers and A2A agents" section shows the other two declarations and links to the quick start's MCP call, Exposing services, A2A chat (feat(node): add A2A support #347) and Gemini Buddy.mcp-clientis no longer a prerequisite for this page.curl --unix-socket … /v1/models.curlexamples for inference and for fetching an A2A card through the proxy path, next to the existing MCP one.<service>.mcp.sam.alt;ParseMeshHost/dialMeshServiceare type-generic, so it now reads<service>.<type>.sam.altformcp,inferenceanda2a.Testing
tests/e2e/standalone.batsmirrored the old passthrough example (python3 -m http.serverdeclared asmcp, fetched via/sam/<peer>/mcp/smoke/hello.txt). It now follows the doc: a stdlib fake OpenAI backend (tests/e2e/fixtures/fake_openai.py) declared asinferenceon node A, asserted through node B's/v1/models(owner is A's peer ID) and/v1/chat/completions. The same server is also declared astype: mcp; the test asserts the node logsnot advertising itand that B's discovery never lists it, so the type contract cannot regress silently.Passes locally in ~6.5s. Ollama itself is not installed here, so the
gemma3:1bsteps were checked against the code path (/v1/modelson the backend root) and the e2e rather than a live Ollama.