Help us shape the future of Go! Take the 2026 Go Developer Survey

mcp

package
v0.21.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 29, 2026 License: AGPL-3.0 Imports: 13 Imported by: 0

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, inspect live runtime state, and maintain the self-service shop's product catalogue.

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.

What a stdio adapter cannot reach

An API token carries roles, and no API token carries productmanager: minting is admin-only and tokenRoles hands an admin minter the legacy set, which ADR-0315 deliberately kept the role out of so that no account is granted catalogue control by an upgrade. So over stdio the catalogue tools read and do not write, and a write answers 403. Over the HTTP transport, where the caller's own credential is forwarded, a signed-in product manager reaches exactly their own catalogues. See ADR-0376.

For stdio, diagnostics go to stderr; stdout carries protocol traffic only.

Index

Constants

View Source
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.

func (*Client) CatalogueOffered added in v0.9.0

func (c *Client) CatalogueOffered() (bool, error)

CatalogueOffered asks the server whether it serves the shop, the catalogue, the orders and the inventory, which an operator can switch off with --catalogue=false (ADR-0434). It is how the stdio adapter, a separate process that cannot read the server's flags, decides whether to build itself WithoutCatalogue. A server that does not say — one older than the switch — offers it. An error is returned as an error and not read as either answer: the caller cannot tell a server that is down from one that decided.

It asks with a short deadline of its own rather than the client's thirty seconds. The adapter asks before it reads its first message, and an agent's host waits on that first answer: a server behind a firewall that drops packets would otherwise hold the whole adapter for half a minute to decide which tools to list.

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

func NewServer(client *Client, opts ...ServerOption) *Server

NewServer builds an MCP server that proxies tool calls to the Atlas server reachable through client.

func (*Server) Serve

func (s *Server) Serve(in io.Reader, out io.Writer) error

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 ServerOption added in v0.9.0

type ServerOption func(*serverConfig)

ServerOption configures a Server at construction.

func WithoutCatalogue added in v0.9.0

func WithoutCatalogue() ServerOption

WithoutCatalogue builds an adapter for a server that switched the shop, the catalogue, the orders and the inventory off (--catalogue=false): it neither lists nor dispatches the tools marked Catalogue, so an agent is not offered a capability whose every call would answer "no such endpoint" (ADR-0434). The server is still what refuses them; this only stops the adapter from advertising what is not there.

type Tool

type Tool struct {
	Name        string
	Description string
	InputSchema map[string]any
	Handler     func(c *Client, args map[string]any) (string, error)
	// Catalogue marks a tool of the shop, the catalogue, the orders or the
	// inventory: one an adapter built WithoutCatalogue does not offer, because the
	// server it fronts does not serve the route behind it
	// (ADR-0434).
	// TestWithoutCatalogueOffersNoToolOfTheArea fails for a tool of the area that
	// does not say so.
	Catalogue bool
}

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL