Repository navigation
fix(plugins): load_skill's outputSchema describes a loaded skill once - #1141
Merged
alexmercerpo merged 4 commits intoNov 5, 2026
Merged
Conversation
load_skill's output schema used the loaded-skill object for both `skill` (skillId) and `skills[].skill` (skillIds), and tools/list wrote that object out twice with no $ref: 866 bytes, twice, on every Skilled OpenAPI server. The loaded-skill schema is now registered with an id, so zod writes it once under `$defs.LoadedSkill` and both places refer to it with `$ref`. The SDK already lists such schemas, keeps `$defs` at the root when elicitation wraps the schema in `oneOf`, and the MCP client's Ajv resolves the reference. What load_skill returns does not change. load_skill's outputSchema goes from 2,118 to 1,337 bytes, and tools/list from 9,723 to 8,942 bytes with a one-skill bundle.
Contributor
|
Warning Review limit reachedYour organization has reached its usage spending cap. Adjust your spending cap in the billing tab. Next included review available in 28 minutes. View limit details
|
frontegg-david
marked this pull request as ready for review
November 5, 2026 12:10
Contributor
Performance Test ResultsStatus: ✅ All tests passed Summary
Total: 101 tests across 21 projects 📊 View full report in workflow run Generated at: 2026-11-05T17:52:51.940Z |
…ix/skilled-load-skill-output-schema
…ix/skilled-load-skill-output-schema
…ix/skilled-load-skill-output-schema
alexmercerpo
approved these changes
Nov 5, 2026
Contributor
frontegg-david
added a commit
that referenced
this pull request
Nov 5, 2026
* Cherry-pick: fix(adapters,plugins,edge): an older saas bundle, pulled or pushed, doesn't roll the server back Cherry-picked from #1119 (merged to release/1.11.x) Original commit: d88f422 Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(sdk,plugins): an @app's Skilled OpenAPI credential resolver reaches execute_action and this.callTool() of an operation Cherry-picked from #1120 (merged to release/1.11.x) Original commit: 00a3b00 Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(adapters,plugins,edge): a push token replayed to another replica or Worker isolate is refused Cherry-picked from #1122 (merged to release/1.11.x) Original commit: 1341026 Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(plugins): a skill a skills:filter hook hides can't be run by naming its actions Cherry-picked from #1123 (merged to release/1.11.x) Original commit: a081fbf Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(sdk): a plugin listed twice in one plugins list is refused at startup instead of keeping only its last entry Cherry-picked from #1127 (merged to release/1.11.x) Original commit: 3dbadd3 Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(plugins,edge): a Cron run that doesn't apply its bundle fails, and /readyz says the bundle served is stale Cherry-picked from #1128 (merged to release/1.11.x) Original commit: 4938d21 Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(sdk): connect() with an authToken connects an anonymous caller again on a server without auth Cherry-picked from #1129 (merged to release/1.11.x) Original commit: 3d238da Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(auth,adapters,plugins,edge): operators can tell why a pull or push token was refused, while callers still get the generic answer Cherry-picked from #1130 (merged to release/1.11.x) Original commit: 913f4f5 Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(sdk,auth,plugins): this.authProviders works: the SDK wires the AuthProviders vault from a new authProvidersVault option Cherry-picked from #1131 (merged to release/1.11.x) Original commit: e14c30c Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(sdk,auth): /oauth/connect connects a verified caller who has no vault yet, and asks an anonymous one to sign in Cherry-picked from #1132 (merged to release/1.11.x) Original commit: f46a87a Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(sdk,plugins): the SDK skill surfaces say a plugin's skills haven't loaded yet, retryable, and carry bundleVersion Cherry-picked from #1133 (merged to release/1.11.x) Original commit: 0d1dc94 Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(sdk,auth,cli,plugins): the credentials-required error keeps its connect link out of the message, and asks through URL elicitation where the client supports it Cherry-picked from #1134 (merged to release/1.11.x) Original commit: 6d8ea24 Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(sdk): a health check registered after startup runs in /readyz, and registerHealthProbe returns a remover Cherry-picked from #1135 (merged to release/1.11.x) Original commit: 7f2f48f Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(sdk,plugins): a bundle swap sends one list_changed per list it changed, not one per entry Cherry-picked from #1136 (merged to release/1.11.x) Original commit: 0296291 Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(adapters,plugins,edge): a restarted server serves its cached bundle in place of an older or refused pull, and doesn't write it back Cherry-picked from #1137 (merged to release/1.11.x) Original commit: 358d114 Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(sdk,adapters,plugins,edge): a push token with a body_sha256 claim can't carry another bundle Cherry-picked from #1138 (merged to release/1.11.x) Original commit: b870325 Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(plugins,edge): managed mode takes confirm, and the audit log says whether the user confirmed a call Cherry-picked from #1139 (merged to release/1.11.x) Original commit: 588289f Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(cli): the generated CLI says unknown command, prints an MCP error prefix once, and offers load_skill only the run lines it has Cherry-picked from #1140 (merged to release/1.11.x) Original commit: 4cfe9a2 Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(plugins): load_skill's outputSchema describes a loaded skill once Cherry-picked from #1141 (merged to release/1.11.x) Original commit: 470010e Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * Cherry-pick: fix(sdk,cli): skills/load's default answer sends formattedContent again, as 1.11.0 did; format: 'markdown' is the opt-in for the smaller one Cherry-picked from #1142 (merged to release/1.11.x) Original commit: a680fe7 Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com> --------- Co-authored-by: agentfront[bot] <agentfront[bot]@users.noreply.github.com> Co-authored-by: frontegg-david <69419539+frontegg-david@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1126.
Stacks on #1140.
What and why
load_skillused one loaded-skill schema in two places of its output schema:skill(forskillId) andskills[].skill(forskillIds).tools/listwrote that object out in full both times, with no$ref. Every Skilled OpenAPI server sent the same 866 bytes twice. (It was 812 bytes in 1.11.1-rc.1; this stack'sasksForConfirmationmarker added 54.)The fix takes the issue's first option, define once and reference, because it doesn't change what
load_skillreturns:.meta({ id: 'LoadedSkill' }). zod'stoJSONSchemathen writes it once, under$defs.LoadedSkill, and both places point to it with{ "$ref": "#/$defs/LoadedSkill" }.$defsreferences, and it already has tests for that. Passingreused: 'ref'in the SDK instead would change the listed schema of every tool that reuses a sub-schema.skillIdcallers get.What reads the listed schema, and how it handles
$defs/$ref:Clientfrom the upstream SDK, through@frontmcp/protocol) compiles eachoutputSchemawith Ajv and checksstructuredContenton everycallTool. Ajv resolves the local$ref, and it rejects a nested skill that breaks the definition.oneOf.extendOutputSchemaForElicitationalready keeps$defsat the root, where#/$defs/...resolves.undeclaredKeys: 'keep'policy walks the whole schema,$defsincluded.z.fromJSONSchema) resolves the reference too.'description'output-schema mode rendersskillasobject, as it did before.$defswith the rest: a lazy app's placeholder tools (built from the build manifest), codecall'sdescribeandgetTool, and the skills HTTP pages.inputSchemafromtools/list, and the webmcp bridge copies onlyinputSchema.Scenarios covered:
skillIdandskillIdsanswers validate, with and without elicitation;User-facing change
tools/list,load_skill'soutputSchemadescribes a loaded skill once, under$defs.LoadedSkill.properties.skillandproperties.skills.items.properties.skillare now{ "$ref": "#/$defs/LoadedSkill" }. Whatload_skillreturns doesn't change.load_skill'soutputSchema: 2,118 → 1,337 (−781, −37%);load_skillintools/list: 3,725 → 2,944;tools/list: 9,723 → 8,942 (−8%).$refin anoutputSchemawould now fail to checkload_skill's answers. The MCP TypeScript SDK's client resolves it, and$defs/$refare core keywords of JSON Schema 2020-12, the dialect MCP assumes.load_skill's listed schema.load_skill's schema. The plugin README'sload_skillrow now says the skill is described once, under$defs.Tests
Added
load-skill.output-schema.spec.ts(8 tests). It connects the MCP client to a two-skill server over the in-memory transport and readsload_skillfromtools/list:skillandskills[].skillare the same$ref,$defsholds onlyLoadedSkill, and the action object is written once;elicitation: { enabled: true }:skillIdandskillIdsanswers pass the client's own check oncallTool;AjvJsonSchemaValidatorfrom@frontmcp/protocolfinds them valid;skills[]with noinstructionsis refused, which shows the reference is followed.The two schema tests fail on the old schema. The validation tests pass on both.
Run:
nx run-many -t build -p sdk,plugin-skilled-openapi,testing: passed.nx test plugin-skilled-openapi: 54 suites, 852 tests passed.nx test skills: 3 suites, 249 tests passed.nx test demo-e2e-skilled-openapi: 11 suites, 99 tests passed.nx run plugin-skilled-openapi:typecheckandtsc --noEmit -p plugins/plugin-skilled-openapi/tsconfig.lib.json: passed.Not run, since nothing they cover changed:
nx test sdkand the bundle-size e2e: the SDK is unchanged;demo-e2e-cli-exec: the generated CLI doesn't read output schemas.