Documentation
¶
Overview ¶
Package mcpserver is devctl serve: the agent-facing commands as MCP tools over streamable HTTP, acting on GitHub as the person who calls them.
A tool answers with the command's JSON document, devctl's envelope included, as structured content: the exit code is a field, and the call is an MCP error only for auth_required. A wait is one call that blocks until its verdict and sends notifications/progress on the caller's progressToken meanwhile, at an interval below the server's registered timeout, so the gateway restarts that timeout on each.
What only a laptop needs is not here: no version gate, no keychain or other credential store, no detached merge state on disk, no SIGHUP handling and no DEVCTL_TIME_SCALE.
Index ¶
- Constants
- type Caller
- type Clusters
- type Config
- type Credentials
- type Dex
- type DexExchange
- type GitHubInstallations
- type GitHubSources
- func (g GitHubSources) PRMerge(_ context.Context, token string, transport http.RoundTripper) (PRMergeSources, error)
- func (g GitHubSources) PRWait(_ context.Context, token string, transport http.RoundTripper) (PRWaitSources, error)
- func (g GitHubSources) ReleasePromote(_ context.Context, token string, transport http.RoundTripper) (*releasepromote.Sources, error)
- func (g GitHubSources) ReleaseWait(_ context.Context, token string, transport http.RoundTripper) (*releasewait.Sources, error)
- type GitHubUsers
- type Installation
- type Installations
- type Metrics
- type MusterGrant
- type NoClusters
- type NoCredentials
- type PRMergeSources
- type PRWaitSources
- type Server
- type Sources
- type Users
Constants ¶
const ( ToolPRWait = "pr_wait" ToolPRMergeStatus = "pr_merge_status" ToolReleaseWait = "release_wait" )
The tools' names.
const Anonymous = "anonymous"
Anonymous is the login of a call refused before its grant named the caller: one without a grant, or one refused as usage.
const DefaultAudience = "dex-k8s-authenticator"
DefaultAudience is the client the API server of a Giant Swarm management cluster accepts OIDC tokens of.
const DefaultInstallationsTTL = 5 * time.Minute
DefaultInstallationsTTL is how long a token's installations are kept.
const DefaultNoProgressTimeout = 20 * time.Second
DefaultNoProgressTimeout bounds a wait called without a progressToken, which no progress keeps alive: below muster's default registered timeout of 30 s with headroom for pr_merge's merge call.
const DefaultProgressInterval = 10 * time.Second
DefaultProgressInterval is how often a wait reports progress: below muster's default registered timeout of 30 s with headroom.
const DefaultUsersTTL = 5 * time.Minute
DefaultUsersTTL is how long a token's user is kept.
const GrantHeaderPrefix = "X-Muster-Grant-" //nolint:gosec // G101: a header name, not a credential
GrantHeaderPrefix starts the header the gateway in front carries the person's token of one provider App in: muster attaches X-Muster-Grant-<app> for every App of the server's registration (spec.auth.providerApps) the person granted.
const IdentitySource = "platform"
IdentitySource is a promotion's identity source on the server: the token the platform handed over for the person.
const MaxTimeout = 55 * time.Minute
MaxTimeout bounds a wait's own timeout: below the hour muster keeps a progress-kept call alive at most, so the wait ends with devctl's own timeout verdict, not the gateway's.
const Name = "devctl"
Name is the server's name in its MCP implementation info.
const StatusGrantRequired = "grant_required"
StatusGrantRequired is the structuredContent status of a result that needs the person's grant of the Apps it names in "apps": muster answers it auth_required with each App's sign-in link (authUrl).
const ToolPRMerge = "pr_merge"
ToolPRMerge is the merge tool's name.
const ToolReleasePromote = "release_promote"
ToolReleasePromote is the promotion tool's name, served with Config.ReleasePromote only.
const ToolRolloutWait = "rollout_wait"
ToolRolloutWait is the rollout wait's name.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Caller ¶
type Caller struct {
// Login is the person's GitHub login.
Login string
// ID is the person's GitHub user id, stable across a renamed login.
ID int64
}
Caller is the person a call is made for, as GitHub names the holder of their grant's token.
type Clusters ¶ added in v8.155.0
type Clusters interface {
// Open is the client of installation's management cluster acting as the
// caller in ctx, its requests going through wrap: auth_required without
// the person's token, not_applicable for an installation the server does
// not reach.
Open(ctx context.Context, installation string, wrap func(http.RoundTripper) http.RoundTripper) (dynamic.Interface, error)
// Installations are the names of the installations it reaches.
Installations() []string
}
Clusters open an installation's management cluster as the person a call is made for.
type Config ¶
type Config struct {
// Version is the version the server reports: the binary's.
Version string
// Credentials answer the person's GitHub token; nil is [NoCredentials].
Credentials Credentials
// Clusters open an installation's management cluster as the person;
// nil is [NoClusters].
Clusters Clusters
// Sources build the clients a wait reads with; nil is [GitHubSources]
// over Endpoints.
Sources Sources
// Endpoints are GitHub's and the registries'; zero is
// [agentcli.DefaultEndpoints].
Endpoints agentcli.Endpoints
// Clock is the waits' clock; nil is the wall clock at scale 1, never
// DEVCTL_TIME_SCALE.
Clock *agentcli.Clock
// ProgressInterval is how often a wait reports progress; zero is
// DefaultProgressInterval.
ProgressInterval time.Duration
// NoProgressTimeout bounds a wait called without a progressToken, so
// it answers within the gateway's registered timeout; zero is
// DefaultNoProgressTimeout.
NoProgressTimeout time.Duration
// Merges are the merges of this server pr_merge_status reads; nil is an
// empty [mergejob.Memory]. pr_merge records its merges in them when they
// take a Put, as a Memory does. Nothing is kept on disk.
Merges mergejob.Jobs
// ReleasePromote serves release_promote, the selector of the one tool
// that cuts a stable release; off, the tool is not listed.
ReleasePromote bool
// Metrics count the calls; nil counts none.
Metrics *Metrics
// Logger logs one line per call; nil logs nothing.
Logger *slog.Logger
}
Config configures a Server.
type Credentials ¶
type Credentials interface {
// GitHubToken is the person's token for the call in ctx; an
// [agentcli.ExitCoder] of [agentcli.ExitAuthRequired] when the server
// holds none for them.
GitHubToken(ctx context.Context) (string, error)
}
Credentials answer the GitHub token of the person a call is made for.
type Dex ¶ added in v8.155.0
type Dex struct {
// TokenEndpoint is Dex's token endpoint, https.
TokenEndpoint string `json:"tokenEndpoint"`
// Issuer is the issuer the exchanged token must name; empty is the
// token endpoint without /token.
Issuer string `json:"issuer,omitempty"`
// ConnectorID is the connector of Dex that trusts the hub's Dex, which
// issued the person's token.
ConnectorID string `json:"connectorId"`
// Audience is the client the API server accepts tokens of, asked for
// as a cross-client audience; empty is dex-k8s-authenticator.
Audience string `json:"audience,omitempty"`
// ClientIDFile and ClientSecretFile hold the client the exchange
// authenticates as, read when the server starts; without
// ClientSecretFile the client is a public one.
ClientIDFile string `json:"clientIdFile"`
ClientSecretFile string `json:"clientSecretFile,omitempty"`
}
Dex is the token exchange at an installation's Dex.
type DexExchange ¶ added in v8.155.0
type DexExchange struct {
// Client sends the exchanges; nil is http.DefaultClient.
Client *http.Client
// Now is the clock of the exchanged tokens' expiry; nil is time.Now.
Now func() time.Time
// contains filtered or unexported fields
}
DexExchange opens the installations it was given as the person: it exchanges the person's token, which the gateway in front forwards in Authorization (muster's forwardToken), at the installation's Dex for a token its API accepts, and sends that with every request. The cluster answers by the person's access; the server holds no kubeconfig and no credential of a cluster.
func NewDexExchange ¶ added in v8.155.0
func NewDexExchange(installations []Installation) (*DexExchange, error)
NewDexExchange validates installations and reads their client files.
func ReadInstallations ¶ added in v8.155.0
func ReadInstallations(path string) (*DexExchange, error)
ReadInstallations reads the installations file: a JSON object with an "installations" list. The client files are read here, once.
func (*DexExchange) Installations ¶ added in v8.155.0
func (d *DexExchange) Installations() []string
Installations implements Clusters.
func (*DexExchange) Open ¶ added in v8.155.0
func (d *DexExchange) Open(ctx context.Context, name string, wrap func(http.RoundTripper) http.RoundTripper) (dynamic.Interface, error)
Open implements Clusters.
type GitHubInstallations ¶
type GitHubInstallations struct {
BaseURL string
Client *http.Client
TTL time.Duration
Now func() time.Time
// contains filtered or unexported fields
}
GitHubInstallations read GET /user/installations at BaseURL and keep each token's answer for TTL.
func (*GitHubInstallations) Owners ¶
Owners implements Installations.
type GitHubSources ¶
GitHubSources are the clients of GitHub and the registries at Endpoints. They hold no CircleCI client: the server has no CircleCI credential, so a pull request's CircleCI state is the commit statuses CircleCI posts to GitHub. The private registry is read anonymously.
func (GitHubSources) PRMerge ¶
func (g GitHubSources) PRMerge(_ context.Context, token string, transport http.RoundTripper) (PRMergeSources, error)
PRMerge implements Sources.
func (GitHubSources) PRWait ¶
func (g GitHubSources) PRWait(_ context.Context, token string, transport http.RoundTripper) (PRWaitSources, error)
PRWait implements Sources.
func (GitHubSources) ReleasePromote ¶
func (g GitHubSources) ReleasePromote(_ context.Context, token string, transport http.RoundTripper) (*releasepromote.Sources, error)
ReleasePromote implements Sources: the person's token, never renewed.
func (GitHubSources) ReleaseWait ¶
func (g GitHubSources) ReleaseWait(_ context.Context, token string, transport http.RoundTripper) (*releasewait.Sources, error)
ReleaseWait implements Sources: no CircleCI client, the wait reads CircleCI through the commit statuses of the tag's commit.
type GitHubUsers ¶ added in v8.154.1
type GitHubUsers struct {
BaseURL string
Client *http.Client
TTL time.Duration
Now func() time.Time
// contains filtered or unexported fields
}
GitHubUsers read GET /user at BaseURL and keep each token's answer for TTL: a token GitHub refuses is auth_required.
type Installation ¶ added in v8.155.0
type Installation struct {
// Name is the installation's name, the tool's argument.
Name string `json:"name"`
// APIServer is the URL of the management cluster's Kubernetes API.
APIServer string `json:"apiServer"`
// CAFile is the API's certificate authority, PEM; empty trusts the
// system's roots.
CAFile string `json:"caFile,omitempty"`
// Dex is the installation's Dex.
Dex Dex `json:"dex"`
}
Installation is one management cluster the server reaches as the person: its API, and its Dex, where the person's token is exchanged for one of that installation (RFC 8693) with the client the hub's muster presents there. The server holds no credential of the cluster itself.
type Installations ¶
Installations answer the accounts a GitHub App is installed on that the holder of a user token of it reaches.
type Metrics ¶
type Metrics struct {
// contains filtered or unexported fields
}
Metrics are the server's call metrics, labelled with the tool, the caller's GitHub login and user id (Anonymous and empty for a call whose grant named none), the repository (owner/repo; empty for a tool that names none or an argument refused as usage) and the verdict.
func NewMetrics ¶
func NewMetrics(registerer prometheus.Registerer) (*Metrics, error)
NewMetrics registers the server's metrics with registerer.
type MusterGrant ¶
type MusterGrant struct {
// App is the provider App's name in muster, the header's suffix.
App string
// GitHubApp is the GitHub App's name, as a refusal names it.
GitHubApp string
// Users answer the person the token acts as, the call's caller; nil
// names none and accepts the token unchecked.
Users Users
// Installations answer the owners the App is installed on that the
// person reaches; nil checks none.
Installations Installations
}
MusterGrant is the person's token of the GitHub App muster keeps as App: muster attaches it to every call the person granted it for. The token names the caller: a call without one GitHub accepts is refused. The server stores no token and runs no sign-in.
func (MusterGrant) GitHubToken ¶
func (g MusterGrant) GitHubToken(ctx context.Context) (string, error)
GitHubToken implements Credentials: the person's token of the App, with the caller it names put on the call; a grant_required auth_required without one or with one GitHub refuses, and not_applicable for a repository whose owner the App is not installed on.
type NoClusters ¶ added in v8.155.0
type NoClusters struct{}
NoClusters is the server that reaches no installation: every rollout wait is not_applicable.
func (NoClusters) Installations ¶ added in v8.155.0
func (NoClusters) Installations() []string
Installations implements Clusters.
func (NoClusters) Open ¶ added in v8.155.0
func (NoClusters) Open(_ context.Context, installation string, _ func(http.RoundTripper) http.RoundTripper) (dynamic.Interface, error)
Open implements Clusters.
type NoCredentials ¶
type NoCredentials struct{}
NoCredentials is the server with no hand-over of a person's token: every call that reads GitHub is auth_required.
func (NoCredentials) GitHubToken ¶
func (NoCredentials) GitHubToken(context.Context) (string, error)
GitHubToken implements Credentials.
type PRMergeSources ¶
type PRMergeSources struct {
GitHub prmerge.GitHub
Rate prwait.RateSource
Entries prwait.EntryFinder
// Policy is the repository's opt-out; nil reads the team files through
// GitHub, a *githubclient.Client.
Policy prmerge.Policy
}
PRMergeSources are what a merge reads and writes, its release wait aside, which reads Sources.ReleaseWait's.
type PRWaitSources ¶
type PRWaitSources struct {
GitHub prwait.GitHub
Rate prwait.RateSource
Entries prwait.EntryFinder
}
PRWaitSources are what a pull request wait reads.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is devctl serve's MCP server.
type Sources ¶
type Sources interface {
PRWait(ctx context.Context, token string, transport http.RoundTripper) (PRWaitSources, error)
PRMerge(ctx context.Context, token string, transport http.RoundTripper) (PRMergeSources, error)
ReleaseWait(ctx context.Context, token string, transport http.RoundTripper) (*releasewait.Sources, error)
ReleasePromote(ctx context.Context, token string, transport http.RoundTripper) (*releasepromote.Sources, error)
}
Sources build the clients of one call from the person's token; the requests go through transport.