Terminology:
- Skills = Claude Code native format (.claude/skills/ with SKILL.md) - Auto-discovered
- Scripts = CLI-based Python workflows (./scripts/) - Agent-agnostic
Dual-Mode MCP pattern: Reusable scripts (PREFERRED, 99.6% reduction) with CLI arguments, OR direct script writing (98.7% reduction) for novel tasks. Progressive disclosure via filesystem. Multi-transport support (stdio + SSE + HTTP).
When to use:
- Multi-step research workflows
- Cross-validation needed
- Data processing pipelines
- Chaining multiple MCP servers
- 99.6% token reduction, 96% time reduction
Pattern:
ls scripts/- Discover available scriptscat scripts/{script}.py- Read script docstring and CLI arguments- Execute with args (DO NOT edit file):
# Example: Simple fetch uv run python -m runtime.harness scripts/simple_fetch.py \ --url "https://example.com" # Example: Multi-tool pipeline uv run python -m runtime.harness scripts/multi_tool_pipeline.py \ --repo-path "." \ --max-commits 5
Generic Example Scripts:
Reusable CLI workflows (./scripts/):
simple_fetch.py- Basic single-tool pattern (--url)multi_tool_pipeline.py- Multi-tool chaining pattern (--repo-path,--max-commits)
Note: These are templates - use as examples to create custom scripts for your specific MCP servers and use cases.
Claude Code Users: These scripts are also available as native Skills in .claude/skills/ (SKILL.md format, auto-discovered).
When to use:
- Single tool call
- Straightforward data retrieval
- Novel workflows not covered by existing scripts
- Prototyping new patterns
Pattern: (existing documentation)
- Explore
servers/to discover tools - Write Python script using tool imports
- Execute:
uv run python -m runtime.harness workspace/script.py
Important: This project uses
mcp_config.jsonin the project root, separate from Claude Code's global MCP configuration (~/.claude.json).To avoid conflicts:
- Option A: Use different servers in each configuration
- Option B: Disable overlapping servers in
~/.claude.jsonwhile using this project
uv run mcp-generate- Gen Python wrappers from project'smcp_config.jsonuv run mcp-discover- Gen Pydantic types from actual API responses (seediscovery_config.json)uv run mcp-exec <script.py>- Run script w/ MCP (direct or sandbox mode)uv run mcp-exec <script> --args- Run script with CLI arguments- Example scripts:
workspace/example_progressive_disclosure.py,tests/integration/test_*.py - User scripts go in:
workspace/(gitignored)
src/runtime/mcp_client.py-McpClientManager: lazy loading,initialize()loads config only,call_tool()connects on-demand, tool format"serverName__toolName", singleton viaget_mcp_client_manager()src/runtime/harness.py- Exec harness: dual-mode (direct/sandbox), asyncio, MCP init, signal handlers, cleanupsrc/runtime/generate_wrappers.py- Auto-gen: connects all servers (stdio/SSE/HTTP), introspects schemas, generatesservers/<server>/<tool>.py+__init__.pysrc/runtime/discover_schemas.py- Schema discovery: calls safe read-only tools, generatesservers/<server>/discovered_types.pyfrom real responsessrc/runtime/normalize_fields.py- Field normalization: auto-converts inconsistent API field casing (e.g., ADO:system.parent→System.Parent)src/runtime/sandbox/- Container sandboxing: rootless isolation, security controls, optional execution mode
servers/ (gitignored, regen w/ uv run mcp-generate):
servers/<serverName>/<toolName>.py # Pydantic models, async wrapper
servers/<serverName>/__init__.py # Barrel exports
servers/<serverName>/discovered_types.py # Optional: Pydantic types from actual API responses
scripts/ (CLI-based parameter templates - edit logic freely):
scripts/<script_name>.py # Workflow with argparse, USAGE docstring
scripts/README.md # Scripts documentation
scripts/SCRIPTS.md # Complete framework guide
mcp_config.json format (multi-transport):
{
"mcpServers": {
"name_stdio": {
"type": "stdio",
"command": "command",
"args": ["arg1"],
"env": {}
},
"name_sse": {
"type": "sse",
"url": "https://...",
"headers": {"Authorization": "Bearer ..."}
},
"name_http": {
"type": "http",
"url": "https://...",
"headers": {"x-api-key": "..."}
}
},
"sandbox": {
"enabled": false,
"runtime": "auto",
"image": "python:3.11-slim"
}
}discovery_config.json format (optional, for schema discovery):
{"servers": {"name": {"safeTools": {"tool_name": {"param1": "value"}}}}}- Discover:
ls scripts/→ see available script templates - Read:
cat scripts/simple_fetch.py→ see CLI arguments and USAGE - Execute:
uv run python -m runtime.harness scripts/simple_fetch.py --url "https://example.com" - Change parameters via CLI args - edit scripts freely to fix bugs or improve logic
- Create your own scripts for your specific workflows using the template
- Add server: edit
mcp_config.json→ specify type (stdio/sse/http) - Generate wrappers:
uv run mcp-generate→ auto-detect transports - Import in script:
from servers.name import tool_name - Execute:
uv run mcp-exec workspace/script.py(auto-connect on first call)
Optional schema discovery: copy discovery_config.example.json → edit w/ safe read-only tools + real params → uv run mcp-discover → from servers.name.discovered_types import ToolNameResult
Script pattern (workspace/ for user scripts, tests/ for examples):
from servers.name import tool_name
from servers.name.discovered_types import ToolNameResult # optional
result = await tool_name(params) # Pydantic model
# Use defensive coding: result.field or fallback
# Return data - LLM can process/summarize in follow-up interactions
# Not all processing needs to happen in-script- Scripts pattern - Change parameters via CLI args, edit scripts freely to fix bugs or improve logic
- Skills (Claude Code) - Native SKILL.md format in .claude/skills/ (auto-discovered by Claude Code)
- Tool ID:
"serverName__toolName"(double underscore) - Progressive disclosure:
- Scripts with CLI args: 110 tokens, 99.6% reduction (PREFERRED)
- Writing scripts from scratch: 2K tokens, 98.7% reduction (ALTERNATIVE)
- Claude Code Skills: Wrapper for script discovery (auto-discovered)
- Multi-transport: stdio (subprocess), SSE (events), HTTP (streamable)
- Processing flexibility: Scripts can return raw data for LLM to process, pre-process for efficiency, or reshape for chaining tool calls - choose based on use case
- Type gen: Pydantic models for all schemas, handles primitives, unions, nested objects, required/optional, docstrings
- Schema discovery: only use safe read-only tools (never mutations), types are hints (fields marked Optional), still use defensive coding
- Field normalization: auto-applied per server (e.g., ADO normalizes all fields to PascalCase for consistency)
- Python: asyncio for concurrency, Pydantic for validation, mypy for type safety
- Sandbox mode: Optional container isolation with security controls (--sandbox flag or config)
- "MCP server not configured": check
mcp_config.jsonkeys - "Connection closed": verify server command with
which <command> - Missing wrappers:
uv run mcp-generate - Import errors: ensure
src/in sys.path (harness handles this) - Type checking:
uv run mypy src/for validation - Script --help:
python scripts/{script}.py --helpshows CLI arguments