Documentation
¶
Overview ¶
Package mcpauth signs magpie in to a remote MCP server that asks for an OAuth sign-in (Neon, Notion, Supabase…), once for every agent (#615). Each agent would otherwise run the sign-in itself and keep its own token, in its own place: magpie signs in, keeps the tokens in mcp-signins.json beside its other sign-ins, renews them, and the gateway's /mcp/<name> relays the agents' requests to the server with them (gateway/mcp.go). The library then gives the agents that address in place of the server's.
The sign-in is the one the MCP spec lays out (2025-06-18, Authorization): the server's 401 names its protected resource metadata (RFC 9728), that names the authorization server, whose metadata (RFC 8414) says where to register a client (RFC 7591), authorize with PKCE (S256) and get tokens. A server of the older spec (2025-03-26) with no resource metadata has its authorization server at its own origin.
Index ¶
- Variables
- func Cancel(id string)
- func Forget(name string) error
- func Rejected(name, access string)
- func Rename(old, name string) error
- func Renew(ctx context.Context, name, stale string) (string, error)
- func SignOut(name string) error
- func SignedIn(name, serverURL string) bool
- func Token(ctx context.Context, name string) (string, error)
- type App
- type Record
- type State
- type Status
Constants ¶
This section is empty.
Variables ¶
var Changed func(name string)
Changed is called when a server is signed in or out, for the library to give the agents its new address.
var Client = &http.Client{Timeout: 30 * time.Second, Transport: proxied()}
Client makes the sign-in's requests, through the proxy magpie's others take; tests point it elsewhere.
var ErrClientRefused = errors.New("this server's sign-in admits only the apps it lists and turned magpie away, so magpie can't sign in for the agents. The agents given it still have the server's own address: sign in from each agent itself (in Claude Code, run /mcp and pick the server)")
ErrClientRefused is a server whose authorization server turned magpie's registration away with 401 or 403: it admits only the clients it lists, as Figma's (mcp.figma.com, a 403 "Forbidden" to any client_name it doesn't list, #1619). magpie doesn't pass itself off as a listed client; a server magpie isn't signed in to is given to the agents at its own address, so each agent signs in there itself. The GUI has it in every language.
var ErrExpired = errors.New("magpie's sign-in to this server has run out: sign in again in the Library")
ErrExpired is a sign-in the server no longer takes: it has to be done again.
var ErrNoRegistration = errors.New("the server's sign-in doesn't let an app register itself (no dynamic client registration), so magpie signs in to it only as an OAuth app of your own: make one with the server's vendor (GitHub's under Settings › Developer settings › OAuth Apps), with http://localhost/callback as its callback URL, then give its client ID and secret under \"OAuth app\" in the server's editor")
ErrNoRegistration is a server whose sign-in doesn't let an app register itself (GitHub's, 新v学员 on Discord): magpie signs in to it only as an OAuth app of the user's own, made with the server's vendor, as Claude Code does with --client-id. The page opens the server's fields for one on it.
var ErrNoSignIn = errors.New("this server already works without signing in, so there is nothing to sign in to: the agents given it can use it as it is. A key it takes goes in Headers; a server that signs in at another address (as Exa's ?login) needs that URL")
ErrNoSignIn is a server that answered an agent's first request without asking for a sign-in: it works as it is. One that takes a key as a header takes it in Headers; one that signs in only at another address (Exa's mcp.exa.ai/mcp?login) is signed in to there. The GUI has it in Chinese.
var ErrNotSignedIn = errors.New("magpie isn't signed in to this server")
ErrNotSignedIn is a server magpie holds no sign-in for.
Functions ¶
func Forget ¶
Forget forgets the sign-in to a server the library no longer has, which gives it to no agent: there is nothing to tell.
func Rejected ¶ added in v0.1.1217
func Rejected(name, access string)
Rejected says the server refused access, a token magpie had just renewed: renewing it again won't help, so the sign-in has run out, and the page says so instead of calling it signed in beside the server's refusal (新v学员 on Discord). A sign-in renewed or redone meanwhile is left as it is.
func Renew ¶
Renew renews the sign-in the server just refused stale, unless another request renewed it meanwhile: then the new token is returned.
Types ¶
type App ¶ added in v0.1.1217
App is an OAuth app of the user's own, for a server whose sign-in doesn't let magpie register itself: Claude Code's --client-id, --client-secret and --callback-port. Its callback is Claude Code's, http://localhost:<port>/callback, so an app made for Claude Code signs magpie in as it is; the callback is still listened for on 127.0.0.1 alone, as Claude Code does. Without a CallbackPort the port is any free one, which a loopback callback URL registered without one takes (GitHub's, RFC 8252).
type Record ¶
type Record struct {
URL string `json:"url"` // the server's, as the library has it
Resource string `json:"resource,omitempty"` // what the tokens are for (RFC 8707)
Issuer string `json:"issuer,omitempty"`
TokenURL string `json:"tokenURL"`
ClientID string `json:"clientID"`
Secret string `json:"clientSecret,omitempty"`
// AuthMethod is how the client authenticates at the token endpoint:
// none, client_secret_post or client_secret_basic
AuthMethod string `json:"authMethod,omitempty"`
Scope string `json:"scope,omitempty"`
Access string `json:"access"`
Refresh string `json:"refresh,omitempty"`
Expires int64 `json:"expires,omitempty"` // unix ms; 0 when the server didn't say
At int64 `json:"at"` // when it was signed in, unix ms
// Dead is a sign-in the server refused to renew: the page asks for it
// again
Dead bool `json:"dead,omitempty"`
}
Record is magpie's sign-in to one server.
type State ¶
type State struct {
ID string `json:"id"`
Server string `json:"server"`
URL string `json:"url,omitempty"` // the sign-in page, to open
State string `json:"state"` // waiting, done, failed or canceled
Error string `json:"error,omitempty"`
}
State is where a sign-in stands, for the page to show.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package mcpauthtest is a remote MCP server behind an OAuth sign-in, as Neon's or Notion's is, for the tests of magpie signing in to one (#615).
|
Package mcpauthtest is a remote MCP server behind an OAuth sign-in, as Neon's or Notion's is, for the tests of magpie signing in to one (#615). |