Skip to content

feat(mcp): discover package children and report inactive grants - #389

Draft
tnunamak wants to merge 1 commit into
mcp/p1-inprocess-dispatchfrom
mcp/b2-child-discovery
Draft

tnunamak wants to merge 1 commit into
mcp/p1-inprocess-dispatchfrom
mcp/b2-child-discovery

Conversation

@tnunamak

Copy link
Copy Markdown
Contributor

With a package token (one token covering several child grants), a model has to name a child with grant_id on every data tool, but nothing lets it learn the valid values or notice that a child has ended. This adds both, as the MCP profile (§3) requires.

For package tokens only, the server now offers a no-argument tool, list_package_children. For each child it returns the grant_id, public source metadata, purpose, streams with the client's own instance handles, access mode and active. Inactive children are listed with active: false. It returns no records, counts, tokens, private bindings or internal subject. When a call names a child that belongs to the package but has ended, the tool result is isError: true with structuredContent.error = {code: "package_child_inactive", grant_id} and the text "Access to grant has ended. Do not retry this call. Ask the owner if this access is needed again." It is never an HTTP 401 or 403 and never switches to another child. An unknown grant_id keeps the earlier selector error, and a package whose last child ended is a token-level 401 invalid_token. A downstream 403 grant_invalid (for example a lost instance mapping) affects only that child.

The hosted adapter reads the package members from getGrantPackageAccess. Today that function returns members with no active field and drops ended children; the identity work will change it to return every member with a boolean active. The adapter accepts both shapes and rejects anything ambiguous before dispatch: a mix of the two, conflicting access modes, an active that is not a boolean, a missing or duplicate grant_id. Those cases return a generic 500 and neither return nor log member data.

Landing order: merge this with, or before, the grant_id PR (#382). That PR makes grant_id required for package tokens, and a client then needs this tool to find a valid value. What an existing session sees after this merge: a session on an ordinary client token sees no change. A package-token session sees the extra list_package_children tool and grant_id on each data tool in tools/list, and calls the discovery tool first. Production sessions run on the current member shape, so the five real-flow hosted package tests run against that producer, not a stub.

Tests: the discovery output whitelist, the inactive-child result over HTTP 200, the 401 when no child is active, sibling isolation, the malformed-member rejections (each fails when the validation is made permissive), and a full replay on a real minted package: tools/list, list_package_children, schema, search, fetch, query_records. Hosted OAuth passes 134 with none skipped; the package tools/list is 23,712 of 24,576 bytes, with 864 left; the client list is unchanged. An independent review by a different model ran three rounds; it caught that the first version returned 401 to every current package session, which is fixed. Not verified: a few descriptions are shorter than the base to fit the size limit (schema-first hints, raw per-field schemas, metadata handles in fetch); the vendor tool-footprint test still fails on a missing operator document. This PR is stacked on #385.

Assisted-by: AI

The hosted package adapter accepts both the current legacy access shape and the frozen member shape. Reject mixed or malformed member lists before MCP dispatch with a generic internal error, and preserve explicit inactive status. The current producer omits revoked children, so those selectors keep B1’s unknown-grant response.

Restore package guidance for field navigation, document versus canonical-record reads, bounded previews, query metadata, source handles, search modes, paging, and aggregate truncation. Re-enable the real hosted package flows and verify a complete current-producer client replay.

Assisted-by: AI
Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant