A command-line interface for managing Model Context Interface (MCI) schemas and dynamically running MCP (Model Context Protocol) servers using defined MCI toolsets.
The MCI CLI tool is organized into the following directory structure:
src/mci/
├── __init__.py # Package initialization, exports main CLI entry point
├── mci.py # Main CLI entry point with Click group
├── cli/ # CLI command modules
│ └── __init__.py # CLI package initialization
├── core/ # Core business logic
│ └── __init__.py # Core package initialization
└── utils/ # Utility functions
└── __init__.py # Utils package initialization
src/mci/: Main package directory containing all MCI CLI codesrc/mci/mci.py: Main entry point withmain()function that implements the CLI using Clicksrc/mci/cli/: Contains all CLI command implementations (install, list, validate, add, run)src/mci/core/: Core business logic including MCI schema management, tool loading, and MCP server creationsrc/mci/utils/: Utility functions for error handling, validation, formatting, and other helpers
The main entry point is the main() function in src/mci/mci.py, which is exported from the package root. This function is a Click command group that serves as the foundation for all CLI commands.
To use the CLI tool:
# Show help and available commands
uv run mci --help
# Show version
uv run mci --versionThe mci install command initializes a new MCI project with starter configuration files and directory structure.
# Initialize a new MCI project with JSON configuration (default)
uv run mci install
# Initialize with YAML configuration
uv run mci install --yamlRunning mci install creates the following files and directories:
project-root/
├── mci.json (or mci.yaml) # Main MCI configuration file
└── mci/ # MCI library directory
├── .gitignore # Git ignore file (includes mcp/)
└── example_toolset.mci.json # Example toolset with CLI tool
The default configuration includes an example echo tool:
{
"schemaVersion": "1.0",
"metadata": {
"name": "Example Project",
"description": "Example MCI configuration"
},
"tools": [
{
"name": "echo_test",
"description": "Simple echo test tool",
"inputSchema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "Message to echo"
}
},
"required": ["message"]
},
"execution": {
"type": "text",
"text": "Echo: {{props.message}}"
}
}
],
"toolsets": [],
"mcp_servers": {}
}The example toolset includes a CLI tool for listing directory contents:
{
"schemaVersion": "1.0",
"metadata": {
"name": "Example Toolset",
"description": "Example MCI toolset with CLI tool"
},
"tools": [
{
"name": "list_files",
"description": "List files in a directory",
"inputSchema": {
"type": "object",
"properties": {
"directory": {
"type": "string",
"description": "Directory to list files from"
}
},
"required": ["directory"]
},
"execution": {
"type": "cli",
"command": "ls",
"args": ["-la", "{{props.directory}}"]
},
"enableAnyPaths": false,
"directoryAllowList": ["{{env.PROJECT_ROOT}}"]
}
],
"toolsets": [],
"mcp_servers": {}
}The install command is idempotent and handles existing files gracefully:
- Existing configuration file: Skips creation and displays a warning
- Existing
.gitignore: Updates ifmcp/entry is missing, otherwise skips - Existing example toolset: Skips creation and displays a warning
No files are overwritten by default, ensuring safe re-runs.
After running mci install, you can:
- Review the configuration: Edit
mci.jsonormci.yamlto customize your tools - Validate your setup: Run
mci validate(when implemented) to check your configuration - List available tools: Run
mci list(when implemented) to see all defined tools - Initialize MCIClient: Use the configuration programmatically:
from mcipy import MCIClient
# Load the generated configuration
client = MCIClient(schema_file_path="mci.json")
# List available tools
tools = client.tools()
for tool in tools:
print(f"{tool.name}: {tool.description}")The ./mci/.gitignore file is automatically created or updated to include:
mcp/
This prevents the ./mci/mcp/ directory (used for MCP server storage) from being committed to version control.
The mci list command displays all available tools from your MCI configuration. It provides a preview of the tool context that would be available when running MCP servers, with support for filtering, multiple output formats, and verbose mode.
# List all tools in table format (default)
uv run mci list
# List tools from a specific configuration file
uv run mci list --file custom.mci.json
# List with verbose output showing tags and parameters
uv run mci list --verboseThe list command supports three output formats:
Displays tools in a beautiful Rich terminal table:
uv run mci listOutput:
🧩 Available Tools (3)
┏━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Name ┃ Source ┃ Description ┃
┡━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ get_weather │ main │ Get current weather │
│ analyze │ main │ Analyze data │
│ send_email │ custom │ Send email notifications │
└─────────────┴────────┴──────────────────────────┘
Export tools to a timestamped JSON file:
uv run mci list --format jsonCreates a file like tools_20241029_143022.json with structure:
{
"timestamp": "2024-10-29T14:30:22Z",
"mci_file": "/path/to/mci.json",
"filters_applied": [],
"total": 3,
"tools": [
{
"name": "get_weather",
"source": "main",
"description": "Get current weather"
}
]
}Export tools to a timestamped YAML file:
uv run mci list --format yamlCreates a file like tools_20241029_143022.yaml.
The list command uses the same filtering logic as the run command, ensuring consistency between what is listed and what will be available when running MCP servers.
Include tools with specific tags (OR logic):
# Show only tools tagged with 'api' OR 'database'
uv run mci list --filter tags:api,databaseInclude or exclude specific tools by name:
# Include only specific tools
uv run mci list --filter only:get_weather,analyze
# Exclude specific tools
uv run mci list --filter except:deprecated_toolInclude tools from specific toolsets:
uv run mci list --filter toolsets:custom,externalVerbose mode shows additional tool metadata including tags, parameters, and execution type:
uv run mci list --verboseOutput:
🧩 Available Tools (2):
get_weather (main)
├── Description: Get current weather for a location
├── Tags: [api, data, weather]
├── Execution: text
└── Parameters: location (string), units (string) (optional)
analyze (main)
├── Description: Analyze data
├── Tags: [data, ml]
├── Execution: cli
└── Parameters: dataset (string), model (string) (optional)
You can combine filtering, output format, and verbose mode:
# Export filtered tools to JSON with verbose metadata
uv run mci list --filter tags:api --format json --verbose
# List only production tools in verbose table format
uv run mci list --filter tags:production --verbose- Preview Tools: See what tools are available before running an MCP server
- Debugging: Verify tool loading and filtering logic
- Documentation: Export tool lists for documentation or sharing
- Validation: Check that toolsets are loaded correctly
- Filtering: Test filter specifications before using them with
mci run
The mci add command adds toolset references to your MCI schema files. It supports optional filtering and automatically preserves the original file format (JSON stays JSON, YAML stays YAML).
# Add a toolset without filter
uv run mci add weather-tools
# Add a toolset with "only" filter
uv run mci add analytics --filter=only:Tool1,Tool2
# Add a toolset with "tags" filter
uv run mci add api-tools --filter=tags:api,database
# Add to a custom file
uv run mci add weather-tools --path=custom.mci.jsonThe add command supports the same filter types as the MCI schema:
Include only specific tools from the toolset:
uv run mci add analytics --filter=only:SummarizeData,AnalyzeSentimentThis adds to your schema:
{
"toolsets": [
{
"name": "analytics",
"filter": "only",
"filterValue": "SummarizeData,AnalyzeSentiment"
}
]
}Exclude specific tools from the toolset:
uv run mci add weather-tools --filter=except:DeprecatedToolInclude tools with specific tags:
uv run mci add api-tools --filter=tags:api,databaseExclude tools with specific tags:
uv run mci add internal-tools --filter=withoutTags:deprecated,experimentalThe add command automatically detects and preserves your file format:
JSON files stay JSON:
# Before (mci.json)
{
"toolsets": []
}
# Run: mci add weather-tools
# After (still JSON)
{
"toolsets": ["weather-tools"]
}YAML files stay YAML:
# Before (mci.yaml)
toolsets: []
# Run: mci add weather-tools
# After (still YAML)
toolsets:
- weather-toolsThe add command handles duplicates gracefully:
- Adding an existing toolset: Updates it with the new filter (if provided)
- No duplicates created: Each toolset appears only once in the array
Example:
# Initial state: toolsets: ["weather-tools"]
uv run mci add weather-tools --filter=tags:api
# Result: toolsets updated, not duplicated
# toolsets: [{"name": "weather-tools", "filter": "tags", "filterValue": "api"}]The add command automatically finds your MCI file:
- Looks for
mci.jsonin the current directory - Falls back to
mci.yamlif JSON not found - Falls back to
mci.ymlif YAML not found
To use a custom path:
uv run mci add weather-tools --path=./config/custom.mci.json- Add toolsets from library: Quickly add pre-built toolsets from your
./mcidirectory - Configure filtering: Add toolsets with specific tool subsets
- Organize tools: Group related tools into toolsets for better organization
- Update existing references: Modify filters on existing toolset references
The mci validate command checks MCI schema files for correctness using mci-py's built-in validation engine. It provides comprehensive validation of schema structure, types, and references, plus additional checks for toolset files and MCP command availability.
# Validate default mci.json/mci.yaml in current directory
uv run mci validate
# Validate a specific file
uv run mci validate --file custom.mci.json
# Validate with environment variables
uv run mci validate -e API_KEY=test123 -e BASE_URL=https://api.example.comThe validate command performs two levels of checks:
These are critical issues that prevent the schema from being used. Validation uses MCIClient from mci-py, which checks:
- Schema structure: Correct JSON/YAML syntax
- Required fields: Presence of
schemaVersionandmetadata - Data types: Field values match expected types
- Tool definitions: Valid execution types and input schemas
- Toolset references: Referenced toolsets must exist in the
mci/directory (validated by MCIClient) - MCP server definitions: Valid server configurations
If any errors are found, validation fails and the schema cannot be used.
These are non-critical issues that don't prevent the schema from being used:
- Missing MCP commands: Checks if MCP server commands are available in PATH
- Commands not in PATH generate warnings but don't fail validation
uv run mci validateOutput:
╭───────────── Validation Successful ──────────────╮
│ ✅ Schema is valid! │
│ │
│ File: /path/to/mci.json │
╰──────────────────────────────────────────────────╯
uv run mci validate --file invalid.mci.jsonOutput:
╭────────── Schema Validation Failed ──────────╮
│ ❌ Validation Errors │
│ │
│ 1. Failed to load schema: Missing required │
│ field 'schemaVersion' │
│ │
╰───────────────────────────────────────────────╯
💡 Fix the errors above and run 'mci validate' again
uv run mci validateOutput:
╭──────────────────── Warnings ─────────────────────╮
│ ⚠️ Validation Warnings │
│ │
│ 1. MCP server command not found in PATH: │
│ weather-mcp (server: weather_server) │
│ 💡 Install the command or ensure it's in PATH │
│ │
╰───────────────────────────────────────────────────╯
╭───────────── Validation Successful ──────────────╮
│ ✅ Schema is valid! │
│ │
│ File: /path/to/mci.json │
╰──────────────────────────────────────────────────╯
Use the -e or --env flag to provide environment variables needed for template substitution:
# Single environment variable
uv run mci validate -e API_KEY=your-api-key
# Multiple environment variables
uv run mci validate \
-e API_KEY=your-api-key \
-e BASE_URL=https://api.example.com \
-e PROJECT_ROOT=/path/to/projectEnvironment variables are merged with os.environ, so you can also set them in your shell:
export API_KEY=your-api-key
uv run mci validateWhen --file is not specified, the validate command searches for:
mci.json(first priority)mci.yamlormci.yml(if JSON not found)
in the current directory.
{
"tools": [] // Missing schemaVersion!
}Error:
Failed to load schema: Missing required field 'schemaVersion'
{
"schemaVersion": "1.0",
"metadata": { "name": "Test" },
"tools": [],
"toolsets": ["nonexistent"] // No file at mci/nonexistent.mci.json
}Error:
Toolset not found: nonexistent. Looked for directory or file with .mci.json/.mci.yaml/.mci.yml extension in ./mci
{
"schemaVersion": "1.0"
"metadata": {} // Missing comma!
}Error:
Failed to load schema: Invalid JSON syntax
- Pre-deployment validation: Verify schemas before deploying
- CI/CD integration: Add validation to your build pipeline
- Development workflow: Check schemas after making changes
- Troubleshooting: Get detailed error messages when schemas don't load
- Team collaboration: Ensure all team members use valid schemas
0: Schema is valid (warnings are OK)1: Validation failed with errors or file not found
The validate command leverages mci-py's built-in validation:
from mci.core.config import MCIConfig
# Programmatic validation (same as CLI)
config = MCIConfig()
is_valid, error = config.validate_schema("mci.json")
if not is_valid:
print(f"Validation error: {error}")All validation logic is provided by MCIClient from mci-py, ensuring consistency between the CLI and programmatic usage.
The mci run command launches an MCP (Model Context Protocol) server over STDIO that dynamically serves tools from an MCI schema file. The server loads tools using MCIClient, converts them to MCP format, and delegates execution back to MCIClient.
# Run server with default mci.json/mci.yaml
uv run mci run
# Run server with specific file
uv run mci run --file custom.mci.json
# Run server with filtered tools
uv run mci run --filter tags:api,databaseThe MCP server created by mci run:
- Loads tools from the MCI schema using MCIClient (including toolsets and environment variable templating)
- Converts tools to MCP format using the Stage 8 infrastructure
- Registers tools with the MCP server for protocol compliance
- Delegates execution back to MCIClient.execute() for each tool call
- Serves over STDIO using the MCP Python SDK
When you run mci run, the server:
- Finds or loads the MCI schema file
- Applies filters if specified
- Creates an MCP server instance
- Registers all tools in MCP format
- Starts listening on STDIO for MCP protocol requests
- Displays startup information
Output:
$ uv run mci run
⚡ Starting MCP server...
📄 Schema: /path/to/mci.json
Press Ctrl+C to stop the serverThe server handles graceful shutdown:
- Press Ctrl+C to stop the server
- The server cleans up resources and exits gracefully
Output:
^C
⏹ Server stopped by userThe run command uses the same filtering logic as the list command, ensuring consistency between what is listed and what the server will serve.
Include tools with specific tags (OR logic):
# Serve only tools tagged with 'api' OR 'database'
uv run mci run --filter tags:api,databaseInclude or exclude specific tools by name:
# Serve only specific tools
uv run mci run --filter only:get_weather,analyze
# Exclude specific tools
uv run mci run --filter except:admin_tools,delete_dataInclude tools from specific toolsets:
# Serve only tools from weather and news toolsets
uv run mci run --filter toolsets:weather,newsExclude tools with specific tags:
# Exclude tools tagged with 'experimental' or 'deprecated'
uv run mci run --filter without-tags:experimental,deprecatedThe server automatically collects and passes environment variables to MCIClient for template substitution in tool definitions:
Tool Definition (mci.json):
{
"name": "get_user_info",
"execution": {
"type": "text",
"text": "User: {{env.USER}}, Home: {{env.HOME}}"
}
}Running the Server:
# Environment variables are automatically available
uv run mci run
# Or set them explicitly before running
export API_KEY=your-api-key
export BASE_URL=https://api.example.com
uv run mci runThe server implements the full MCP protocol for tool serving:
The server responds to MCP tools/list requests with all registered tools:
{
"tools": [
{
"name": "get_weather",
"description": "Get current weather for a location",
"inputSchema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name or coordinates"
}
},
"required": ["location"]
}
}
]
}The server handles MCP tools/call requests by delegating to MCIClient:
Request:
{
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"location": "San Francisco"
}
}
}Response:
{
"content": [
{
"type": "text",
"text": "Weather in San Francisco: Sunny, 72°F"
}
]
}Test your MCI tools with an MCP client:
# Start server with all tools
uv run mci run
# Start server with only production tools
uv run mci run --filter tags:production
# Start server with specific test tools
uv run mci run --filter only:test_tool1,test_tool2Use with any MCP-compatible client:
- Claude Desktop: Configure as an MCP server
- MCP CLI clients: Connect via STDIO
- Custom integrations: Use the MCP Python SDK to connect
# Test with specific toolsets
uv run mci run --filter toolsets:api
# Test excluding deprecated tools
uv run mci run --filter except:old_tool,deprecated_tool
# Test with custom schema during development
uv run mci run --file dev.mci.jsonThe server handles errors gracefully:
$ uv run mci run
✗ No MCI schema file found. Run 'mci install' to create one or specify --file.$ uv run mci run --filter invalid-format
✗ Invalid filter: Invalid filter specification: 'invalid-format'.
Expected format: 'type:value1,value2,...' where type is one of: only, except, tags, without-tags, toolsetsWhen a tool fails during execution, the server returns the error in MCP format:
{
"content": [
{
"type": "text",
"text": "Tool execution failed: Connection timeout"
}
],
"isError": true
}The run command integrates seamlessly with other MCI commands:
# 1. Install MCI schema
uv run mci install
# 2. Add toolsets
uv run mci add weather-tools
uv run mci add api-tools
# 3. List tools to preview what will be served
uv run mci list
# 4. Validate schema before running
uv run mci validate
# 5. Run server with filtered tools
uv run mci run --filter tags:productionThe server is created with the name mci-dynamic-server by default. This is the name reported to MCP clients during initialization.
You can run multiple instances with different schemas or filters:
# Terminal 1: Serve all tools
uv run mci run --file all-tools.mci.json
# Terminal 2: Serve only API tools
uv run mci run --file api-only.mci.json --filter tags:apiYou can also use the dynamic server programmatically:
from mci.core.dynamic_server import DynamicMCPServer
# Create and configure server
server = DynamicMCPServer(
schema_path="mci.json",
filter_spec="tags:api",
env_vars={"API_KEY": "your-key"}
)
# Create server instance
instance = await server.create_from_mci_schema(
server_name="my-api-server",
server_version="1.0.0"
)
# Start STDIO server
await server.start_stdio()-
Check schema file exists:
uv run mci validate
-
Verify filter syntax:
uv run mci list --filter tags:api # Test filter -
Check for errors in schema:
uv run mci validate --file mci.json
-
List tools to verify they're loaded:
uv run mci list
-
Check filter is working as expected:
uv run mci list --filter tags:api
-
Verify toolsets are loaded:
uv run mci validate # Checks toolset files exist
-
Check environment variables:
echo $API_KEY # Verify env vars are set
-
Test tool execution with mci-py directly:
from mcipy import MCIClient client = MCIClient(schema_file_path="mci.json") result = client.execute("tool_name", properties={"param": "value"})
All further development stages build on this foundational structure:
- Stage 1: ✅ Project Setup & Core Dependencies
- Stage 2: ✅ Configuration & File Discovery
- Stage 3: ✅ CLI Command:
mci install - Stage 4: ✅ MCI-PY Integration & Tool Loading
- Stage 5: ✅ CLI Command:
mci list - Stage 6: ✅ CLI Command:
mci validate - Stage 7: ✅ CLI Command:
mci add - Stage 8: ✅ MCP Server Creation Infrastructure
- Stage 9: ✅ CLI Command:
mci run(STDIO MCP Server) - Stage 10: Error Handling, Documentation & Final Polish
The MCI CLI tool integrates with the mci-py library for robust loading and management of MCI tools. All tool loading, filtering, and schema operations are delegated to MCIClient from mci-py, ensuring consistency with the upstream adapter and future-proof functionality.
The MCIClientWrapper class provides a CLI-friendly interface to MCIClient from mci-py:
from mci.core.mci_client import MCIClientWrapper
# Load MCI schema
wrapper = MCIClientWrapper("mci.json")
# Get all tools
tools = wrapper.get_tools()
for tool in tools:
print(f"{tool.name}: {tool.description}")
# Filter tools
api_tools = wrapper.filter_tags(["api"])
safe_tools = wrapper.filter_except(["deprecated_tool"])
specific_tools = wrapper.filter_only(["tool1", "tool2"])The ToolManager class parses CLI filter specifications and applies filters using MCIClient methods:
from mci.core.mci_client import MCIClientWrapper
from mci.core.tool_manager import ToolManager
wrapper = MCIClientWrapper("mci.json")
# Apply filter specifications
api_tools = ToolManager.apply_filter_spec(wrapper, "tags:api,database")
non_deprecated = ToolManager.apply_filter_spec(wrapper, "without-tags:deprecated")
selected_tools = ToolManager.apply_filter_spec(wrapper, "only:tool1,tool2,tool3")Supported Filter Types:
only:tool1,tool2,...- Include only specified tools by nameexcept:tool1,tool2,...- Exclude specified tools by nametags:tag1,tag2,...- Include tools with any of these tags (OR logic)without-tags:tag1,tag2,...- Exclude tools with any of these tags (OR logic)toolsets:toolset1,toolset2,...- Include tools from specified toolsets
All tool operations delegate to MCIClient from mci-py:
- Schema parsing:
MCIClientvalidates and loads MCI schemas - Tool loading: Uses Pydantic models from mci-py for type-safe tool definitions
- Filtering: Leverages built-in methods:
only(),without(),tags(),withoutTags(),toolsets() - Environment variables: Template substitution via
MCIClient - Validation: Schema validation performed by
MCIClientduring initialization
No filtering or validation logic is reimplemented in the CLI. The wrapper focuses on:
- CLI-specific error handling
- Filter specification parsing
- Output formatting for terminal display
The ErrorHandler class formats MCIClientError exceptions for CLI-friendly display:
from mci.core.mci_client import MCIClientWrapper
from mci.utils.error_handler import ErrorHandler
from mcipy import MCIClientError
try:
wrapper = MCIClientWrapper("nonexistent.mci.json")
except MCIClientError as e:
# Format error for CLI display
formatted_error = ErrorHandler.format_mci_client_error(e)
print(formatted_error)Error messages include:
- Clear error descriptions
- Helpful suggestions for resolution
- Visual indicators (emoji) for better readability
from mci.core.mci_client import MCIClientWrapper
# Load with environment variables for template substitution
env_vars = {
"API_KEY": "your-api-key",
"BASE_URL": "https://api.example.com",
"PROJECT_ROOT": "/path/to/project"
}
wrapper = MCIClientWrapper("mci.json", env_vars=env_vars)
tools = wrapper.get_tools()Environment variables are used in tool definitions:
{
"name": "api_tool",
"execution": {
"type": "http",
"url": "{{env.BASE_URL}}/endpoint",
"headers": {
"Authorization": "Bearer {{env.API_KEY}}"
}
}
}All tool objects are Pydantic models from mci-py:
from mci.core.mci_client import MCIClientWrapper
wrapper = MCIClientWrapper("mci.json")
tools = wrapper.get_tools()
for tool in tools:
# Access Pydantic model properties
print(f"Name: {tool.name}")
print(f"Description: {tool.description}")
print(f"Tags: {tool.tags}")
print(f"Input Schema: {tool.inputSchema}")
print(f"Execution Type: {tool.execution.type}")Both JSON and YAML schema files are supported:
from mci.core.mci_client import MCIClientWrapper
# Load JSON schema
json_wrapper = MCIClientWrapper("mci.json")
# Load YAML schema
yaml_wrapper = MCIClientWrapper("mci.yaml")
# Both work identically
tools = json_wrapper.get_tools()The MCI CLI tool includes robust configuration file discovery and validation functionality.
The MCIFileFinder class provides methods to locate MCI configuration files in a directory:
from mci.core.file_finder import MCIFileFinder
# Find MCI configuration file (mci.json or mci.yaml)
finder = MCIFileFinder()
config_file = finder.find_mci_file("./my_project")
if config_file:
print(f"Found: {config_file}")
else:
print("No MCI configuration file found")File Priority: When both mci.json and mci.yaml exist in the same directory, JSON format is prioritized.
Supported Formats:
mci.json(preferred)mci.yamlmci.yml
from mci.core.file_finder import MCIFileFinder
finder = MCIFileFinder()
file_format = finder.get_file_format("./mci.json")
print(file_format) # Output: "json"
file_format = finder.get_file_format("./mci.yaml")
print(file_format) # Output: "yaml"The MCIConfig class uses MCIClient from mci-py to load and validate MCI configuration files:
from mci.core.config import MCIConfig
from mcipy import MCIClientError
# Load and validate configuration
config = MCIConfig()
try:
client = config.load("mci.json")
tools = client.tools()
print(f"Loaded {len(tools)} tools")
except MCIClientError as e:
print(f"Schema invalid: {e}")from mci.core.config import MCIConfig
# Validate schema without loading
config = MCIConfig()
is_valid, error = config.validate_schema("mci.json")
if is_valid:
print("Schema is valid")
else:
print(f"Validation failed: {error}")Support for environment variable substitution in MCI schemas:
from mci.core.config import MCIConfig
# Load with environment variables
config = MCIConfig()
env_vars = {
"API_KEY": "your-api-key",
"BASE_URL": "https://api.example.com"
}
client = config.load("mci.json", env_vars)The configuration system provides user-friendly error messages by leveraging mci-py's built-in validation:
- MCIClient Validation: Schema validation is performed by
MCIClientduring initialization - Error Extraction: Error messages from
MCIClientErrorare extracted and presented to users - File Not Found: Specific handling for missing configuration files
- Malformed Files: Detection of JSON/YAML parsing errors
Example error handling:
from mci.core.config import MCIConfig
from mcipy import MCIClientError
config = MCIConfig()
is_valid, error = config.validate_schema("path/to/mci.json")
if not is_valid:
# Error message contains details from MCIClient validation
print(f"Configuration error: {error}")
# Take corrective actionThe MCI CLI provides infrastructure for creating MCP (Model Context Protocol) servers that dynamically serve tools from MCI schemas. This allows you to expose MCI tools via the MCP protocol, making them available to MCP-compatible clients.
The MCP server creation system consists of three main components:
- MCIToolConverter: Converts MCI tool definitions to MCP tool format
- MCPServerBuilder: Creates and configures MCP servers with MCI tools
- ServerInstance: Manages server lifecycle and delegates execution to MCIClient
- Dynamic Tool Loading: Tools are loaded from MCI schemas using MCIClient and kept in memory
- Automatic Conversion: MCI tools are automatically converted to MCP-compatible tool definitions
- Execution Delegation: Tool execution is delegated back to MCIClient, ensuring consistency
- Flexible Filtering: Use MCIClient's filtering capabilities to selectively expose tools
- MCP Protocol Compliance: Full support for MCP tool listing and execution protocols
MCI Schema → MCIClient → MCPServerBuilder → MCP Server → STDIO
↓ ↓ ↓
Tools loaded Converted Tool execution
from schema to MCP format via MCIClient
from mcipy import MCIClient
from mci.core.mcp_server import MCPServerBuilder, ServerInstance
# Step 1: Load MCI schema
mci_client = MCIClient(schema_file_path="mci.json")
tools = mci_client.tools()
# Step 2: Create MCP server
builder = MCPServerBuilder(mci_client)
server = await builder.create_server("my-mci-server", "1.0.0")
# Step 3: Register tools
await builder.register_all_tools(server, tools)
# Step 4: Create and start server instance
instance = ServerInstance(server, mci_client)
await instance.start(stdio=True) # Runs server on STDIOMCI tools are automatically converted to MCP tool format:
MCI Tool:
{
"name": "greet",
"description": "Greet a person by name",
"inputSchema": {
"type": "object",
"properties": {
"name": {"type": "string"}
}
},
"execution": {
"type": "text",
"text": "Hello, {{props.name}}!"
}
}MCP Tool (after conversion):
types.Tool(
name="greet",
description="Greet a person by name",
inputSchema={
"type": "object",
"properties": {
"name": {"type": "string"}
}
}
)You can use MCIClient's filtering methods to selectively expose tools:
# Expose only API-related tools
api_tools = mci_client.tags(["api"])
await builder.register_all_tools(server, api_tools)
# Expose specific tools by name
specific_tools = mci_client.only(["get_weather", "get_forecast"])
await builder.register_all_tools(server, specific_tools)
# Exclude certain tools
safe_tools = mci_client.without(["dangerous_operation"])
await builder.register_all_tools(server, safe_tools)When an MCP client calls a tool, the server:
- Receives the tool call via MCP protocol
- Delegates execution to
MCIClient.execute() - Converts the result to MCP TextContent format
- Returns the response to the client
This ensures that all execution logic remains in MCIClient, avoiding duplication.
The ServerInstance class manages the server lifecycle:
- Startup: Initialize MCP protocol handlers and prepare for requests
- Runtime: Handle tool listing and execution requests
- Shutdown: Clean up resources (handled by async context manager)
For advanced MCP server features, including:
- Lifespan management with resource initialization/cleanup
- Structured output support
- Direct
CallToolResultreturns with_metafield - Low-level server API usage
See mcp-server-docs.md for comprehensive documentation.
The MCP server infrastructure is designed to be used by the mci run command (Stage 9), which will:
- Load tools from an MCI schema file
- Create an MCP server with those tools
- Start the server on STDIO
- Handle incoming MCP protocol requests
This allows users to instantly turn any MCI schema into a running MCP server.
For how to install uv and Python, see installation.md.
For development workflows, see development.md.
For the full implementation plan, see PLAN.md.
For instructions on publishing to PyPI, see publishing.md.
This project was built from simple-modern-uv.