fix: reject unknown call flags (#35)
This commit is contained in:
parent
97ac209049
commit
d7cfc29bff
@ -328,6 +328,7 @@
|
||||
- Expanded the ad-hoc/OAuth story across `README.md`, `docs/adhoc.md`, `docs/local.md`, `docs/known-issues.md`, and `docs/supabase-auth-issue.md`, detailing when servers auto-promote to OAuth, how retries behave, and how to persist generated definitions safely.
|
||||
- Updated the README, CLI reference, and generator docs to cover the new `--all-parameters` flag, list formatter, metadata embedding, the `mcporter emit-ts` workflow, and refreshed branding so the CLI and docs consistently introduce the project as **MCPorter**.
|
||||
- Tightened `docs/RELEASE.md` with a zero-warning policy so `pnpm check`, `pnpm test`, `npm pack --dry-run`, and friends must run clean before publishing.
|
||||
- `mcporter call` now rejects unknown long flags like `--source` instead of silently treating them as positional tool arguments; use `key=value`, `--args`, or `--` for literal `--value` positionals (PR #35, thanks @beverm2391).
|
||||
|
||||
## [0.2.0] - 2025-11-06
|
||||
|
||||
|
||||
@ -71,5 +71,6 @@ Key details:
|
||||
- By default, arguments keep the same validation pipeline as the function-call syntax—enums, numbers, and booleans are coerced automatically, and missing required fields raise errors.
|
||||
- `--raw-strings` disables numeric coercion for flag-style and positional values so IDs/codes stay literal strings (`code=12345` stays `"12345"`).
|
||||
- `--no-coerce` disables all coercion for flag-style and positional values (`true`, `null`, and JSON-like values remain strings).
|
||||
- Unknown long flags like `--source` now fail fast instead of silently becoming positional tool arguments. Use `source=value`, `--args '{"source":"value"}'`, or insert `--` before literal positional values that start with `--`.
|
||||
- `--save-images <dir>` keeps stdout formatting untouched while writing image content blocks to disk when a tool response includes `type: "image"` entries.
|
||||
- `tool=value`/`tool:value` and `server=value` still act as aliases for `--tool` / `--server` when you need to override the selector.
|
||||
|
||||
@ -26,6 +26,7 @@ A quick reference for the primary `mcporter` subcommands. Each command inherits
|
||||
pseudo-TS syntax and `--arg` flags.
|
||||
- Useful flags:
|
||||
- `--server`, `--tool` – alternate way to target a tool.
|
||||
- `--` – stop flag parsing so remaining tokens stay literal positional values.
|
||||
- `--timeout <ms>` – override call timeout (defaults to `CALL_TIMEOUT_MS`).
|
||||
- `--output text|markdown|json|raw` – choose how to render the `CallResult`.
|
||||
- `--save-images <dir>` – persist image content blocks to files under the specified directory.
|
||||
|
||||
@ -31,6 +31,7 @@ mcporter call context7.resolve-library-id libraryName: value
|
||||
- Use `--flag value` when you prefer long-form CLI syntax.
|
||||
- Mixed forms are fine: `mcporter call linear.create_issue --team ENG title=value due: tomorrow`.
|
||||
- `--args '{"title":"Bug"}'` still ingests JSON payloads directly.
|
||||
- Unknown long flags now error instead of silently becoming tool arguments; use `title=value`, `--args`, or `--` before literal positional values beginning with `--`.
|
||||
|
||||
## 3. Function-Call Syntax
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
shouldPromoteSelectorToCommand,
|
||||
} from './call-argument-values.js';
|
||||
import { extractEphemeralServerFlags } from './ephemeral-flags.js';
|
||||
import { CliUsageError } from './errors.js';
|
||||
import { consumeOutputFormat } from './output-format.js';
|
||||
import type { OutputFormat } from './output-utils.js';
|
||||
import { consumeTimeoutFlag } from './timeouts.js';
|
||||
@ -60,6 +61,7 @@ export function parseCallArguments(args: string[]): CallArgsParseResult {
|
||||
defaultFormat: 'auto',
|
||||
});
|
||||
const positional: string[] = [];
|
||||
const literalPositional: string[] = [];
|
||||
let index = 0;
|
||||
while (index < args.length) {
|
||||
const token = args[index];
|
||||
@ -67,11 +69,25 @@ export function parseCallArguments(args: string[]): CallArgsParseResult {
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
if (token === '--') {
|
||||
literalPositional.push(...args.slice(index + 1).filter(Boolean));
|
||||
break;
|
||||
}
|
||||
const flagHandler = FLAG_HANDLERS[token];
|
||||
if (flagHandler) {
|
||||
index = flagHandler({ args, index, result, state: flagState });
|
||||
continue;
|
||||
}
|
||||
if (token.startsWith('--')) {
|
||||
throw new CliUsageError(
|
||||
[
|
||||
`Unknown flag '${token}' passed to call command.`,
|
||||
`If you intended to pass a tool argument, use '${token.slice(2)}=<value>' or --args '{"${token.slice(2)}": ...}'.`,
|
||||
"If you intended to pass a literal positional value, insert '--' before it.",
|
||||
"Run 'mcporter call --help' to see available flags.",
|
||||
].join('\n')
|
||||
);
|
||||
}
|
||||
positional.push(token);
|
||||
index += 1;
|
||||
}
|
||||
@ -168,6 +184,12 @@ export function parseCallArguments(args: string[]): CallArgsParseResult {
|
||||
if (trailingPositional.length > 0) {
|
||||
result.positionalArgs = [...(result.positionalArgs ?? []), ...trailingPositional];
|
||||
}
|
||||
if (literalPositional.length > 0) {
|
||||
result.positionalArgs = [
|
||||
...(result.positionalArgs ?? []),
|
||||
...literalPositional.map((token) => coerceValue(token, flagState.coercionMode)),
|
||||
];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -174,6 +174,7 @@ export function printCallHelp(): void {
|
||||
' function-call syntax \'server.tool(arg: "value", other: 1)\'.',
|
||||
' --args <json> Provide a JSON object payload.',
|
||||
' positional values Accepted when schema order is known.',
|
||||
' -- Treat remaining tokens as literal positional values.',
|
||||
'',
|
||||
'Runtime flags:',
|
||||
' --timeout <ms> Override the call timeout.',
|
||||
|
||||
@ -40,6 +40,21 @@ describe('parseCallArguments', () => {
|
||||
expect(parsed.args.orderBy).toBe('updatedAt');
|
||||
});
|
||||
|
||||
it.each([
|
||||
['--source', '--source'],
|
||||
['--source=import', '--source=import'],
|
||||
] as const)('throws on unknown long flags like %s', (flag, expectedToken) => {
|
||||
expect(() => parseCallArguments(['server.tool', flag])).toThrow(
|
||||
new RegExp(`Unknown flag '${expectedToken.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}'`)
|
||||
);
|
||||
});
|
||||
|
||||
it('treats values after -- as literal positional arguments', () => {
|
||||
const parsed = parseCallArguments(['server.tool', '--', '--source', 'import', '--raw=true']);
|
||||
expect(parsed.selector).toBe('server.tool');
|
||||
expect(parsed.positionalArgs).toEqual(['--source', 'import', '--raw=true']);
|
||||
});
|
||||
|
||||
it('throws when flags conflict with call expression content', () => {
|
||||
expect(() => parseCallArguments(['--server', 'linear', 'cursor.list_documents(limit:1)'])).toThrow(
|
||||
/Conflicting server names/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user