Hands-on examples for every apexe use case — from 30-second quick start to full Rust library integration.
| Example | Type | What You'll Learn | Run |
|---|---|---|---|
| basic | Shell script | Scan a tool, inspect results, start MCP server | ./examples/basic/run.sh |
| programmatic | Rust code | Use apexe as a library: scan → convert → export → serve | cargo run --example programmatic |
# From the repo root
cargo install --path .
apexe --version
# apexe 0.1.0A shell script that walks through the complete apexe workflow:
scan git → write bindings → write ACL → list modules → print configs → start server
cd examples/basic
./run.sh=== Step 1: Scan git ===
Tool: git (2.39.5)
Binary: /usr/bin/git
Scan tier: 2
Subcommands: 12
Global flags: 3
=== Step 2: List generated modules ===
MODULE ID DESCRIPTION
──────────────────────────────────────── ────────────────────────────────────────
cli.git.add Add file contents to the index
cli.git.commit Record changes to the repository
cli.git.push Update remote refs
cli.git.status Show the working tree status
...
12 module(s) found.
=== Step 3: Inspect ACL ===
rules:
- callers: ["*"]
targets: ["cli.git.status", "cli.git.log", "cli.git.diff"]
effect: allow
description: Auto-allow readonly CLI commands
- callers: ["*"]
targets: ["cli.git.rm"]
effect: deny
description: Block destructive CLI commands by default
conditions:
require_approval: true
default_effect: deny
If git shows 0 subcommands, the cache has a stale result. Force re-scan:
apexe scan git --no-cache --depth 3output/
modules/
cli.git.binding.yaml # JSON Schema for every git subcommand
~/.apexe/
acl.yaml # Access control rules
Shows how to embed apexe in your own Rust application:
- Scan CLI tools programmatically
- Convert scan results to apcore
ScannedModule - Write binding YAML files
- Export OpenAI-compatible tool definitions
- Build an MCP server (without starting it)
cargo run --example programmatic=== Scanning 'echo' (a simple tool for demonstration) ===
Scanned: echo (tier 1, 0 subcommands, 0 global flags)
=== Converting to ScannedModules ===
Module: cli.echo — Execute echo
readonly=false, destructive=false, requires_approval=false
display alias: echo
=== Writing binding files ===
Written: /Users/you/.apexe/modules/cli.echo.binding.yaml
=== Exporting OpenAI-compatible tool definitions ===
1 tool(s) exported:
[
{
"function": {
"description": "Execute echo",
"name": "cli-echo",
"parameters": { "type": "object", "properties": {} }
},
"type": "function"
}
]
=== Building MCP server (not starting) ===
MCP server built successfully. Call server.serve() to start.
Scan a tool:
use apexe::config::ApexeConfig;
use apexe::scanner::ScanOrchestrator;
let config = ApexeConfig::default();
let orchestrator = ScanOrchestrator::new(config);
let tools = orchestrator.scan(&["git".to_string()], false, 2)?;Convert to ScannedModules:
use apexe::adapter::CliToolConverter;
let converter = CliToolConverter::new();
let modules = converter.convert_all(&tools);
// Each module has: module_id, input_schema, output_schema, annotations, display metadataWrite binding YAML:
use apexe::output::YamlOutput;
let yaml = YamlOutput::new(); // with verification
let results = yaml.write(&modules, output_dir, false)?;Export OpenAI function calling format:
use apexe::mcp::McpServerBuilder;
let tools = McpServerBuilder::new()
.modules_dir("/path/to/modules")
.export_openai_tools()?;
// Returns Vec<serde_json::Value> in OpenAI function_tools formatBuild and start MCP server:
let server = McpServerBuilder::new()
.name("my-tools")
.transport("http") // or "stdio", "sse"
.port(8000)
.explorer(true) // browser-based tool explorer UI
.modules_dir("/path/to/modules")
.enable_logging(true) // structured logging middleware
.enable_approval(true) // approval dialog for destructive commands
.tags(vec!["readonly".into()]) // only expose readonly tools
.build()?;
server.serve()?; // blocking — starts the serverapexe scan ls jq curl --no-cache
apexe list
# Shows all modules from all toolsapexe serve --transport http --port 8000 --explorer
# Open http://127.0.0.1:8000/explorer in your browser- Scan ls, jq, and curl:
apexe scan ls jq curl --no-cache
apexe serve --transport http --port 8000 --explorer-
Open http://127.0.0.1:8000/explorer in your browser
-
Click
cli.ls→ type{}→ click Call. Instant file listing:
{}Response:
{
"content": [
{
"type": "text",
"text": "{\"stdout\":\"Cargo.toml\\nREADME.md\\nsrc\\n...\",\"stderr\":\"\",\"exit_code\":0}"
}
]
}- Click
cli.jq→ 22 form fields! Try:
{"compact_output": true, "raw_output": true}- Click
cli.curl→ 12 form fields. Try:
{"verbose": true, "silent": true}Start the server in one terminal, then call tools from another:
# Terminal 1: start server
apexe scan ls jq curl --no-cache
apexe serve --transport http --port 8000 --explorer# Terminal 2: MCP protocol — initialize handshake
curl -s -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {"name": "curl-test", "version": "1.0"}
}
}' | python3 -m json.tool# List all available tools
curl -s -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}' | python3 -m json.tool# Execute: list files in current directory (cli.ls)
curl -s -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "cli.ls",
"arguments": {}
}
}' | python3 -m json.tool# Execute: search for "TODO" in .rs files (cli.grep)
curl -s -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "cli.grep",
"arguments": {}
}
}' | python3 -m json.tool# Execute via Explorer UI shortcut (simpler format)
curl -s -X POST http://localhost:8000/explorer/tools/cli.ls/call \
-H "Content-Type: application/json" \
-d '{}' | python3 -m json.tool# Execute: find files by name pattern (cli.find)
curl -s -X POST http://localhost:8000/explorer/tools/cli.find/call \
-H "Content-Type: application/json" \
-d '{}' | python3 -m json.toolExpected response (cli.ls example):
{
"content": [
{
"type": "text",
"text": "{\"stdout\":\"Cargo.toml\\nREADME.md\\nsrc\\ntests\\n...\",\"stderr\":\"\",\"exit_code\":0,\"trace_id\":\"abc-123\",\"duration_ms\":5}"
}
]
}If you get AclDenied: you're running with --acl. Remove it or start without ACL:
apexe serve --transport http --port 8000 --explorer
# No --acl flag = no access control = all tools allowed# 1. Scan tools
apexe scan git curl grep
# 2. Get integration config
apexe serve --show-config claude-desktop
# Output:
# {
# "mcpServers": {
# "apexe": {
# "command": "apexe",
# "args": ["serve", "--transport", "stdio"]
# }
# }
# }
# 3. Copy to config file
# macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
# Linux: ~/.config/claude/claude_desktop_config.json
# 4. Restart Claude Desktop — tools appear in MCP tool listapexe serve --show-config cursor
# Add the JSON to Cursor's MCP settingsapexe scan git --output-dir ./my-project/tools
apexe serve --modules-dir ./my-project/toolsapexe scan git --format json | jq '.subcommands[0].flags'
# Shows parsed flags with types, defaults, descriptionsapexe scan git --format yaml | grep -A5 "annotations"
# readonly: true/false, destructive: true/false, requires_approval: true/falseCache has a stale entry. Force re-scan:
apexe scan git --no-cache --depth 3Or clear the entire cache:
rm -rf ~/.apexe/cache/The tool must be installed and accessible:
which git # should print a path
apexe scan gitStdio mode communicates via stdin/stdout — it's meant to be launched by AI agents, not run interactively. Use --show-config to get the agent integration snippet, or use HTTP mode for manual testing:
apexe serve --transport http --port 8000 --explorerThe default ACL denies destructive and unknown commands. Edit ~/.apexe/acl.yaml:
rules:
- callers: ["*"]
targets: ["cli.git.push"]
effect: allow
description: "Allow git push"
default_effect: denyCreate a .rs file in examples/ — Cargo auto-discovers it:
# examples/my_example.rs
cargo run --example my_exampleKey imports:
use apexe::adapter::CliToolConverter;
use apexe::config::ApexeConfig;
use apexe::governance::{AclManager, AuditManager};
use apexe::mcp::McpServerBuilder;
use apexe::module::CliModule;
use apexe::output::{YamlOutput, load_modules_from_dir};
use apexe::scanner::ScanOrchestrator;Create a directory under examples/ with a run.sh and README.md:
examples/my-scenario/
README.md
run.sh # chmod +x