Repository navigation
feat(sdk,cli): a generated CLI's skills commands are the Skilled OpenAPI tools, top-level on a skilled-only server, with terminal confirmation - #1102
Merged
Conversation
…-vm/browser peer The plugin's package.json gained the peer, but the lockfile's workspace entry did not, so yarn install --frozen-lockfile refused to run.
…cli-skilled-commands
…'s questions A CLI-mode scope opened no elicitation store, so once a client could answer, this.elicit() failed with "ElicitationStore not initialized". In CLI mode the store now stays in memory: the process asks its own user and ends with the command. Persistent questions and the sendElicitationResult fallback tool stay off there, as before. The browser bundles of create() grow by 83 and 81 bytes; their budgets take it.
…l confirmation When the server has the Skilled OpenAPI plugin's four tools, the build generates commands for them in place of the standard skills commands, which showed no actions for bundle skills: - skills search, load, execute, run, read and list, always; - search_skill, load_skill, execute and run_workflow at the top level too, on a server whose only tools are the plugin's. They answer to their kebab-case names and keep the 1.11.0 --query, --skill-id and --script flags. load prints each action with a ready execute command. execute takes --input, --input - or --input-file; run_workflow takes the script, --file or -. The plugin's tools are no longer plain tool commands. --output json prints the tool's structured content; a tool error exits 1, a usage error 2. The CLI now answers a server's elicitation, in-process and through the daemon, which reads the SSE stream as it arrives: a yes/no question, such as the confirmation of a destructive action, reads y/N on a terminal, the global --yes answers yes, and with no terminal the CLI declines. The sendElicitationResult fallback tool is no longer a command.
…ion, end to end A CLI built for a server with only the plugin's tools: help, search, load with its execute lines, execute (data, --input-file, --input -, failure, unknown action), run_workflow (argument, --file, -, failure), --output json, the 1.11.0 flags, and a destructive action declined with no terminal and run with --yes, in-process and through the daemon. A second fixture with a tool of its own has the commands only under skills.
frontegg-david
marked this pull request as ready for review
November 4, 2026 21:42
Contributor
Author
|
@coderabbitai review |
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 26 minutes. View limit details
|
Contributor
Action not completed
|
alexmercerpo
approved these changes
Nov 4, 2026
Contributor
Performance Test ResultsStatus: ✅ All tests passed Summary
Total: 101 tests across 21 projects 📊 View full report in workflow run Generated at: 2026-11-04T22:24:39.889Z |
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.
What and why
Stacks on #1101.
The CLI that
frontmcp build --target climakes (mymcpbelow) treated a Skilled OpenAPI server like any other:search-skill --query,load-skill --skill-id(one id),run-workflow --script(the script only as a flag value), andexecute-action --action-id;skills searchandskills loadcalled the SDK's skill methods, which return no actions for bundle skills;confirmoption names was always refused (this client can't ask for it), because the CLI couldn't answer an MCP elicitation.A Skilled OpenAPI server's skills are tools, not standard skills, so this PR gives the CLI commands for them.
Commands
The build detects the plugin from its four tools (
search_skill,load_skill,execute_action,run_workflow). It then generates these commands in place of the standardskillscommands:skills search <query...> [--limit n] [--tags a,b] [--not-query x]search_skillskills load <skill...>load_skill(skillIdfor one,skillIdsfor several)mymcp execute <actionId> --input '<json>'line built from the input schema's required fields, and its optional fieldsskills execute <actionId> [--input '<json>' | --input - | --input-file f.json]execute_actionskills run [script] [--file f], or-for stdinrun_workflowskills read <skill>skill://<name>/SKILL.mdskills listskill://index.jsonOn a server whose only tools are the plugin's, the same commands are also top-level:
search-skill,load-skill,execute_action/execute-actionandrun-workflowtoo.skills, so scripts that useskills ...keep working if the server later gains tools.cli.excludeToolsnaming one of the plugin's tools leaves its command out.The plugin's tools as tool commands
They are hidden: the plugin's four tools are no longer generated as tool commands. To keep 1.11.0 scripts working, the top-level commands also take the old flags, hidden from
--help:search-skill --query,load-skill --skill-idandrun-workflow --script. On a server with tools of its own there are no top-level commands, so a 1.11.0 script there moves toskills search,skills loadorskills run.Output and exit codes
--output jsonprints the tool's structured content, or the whole result when there is none.isError: a failed action or workflow, a skill not found, an authority denial, a declined confirmation); 2 for a usage error (no query or script, two script sources,--inputthat isn't a JSON object,--inputwith--input-file, an unreadable file). The error text goes to stderr.Confirming a destructive action
The CLI now answers a server's elicitation:
connect(), and hands the same handler to its daemon client.y/Nwhen stdin is a terminal.--yesanswers yes without asking. Commander reads a program option anywhere, so it works before or after the command.--yes, the CLI declines and prints the question andDeclined: there is no terminal to ask on. Run the command again with --yes to confirm.The action isn't sent, and the command exits 1 withthe user declined: voidInvoice.The daemon's transport carries server-to-client requests, so nothing falls back to in-process:
elicitationcapability when it has a handler.elicitation/createarrives, it answers with a POST to the session. Any other server request getsMethod not found.method.Two related changes:
connect(..., { mode: 'cli' })) opened no elicitation store, so in-processthis.elicit()failed withElicitationStore not initializedonce the client could answer. In CLI mode, the store now stays in memory: the process asks its own user and ends with the command. Persistent questions and thesendElicitationResultfallback tool stay off in CLI mode, as before.sendElicitationResultfallback tool anymore. The server lists that tool only to clients that can't answer, and the CLI now can. The tool also no longer counts as a tool of the server's own when the build decides whether a server is Skilled OpenAPI only.Lockfile
#1101's
yarn.locklacked the plugin's optional@enclave-vm/browserpeer. This branch fixed the same three lines (117cba2) before #1101's own fix (2a57dc5) landed, and the merge leaves no difference.yarn install --immutablepasses.Bundle size
The SDK change grows the browser bundles of
create()+ one tool by 83 bytes (1,288,965) and ofcreate()+ WebMcpPlugin + one tool by 81 bytes (1,296,155). The budgets are set to these sizes. The Vite initial chunk is unchanged.User-facing change
skills search,skills load,skills execute,skills run,skills readandskills list, which call the plugin's tools.search_skill,load_skill,executeandrun_workflowat the top level.y/Non a terminal, a new global--yes, and a decline with no terminal.connect()inmode: 'cli'can elicit.mymcp search-skill --query x→mymcp search_skill x(the old form still works on a skilled-only server).--limit,--tags a,band--not-queryare new.mymcp load-skill --skill-id xprinted JSON →mymcp load_skill x [y ...]prints the instructions and a readyexecuteline per action.mymcp execute-action --action-id x --input j→mymcp execute x --input j,--input -or--input-file f.json.mymcp run-workflow --script s→mymcp run_workflow s,--file for-.--output jsonon these commands printed the wholeCallToolResult→ it prints the tool's structured content.skills.skills loadon a Skilled OpenAPI server printedLoaded 1 of 1 skill(s).with no actions → it prints the actions.this client can't ask for it→ the CLI asks,--yesconfirms, and with no terminal it declines (the user declined: <actionId>, exit 1).send-elicitation-resultcommand, generated for servers withelicitation.enabled, is gone.connect(config, { mode: 'cli', onElicitation })failed withElicitationStore not initialized→ it asks the handler.frontmcp-deployment/references/build-for-cli.md: new "Skilled OpenAPI commands" and "Questions from the server" sections, and the troubleshooting rows;frontmcp-config/references/configure-elicitation.md: the generated CLI asks in the terminal.The CLI README and the plugin README are updated too.
Tests
Added:
libs/cligeneration, ingenerate-cli-entry.spec.ts(7 tests):skillscommands;excludeToolsdrops a command;--yesand the daemon handler are wired;sendElicitationResultgets no command.generated-cli-smoke.spec.ts).skilled-commands.spec.ts(39 tests), run on a real commander program with a fake client:--input -,--input-file,--fileand-for stdin;--yesafter the command;skills read(an encoded name) andskills list;terminal-elicitation.spec.ts(9 tests):--yes, no terminal,y/n/ empty / other answers, and per-field questions.daemon-client.spec.ts(3 tests): it answers anelicitation/createduring a call and then reads the result, declines when its handler fails, and declares no elicitation without a handler.connect-client.spec.ts(1 test):connect()inmode: 'cli'asks the handler. This test fails without the fix.demo-e2e-cli-exec, incli-skilled-openapi.e2e.spec.ts, rewritten (28 tests), on a built CLI with a Skilled OpenAPI bundle and a loopback API:skills readandskills list;--input-file,--input -, a 404 failure, an unknown action, bad JSON;--file, stdin, the 1.11.0--script, a failure;--yesbefore and after, a workflow asked once;skills.Run:
npx nx test cli: 131 suites, 2180 tests passed.libs/sdk, the whole jest suite: 691 suites, 9640 tests passed.demo-e2e-cli-exec, the whole app: 42 suites, 252 tests passed; 1 suite (4 tests) skipped. The skipped one is the login-identity suite, which skips on macOS so it never writes to the Keychain, so it runs only on Linux CI. It lists skills withskills list, which now readsskill://index.json. The plugin's authorization tests check that this resource is filtered per caller.demo-e2e-bundle-size: 12 suites, 63 tests passed, after the budget update.npx nx run cli:typecheck,sdk:typecheck,demo-e2e-cli-exec:typecheck: pass.npx tsc --noEmit -p libs/cli/tsconfig.lib.jsonand-p libs/sdk/tsconfig.lib.json: pass.index.ts).yarn install --immutable: passes.