fix(pier): widen returning identities, warm the Redis store, end stateless listen streams, refuse personal tokens without a TokenID
- Identity.fingerprint covers scopes, both subjects, the ceiling and the token kind; a stateful lookup or stateless hit whose fingerprint changed re-filters the server with the event diff under its own mutex (A-WR-04) - Mount warms a Redis store in the background with a 1 s to 30 s backoff and every request kicks a pending open without waiting, so stateless-only instances subscribe to fan-out (A-WR-05) - a stateless subscriptions/listen POST re-verifies its bearer every recheck interval; an LRU-evicted stateless server closes its sessions (A-WR-06) - resolvePersonalToken refuses a subject with TokenID 0, and the pact.MCPPersonalTokenResolver contract says one resolver per application, false means unauthorized and TokenID keys the binding (A-WR-09, A-IN-03)
This commit is contained in:
@@ -33,6 +33,7 @@ const (
|
||||
methodListPrompts = "prompts/list"
|
||||
methodGetPrompt = "prompts/get"
|
||||
methodDiscover = "server/discover"
|
||||
methodListen = "subscriptions/listen"
|
||||
)
|
||||
|
||||
// ephemeralSession is the session value of the audit line of a tool call
|
||||
@@ -64,10 +65,11 @@ type localSession struct {
|
||||
transport *mcp.StreamableServerTransport
|
||||
ss *mcp.ServerSession
|
||||
|
||||
mu sync.Mutex
|
||||
identity Identity
|
||||
tools map[string]bool
|
||||
prompts map[string]bool
|
||||
mu sync.Mutex
|
||||
identity Identity
|
||||
fingerprint string // of the identity the tool set was last filtered for
|
||||
tools map[string]bool
|
||||
prompts map[string]bool
|
||||
|
||||
initialized atomic.Bool
|
||||
persisted atomic.Bool
|
||||
@@ -329,6 +331,7 @@ func (sr *sessionRouter) lookup(w http.ResponseWriter, r *http.Request, id Ident
|
||||
}
|
||||
ls.mu.Lock()
|
||||
ls.identity = id
|
||||
sr.p.widen(ctx, ls.server, id, &ls.fingerprint, ls.tools, ls.prompts)
|
||||
ls.mu.Unlock()
|
||||
if err := sr.p.store.Touch(ctx, sid, sr.p.cfg.IdleTTL); err != nil {
|
||||
sr.p.storeUnavailable(w, err)
|
||||
@@ -341,7 +344,7 @@ func (sr *sessionRouter) lookup(w http.ResponseWriter, r *http.Request, id Ident
|
||||
// with the session id, from the stored state when rehydrating. A goroutine
|
||||
// drops the local entry when the session closes.
|
||||
func (sr *sessionRouter) connect(ctx context.Context, sid string, id Identity, state *mcp.ServerSessionState) (*localSession, error) {
|
||||
ls := &localSession{id: sid, binding: id.Binding, created: time.Now().UTC(), identity: id}
|
||||
ls := &localSession{id: sid, binding: id.Binding, created: time.Now().UTC(), identity: id, fingerprint: id.fingerprint()}
|
||||
srv, tools, prompts := sr.p.newServer(ctx, id, func() { ls.initialized.Store(true) })
|
||||
ls.server, ls.tools, ls.prompts = srv, tools, prompts
|
||||
ls.transport = &mcp.StreamableServerTransport{SessionID: sid}
|
||||
|
||||
Reference in New Issue
Block a user