Module Service Protocol
Version 1.0
This document outlines the Protocol specification for creating service that implements the Module Service Protocol, compatible with SynthGrid. SynthGrid will connect to your service, but your module remains entirely your own IP and is completely independent on SynthGrid. MindFront never needs to view, introspect or have access to your code or logic.
Your service must implement two main components: a metadata endpoint and one or more action endpoints.
High-level MSP overview
flowchart LR subgraph YM["Your Module Service"] direction LR meta["/meta"] action1["/action1"] action2["/action2"] end SynthGrid --Reads--> meta SynthGrid --Calls--> action1 action1 --> YI["Your Data/Services"]
Module Service Protocol Sequence
sequenceDiagram participant SG as SynthGrid participant CM as Custom Module Note over SG,CM: Module Registration SG->>CM: Request module metadata CM-->>SG: Provide metadata (actions, schemas) Note over SG: Register and setup module Note over SG,CM: Action Execution SG->>CM: Call specific action activate CM Note over CM: Execute action CM-->>SG: Return action result deactivate CM Note over SG: Process result
Protocol Version
The current version of this Protocol specification is 1.0.
Base URL
You may choose any base URL for your service. The endpoints described below should be appended to your chosen base URL. We highly encourage HTTPS, CORS restrictions and strong TLS settings.
Meta Endpoint
Request
- URL:
/meta
- Method:
GET
Response
The response must be a JSON object with the following structure:
{
"protocolVersion": 1,
"moduleVersion": "x.y.z",
"moduleName": "string",
"description": "string",
"actions": [
{
"name": "string",
"description": "string",
"route": "string",
"riskLevel": "safe" | "machineApprovalRequired" | "humanApprovalRequired" | "forbidden",
"input": {
// JSON Schema for input
},
"output": {
// JSON Schema for output
}
}
]
}
Field | Description |
---|---|
protocolVersion |
The MSP version your module implements. |
moduleVersion |
The version of YOUR module (following semantic versioning: MAJOR.MINOR.PATCH). |
moduleName |
A unique name for your module. |
description |
A brief description of what your module does. |
actions |
An array of action objects, each describing an action your module can perform. |
Action Schema
Each action in a SynthGrid third-party module is defined by the following schema:
Field | Description |
---|---|
name |
Unique identifier for the action within the module. |
description |
Brief explanation of the action’s purpose. |
route |
API endpoint for invoking this action. |
riskLevel |
Indicates the action’s risk level and required approval process. |
input |
JSON schema defining the expected input parameters. |
output |
JSON schema defining the structure of the action’s response. |
Risk Levels
The riskLevel
field can have one of four values:
Number | Risk Level | Description |
---|---|---|
1 | "safe" |
No significant risk. Executed immediately without additional checks. |
2 | "machineApprovalRequired" |
Potential risk, requires automated verification before execution. |
3 | "humanApprovalRequired" |
High-risk, requires human review and approval before execution. |
4 | "forbidden" |
Not allowed to be executed under any circumstances. Immediately rejected. |
Action Endpoints
For each action defined in your metadata, you must implement a corresponding endpoint.
Request
- URL: The route specified in the action’s metadata (e.g.,
/action/yourActionName
) - Method: POST
- Body: JSON object matching the input schema defined in the action’s metadata
Response
The response must be a JSON object with the following structure:
{
"status": "success" | "failure" | "invalidInput",
"data": {
// Action-specific output as per the schema (for success)
},
"error": {
"message": "string" // For failure or invalidInput
}
}
status
: Must be one of “success”, “failure”, or “invalidInput”.data
: Present only when status is “success”. Structure must match the output schema defined in the action’s metadata.error
: Present only when status is “failure” or “invalidInput”. Contains an error message explaining what went wrong.
Implementation Notes
- All endpoints must use HTTPS in production environments.
- Your module should handle errors gracefully and return appropriate status codes and error messages.
- Input and output schemas should be kept as simple as possible. Avoid complex nested structures or conditional logic.
- Ensure your module can handle concurrent requests if necessary.
Example
Here’s a minimal example of a metadata response for a module that provides random commit messages:
{
"protocolVersion": 1,
"moduleVersion": "1.0.0",
"moduleName": "RandomCommitMessage",
"description": "Provides random commit messages from whatthecommit.com",
"actions": [
{
"name": "getRandomCommitMessage",
"description": "Retrieves a random commit message",
"riskLevel": "machineApprovalRequired",
"route": "/action/getRandomCommitMessage",
"input": {
"type": "object",
"properties": {}
},
"output": {
"type": "object",
"properties": {
"message": {"type": "string"}
},
"required": ["message"]
}
}
]
}
How the Risk Evaluation Works
flowchart TB A[Start: Action Request] --> B{Check riskLevel} B -->|safe| C[Execute Action] B -->|machineApprovalRequired| D{Automated Check} B -->|humanApprovalRequired| E{Human Review} B -->|forbidden| F[Reject Action] D -->|Pass| C D -->|Fail| F E -->|Approved| C E -->|Rejected| F C --> G[Return Result] F --> H[Return Error] G --> I[End] H --> I
Example MSP Service
This is a super simple example service that implements the Module Service Protocol that should run/execute on almost any system with zero dependencies.
Save it to a file called example.py
.
Then to run it:
chmod +x example.py
./example.py
#!/usr/bin/env python3
import json
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.request import urlopen
MODULE_METADATA = {
"protocolVersion": 1,
"moduleVersion": "1.0.0",
"moduleName": "RandomCommitMessage",
"description": "Provides random commit messages from whatthecommit.com",
"actions": [
{
"name": "getRandomCommitMessage",
"description": "Retrieves a random commit message",
"route": "/action/getRandomCommitMessage",
"riskLevel": "machineApprovalRequired",
"input": {"type": "object", "properties": {}},
"output": {"type": "object", "properties": {"message": {"type": "string"}}, "required": ["message"]},
}
],
}
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == "/meta":
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
self.wfile.write(json.dumps(MODULE_METADATA).encode())
else:
self.send_error(404)
def do_POST(self):
if self.path == "/action/getRandomCommitMessage":
try:
content_length = int(self.headers["Content-Length"])
post_data = self.rfile.read(content_length)
json.loads(post_data.decode("utf-8")) # Validate JSON
with urlopen("http://whatthecommit.com/index.txt") as response:
commit_message = response.read().decode("utf-8").strip()
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
self.wfile.write(json.dumps({"status": "success", "data": {"message": commit_message}}).encode())
except Exception as e:
self.send_response(500)
self.send_header("Content-type", "application/json")
self.end_headers()
self.wfile.write(json.dumps({"status": "failure", "error": {"message": str(e)}}).encode())
else:
self.send_error(404)
if __name__ == "__main__":
HTTPServer(("", 9876), Handler).serve_forever()
You can check this is working by:
curl -X POST "localhost:9876/action/getRandomCommitMessage" -d '{}'
or
curl "http://127.0.0.1:9876/meta"