Documentation
¶
Overview ¶
Package mcp is Atlas's Model Context Protocol server: it lets an AI agent drive a running Atlas server through tools — deploy a BPMN model, manage design-time projects and artifacts, start an instance, complete human tasks, and inspect live runtime state.
Shape: an adapter over the HTTP API, on two transports ¶
The server speaks JSON-RPC 2.0 and translates each tool call into an HTTP request against a running Atlas server; it holds no engine state of its own. Two transports share one dispatch path:
- stdio (Serve) — newline-delimited JSON, one message per line. This is the MCP stdio transport a local client (Claude Desktop, Claude Code) spawns.
- Streamable HTTP (ServeHTTP) — the remote transport. Mount it at a path such as /mcp and a remote client can reach the same tools. Mounted through api.WithMCP it sits inside the Atlas server's own access boundary, so under --auth a request without a credential is refused there; the transport then forwards whatever authenticated the caller to the API, so a tool call is exactly as privileged as whoever made it and no more (ADR-0196).
This is deliberate. The engine is a single-writer partition (invariant I3): exactly one goroutine may touch a partition's processor and state, a discipline the api package already enforces behind its HTTP surface. By proxying to that surface rather than embedding the engine, the MCP server can never violate an engine invariant — it only ever makes HTTP calls. It is a pure adapter, and an AI agent sees the same deployments and instances a human sees in the web UI.
Project deletion ¶
A design-time project is a grouping folder, not an execution aggregate (ADR-0034). atlas_delete_project therefore calls the public project DELETE endpoint and removes only that folder. Drafts and decision references tagged with its id remain available as ungrouped artifacts; deployed definitions and process instances are unaffected. The API operation is idempotent and enforces the project owner role when authentication is enabled.
No new dependencies ¶
The protocol is implemented by hand (see server.go), matching the repository's preference for small, self-contained code over pulled-in SDKs. The only surface area is the four MCP methods a tools-only server needs: initialize, tools/list, tools/call, and ping.
Running it ¶
Remote (Streamable HTTP) — atlas serve mounts the transport at /mcp:
atlas serve --addr :8080 # engine + HTTP API + UI + /mcp
Local (stdio) — a per-agent, short-lived adapter an MCP client spawns:
atlas mcp --server http://localhost:8080 atlas mcp --server https://atlas.example.com --token "$ATLAS_TOKEN"
The token is what a stdio adapter authenticates with against a server running --auth, and is needed there: unlike the HTTP transport, which forwards each request's own caller, a stdio adapter is one process with one identity for its whole life. Without it every tool call comes back 401.
For stdio, diagnostics go to stderr; stdout carries protocol traffic only.
Index ¶
Constants ¶
const TransportHeader = "X-Atlas-Via-MCP"
TransportHeader marks an API request as one a tool call made, rather than one a client made directly against /api/v1 with the same credential.
Atlas stamps it on every request entering /mcp and this adapter forwards it, the same way it forwards the caller's own credential and for the same reason: what arrives at the API has to be recognisable as what it is. A token a person approved for the transport alone is otherwise confined away from the very API calls its tools are made of.
It is not a credential this adapter holds — it holds none (ADR-0196). It arrives on the request, is carried verbatim like the other two, and means nothing except to the server that wrote it.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a thin HTTP client for the Atlas server API (see the api package). The MCP server owns no engine state of its own; every tool call is translated into an HTTP request against a running Atlas server, which remains the single writer of its partition (invariant I3). That keeps the MCP surface a pure adapter — it can never violate an engine invariant because it never touches the engine directly.
func NewClient ¶
func NewClient(baseURL string, opts ...ClientOption) *Client
NewClient builds a Client for the Atlas server at baseURL (e.g. "http://localhost:8080"). A trailing slash is tolerated.
type ClientOption ¶
type ClientOption func(*Client)
ClientOption configures a Client at construction.
func WithBearer ¶
func WithBearer(token string) ClientOption
WithBearer attaches an Authorization: Bearer <token> header to every request that carries no caller credential of its own. That is the stdio adapter's case: it is a per-agent process with one identity for its whole life, given on the command line (atlas mcp --token).
The HTTP transport does not use it. There, each request brings its own caller and forCaller takes precedence — see ADR-0196 for why the adapter no longer holds a credential of its own on that path.
An empty token is a no-op, so callers can pass it unconditionally.
func WithTLSRoots ¶ added in v0.5.0
func WithTLSRoots(pool *x509.CertPool) ClientOption
WithTLSRoots verifies the server's certificate against pool in addition to the host's roots, for the stdio adapter pointed at an https:// Atlas whose certificate an internal CA issued (atlas mcp --tls-ca).
It is a trust anchor and not a way around verification: there is no skip-verify switch here, in api/targetstore.go, or anywhere else in Atlas (ADR-0191). A nil pool leaves the client exactly as it was — verifying against the host's roots — so callers can pass it unconditionally.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is a Model Context Protocol server that exposes the Atlas API as MCP tools over a stdio JSON-RPC 2.0 transport. It is deliberately dependency-free and hand-written, in keeping with the rest of the repository.
func NewServer ¶
NewServer builds an MCP server that proxies tool calls to the Atlas server reachable through client.
func (*Server) Serve ¶
Serve runs the JSON-RPC loop, reading newline-delimited messages from in and writing responses to out, until in reaches EOF. It returns the first read error, or nil on a clean EOF. Diagnostics must never be written to out (that is the protocol channel); callers should log to stderr.
func (*Server) ServeHTTP ¶
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP makes Server an http.Handler implementing the MCP "Streamable HTTP" transport, so the same tool surface reachable over stdio (Serve) can be mounted at a path such as /mcp and reached by a remote MCP client — for example a claude.ai custom connector.
Message dispatch is shared with the stdio loop via handleWith; this method is transport only. The handler is stateless: it assigns no Mcp-Session-Id and requires none, which is sufficient for a tools-only server.
Authentication is the api package's, not this handler's: mount it with api.WithMCP and it sits inside the same boundary as every other route, so a request without a credential never reaches here. What this method does is the other half — it forwards the credential the request arrived with to the Atlas API, so a tool call is exactly as privileged as whoever made it. It carries no identity of its own to lend (ADR-0196).
type Tool ¶
type Tool struct {
Name string
Description string
InputSchema map[string]any
Handler func(c *Client, args map[string]any) (string, error)
}
Tool is one MCP tool: its advertised name, human/model-facing description, JSON Schema for arguments, and the handler that fulfils a call by talking to the Atlas server.