use clap::{Parser, Subcommand};
use std::path::PathBuf;
#[derive(Parser)]
#[command(name = "mrapids")]
#[command(about = "Your OpenAPI, but executable", long_about = None)]
#[command(version)]
#[command(before_help = crate::core::banner::get_help_header())]
#[command(after_help = get_help_footer())]
#[command(override_help = get_grouped_help())]
pub struct Args {
#[command(subcommand)]
pub command: Commands,
#[arg(long, global = true, value_name = "ENV")]
pub env: Option<String>,
#[arg(long = "output-format", global = true, value_name = "FORMAT")]
pub output_format: Option<String>,
#[arg(long, short = 'q', global = true)]
pub quiet: bool,
#[arg(long, short = 'v', global = true)]
pub verbose: bool,
#[arg(long, global = true)]
pub trace: bool,
#[arg(long, global = true)]
pub no_color: bool,
#[arg(long, global = true, help_heading = "Agent Automation")]
pub json: bool,
#[arg(long, global = true, help_heading = "Agent Automation")]
pub machine: bool,
}
#[derive(Subcommand)]
pub enum Commands {
#[command(display_order = 1)]
Init(InitCommand),
#[command(alias = "search", alias = "discover", display_order = 2)]
Explore(ExploreCommand),
#[command(display_order = 3)]
Show(ShowCommand),
#[command(display_order = 4)]
Validate(ValidateCommand),
#[command(display_order = 5)]
Run(RunCommand),
#[command(display_order = 6)]
Test(TestCommand),
#[command(display_order = 7)]
List(ListCommand),
#[command(alias = "generate", display_order = 8)]
Gen(GenCommand),
#[command(display_order = 9)]
Flatten(FlattenCommand),
#[command(display_order = 10)]
Collection(CollectionCommand),
#[command(alias = "tests-init", display_order = 11)]
SetupTests(SetupTestsCommand),
#[command(display_order = 12)]
Auth(AuthCommand),
#[command(display_order = 13)]
Env(EnvCommand),
#[command(display_order = 14)]
Diff(DiffCommand),
#[command(display_order = 15)]
Cleanup(CleanupCommand),
#[command(display_order = 16)]
Doctor(DoctorCommand),
#[command(display_order = 17)]
Db(DbCommand),
#[command(display_order = 18)]
Sql(SqlCommand),
#[command(display_order = 19)]
Compare(CompareCommand),
#[command(display_order = 20)]
History(HistoryCommand),
#[command(display_order = 21)]
Export(ExportCommand),
#[command(display_order = 22)]
Index(IndexCommand),
#[command(display_order = 23)]
Find(FindCommand),
#[command(display_order = 25)]
Plan(PlanCommand),
#[command(display_order = 24)]
Policy(PolicyCommand),
#[command(display_order = 26)]
Mcp(McpCommand),
}
#[derive(Parser)]
pub struct PolicyCommand {
#[command(subcommand)]
pub command: PolicySubcommand,
}
#[derive(Subcommand)]
pub enum PolicySubcommand {
Init {
#[arg(long)]
spec: Option<PathBuf>,
#[arg(long, short)]
output: Option<PathBuf>,
#[arg(long)]
read_only: bool,
#[arg(long)]
preset: Option<String>,
},
Validate {
#[arg(long)]
policy: Option<PathBuf>,
},
Report {
#[arg(long)]
policy: Option<PathBuf>,
},
}
#[derive(Parser)]
pub struct ValidateCommand {
pub spec: PathBuf,
#[arg(long)]
pub strict: bool,
#[arg(long)]
pub lint: bool,
#[arg(long, requires = "lint")]
pub rules: Option<PathBuf>,
#[arg(short, long, value_enum, default_value = "text")]
pub format: ValidateFormat,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum ValidateFormat {
Text,
Json,
}
#[derive(Parser)]
pub struct InitCommand {
#[arg(default_value = "my-api-project")]
pub name: String,
#[arg(short, long, default_value = "rest")]
pub template: String,
#[arg(long, value_name = "URL", conflicts_with = "from_file")]
pub from_url: Option<String>,
#[arg(long, value_name = "FILE", conflicts_with = "from_url")]
pub from_file: Option<String>,
#[arg(short, long)]
pub force: bool,
#[arg(long)]
pub allow_insecure: bool,
}
#[derive(Parser, Clone)]
#[command(
args_override_self = true,
after_help = "AGENT/AUTOMATION:
--json-output Structured JSON with run_id, metadata, request/response
--machine No colors, no decorations
Exit codes: 0=success 2=args 3=auth 4=network 5=rate-limit 7=validation
WORKFLOW:
mrapids run <operation> -Q # See parameters + copy-ready command
mrapids run <operation> --param key=value # Execute with parameters
mrapids run <operation> --json-output # JSON for scripts/agents
COPY-READY EXAMPLES:
# 1. Discover what parameters an operation needs
mrapids run getPetById -Q
# 2. Execute GET with path/query parameters
mrapids run getPetById --param petId=1
# 3. Execute POST with JSON body
mrapids run createUser --data '{\"name\": \"john\", \"email\": \"john@example.com\"}'
# 4. Use saved auth profile
mrapids run getProfile --profile github
# 5. JSON output for scripts/agents
mrapids run listUsers --param limit=10 --json-output
# 6. Preview as curl (don't send)
mrapids run getUser --param id=123 --as-curl
# 7. Dry run (preview request without sending)
mrapids run createOrder --data @order.json --dry-run
TIPS:
• Parameters are auto URL-encoded - pass plain text
• Use quotes for spaces: --param q=\"status:active type:user\"
• Read body from file: --data @request.json or --file request.json
• Save response: --save response.json"
)]
pub struct RunCommand {
#[arg(required_unless_present_any = ["list_queries", "load_query"])]
pub operation: Option<String>,
#[arg(
short = 's',
long,
value_name = "FILE",
help_heading = "Spec Selection"
)]
pub spec: Option<PathBuf>,
#[arg(short, long, conflicts_with = "file", help_heading = "Data Input")]
pub data: Option<String>,
#[arg(short, long, conflicts_with = "data", help_heading = "Data Input")]
pub file: Option<PathBuf>,
#[arg(long, help_heading = "Common Parameters")]
pub id: Option<String>,
#[arg(long, help_heading = "Common Parameters")]
pub name: Option<String>,
#[arg(long, help_heading = "Common Parameters")]
pub status: Option<String>,
#[arg(long, help_heading = "Common Parameters")]
pub limit: Option<u32>,
#[arg(long, help_heading = "Common Parameters")]
pub offset: Option<u32>,
#[arg(long, help_heading = "Common Parameters")]
pub sort: Option<String>,
#[arg(
long = "param",
value_name = "KEY=VALUE",
help_heading = "Request Parameters"
)]
pub params: Vec<String>,
#[arg(
long = "query",
value_name = "KEY=VALUE",
help_heading = "Request Parameters"
)]
pub query_params: Vec<String>,
#[arg(
short = 'H',
long = "header",
value_name = "KEY: VALUE",
help_heading = "Request Parameters"
)]
pub headers: Vec<String>,
#[arg(long, conflicts_with = "auth_profile", help_heading = "Authentication")]
pub auth: Option<String>,
#[arg(long, conflicts_with = "auth_profile", help_heading = "Authentication")]
pub api_key: Option<String>,
#[arg(long = "profile", value_name = "PROFILE", conflicts_with_all = &["auth", "api_key"], help_heading = "Authentication")]
pub auth_profile: Option<String>,
#[arg(short, long)]
pub env: Option<String>,
#[arg(short, long)]
pub url: Option<String>,
#[arg(short, long, default_value = "pretty")]
pub output: String,
#[arg(long)]
pub save: Option<PathBuf>,
#[arg(long)]
pub template: Option<String>,
#[arg(long = "set", value_name = "KEY=VALUE")]
pub template_vars: Vec<String>,
#[arg(long, help_heading = "Testing & Debugging")]
pub required_only: bool,
#[arg(short, long, help_heading = "Testing & Debugging")]
pub verbose: bool,
#[arg(long, help_heading = "Testing & Debugging")]
pub dry_run: bool,
#[arg(long, help_heading = "Testing & Debugging")]
pub as_curl: bool,
#[arg(long, help_heading = "Testing & Debugging")]
pub log_decisions: bool,
#[arg(long, help_heading = "Data Input")]
pub edit: bool,
#[arg(long, help_heading = "Data Input")]
pub stdin: bool,
#[arg(long, default_value = "0", help_heading = "Request Options")]
pub retry: u32,
#[arg(long, default_value = "30", help_heading = "Request Options")]
pub timeout: u32,
#[arg(long, help_heading = "Security")]
pub allow_insecure: bool,
#[arg(long, help_heading = "Security")]
pub allow_localhost: bool,
#[arg(long, help_heading = "Security")]
pub no_warnings: bool,
#[arg(long, help_heading = "Security")]
pub redact: bool,
#[arg(short = 'i', long, conflicts_with_all = &["data", "file", "stdin"], help_heading = "Interactive Mode")]
pub interactive: bool,
#[arg(
long,
requires = "interactive",
value_name = "FILE",
help_heading = "Interactive Mode"
)]
pub save_as: Option<PathBuf>,
#[arg(long, requires = "interactive", help_heading = "Interactive Mode")]
pub minimal: bool,
#[arg(long, help_heading = "Query Assistance")]
pub help_query: bool,
#[arg(short = 'Q', long, conflicts_with_all = &["data", "file", "stdin", "interactive"], help_heading = "Query Assistance")]
pub build_query: bool,
#[arg(long, value_name = "FILE", help_heading = "Query Assistance")]
pub query_file: Option<PathBuf>,
#[arg(long, help_heading = "Query Assistance")]
pub replay_last: bool,
#[arg(long, value_name = "NAME", help_heading = "Query Assistance")]
pub save_query: Option<String>,
#[arg(long, value_name = "NAME", help_heading = "Query Assistance")]
pub load_query: Option<String>,
#[arg(long, help_heading = "Query Assistance")]
pub list_queries: bool,
#[arg(long, help_heading = "Collection Management")]
pub save_to_collection: bool,
#[arg(long, value_name = "NAME", help_heading = "Collection Management")]
pub collection: Option<String>,
#[arg(
long,
value_name = "NAME",
requires = "save_to_collection",
help_heading = "Collection Management"
)]
pub save_as_request: Option<String>,
#[arg(long, help_heading = "Agent Automation")]
pub json_output: bool,
}
#[derive(Parser)]
pub struct TestCommand {
pub spec: PathBuf,
#[arg(long)]
pub all: bool,
#[arg(short, long)]
pub operation: Option<String>,
#[arg(long, default_value = "true")]
pub cleanup: bool,
#[arg(long)]
pub keep_artifacts: bool,
#[arg(long)]
pub allow_insecure: bool,
#[arg(long)]
pub no_warnings: bool,
}
#[derive(Parser)]
pub struct AnalyzeCommand {
pub spec: Option<PathBuf>,
#[arg(short, long)]
pub operation: Option<String>,
#[arg(short = 'd', long, default_value = ".")]
pub output: PathBuf,
#[arg(long)]
pub all: bool,
#[arg(long)]
pub skip_data: bool,
#[arg(long)]
pub skip_validate: bool,
#[arg(short, long)]
pub force: bool,
#[arg(long, default_value = "true")]
pub cleanup_backups: bool,
}
#[derive(Parser)]
pub struct ListCommand {
#[arg(value_enum, default_value = "operations")]
pub resource: ListResource,
pub spec: Option<PathBuf>,
#[arg(short, long)]
pub filter: Option<String>,
#[arg(short, long)]
pub method: Option<String>,
#[arg(short, long)]
pub tag: Option<String>,
#[arg(long, value_enum, default_value = "table")]
pub format: ListFormat,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum ListResource {
Operations,
Requests,
All,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum ListFormat {
Table,
Simple,
Json,
Yaml,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum GenerateTarget {
Typescript,
Python,
Go,
Rust,
Java,
Csharp,
Ruby,
Php,
Swift,
Kotlin,
Curl,
Postman,
}
#[derive(Parser)]
pub struct SetupTestsCommand {
pub spec: PathBuf,
#[arg(short, long, value_enum, default_value = "npm")]
pub format: TestSetupFormat,
#[arg(short, long, default_value = ".")]
pub output: PathBuf,
#[arg(long)]
pub force: bool,
#[arg(long)]
pub dry_run: bool,
#[arg(long)]
pub with_examples: bool,
#[arg(long)]
pub with_env: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum TestSetupFormat {
Npm,
Make,
Shell,
Compose,
Curl,
All,
}
#[derive(Parser)]
pub struct CleanupCommand {
#[arg(long, default_value = "true")]
pub test_artifacts: bool,
#[arg(long, default_value = "true")]
pub empty_dirs: bool,
#[arg(long, default_value = "true")]
pub backups: bool,
#[arg(long, default_value = "true")]
pub preserve_specs: bool,
#[arg(short, long, default_value = ".")]
pub path: PathBuf,
#[arg(long)]
pub dry_run: bool,
}
#[derive(Parser)]
pub struct DoctorCommand {
#[arg(long)]
pub fix: bool,
#[arg(long, default_value = "all")]
pub check: String,
#[arg(short, long, default_value = ".")]
pub path: PathBuf,
#[arg(short, long, default_value = "text")]
pub format: String,
#[arg(short, long)]
pub verbose: bool,
}
#[derive(Parser)]
pub struct ShowCommand {
pub operation: String,
pub spec: Option<PathBuf>,
#[arg(long)]
pub examples: bool,
#[arg(long)]
pub template: bool,
#[arg(short, long, value_enum, default_value = "pretty")]
pub format: ShowFormat,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum ShowFormat {
Pretty,
Json,
Yaml,
}
#[derive(Parser)]
pub struct ExploreCommand {
pub keyword: String,
#[arg(short, long)]
pub spec: Option<PathBuf>,
#[arg(short, long, default_value = "5")]
pub limit: usize,
#[arg(long)]
pub detailed: bool,
#[arg(short, long, value_enum, default_value = "pretty")]
pub format: ExploreFormat,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum ExploreFormat {
Pretty,
Simple,
Json,
}
#[derive(Parser)]
pub struct AuthCommand {
#[command(subcommand)]
pub command: AuthCommands,
}
#[derive(Parser)]
pub struct EnvCommand {
#[command(subcommand)]
pub command: EnvCommands,
}
#[derive(Subcommand)]
pub enum EnvCommands {
List {
#[arg(short, long)]
verbose: bool,
},
Show {
environment: String,
#[arg(short, long)]
full: bool,
},
Create {
name: String,
#[arg(long)]
from: Option<String>,
#[arg(long)]
base_url: Option<String>,
},
Validate {
environment: Option<String>,
},
}
#[derive(Subcommand)]
pub enum AuthCommands {
Login {
provider: String,
#[arg(long)]
client_id: Option<String>,
#[arg(long)]
client_secret: Option<String>,
#[arg(long)]
auth_url: Option<String>,
#[arg(long)]
token_url: Option<String>,
#[arg(long, value_delimiter = ' ')]
scopes: Vec<String>,
#[arg(long)]
profile: Option<String>,
#[arg(long)]
setup_help: bool,
},
List {
#[arg(long)]
detailed: bool,
},
Show {
profile: String,
#[arg(long)]
show_tokens: bool,
},
Refresh {
profile: String,
},
Logout {
profile: String,
#[arg(long)]
force: bool,
},
Test {
profile: String,
},
Setup {
provider: String,
},
Detect {
#[arg(short, long)]
spec: Option<String>,
#[arg(short, long, value_enum, default_value = "table")]
format: DetectOutputFormat,
#[arg(long)]
operations: bool,
#[arg(long)]
summary_only: bool,
},
Connect {
scheme: String,
#[arg(short = 't', long)]
auth_type: Option<String>,
#[arg(long, conflicts_with_all = &["token", "username"])]
api_key: Option<String>,
#[arg(long, conflicts_with_all = &["api_key", "username"])]
token: Option<String>,
#[arg(long, requires = "password", conflicts_with_all = &["api_key", "token"])]
username: Option<String>,
#[arg(long, requires = "username")]
password: Option<String>,
#[arg(long, value_enum)]
flow: Option<OAuth2FlowType>,
#[arg(long)]
client_id: Option<String>,
#[arg(long)]
client_secret: Option<String>,
#[arg(long)]
scopes: Option<String>,
#[arg(long)]
non_interactive: bool,
#[arg(short, long)]
force: bool,
#[arg(short, long, default_value = "local")]
env: String,
},
Validate {
#[arg(short, long)]
scheme: Option<String>,
#[arg(long)]
spec: Option<String>,
#[arg(short = 'e', long)]
endpoint: Option<String>,
#[arg(short, long)]
verbose: bool,
#[arg(long)]
debug: bool,
#[arg(short, long)]
quick: bool,
},
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum DetectOutputFormat {
Table,
Json,
Yaml,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum OAuth2FlowType {
ClientCredentials,
AuthorizationCode,
DeviceCode,
Password,
}
#[derive(Parser)]
pub struct FlattenCommand {
pub spec: PathBuf,
#[arg(short, long)]
pub output: Option<PathBuf>,
#[arg(short, long, value_enum, default_value = "yaml")]
pub format: FlattenFormat,
#[arg(long)]
pub include_unused: bool,
#[arg(long)]
pub resolve_external: bool,
#[arg(long)]
pub allow_insecure: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum FlattenFormat {
Yaml,
Json,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum SdkLanguage {
Typescript,
Python,
Go,
Rust,
}
#[derive(Parser)]
pub struct DiffCommand {
pub old_spec: PathBuf,
pub new_spec: PathBuf,
#[arg(long, alias = "breaking")]
pub breaking_only: bool,
#[arg(short, long, value_enum, default_value = "text")]
pub format: DiffFormat,
#[arg(long)]
pub fail_on_breaking: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum DiffFormat {
Text,
Json,
Markdown,
}
#[derive(Parser)]
pub struct GenCommand {
#[command(subcommand)]
pub target: GenTarget,
}
#[derive(Subcommand)]
pub enum GenTarget {
Snippets(GenSnippetsCommand),
Sdk(GenSdkCommand),
Stubs(GenStubsCommand),
Fixtures(GenFixturesCommand),
}
#[derive(Parser)]
pub struct GenSnippetsCommand {
pub spec: Option<PathBuf>,
#[arg(short, long, default_value = "./examples")]
pub output: PathBuf,
#[arg(long)]
pub operation: Option<String>,
#[arg(long, value_enum, default_value = "json")]
pub format: SnippetFormat,
#[arg(long)]
pub curl: bool,
#[arg(long)]
pub httpie: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum SnippetFormat {
Json,
Yaml,
Curl,
Httpie,
All,
}
#[derive(Parser)]
pub struct GenSdkCommand {
pub spec: Option<PathBuf>,
#[arg(short, long, value_enum)]
pub language: SdkLanguage,
#[arg(short, long)]
pub output: Option<PathBuf>,
#[arg(long)]
pub package: Option<String>,
#[arg(long, default_value = "true")]
pub docs: bool,
#[arg(long, default_value = "true")]
pub examples: bool,
}
#[derive(Parser)]
pub struct GenStubsCommand {
pub spec: Option<PathBuf>,
#[arg(short, long)]
pub framework: String,
#[arg(short, long)]
pub output: Option<PathBuf>,
#[arg(long)]
pub with_tests: bool,
#[arg(long)]
pub with_validation: bool,
}
#[derive(Parser)]
pub struct GenFixturesCommand {
pub spec: Option<PathBuf>,
#[arg(short, long, default_value = "./fixtures")]
pub output: PathBuf,
#[arg(long, default_value = "10")]
pub count: u32,
#[arg(long)]
pub schema: Vec<String>,
#[arg(long)]
pub seed: Option<u64>,
#[arg(long, value_enum, default_value = "json")]
pub format: FixtureFormat,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum FixtureFormat {
Json,
Yaml,
Csv,
}
#[derive(Parser)]
pub struct CollectionCommand {
#[command(subcommand)]
pub command: CollectionSubcommand,
}
#[derive(Parser)]
pub struct DbCommand {
#[command(subcommand)]
pub command: DbSubcommand,
}
#[derive(Subcommand)]
pub enum DbSubcommand {
Status {
#[arg(short, long)]
verbose: bool,
},
Schema {
#[arg(short, long)]
table: Option<String>,
#[arg(short, long, value_enum, default_value = "table")]
format: DbSchemaFormat,
},
Query {
sql: String,
#[arg(short, long, value_enum, default_value = "table")]
format: DbOutputFormat,
},
Stats {
#[arg(long)]
spec: Option<String>,
#[arg(long)]
operation: Option<String>,
#[arg(long, default_value = "all")]
range: String,
},
Runs {
#[arg(short, long, default_value = "10")]
limit: usize,
#[arg(short, long, value_enum, default_value = "table")]
format: DbOutputFormat,
},
Run {
run_id: String,
#[arg(short, long, value_enum, default_value = "table")]
format: DbOutputFormat,
},
Request {
request_id: String,
#[arg(short, long, value_enum, default_value = "json")]
format: DbOutputFormat,
},
Reset {
#[arg(short, long)]
force: bool,
},
Check {
#[arg(short, long, value_enum, default_value = "text")]
format: DbCheckFormat,
#[arg(long)]
fix: bool,
},
Migrations,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum DbCheckFormat {
Text,
Json,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum DbOutputFormat {
Json,
Table,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum DbSchemaFormat {
Table,
Json,
Sql,
}
#[derive(Parser)]
#[command(after_help = "EXAMPLES:
# Run inline SQL query
mrapids sql \"SELECT count(*) FROM responses\"
mrapids sql \"SELECT * FROM runs\" --json
# Save a query for reuse
mrapids sql save slow-requests \"SELECT * FROM responses WHERE duration_ms > 1000\"
# Run a saved query
mrapids sql run slow-requests
mrapids sql run slow-requests --csv
# List saved queries
mrapids sql list
AVAILABLE TABLES:
runs - API execution sessions (run_id, timestamp, status, duration_ms)
requests - Request details (request_id, method, endpoint, url, headers)
responses - Response details (status_code, body, duration_ms, success)")]
pub struct SqlCommand {
#[command(subcommand)]
pub command: Option<SqlSubcommand>,
pub query: Option<String>,
#[arg(long, conflicts_with_all = &["csv", "table"])]
pub json: bool,
#[arg(long, conflicts_with_all = &["json", "table"])]
pub csv: bool,
#[arg(long, conflicts_with_all = &["json", "csv"])]
pub table: bool,
#[arg(long)]
pub no_header: bool,
}
#[derive(Subcommand)]
pub enum SqlSubcommand {
Save {
name: String,
query: String,
#[arg(short, long)]
description: Option<String>,
},
Run {
name: String,
#[arg(long, conflicts_with_all = &["csv", "table"])]
json: bool,
#[arg(long, conflicts_with_all = &["json", "table"])]
csv: bool,
#[arg(long, conflicts_with_all = &["json", "csv"])]
table: bool,
#[arg(long)]
no_header: bool,
},
List,
Delete {
name: String,
#[arg(short, long)]
force: bool,
},
}
#[derive(Parser)]
#[command(
about = "Compare two API runs and identify differences",
long_about = r#"Compare two API runs side-by-side to identify differences.
This is useful for:
- Comparing legacy vs new API implementations
- Detecting regressions between deployments
- Validating API migrations
The comparison identifies:
- Status code differences
- Response body changes
- Missing/new endpoints
- Performance variations
Examples:
mrapids compare --left abc123 --right def456
mrapids compare --left abc123 --right def456 --json
mrapids compare --left abc123 --right def456 --ignore-headers"#
)]
pub struct CompareCommand {
#[arg(long)]
pub left: String,
#[arg(long)]
pub right: String,
#[arg(long)]
pub json: bool,
#[arg(long)]
pub ignore_headers: bool,
#[arg(long)]
pub ignore_timing: bool,
#[arg(long)]
pub breaking_only: bool,
}
#[derive(Parser)]
#[command(
about = "Show API run history",
long_about = r#"Display a history of all API runs stored in the local database.
Shows run ID, timestamp, spec file, request counts, duration, and status.
Examples:
mrapids history
mrapids history --limit 20
mrapids history --json"#
)]
pub struct HistoryCommand {
#[arg(short, long, default_value = "10")]
pub limit: usize,
#[arg(long)]
pub json: bool,
#[arg(long)]
pub spec: Option<String>,
#[arg(long)]
pub failed: bool,
}
#[derive(Clone, Debug, clap::ValueEnum)]
pub enum ExportFormat {
Parquet,
Csv,
Json,
}
#[derive(Parser)]
#[command(
about = "Export data to Parquet, CSV, or JSON",
long_about = r#"Export DuckDB tables to external file formats for analysis in other tools.
Supported formats:
- parquet: Columnar format, ideal for analytics (Spark, DuckDB, Pandas)
- csv: Universal format for spreadsheets and data tools
- json: JSON array format for web applications
Examples:
mrapids export --table responses --format parquet
mrapids export --table runs --format csv --output runs.csv
mrapids export --query "SELECT * FROM responses WHERE status_code >= 400" --format json"#
)]
pub struct ExportCommand {
#[arg(long, conflicts_with = "query")]
pub table: Option<String>,
#[arg(long, conflicts_with = "table")]
pub query: Option<String>,
#[arg(long, short, value_enum, default_value = "parquet")]
pub format: ExportFormat,
#[arg(long, short)]
pub output: Option<PathBuf>,
}
#[derive(Subcommand)]
pub enum CollectionSubcommand {
List {
#[arg(long, default_value = "collections")]
dir: PathBuf,
},
Show {
name: String,
#[arg(long, default_value = "collections")]
dir: PathBuf,
},
Validate {
name: String,
#[arg(long, default_value = "collections")]
dir: PathBuf,
#[arg(long)]
spec: Option<PathBuf>,
},
Run {
name: String,
#[arg(long, default_value = "collections")]
dir: PathBuf,
#[arg(long, default_value = "pretty")]
output: String,
#[arg(long)]
save_all: Option<PathBuf>,
#[arg(long)]
save_summary: Option<PathBuf>,
#[arg(long = "var", value_parser = parse_key_val::<String, String>)]
variables: Vec<(String, String)>,
#[arg(long = "profile", value_name = "PROFILE")]
auth_profile: Option<String>,
#[arg(long)]
continue_on_error: bool,
#[arg(long = "request")]
requests: Vec<String>,
#[arg(long = "skip")]
skip_requests: Vec<String>,
#[arg(long)]
use_env: bool,
#[arg(long)]
env_file: Option<PathBuf>,
#[arg(long)]
spec: Option<PathBuf>,
#[arg(long)]
env: Option<String>,
},
Test {
name: String,
#[arg(long, default_value = "collections")]
dir: PathBuf,
#[arg(long)]
spec: Option<PathBuf>,
#[arg(long = "profile", value_name = "PROFILE")]
auth_profile: Option<String>,
#[arg(long, default_value = "pretty")]
output: String,
#[arg(long)]
continue_on_error: bool,
},
}
#[derive(Parser)]
#[command(
about = "Sketch execution plans from operations or collections",
long_about = r#"Generate read-only execution plan sketches showing how operations
would compose into a workflow. No side effects, no tokens, no execution.
Examples:
mrapids plan sketch getPetById updatePet deletePet
mrapids plan sketch --from my-collection
mrapids plan sketch --from my-collection --format json"#
)]
pub struct PlanCommand {
#[command(subcommand)]
pub command: PlanSubcommand,
}
#[derive(Subcommand)]
pub enum PlanSubcommand {
Sketch {
#[arg(required_unless_present = "from")]
operations: Vec<String>,
#[arg(long, value_name = "COLLECTION", conflicts_with = "operations")]
from: Option<String>,
#[arg(long, default_value = "collections")]
dir: PathBuf,
#[arg(long)]
spec: Option<PathBuf>,
#[arg(long, value_enum, default_value = "text")]
format: PlanFormat,
#[arg(long)]
show_gaps: bool,
},
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum PlanFormat {
Text,
Json,
}
#[derive(Parser)]
#[command(
about = "Build and manage operation index for semantic search",
long_about = r#"Build and manage an index of API operations for semantic search.
The index stores operation cards - structured representations of API operations
that enable fast keyword and semantic search across multiple specs.
Examples:
mrapids index build # Build index from current project spec
mrapids index add ./other-api.yaml # Add another spec to the index
mrapids index list # List all indexed specs
mrapids index status # Show index health and stats
mrapids index rebuild # Rebuild entire index"#
)]
pub struct IndexCommand {
#[command(subcommand)]
pub command: IndexSubcommand,
}
#[derive(Subcommand)]
pub enum IndexSubcommand {
Build {
#[arg(long)]
spec: Option<PathBuf>,
#[arg(long)]
id: Option<String>,
#[arg(short, long)]
force: bool,
#[arg(long, default_value = "none")]
embed: String,
},
Add {
spec: PathBuf,
#[arg(long)]
id: Option<String>,
#[arg(short, long)]
force: bool,
#[arg(long, default_value = "none")]
embed: String,
},
List {
#[arg(long, value_enum, default_value = "table")]
format: IndexOutputFormat,
},
Status {
#[arg(long, value_enum, default_value = "table")]
format: IndexOutputFormat,
},
Rebuild {
#[arg(long)]
spec: Option<String>,
#[arg(long, default_value = "none")]
embed: String,
},
Remove {
spec_id: String,
#[arg(short, long)]
force: bool,
},
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum IndexOutputFormat {
Table,
Json,
}
#[derive(Parser)]
#[command(
about = "Find operations using semantic search",
long_about = r#"Search for API operations using natural language queries.
Uses the operation index to find relevant operations based on:
- Operation IDs and paths
- Summaries and descriptions
- Parameter names and types
- Request/response schemas
Examples:
mrapids find "create user" # Find operations related to user creation
mrapids find "list products" --limit 5 # Limit results
mrapids find "auth" --spec users-api # Search within specific spec
mrapids find "POST" --method POST # Filter by HTTP method
mrapids find "update" --risk write # Filter by risk level"#
)]
pub struct FindCommand {
pub query: String,
#[arg(short, long, default_value = "10")]
pub limit: usize,
#[arg(long)]
pub spec: Option<String>,
#[arg(long)]
pub method: Option<String>,
#[arg(long)]
pub risk: Option<String>,
#[arg(long, value_enum, default_value = "table")]
pub format: FindOutputFormat,
#[arg(long)]
pub semantic: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum FindOutputFormat {
Table,
Json,
Ids,
}
#[derive(Parser)]
#[command(
about = "MCP server for AI agent integration",
long_about = r#"Run an MCP (Model Context Protocol) server that provides AI agents
with secure access to API operations.
SECURITY FEATURES:
- Zero Trust: Every request validated against policies
- Credential Isolation: AI never sees raw tokens
- Audit Logging: Complete logging of all AI actions
- Policy-based Access Control: Define what operations AI can perform
TOOLS PROVIDED:
api_find - Search for API operations using natural language
api_run - Execute API operations with credential injection
api_auth - Check authentication status
Examples:
# Start MCP server (stdio transport for Claude Desktop)
mrapids mcp serve
# Start with specific policy file
mrapids mcp serve --policy ./policy.yaml
# Show available tools
mrapids mcp tools
# Test a tool locally
mrapids mcp test api_find --query "create user""#
)]
pub struct McpCommand {
#[command(subcommand)]
pub command: McpSubcommand,
}
#[derive(Subcommand)]
pub enum McpSubcommand {
Serve {
#[arg(long)]
policy: Option<std::path::PathBuf>,
#[arg(long)]
spec: Option<std::path::PathBuf>,
#[arg(long)]
allow_localhost: bool,
#[arg(long)]
debug: bool,
#[arg(long)]
log_decisions: Option<Option<std::path::PathBuf>>,
},
Http {
#[arg(long, default_value = "8420")]
port: u16,
#[arg(long, default_value = "127.0.0.1")]
bind: String,
#[arg(long)]
api_key: Option<String>,
#[arg(long)]
policy: Option<std::path::PathBuf>,
#[arg(long)]
spec: Option<std::path::PathBuf>,
#[arg(long)]
base_url: Option<String>,
#[arg(long)]
allow_localhost: bool,
#[arg(long)]
debug: bool,
},
Tools,
Test {
tool: String,
#[arg(long)]
query: Option<String>,
#[arg(long)]
operation: Option<String>,
#[arg(long)]
params: Option<String>,
},
Status,
}
fn parse_key_val<T, U>(
s: &str,
) -> Result<(T, U), Box<dyn std::error::Error + Send + Sync + 'static>>
where
T: std::str::FromStr,
T::Err: std::error::Error + Send + Sync + 'static,
U: std::str::FromStr,
U::Err: std::error::Error + Send + Sync + 'static,
{
let pos = s
.find('=')
.ok_or_else(|| format!("invalid KEY=value: no `=` found in `{}`", s))?;
Ok((s[..pos].parse()?, s[pos + 1..].parse()?))
}
fn get_grouped_help() -> &'static str {
r#"mrapids - Your OpenAPI, but executable
Usage: mrapids [OPTIONS] <COMMAND>
QUICK START (your first 5 minutes):
mrapids init my-api --from-url https://api.example.com/openapi.json
mrapids explore "user" # Find operations
mrapids run <operation> -Q # See parameters + copy-ready command
mrapids run <operation> --param id=123 # Execute
mrapids history # See past runs
mrapids compare --left <run1> --right <run2> # Diff two runs
AGENT/AUTOMATION MODE:
--json Structured JSON output (run_id, metadata, errors)
--machine No colors, no decorations, parseable output
Exit codes: 0=success 2=args 3=auth 4=network 5=rate-limit 7=validation
COMMANDS
Getting Started:
init Create project from OpenAPI/GraphQL spec
explore Search operations by keyword (aliases: search, discover)
show Display operation details, parameters, examples
validate Check spec correctness + linting
doctor Diagnose issues with auto-fix (--fix)
Execution:
run Execute API operations
-Q Show parameters + copy-ready command
--as-curl Output as curl command
--dry-run Preview without sending
--json Structured output for agents
test Run automated tests against your API
list List operations, requests, or resources
Authentication:
auth detect Auto-detect auth requirements from spec
auth connect Configure credentials (API key, Bearer, OAuth)
auth login OAuth flow (GitHub, Google, custom)
auth validate Test configured credentials
auth list Show all auth profiles
Analytics (DuckDB-powered):
history Show recent API runs
sql Query history: mrapids sql "SELECT * FROM responses"
compare Diff two runs (regression/migration testing)
export Export to Parquet, CSV, JSON
db status Database stats and health
Workflows:
collection run Execute request sequences with dependencies
collection test Run collections as test suites
setup-tests Auto-generate test harness
Code Generation:
gen snippets Generate request/response examples
gen sdk [BETA] Generate SDK (TypeScript, Python, Go, Rust)
gen stubs [BETA] Generate server stubs
gen fixtures Generate test data from schemas
flatten Resolve all $ref references
Configuration:
env list/show/create Manage environments (dev, staging, prod)
Utilities:
diff Compare specs for breaking changes
cleanup Remove test artifacts
help Show help for any command
OPTIONS
--env <ENV> Environment (dev, staging, prod)
--output-format <FORMAT> Output format (json, yaml, table, pretty)
-q, --quiet Suppress output except errors
-v, --verbose Verbose output
--trace Trace HTTP requests/responses
--no-color Disable colors
-h, --help Print help
-V, --version Print version
COPY-READY EXAMPLES:
# 1. Initialize from remote spec
mrapids init my-api --from-url https://petstore.swagger.io/v2/swagger.json
# 2. Find operations
mrapids explore "pet"
# 3. See what parameters an operation needs
mrapids run getPetById -Q
# 4. Execute with parameters (JSON output for scripts)
mrapids run getPetById --param petId=1 --json
# 5. Query your API history
mrapids sql "SELECT operation_id, status_code, duration_ms FROM responses LIMIT 10"
# 6. Compare two runs (migration/regression testing)
mrapids compare --left abc123 --right def456
More help:
mrapids <command> --help
mrapids auth --help
mrapids db --help
https://microrapid.io"#
}
fn get_help_footer() -> &'static str {
r#"
More help: mrapids <command> --help
Docs: https://microrapid.io"#
}