This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
NUTS (Network Universal Testing Suite) is a Rust CLI tool for MCP server testing and API testing. It operates in two modes:
- Non-interactive CLI --
nuts call,nuts mcp discover,nuts mcp test, etc. Designed for scripts and CI. - Interactive REPL --
nuts shellenters the original interactive shell with tab completion.
AI features (security scanning, test generation) use Anthropic's Claude API via a centralized AiService.
cargo build # Build the project
cargo run # Run the CLI (shows help, not REPL)
cargo run -- shell # Enter the interactive REPL
cargo install --path . # Install locally as `nuts` binary
cargo test # Run all tests
cargo test --lib # Library tests only
cargo test --bin nuts # Binary tests only
cargo test <test_name> # Run a single test by name
cargo test mcp # Run MCP-related tests
cargo fmt # Format code (CI enforces --check)
cargo clippy --all-targets --all-features -- -D warnings # Lint (CI treats warnings as errors)
cargo check # Quick compile checkThe GitHub Actions CI pipeline (.github/workflows/ci.yml) runs on PRs to main and develop:
cargo fmt -- --check-- formatting must passcargo clippy --all-targets --all-features -- -D warnings-- no clippy warnings allowedcargo test --verbosecargo doc --no-deps --document-private-items- Cross-platform builds (Linux, Windows, macOS)
cargo auditfor security vulnerabilities
main.rs uses clap derive macros for CLI parsing. The Cli struct has a Commands enum with subcommands: Call, Perf, Security, Ask, Mcp, Config, Shell. No subcommand prints brief help.
Each run_* function creates a tokio::runtime::Runtime and calls block_on for async work. The shell subcommand delegates to NutsShell::run() (the original REPL).
Global flags: --json, --quiet, --no-color, --verbose, --env. TTY detection sets NO_COLOR when piped.
MCP subcommands use McpTransportArgs for transport selection (--stdio, --sse, --http). The resolve_transport() function converts these to a TransportConfig enum.
Working subcommands:
nuts mcp connect --stdio "cmd"-- connect, print server info, disconnectnuts mcp discover --stdio "cmd" [--json]-- full capability listingnuts mcp generate --stdio "cmd" [--json]-- AI-generate test YAML from discovered schemas
Placeholder subcommands (not yet wired): test, perf, security, snapshot.
NutsError enum with thiserror + miette:
- Variants:
Http,Ai,Config,Mcp,Protocol,Flow,AuthRequired,Io,InvalidInput pub type Result<T> = std::result::Result<T, NutsError>;- Auto-conversions from
reqwest::Error,serde_json::Error,serde_yaml::Error,std::io::Error
client.rs--McpClientwraps thermcpSDK. Methods:connect_stdio,connect_sse,connect_http,connect(fromTransportConfig),discover,list_tools,call_tool,list_resources,read_resource,list_prompts,get_prompt,disconnect.types.rs-- Data types:ServerCapabilities,Tool,Resource,ResourceTemplate,Prompt,PromptArgument,ToolResult,ContentItem(Text/Image/Audio/Resource),ResourceContent,PromptResult,PromptMessage,TransportConfig(Stdio/Sse/Http).discovery.rs--discover()convenience function,format_discovery_human(),format_discovery_json().generate.rs--generate_tests(client, ai)discovers tools and AI-generates YAML test cases. Handles markdown fence stripping.test_runner.rs-- YAML test file parser and assertion engine.TestFile/ServerConfig/TestCase/TestStepstructs.run_tests(path)connects to server, executes tests, returnsTestSummary. Supports captures ($.fieldJSONPath) and variable references (${var}). Human and JSON summary formatters.
service.rs--AiServiceholds aBox<dyn AiProvider>, tracks token usage, maintains conversation buffer. Methods:complete(),complete_with_system(),chat(),converse(),generate_test_cases(),security_scan(),explain(),validate_output(),suggest_command(). Default model:claude-sonnet-4-5-20250929.provider.rs--AiProvidertrait +AnthropicProvider.MockProviderfor tests.prompts.rs-- All prompt templates as functions. MCP-specific:mcp_test_generation(),mcp_security_scan(),mcp_output_validation(). API:api_security_analysis(),command_suggestion(),explain_response(),natural_language_command(), etc.
renderer.rs--render_status_line(),render_json_body()(syntax highlighted),render_headers(),render_table()(comfy-table),render_error()(what/why/fix),render_ai_insight(),render_test_result(),render_section(),spinner_style().OutputModeenum: Human/Json/Junit/Quiet.colors.rs-- Semantic color system usingconsolecrate.init_colors(),colors_enabled(). Styles: success, warning, error, info, muted, accent (+ bold). JSON: json_key (cyan), json_string (green), json_number (yellow), json_bool (magenta), json_null (dim red). RespectsNO_COLOR.welcome.rs--welcome_message()(3 lines),first_run_message(),help_text()(grouped by task: MCP TESTING, MAKING REQUESTS, etc.),command_help(cmd)per-command help.
src/shell.rs-- Interactive REPL with rustyline, tab completion, command dispatch viaprocess_command()match blocksrc/commands/-- Original command implementations (call, perf, security, ask, monitor, generate, etc.)src/flows/-- OpenAPI flow management and collection systemsrc/story/-- AI-guided workflow explorationsrc/models/--ApiAnalysis,Metrics,MetricsSummarysrc/config.rs-- Config stored at~/.nuts/config.jsonsrc/completer.rs-- Tab completion for shell mode
- Error handling: New modules use
NutsErrorviathiserror/miette. Legacy code still usesBox<dyn Error>.main.rsrun functions returnBox<dyn Error>to bridge both. - AI integration: New code uses
AiService(one instance, shared). Legacy commands still create per-callanthropic::client::Client. - Async: Each
run_*function in main.rs creates its owntokio::runtime::Runtime. The shell creates one inNutsShell::run(). - MCP transport: All MCP commands resolve
--stdio/--sse/--httpflags toTransportConfig, then callMcpClient::connect(). - User data: All persisted data lives under
~/.nuts/(config, flows). No database.
Test files (.test.yaml) have server: (transport config) and tests: (array of test cases). See docs/mcp-test-format.md for the full specification. Key structures:
server:
command: "node server.js" # or sse: / http:
timeout: 30
tests:
- name: "test name"
tool: "tool_name" # or resource: / prompt:
input: { key: value }
assert:
status: success
result.type: object
result.has_field: [id, name]
duration_ms: { max: 5000 }
capture:
var_name: "$.field.path"
- name: "multi-step"
steps:
- tool: "create"
input: { title: "test" }
capture: { id: "$.id" }
- tool: "get"
input: { id: "${id}" }Key crates:
- CLI:
clap(derive macros) - MCP:
rmcp(client, transport-child-process, transport-streamable-http, transport-sse) - AI:
anthropicclient crate - Error:
thiserror,miette(fancy diagnostics) - HTTP:
reqwest,axum,hyper,tower - Output:
comfy-table,console,indicatif,crossterm - Serialization:
serde,serde_json,serde_yaml - Async:
tokio,async-trait - Shell:
rustyline