Documentation
¶
Overview ¶
Package app is the startup assembly every entry point shares: open the profile, settle the OAuth application, build the HTTP transport, the token source and the GitLab client, refuse a mode the sign-in cannot serve, and wire the MCP server.
It lives outside package main so the commands, the tests and any later driver assemble the server the way the binary does, rather than each re-deriving the sequence and dropping a step on the way. Nothing here prints or exits; the caller decides what a failure means.
Index ¶
- func InstanceKind(i instance.Instance) string
- func IsDisconnect(err error) bool
- func NewHTTPClient() *http.Client
- func SameInstance(recorded string, inst instance.Instance) bool
- type Options
- type Profile
- type Runtime
- type Settings
- func (s *Settings) Application() *auth.Application
- func (s *Settings) CheckScopes(granted []string) error
- func (s *Settings) Client(logger *slog.Logger, version string) (*gapi.Client, error)
- func (s *Settings) ClientWith(o gapi.Options) (*gapi.Client, error)
- func (s Settings) LogValue() slog.Value
- func (s *Settings) Probe(ctx context.Context, logger *slog.Logger, version string) Startup
- func (s Settings) String() string
- func (s *Settings) Tokens() gapi.TokenSource
- type Startup
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func InstanceKind ¶
InstanceKind names an instance without naming its host: "gitlab.com", or "test instance" for the loopback stand-in.
func IsDisconnect ¶
IsDisconnect reports the ordinary end of a stdio session. The SDK reports a closed connection as JSON-RPC -32004 or -32003 with the EOF only as message text, so errors.Is(err, io.EOF) misses it and the process would exit non-zero, which hosts log as a crash. The code is matched, never the text.
func NewHTTPClient ¶
NewHTTPClient builds the transport every call to the instance uses: proxies from the standard environment variables and the system's certificate authorities. No redirect is followed.
Types ¶
type Options ¶
type Options struct {
// Env reads the environment; the credential store takes its
// refresh-token override from it.
Env func(string) string
// Keyring is the OS keyring, or a fake in tests. nil means no
// keyring: the token lives in the profile's file.
Keyring credentials.Backend
// Logger receives startup findings. Never the payload.
Logger *slog.Logger
// Version is this build's version.
Version string
// Warn receives credential warnings, such as every use of the
// plaintext file. nil logs them.
Warn func(string)
}
Options are the process-level inputs to Resolve and Assemble.
type Profile ¶
type Profile struct {
Name string
Dir userconfig.Dir
// User is the stored profile state; HasUser says a file existed.
User userconfig.Config
HasUser bool
Store *credentials.Store
}
Profile is one configured profile: its name, what the last login stored, and its credential store.
func OpenProfile ¶
func OpenProfile(cfg config.Config, keyring credentials.Backend, env func(string) string, warn func(string)) (*Profile, error)
OpenProfile resolves the profile name (the one named, else "default"), reads its stored state and builds its credential store. warn receives the plaintext-file warning on every use of it.
type Runtime ¶
Runtime is an assembled server.
func Assemble ¶
Assemble builds the server. It fails on a configuration that cannot work (a sign-in whose scopes the mode exceeds), and not on a missing sign-in or an unreachable instance: those surface per call.
type Settings ¶
type Settings struct {
Config config.Config
Profile *Profile
// Instance is gitlab.com, or the loopback stand-in of
// GITLAB_MCP_TEST_INSTANCE.
Instance instance.Instance
// ClientID is the OAuth application: the override, else the
// profile's.
ClientID string
// HTTPClient carries the proxy.
HTTPClient *http.Client
// CredentialsErr is why the stored sign-in will not be used, or nil.
// The server still starts without one, so tools/list works before
// anyone signs in and every call says to log in.
CredentialsErr error
// contains filtered or unexported fields
}
Settings is the configuration settled against the profile: which application, which transport. The token source is unexported, and String and LogValue both render the same safe fields, because %+v reads unexported fields and a log line reads String.
func Resolve ¶
Resolve settles the configuration against the profile. It reads the profile and touches no network.
A profile signed in to another instance than this one keeps its token to itself, since a token is only ever sent to the instance that issued it: one signed in to the test instance never reaches gitlab.com, and the reverse.
func (*Settings) Application ¶
func (s *Settings) Application() *auth.Application
Application is the OAuth application these settings sign in with.
func (*Settings) CheckScopes ¶
CheckScopes refuses a configuration the sign-in cannot serve: a read_api token with the write tools on, above all (§9.4). An unknown grant passes, and the calls report what is missing.
func (*Settings) ClientWith ¶
ClientWith builds a GitLab client for these settings with o's tuning. The instance and the transport are always these settings'; the token source and the header timeout are theirs unless o sets them.
func (Settings) LogValue ¶
LogValue renders the settings for slog: the profile, the kind of instance and the flags. Never the host, the application id in full, the account or the token.
func (*Settings) Probe ¶
Probe reads the token's scopes. Registration needs them before the server exists, so they are read before serving; a failure is logged and left for the calls to report, so an instance that is down at start still gets a server.
Probe refreshes only when no login recorded the scopes: a host may kill the server before the MCP handshake, and a refresh cut short there spends the profile's refresh token. With the access token due, the scopes of the last login stand until the first call.
func (*Settings) Tokens ¶
func (s *Settings) Tokens() gapi.TokenSource
Tokens is the token source: the refreshing one, or one that answers every call with the reason there are no credentials.