Documentation
¶
Overview ¶
Package mcps wires MCP servers declared in baifo.yaml to ADK toolsets.
In Phase 2.x the package supports the two built-in MCPs (filesystem and browse) in-process. HTTP and stdio transports are accepted by the validator but not yet wired up — calling Tools on one of those returns ErrTransportNotImplemented.
Index ¶
- Constants
- Variables
- type AuthenticateOptions
- type AuthenticateResult
- type BrowseConfig
- type Builders
- type DCRClientStore
- type FilesystemConfig
- type PersistedDCRClient
- type Registry
- func (r *Registry) Authenticate(ctx context.Context, name string, opts AuthenticateOptions) (*AuthenticateResult, error)
- func (r *Registry) ClearAuth(name string) error
- func (r *Registry) IsExternal(name string) (bool, error)
- func (r *Registry) Names() []string
- func (r *Registry) Spec(name string) (Spec, error)
- func (r *Registry) TestConnection(ctx context.Context, name string) (*TestConnectionResult, error)
- func (r *Registry) Tools(name string) ([]tool.Tool, error)
- func (r *Registry) Toolset(name string) (tool.Toolset, error)
- func (r *Registry) WithDCRClientStore(c *DCRClientStore) *Registry
- func (r *Registry) WithSecrets(s *secrets.Store) *Registry
- func (r *Registry) WithTokenStore(t *TokenStore) *Registry
- type Spec
- type TestConnectionResult
- type TokenStore
Constants ¶
const ( TypeBuiltin = "builtin" TypeHTTP = "http" TypeStdio = "stdio" )
MCP types accepted in baifo.yaml.
const ( BuiltinFilesystem = "filesystem" BuiltinBrowse = "browse" )
Built-in slugs accepted when type == "builtin".
Variables ¶
var ErrTransportNotImplemented = errors.New("MCP transport not implemented yet")
ErrTransportNotImplemented is returned by Tools when the MCP entry uses a transport (http, stdio) whose wiring is still pending.
var ErrUnknownMCP = errors.New("unknown MCP")
ErrUnknownMCP is returned when a caller references an MCP name that was not declared in mcps[].
var ErrUnsupportedBuiltin = errors.New("unsupported built-in MCP")
ErrUnsupportedBuiltin is returned when type=builtin but the `builtin` slug is not one of the supported ones.
var ErrUnsupportedType = errors.New("unsupported MCP type")
ErrUnsupportedType is returned when an entry uses a type that baifo does not know how to handle.
Functions ¶
This section is empty.
Types ¶
type AuthenticateOptions ¶
type AuthenticateOptions struct {
// Force forgets any cached token + DCR client registration
// and runs the full interactive flow from scratch. Used by
// the `/mcps auth NAME --force` CLI path when the user
// suspects a stuck credential.
Force bool
}
AuthenticateOptions tweaks how Authenticate behaves. Zero value is the default ("reuse cached token if possible, prompt only when needed"). The Force flag is the only knob we expose today; add more here when the need arises rather than growing the Authenticate signature.
type AuthenticateResult ¶
type AuthenticateResult struct {
MCPName string
Reused bool // true when an existing cached token was still valid
ServerHint string
}
AuthenticateResult is what Authenticate returns on a successful OAuth flow. Today it carries only the MCP name plus a flag telling the caller whether we actually opened a browser or reused the cached token; the TUI uses it to print a precise chat row.
type BrowseConfig ¶
BrowseConfig groups the options handed to the built-in browse MCP when the registry instantiates it. Baifo's main wiring fills these from baifo.yaml (download_dir, optional Tavily/Serper keys, ...).
type Builders ¶
type Builders struct {
Filesystem FilesystemConfig
Browse BrowseConfig
}
Builders bundles the construction-time options for every built-in MCP. Callers pass it once to NewRegistry; each builtin instance is lazily created on first Tools() call.
type DCRClientStore ¶
type DCRClientStore struct {
// contains filtered or unexported fields
}
DCRClientStore persists the client credentials that a Dynamic Client Registration (RFC 7591) handshake produced for each MCP.
func NewDCRClientStore ¶
func NewDCRClientStore(db *storage.DB) *DCRClientStore
NewDCRClientStore returns a store backed by storage SQLite DB.
func (*DCRClientStore) Delete ¶
func (s *DCRClientStore) Delete(mcpName string) error
Delete removes the persisted client for mcpName, if any.
func (*DCRClientStore) Load ¶
func (s *DCRClientStore) Load(mcpName string) (*PersistedDCRClient, error)
Load returns the persisted client for mcpName, or nil if none exists.
func (*DCRClientStore) Save ¶
func (s *DCRClientStore) Save(mcpName string, c *PersistedDCRClient) error
Save writes c under the given mcpName, replacing whatever was there before.
type FilesystemConfig ¶
type FilesystemConfig = filesystem.Config
FilesystemConfig groups the options handed to the built-in filesystem MCP. Kept thin on purpose so future per-agent overrides (sandbox path, log sink, ...) can be added here without touching every caller.
type PersistedDCRClient ¶
type PersistedDCRClient struct {
Issuer string `json:"issuer,omitempty"`
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret,omitempty"`
RegistrationAccessToken string `json:"registration_access_token,omitempty"`
RegistrationClientURI string `json:"registration_client_uri,omitempty"`
}
PersistedDCRClient is the on-disk shape of a registered client.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry validates the MCP declarations from baifo.yaml and resolves them on demand into ADK toolsets.
func NewRegistry ¶
NewRegistry parses entries from baifo.yaml, validates each one, and returns a Registry ready to be queried by name.
func (*Registry) Authenticate ¶
func (r *Registry) Authenticate(ctx context.Context, name string, opts AuthenticateOptions) (*AuthenticateResult, error)
Authenticate kicks the OAuth dance for the named MCP. The behaviour depends on auth.kind and credentials configured:
client_credentials: the SDK handler picks up a 401 challenge, fetches a fresh token at the discovered token endpoint, and persists it. No user interaction needed.
authorization_code (DCR / CIMD / preregistered): the SDK handler's AuthorizationCodeFetcher is wired to open the user's browser and spin a local server to receive the callback. We first try to reuse a token persisted from a previous run; if that works the call returns immediately with Reused=true.
The "kick" is a real MCP Initialize round trip — we connect a fresh mcp.Client against the transport, which triggers the SDK's auth machinery on the first 401/403. Doing it through the real protocol (instead of a synthetic HTTP GET) means a well-behaved MCP that authenticates at the JSON-RPC layer (i.e. inside Initialize, not on every HTTP method) still reaches the OAuth flow.
Authenticate is single-shot: when it returns, either a token has been persisted or an error explains why not. Callers should treat it as blocking for the duration of the round trip (seconds in the service flow, up to ~minute in the interactive one).
func (*Registry) ClearAuth ¶
ClearAuth drops every cached credential baifo holds for the named MCP — the access/refresh token in TokenStore AND the Dynamic Client Registration credentials in DCRClientStore. The next Authenticate (or first agent message that touches the MCP) will start from scratch: re-register a client if DCR is needed, open the browser for the user, mint a fresh token.
Used by `/mcps logout NAME` and the Settings "Forget credentials" action when an authorisation gets stuck (consent revoked upstream, AS rotated keys, refresh token poisoned).
Returns nil even when nothing was cached — the operation is idempotent on purpose; the user just wants "no creds left", not a report.
func (*Registry) IsExternal ¶
IsExternal reports whether the named MCP uses an external transport (http or stdio). Used by the agent builder to decide between the Tools() and Toolset() paths.
func (*Registry) TestConnection ¶
TestConnection opens a fresh MCP session against the named server and lists its tools as a smoke test. Returns a populated TestConnectionResult on success or a descriptive error on failure. Built-in MCPs short-circuit to "always healthy" because they live in-process — there's nothing remote to test.
We use a deliberate 15 second deadline so a hung MCP doesn't freeze the TUI; that's enough for one round trip through OAuth + protocol initialise + ListTools on any reasonable network.
func (*Registry) Tools ¶
Tools resolves the MCP named name into an ADK tool list. Built-in MCPs are constructed lazily and cached on first call so multiple agents that share an MCP also share its in-memory state (undo, scratch, processes). HTTP and stdio transports return ErrTransportNotImplemented for now.
func (*Registry) Toolset ¶
Toolset returns a lazily-connected ADK Toolset for the named MCP. Use this for HTTP and stdio transports; builtin MCPs go through Tools() instead because they are in-process and don't need the MCP wire protocol.
The toolset connects to the server lazily on the first ListTools call (driven by the agent runtime). That means boot stays fast even when an MCP server is slow or unreachable; the failure surfaces at the user's first turn instead, with a clear "MCP server X is unreachable" message coming back from the model loop.
We do NOT cache the toolset between calls. Each Toolset() returns a fresh instance so reload events (config edits, secret rotation) produce a brand-new client with the updated transport. The MCP client itself memoises its connection internally, so this is not a correctness issue, only a small allocation.
func (*Registry) WithDCRClientStore ¶
func (r *Registry) WithDCRClientStore(c *DCRClientStore) *Registry
WithDCRClientStore attaches the SQLite-backed Dynamic Client Registration persistence so the registry can reuse client_id / client_secret across boots and avoid registering a fresh client with the authorisation server on every authenticate call. Optional; when nil, every interactive flow re-registers.
func (*Registry) WithSecrets ¶
WithSecrets attaches a secrets store to the registry so HTTP header values and stdio env entries can reference ${secret:NAME} placeholders. Idempotent; callers typically wire it once in App.New right after the secrets store opens.
func (*Registry) WithTokenStore ¶
func (r *Registry) WithTokenStore(t *TokenStore) *Registry
WithTokenStore attaches the SQLite-backed OAuth token persistence so the registry can reuse tokens across process restarts and let the underlying handler refresh them transparently. Optional; when nil, OAuth flows still work but tokens are lost on every boot.
type Spec ¶
type Spec struct {
Name string
Type string
// Builtin slug; only meaningful when Type == TypeBuiltin.
Builtin string
// HTTP transport fields.
Endpoint string
Headers map[string]string
Insecure bool
// Stdio transport fields.
Command string
Args []string
Env map[string]string
Workdir string
// Auth carries the authentication descriptor for HTTP MCPs. The
// zero value means no authentication; Headers are still applied on
// top of whatever auth produces, so a fully-static "X-API-Key"
// setup uses Auth{Kind: none} + a header.
Auth config.MCPAuth
// Options carries the output-cap and tuning settings for
// type=builtin MCPs. Ignored for all other MCP types.
Options config.MCPOptions
}
Spec is the in-memory description of one MCP declaration. It mirrors config.MCPEntry but lives in this package so callers do not couple themselves to the on-disk YAML shape.
type TestConnectionResult ¶
type TestConnectionResult struct {
MCPName string
ServerName string
ServerVersion string
ToolCount int
Elapsed time.Duration
}
TestConnectionResult is the outcome of a TestConnection call. Fields are populated best-effort: ServerName / ServerVersion may be empty if the server doesn't supply InitializeResult.ServerInfo (it's optional per the MCP spec), and ToolCount is 0 when the server returns no tools.
type TokenStore ¶
type TokenStore struct {
// contains filtered or unexported fields
}
TokenStore persists OAuth tokens per MCP across process restarts.
func NewTokenStore ¶
func NewTokenStore(db *storage.DB) *TokenStore
NewTokenStore returns a store backed by storage SQLite DB.
func (*TokenStore) Delete ¶
func (s *TokenStore) Delete(mcpName string) error
Delete removes the token for mcpName, if any.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
builtin
|
|
|
browse
Package browse implements the in-process built-in browse MCP.
|
Package browse implements the in-process built-in browse MCP. |
|
browse/web
Package web is the low-level HTTP primitive used by the built-in browse MCP.
|
Package web is the low-level HTTP primitive used by the built-in browse MCP. |
|
filesystem
Package filesystem implements the in-process built-in filesystem MCP.
|
Package filesystem implements the in-process built-in filesystem MCP. |