mcpauth

package
v0.1.1248 Latest Latest
Warning

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

Go to latest
Published: Oct 15, 2026 License: MIT Imports: 25 Imported by: 0

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

Constants

This section is empty.

Variables

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

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

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

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

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

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

View Source
var ErrNotSignedIn = errors.New("magpie isn't signed in to this server")

ErrNotSignedIn is a server magpie holds no sign-in for.

Functions

func Cancel

func Cancel(id string)

Cancel ends a sign-in Start began.

func Forget

func Forget(name string) error

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 Rename

func Rename(old, name string) error

Rename moves a sign-in to the server's new name.

func Renew

func Renew(ctx context.Context, name, stale string) (string, error)

Renew renews the sign-in the server just refused stale, unless another request renewed it meanwhile: then the new token is returned.

func SignOut

func SignOut(name string) error

SignOut forgets magpie's sign-in to the server.

func SignedIn

func SignedIn(name, serverURL string) bool

SignedIn says whether magpie holds a sign-in to the server by that name at that URL: one to give the agents magpie's address for. One the server refused to renew still is, so the agents get magpie's word to sign in again rather than a sign-in of their own.

func Token

func Token(ctx context.Context, name string) (string, error)

Token is the access token for the server by that name, renewed first when it runs out within renewLead.

Types

type App added in v0.1.1217

type App struct {
	ClientID     string
	ClientSecret string
	CallbackPort int
}

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.

func Get

func Get(name string) (Record, bool)

Get is the sign-in to the server by that name.

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.

func Progress

func Progress(id string) (State, bool)

Progress is a sign-in Start began.

func Start

func Start(ctx context.Context, name, serverURL string) (State, error)

Start begins signing magpie in to the server called name at serverURL: open the State's URL in a browser and the rest happens on its own; StatusOf follows it.

func StartWith added in v0.1.1217

func StartWith(ctx context.Context, name, serverURL string, app *App) (State, error)

StartWith is Start as app when there is one, which magpie then doesn't register in its place.

type Status

type Status struct {
	SignedIn bool  `json:"signedIn"`
	Dead     bool  `json:"dead,omitempty"`
	At       int64 `json:"at,omitempty"`
}

Status is a server's sign-in as the page shows it.

func StatusOf

func StatusOf(name, serverURL string) Status

StatusOf is the sign-in to the server by that name at that URL.

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).

Jump to

Keyboard shortcuts

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