Using the API
Everything the app's own UI can do is also reachable over three transports, all backed by the exact same
MaslowService Rust methods:
- gRPC -
MachineService,JobService,ConfigService,FilesService,CalibrationService, defined inproto/maslow/v1/*.proto. - HTTP/JSON - a REST-ish gateway over the same operations, following an AIP-136-style
convention (a
:verbsuffix on the resource path for actions that aren't plain CRUD, e.g.POST /v1/machines/default:jog). - MCP - a Model Context Protocol server so an LLM can call the same operations as tools,
mounted at
/mcpon the HTTP gateway.
None of the three are reachable until you enable the API and generate a key.
Enabling the API
Both servers are off by default. In the app's Config → Settings tab:
- Toggle the API on.
- Click Generate key (or Regenerate key) to get a plaintext API key. This is the only time the plaintext key is ever shown: only its SHA-256 hash is persisted to disk, so store the key somewhere safe.
- Note the ports shown: HTTP defaults to
8642, gRPC to50051. Both servers bind to127.0.0.1only (loopback), not to your LAN interface.
Toggling the API or regenerating the key takes effect immediately: the running servers are restarted in place, no app restart required.
Authenticating requests
Every request on every transport needs the same bearer token:
Authorization: Bearer <your-api-key>
- HTTP: an
Authorization: Bearer <key>header, checked by an axum middleware in front of every route (including/mcp). - gRPC: an
authorizationmetadata entry of the formBearer <key>, checked by a per-service tonic interceptor. - MCP: MCP requests ride the same axum router as the HTTP gateway (mounted at
/mcp), so they go through the identicalAuthorization: Bearer <key>header check; there is no separate MCP-specific auth path.
A request with a missing or invalid key gets 401 Unauthorized (HTTP) or UNAUTHENTICATED (gRPC). The check is
against the current live settings on every request, not a value cached at server startup, so a key you just
regenerated (or an API you just disabled) takes effect on the very next request.
Connecting an MCP client
The MCP server speaks the Streamable HTTP transport at:
http://127.0.0.1:8642/mcp
(the same host/port as the HTTP gateway, since it's mounted on that router - not a separate port). Most MCP clients that support remote/HTTP servers take a URL plus custom headers.
Claude Code
claude mcp add --transport http maslow-desktop http://127.0.0.1:8642/mcp \
--header "Authorization: Bearer <your-api-key>"
Other clients (Claude Desktop and similar mcpServers-config clients)
{
"mcpServers": {
"maslow-desktop": {
"type": "http",
"url": "http://127.0.0.1:8642/mcp",
"headers": {
"Authorization": "Bearer <your-api-key>"
}
}
}
}
Substitute the API key you generated on the Settings tab. If the client only accepts a bare command-line MCP server (stdio-based) rather than a URL, it can't reach this server: this app's MCP server is HTTP-only, by design, so it can share the same enable toggle and API key as the rest of the control API (see Using the API above) rather than needing its own separate auth story.
Example
curl -H "Authorization: Bearer $MASLOW_API_KEY" http://127.0.0.1:8642/v1/machines/default:snapshot
See the HTTP, gRPC, and MCP reference pages for the full set of operations, request/response shapes, and (for MCP) tool parameter schemas.