Skip to main content

Documentation Index

Fetch the complete documentation index at: https://usemci.dev/llms.txt

Use this file to discover all available pages before exploring further.

MCIClient Class

The MCIClient class is the main entry point for the MCI Python adapter. It provides methods for loading, filtering, and executing MCI tools from a JSON or YAML schema file.

Initialization

MCIClient(schema_file_path=None, env_vars=None, json_file_path=None, validating=False)

Initialize the MCI client with a schema file and optional environment variables. Parameters:
NameTypeRequiredDescription
schema_file_pathstrConditional*Path to the MCI schema file (.json, .yaml, or .yml)
env_varsdict[str, Any]NoEnvironment variables for template substitution (default: {})
json_file_pathstrConditional*DEPRECATED. Use schema_file_path instead. Kept for backward compatibility.
validatingboolNoEnable pure schema validation mode without loading MCP servers, toolsets, or resolving templates. Tool execution is disabled in this mode. (default: False)
*Either schema_file_path or json_file_path must be provided. Raises:
  • MCIClientError - If the schema file cannot be loaded or parsed
  • MCIClientError - If neither schema_file_path nor json_file_path is provided
Example:
from mcipy import MCIClient

# Initialize with JSON file (recommended)
client = MCIClient(schema_file_path="example.mci.json")

# Initialize with YAML file
client = MCIClient(schema_file_path="example.mci.yaml")

# Initialize with environment variables
client = MCIClient(
    schema_file_path="example.mci.json",
    env_vars={
        "API_KEY": "your-secret-key",
        "USERNAME": "demo_user",
        "BEARER_TOKEN": "token-123"
    }
)

# Validating mode: validate schema without loading toolsets or MCP servers
# Useful for CI validation, IDE plugins, or schema checking
client = MCIClient(
    schema_file_path="example.mci.json",
    validating=True  # No env vars needed, no side effects
)

# Check what tools are defined (inline tools only in validating mode)
tool_names = client.list_tools()

# Backward compatibility: json_file_path still works
client = MCIClient(json_file_path="example.mci.json")
# Works with YAML too
client = MCIClient(json_file_path="example.mci.yaml")
Success Response: Returns an initialized MCIClient instance ready to use. Error Response:
# Raises MCIClientError
MCIClientError: Failed to load schema from invalid.json: [Errno 2] No such file or directory: 'invalid.json'

# Unsupported file extension
MCIClientError: Failed to load schema from file.txt: Unsupported file extension '.txt'. Supported extensions: .json, .yaml, .yml

Validating Mode

When validating=True is specified, the client operates in a special validation-only mode: What happens in validating mode:
  • ✅ Schema file is parsed and validated (JSON/YAML syntax, structure, types)
  • ✅ Schema version is checked for compatibility
  • ✅ Tool definitions are validated (required fields, execution types)
  • ✅ Toolset files are checked for existence (but not loaded)
  • ✅ MCP server configurations are validated (but servers are not contacted)
  • ✅ Read-only operations work normally (list_tools(), tools(), only(), without(), etc.)
What does NOT happen in validating mode:
  • ❌ No template resolution (placeholders like {{env.VAR}} are accepted as-is)
  • ❌ No MCP server connections or tool fetching
  • ❌ No toolset file loading (only existence is checked)
  • ❌ No file writes or cache directory creation
  • ❌ No network requests
  • ❌ Tool execution is blocked (raises MCIClientError)
Use cases for validating mode:
  • CI/CD validation: Check schema validity without requiring environment variables
  • IDE/Editor plugins: Validate schemas and provide autocomplete without side effects
  • Schema testing: Verify schema structure before deployment
  • Documentation generation: Parse schemas to generate tool documentation
  • Pre-deployment checks: Validate schemas before committing to version control
Example:
from mcipy import MCIClient, MCIClientError

# Validate a schema with MCP servers that require env vars
client = MCIClient(
    schema_file_path="schema_with_mcp.mci.json",
    validating=True  # No env vars needed!
)

# This works - checking what tools are defined
print(f"Schema contains {len(client.list_tools())} inline tools")

# This works - listing toolsets (just checks they exist)
# Toolsets are not loaded, so tools from toolsets won't appear in list_tools()

# This raises an error - execution is disabled
try:
    client.execute("some_tool", {})
except MCIClientError as e:
    print(f"Expected error: {e}")
    # Output: Tool execution is disabled in validating mode. Initialize MCIClient with validating=False to execute tools.

Methods

tools()

Get all available tools from the loaded schema. Method Signature:
def tools(self) -> list[Tool]
Parameters: None Returns:
TypeDescription
list[Tool]List of all Tool objects in the schema
Example:
from mcipy import MCIClient

client = MCIClient(json_file_path="example.mci.json")
all_tools = client.tools()

for tool in all_tools:
    print(f"Tool: {tool.name} - {tool.description}")
Success Response:
[
    Tool(
        name="get_weather",
        annotations=Annotations(title="Get Weather Information"),
        description="Fetch current weather information for a location",
        inputSchema={
            "type": "object",
            "properties": {
                "location": {"type": "string", "description": "City name or location"}
            },
            "required": ["location"]
        },
        execution=HTTPExecutionConfig(...)
    ),
    Tool(
        name="create_report",
        annotations=Annotations(title="Create Report"),
        description="Create a new report using HTTP POST request",
        inputSchema={...},
        execution=HTTPExecutionConfig(...)
    )
]
Error Response: No errors - always returns a list (may be empty if no tools defined).

only()

Filter tools to include only specified tools by name. Method Signature:
def only(self, tool_names: list[str]) -> list[Tool]
Parameters:
NameTypeRequiredDescription
tool_nameslist[str]YesList of tool names to include
Returns:
TypeDescription
list[Tool]Filtered list of Tool objects matching the specified names
Example:
from mcipy import MCIClient

client = MCIClient(json_file_path="example.mci.json")

# Get only weather-related tools
weather_tools = client.only(["get_weather", "get_forecast"])

for tool in weather_tools:
    print(f"Weather tool: {tool.name}")
Success Response:
[
    Tool(
        name="get_weather",
        annotations=Annotations(title="Get Weather Information"),
        description="Fetch current weather information for a location",
        inputSchema={...},
        execution=HTTPExecutionConfig(...)
    ),
    Tool(
        name="get_forecast",
        annotations=Annotations(title="Get Weather Forecast"),
        description="Get weather forecast for the next 7 days",
        inputSchema={...},
        execution=HTTPExecutionConfig(...)
    )
]
Error Response: No errors - returns empty list if no tools match the specified names.

without()

Filter tools to exclude specified tools by name. Method Signature:
def without(self, tool_names: list[str]) -> list[Tool]
Parameters:
NameTypeRequiredDescription
tool_nameslist[str]YesList of tool names to exclude
Returns:
TypeDescription
list[Tool]Filtered list of Tool objects excluding the specified names
Example:
from mcipy import MCIClient

client = MCIClient(json_file_path="example.mci.json")

# Get all tools except dangerous ones
safe_tools = client.without(["delete_data", "admin_tools"])

for tool in safe_tools:
    print(f"Safe tool: {tool.name}")
Success Response:
[
    Tool(
        name="get_weather",
        annotations=Annotations(title="Get Weather Information"),
        description="Fetch current weather information for a location",
        inputSchema={...},
        execution=HTTPExecutionConfig(...)
    ),
    Tool(
        name="search_data",
        annotations=Annotations(title="Search Data"),
        description="Search for data in the database",
        inputSchema={...},
        execution=HTTPExecutionConfig(...)
    )
    # delete_data and admin_tools are excluded
]
Error Response: No errors - returns all tools if specified names don’t exist.

tags()

Filter tools to include only those with at least one matching tag. Method Signature:
def tags(self, tags: list[str]) -> list[Tool]
Parameters:
NameTypeRequiredDescription
tagslist[str]YesList of tags to filter by (OR logic - tool must have at least one matching tag)
Returns:
TypeDescription
list[Tool]Filtered list of Tool objects that have at least one of the specified tags
Example:
from mcipy import MCIClient

client = MCIClient(schema_file_path="example.mci.json")

# Get all tools tagged with "api" or "database"
api_or_db_tools = client.tags(["api", "database"])

for tool in api_or_db_tools:
    print(f"Tool: {tool.name}, Tags: {tool.tags}")
Success Response:
[
    Tool(
        name="github_api",
        description="GitHub API client",
        tags=["api", "external"],
        execution=HTTPExecutionConfig(...)
    ),
    Tool(
        name="database_query",
        description="Query database",
        tags=["database", "internal"],
        execution=CLIExecutionConfig(...)
    )
]
Error Response: No errors - returns empty list if no tools have any of the specified tags. Notes:
  • Tags are case-sensitive and matched exactly as provided
  • Uses OR logic: a tool is included if it has ANY of the specified tags
  • Tools without tags are never included
  • Empty tag list returns empty result

withoutTags()

Filter tools to exclude those with any matching tag. Method Signature:
def withoutTags(self, tags: list[str]) -> list[Tool]
Parameters:
NameTypeRequiredDescription
tagslist[str]YesList of tags to exclude (OR logic - tool is excluded if it has any matching tag)
Returns:
TypeDescription
list[Tool]Filtered list of Tool objects that do NOT have any of the specified tags
Example:
from mcipy import MCIClient

client = MCIClient(schema_file_path="example.mci.json")

# Get all tools that are NOT tagged with "external" or "deprecated"
internal_tools = client.withoutTags(["external", "deprecated"])

for tool in internal_tools:
    print(f"Internal tool: {tool.name}")
Success Response:
[
    Tool(
        name="database_query",
        description="Query database",
        tags=["database", "internal"],
        execution=CLIExecutionConfig(...)
    ),
    Tool(
        name="generate_report",
        description="Generate internal report",
        tags=["internal", "reporting"],
        execution=TextExecutionConfig(...)
    )
    # Tools with "external" or "deprecated" tags are excluded
]
Error Response: No errors - returns all tools if none have any of the specified tags. Notes:
  • Tags are case-sensitive and matched exactly as provided
  • Uses OR logic for exclusion: a tool is excluded if it has ANY of the specified tags
  • Tools without tags are always included (they don’t have the excluded tags)
  • Empty tag list returns all tools

toolsets()

Filter tools to include only those from specified toolsets. Method Signature:
def toolsets(self, toolset_names: list[str]) -> list[Tool]
Parameters:
NameTypeRequiredDescription
toolset_nameslist[str]YesList of toolset names to include (OR logic - tool is included if it came from any matching toolset)
Returns:
TypeDescription
list[Tool]Filtered list of Tool objects from the specified toolsets
Example:
from mcipy import MCIClient

client = MCIClient(schema_file_path="example.mci.json")

# Get all tools from the "weather" toolset
weather_tools = client.toolsets(["weather"])

# Get tools from multiple toolsets
api_tools = client.toolsets(["weather", "database", "github"])

for tool in api_tools:
    print(f"Tool: {tool.name} (from {tool.toolset_source})")
Success Response:
[
    Tool(
        name="get_weather",
        description="Get current weather",
        tags=["weather", "read"],
        toolset_source="weather",
        execution=HTTPExecutionConfig(...)
    ),
    Tool(
        name="query_data",
        description="Query database",
        tags=["database", "read"],
        toolset_source="database",
        execution=CLIExecutionConfig(...)
    )
]
Error Response: No errors - returns empty list if no tools match the specified toolset names. Notes:
  • Only returns tools that were loaded from toolsets (not main schema tools)
  • Uses OR logic: a tool is included if it came from ANY of the specified toolsets
  • Toolset filtering respects schema-level filters (only tools registered by their toolset’s filter are included)
  • Empty toolset list returns no tools
  • Tools must have been loaded via the toolsets field in the main schema
  • The toolset_source field on each Tool indicates which toolset it came from

execute()

Execute a tool by name with the provided properties. Method Signature:
def execute(self, tool_name: str, properties: dict[str, Any] | None = None) -> ExecutionResult
Parameters:
NameTypeRequiredDescription
tool_namestrYesName of the tool to execute
propertiesdict[str, Any]NoProperties/parameters to pass to the tool (default: {})
Returns:
TypeDescription
ExecutionResultResult object with success/error status and content
Raises:
  • MCIClientError - If tool not found or execution fails with validation error
Example:
from mcipy import MCIClient

client = MCIClient(
    json_file_path="example.mci.json",
    env_vars={"API_KEY": "your-secret-key"}
)

# Execute a tool with properties
result = client.execute(
    tool_name="get_weather",
    properties={"location": "New York"}
)

# Handle result
if result.result.isError:
    print(f"Error: {result.result.content[0].text}")
else:
    print(f"Success: {result.result.content[0].text}")
    if result.metadata:
        print(f"Metadata: {result.metadata}")
Success Response:
ExecutionResult(
    isError=False,
    content={
        "location": "New York",
        "temperature": 72,
        "conditions": "Sunny",
        "humidity": 45
    },
    error=None,
    metadata={
        "status_code": 200,
        "execution_time_ms": 150
    }
)
Error Response - Tool Not Found:
# Raises MCIClientError
MCIClientError: Tool not found: invalid_tool_name
Error Response - Execution Error:
ExecutionResult(
    isError=True,
    content=None,
    error="HTTP request failed: 404 Not Found",
    metadata={
        "status_code": 404,
        "execution_time_ms": 75
    }
)
Error Response - Network Error:
ExecutionResult(
    isError=True,
    content=None,
    error="Connection timeout after 5000ms",
    metadata=None
)

list_tools()

List available tool names as strings. Method Signature:
def list_tools(self) -> list[str]
Parameters: None Returns:
TypeDescription
list[str]List of tool names (strings)
Example:
from mcipy import MCIClient

client = MCIClient(json_file_path="example.mci.json")
tool_names = client.list_tools()

print(f"Available tools: {tool_names}")
Success Response:
["get_weather", "create_report", "search_files", "load_file", "generate_text"]
Error Response: No errors - returns empty list if no tools defined.

get_tool_schema()

Get a tool’s input schema (JSON Schema format). Method Signature:
def get_tool_schema(self, tool_name: str) -> dict[str, Any]
Parameters:
NameTypeRequiredDescription
tool_namestrYesName of the tool
Returns:
TypeDescription
dict[str, Any]Tool’s input schema as a dictionary (or empty dict if no schema)
Raises:
  • MCIClientError - If tool not found
Example:
from mcipy import MCIClient

client = MCIClient(json_file_path="example.mci.json")
schema = client.get_tool_schema("get_weather")

print(f"Schema: {schema}")
Success Response:
{
    "type": "object",
    "properties": {
        "location": {
            "type": "string",
            "description": "City name or location"
        },
        "unit": {
            "type": "string",
            "description": "Temperature unit (celsius or fahrenheit)",
            "enum": ["celsius", "fahrenheit"]
        }
    },
    "required": ["location"]
}
Success Response - No Schema:
{}  # Empty dict if tool has no input schema
Error Response:
# Raises MCIClientError
MCIClientError: Tool not found: invalid_tool_name

Data Models

MCISchema

Top-level MCI schema representing the complete MCI context file. Fields:
FieldTypeRequiredDescription
schemaVersionstrYesSchema version (e.g., “1.0”)
metadataMetadataNoOptional metadata about the tool collection
toolslist[Tool]YesList of tool definitions
Example:
{
    "schemaVersion": "1.0",
    "metadata": {
        "name": "Example MCI Tools",
        "description": "Example tool collection",
        "version": "1.0.0",
        "license": "MIT",
        "authors": ["MCI Team"]
    },
    "tools": [
        {
            "name": "get_weather",
            "annotations": {
        "title": "Get Weather"
            },
            "description": "Get weather information",
            "inputSchema": {...},
            "execution": {...}
        }
    ]
}

Tool

Individual tool definition with name, description, input schema, and execution configuration. Fields:
FieldTypeRequiredDescription
namestrYesUnique identifier for the tool
annotationsAnnotationsNoTool metadata and hints
disabledboolNoIf true, tool is ignored (default: false)
descriptionstrNoDescription of what the tool does
inputSchemadict[str, Any]NoJSON Schema defining expected input properties
executionHTTPExecutionConfig | CLIExecutionConfig | FileExecutionConfig | TextExecutionConfigYesExecution configuration (determines how tool is executed)
Example:
{
    "name": "get_weather",
    "annotations": {
        "title": "Get Weather Information"
    },
    "description": "Fetch current weather information for a location",
    "inputSchema": {
        "type": "object",
        "properties": {
            "location": {
                "type": "string",
                "description": "City name or location"
            }
        },
        "required": ["location"]
    },
    "execution": {
        "type": "http",
        "method": "GET",
        "url": "https://api.example.com/weather",
        "params": {
            "location": "{{props.location}}"
        }
    }
}

ExecutionResult

Result format returned from tool execution. Fields:
FieldTypeRequiredDescription
isErrorboolYesWhether an error occurred during execution
contentAnyNoResult content (None if error)
errorstrNoError message (None if success)
metadatadict[str, Any]NoAdditional metadata (e.g., status_code, execution_time_ms)
Example - Success:
ExecutionResult(
    isError=False,
    content={
        "location": "New York",
        "temperature": 72,
        "conditions": "Sunny"
    },
    error=None,
    metadata={
        "status_code": 200,
        "execution_time_ms": 150
    }
)
Example - Error:
ExecutionResult(
    isError=True,
    content=None,
    error="HTTP request failed: 404 Not Found",
    metadata={
        "status_code": 404,
        "execution_time_ms": 75
    }
)
Example - Text Content:
ExecutionResult(
    isError=False,
    content="Hello, World!",
    error=None,
    metadata=None
)
Example - File Content:
ExecutionResult(
    isError=False,
    content="File content with template: user@example.com",
    error=None,
    metadata=None
)

Metadata

Optional metadata about the MCI tool collection. Fields:
FieldTypeRequiredDescription
namestrNoName of the tool collection
descriptionstrNoDescription of the collection
versionstrNoVersion number (e.g., “1.0.0”)
licensestrNoLicense type (e.g., “MIT”)
authorslist[str]NoList of author names
Example:
{
    "name": "Weather Tools",
    "description": "Collection of weather-related tools",
    "version": "1.0.0",
    "license": "MIT",
    "authors": ["Alice Smith", "Bob Jones"]
}

Execution Configurations

HTTPExecutionConfig

Configuration for HTTP-based tool execution. Fields:
FieldTypeRequiredDefaultDescription
typeExecutionTypeYes"http"Execution type identifier
methodstrNo"GET"HTTP method (GET, POST, PUT, DELETE, etc.)
urlstrYes-URL endpoint for the request
headersdict[str, str]NoNoneHTTP headers
authAuthConfigNoNoneAuthentication configuration
paramsdict[str, Any]NoNoneQuery parameters
bodyHTTPBodyConfigNoNoneRequest body configuration
timeout_msintNo30000Request timeout in milliseconds
retriesRetryConfigNoNoneRetry configuration
Example - GET Request:
{
    "type": "http",
    "method": "GET",
    "url": "https://api.example.com/weather",
    "params": {
        "location": "{{props.location}}",
        "units": "metric"
    },
    "headers": {
        "Accept": "application/json"
    },
    "timeout_ms": 5000
}
Example - POST Request with Authentication:
{
    "type": "http",
    "method": "POST",
    "url": "https://api.example.com/reports",
    "headers": {
        "Content-Type": "application/json"
    },
    "auth": {
        "type": "bearer",
        "token": "{{env.BEARER_TOKEN}}"
    },
    "body": {
        "type": "json",
        "content": {
            "title": "{{props.title}}",
            "content": "{{props.content}}"
        }
    },
    "timeout_ms": 10000,
    "retries": {
        "attempts": 3,
        "backoff_ms": 1000
    }
}

CLIExecutionConfig

Configuration for command-line tool execution. Fields:
FieldTypeRequiredDefaultDescription
typeExecutionTypeYes"cli"Execution type identifier
commandstrYes-Command to execute
argslist[str]NoNoneCommand arguments
flagsdict[str, FlagConfig]NoNoneCommand flags configuration
cwdstrNoNoneWorking directory for command execution
timeout_msintNo30000Execution timeout in milliseconds
Example - Simple Command:
{
    "type": "cli",
    "command": "ls",
    "args": ["-la", "/home/user"],
    "timeout_ms": 5000
}
Example - Command with Flags:
{
    "type": "cli",
    "command": "grep",
    "args": ["-r", "{{props.pattern}}"],
    "flags": {
        "--color": {
            "from": "props.color",
            "type": "boolean"
        }
    },
    "cwd": "/home/user/projects",
    "timeout_ms": 10000
}

FileExecutionConfig

Configuration for file reading and templating. Fields:
FieldTypeRequiredDefaultDescription
typeExecutionTypeYes"file"Execution type identifier
pathstrYes-Path to the file to read
enableTemplatingboolNoTrueWhether to process template placeholders in file content
Example - Read File with Templating:
{
    "type": "file",
    "path": "/home/user/templates/email.txt",
    "enableTemplating": true
}
Example - Read File Without Templating:
{
    "type": "file",
    "path": "/home/user/data/config.json",
    "enableTemplating": false
}

TextExecutionConfig

Configuration for simple text template execution. Fields:
FieldTypeRequiredDefaultDescription
typeExecutionTypeYes"text"Execution type identifier
textstrYes-Text template with placeholder support
Example:
{
    "type": "text",
    "text": "Hello {{props.name}}! Your email is {{env.USER_EMAIL}}."
}
Execution Result:
# With properties={"name": "Alice"} and env_vars={"USER_EMAIL": "alice@example.com"}
ExecutionResult(
    isError=False,
    content="Hello Alice! Your email is alice@example.com.",
    error=None,
    metadata=None
)

Authentication Models

ApiKeyAuth

API Key authentication configuration. Fields:
FieldTypeRequiredDefaultDescription
typestrYes"apiKey"Authentication type
instrYes-Where to place the key: “header” or “query”
namestrYes-Name of the header or query parameter
valuestrYes-API key value (supports templates)
Example - Header-based:
{
    "type": "apiKey",
    "in": "header",
    "name": "X-API-Key",
    "value": "{{env.API_KEY}}"
}
Example - Query parameter:
{
    "type": "apiKey",
    "in": "query",
    "name": "api_key",
    "value": "{{env.API_KEY}}"
}

BearerAuth

Bearer token authentication configuration. Fields:
FieldTypeRequiredDefaultDescription
typestrYes"bearer"Authentication type
tokenstrYes-Bearer token value (supports templates)
Example:
{
    "type": "bearer",
    "token": "{{env.BEARER_TOKEN}}"
}

BasicAuth

Basic authentication (username/password) configuration. Fields:
FieldTypeRequiredDefaultDescription
typestrYes"basic"Authentication type
usernamestrYes-Username (supports templates)
passwordstrYes-Password (supports templates)
Example:
{
    "type": "basic",
    "username": "{{env.USERNAME}}",
    "password": "{{env.PASSWORD}}"
}

OAuth2Auth

OAuth2 authentication configuration. Fields:
FieldTypeRequiredDefaultDescription
typestrYes"oauth2"Authentication type
flowstrYes-OAuth2 flow type (e.g., “clientCredentials”)
tokenUrlstrYes-Token endpoint URL
clientIdstrYes-OAuth2 client ID
clientSecretstrYes-OAuth2 client secret (supports templates)
scopeslist[str]NoNoneOptional OAuth2 scopes
Example:
{
    "type": "oauth2",
    "flow": "clientCredentials",
    "tokenUrl": "https://auth.example.com/oauth/token",
    "clientId": "my-client-id",
    "clientSecret": "{{env.OAUTH_CLIENT_SECRET}}",
    "scopes": ["read:data", "write:data"]
}

Error Handling

The MCI Python adapter provides consistent error handling across all operations.

Exception Types

MCIClientError

Raised by MCIClient methods for client-level errors. Common Causes:
  • Schema file not found or invalid
  • Tool not found
  • Invalid tool execution
Example:
from mcipy import MCIClient, MCIClientError

try:
    client = MCIClient(json_file_path="nonexistent.json")
except MCIClientError as e:
    print(f"Client error: {e}")
    # Output: Client error: Failed to load schema from nonexistent.json: [Errno 2] No such file or directory

ExecutionResult Error Format

Execution errors are returned as ExecutionResult objects with isError=True. Error Fields:
FieldDescription
isErrorAlways True for errors
contentAlways None for errors
errorHuman-readable error message
metadataOptional additional error context
Example Error Scenarios: HTTP Request Failed:
result = client.execute("get_weather", {"location": "InvalidCity"})
# ExecutionResult(
#     isError=True,
#     content=None,
#     error="HTTP request failed: 404 Not Found",
#     metadata={"status_code": 404, "execution_time_ms": 75}
# )
Connection Timeout:
result = client.execute("slow_api", {})
# ExecutionResult(
#     isError=True,
#     content=None,
#     error="Connection timeout after 30000ms",
#     metadata=None
# )
CLI Command Failed:
result = client.execute("invalid_command", {})
# ExecutionResult(
#     isError=True,
#     content=None,
#     error="Command failed with exit code 127: command not found",
#     metadata={"exit_code": 127}
# )
File Not Found:
result = client.execute("read_config", {})
# ExecutionResult(
#     isError=True,
#     content=None,
#     error="File not found: /path/to/config.json",
#     metadata=None
# )
Template Variable Missing:
# If {{env.MISSING_VAR}} is referenced but not provided
result = client.execute("template_tool", {})
# ExecutionResult(
#     isError=True,
#     content=None,
#     error="Template variable not found: env.MISSING_VAR",
#     metadata=None
# )
Path Validation Error:
# When a tool attempts to access a file outside allowed directories
result = client.execute("read_file", {"path": "/etc/passwd"})
# ExecutionResult(
#     isError=True,
#     content=None,
#     error="File path access outside context directory and allow-list is not allowed unless enableAnyPaths is true. Path: /etc/passwd",
#     metadata=None
# )

Security: Path Validation

The MCI Python adapter includes built-in path validation to prevent unauthorized file system access. Default Behavior:
  • File and CLI execution are restricted to the schema file’s directory
  • Subdirectories of the schema directory are allowed
  • Paths outside the schema directory are blocked unless explicitly allowed
Configuration Options:
  1. Schema-level settings (applies to all tools):
    {
      "schemaVersion": "1.0",
      "enableAnyPaths": false,
      "directoryAllowList": ["/home/user/data", "./configs"],
      "tools": [...]
    }
    
  2. Tool-level settings (overrides schema-level):
    {
      "name": "read_system_file",
      "enableAnyPaths": true,
      "execution": {
        "type": "file",
        "path": "{{props.file_path}}"
      }
    }
    
Path Validation Behavior:
ScenarioAllowed?
File in schema directory✓ Yes
File in subdirectory of schema directory✓ Yes
File outside schema directory (no config)✗ No - Error
File in directoryAllowList✓ Yes
Any path with enableAnyPaths: true✓ Yes
Best Practices:
  • Keep enableAnyPaths disabled unless absolutely necessary
  • Use directoryAllowList for specific directories instead of enableAnyPaths
  • Validate user input before passing to tools that access files
  • Review tool configurations regularly for security implications

Error Handling Best Practices

Check isError Flag:
result = client.execute("get_weather", {"location": "New York"})

if result.result.isError:
    print(f"Error occurred: {result.result.content[0].text}")
    if result.metadata:
        print(f"Additional context: {result.metadata}")
else:
    print(f"Success: {result.result.content[0].text}")
Try-Except for Client Errors:
try:
    client = MCIClient(json_file_path="example.mci.json")
    result = client.execute("get_weather", {"location": "New York"})

    if result.result.isError:
        # Handle execution errors
        print(f"Execution failed: {result.result.content[0].text}")
    else:
        # Process successful result
        print(f"Weather data: {result.result.content[0].text}")

except MCIClientError as e:
    # Handle client-level errors (tool not found, invalid schema, etc.)
    print(f"Client error: {e}")
Validate Tools Before Execution:
client = MCIClient(json_file_path="example.mci.json")

# Check if tool exists
available_tools = client.list_tools()
if "get_weather" in available_tools:
    result = client.execute("get_weather", {"location": "New York"})
else:
    print("Tool 'get_weather' not available")

Complete Usage Example

Here’s a comprehensive example demonstrating all major features:
from mcipy import MCIClient, MCIClientError

# Initialize client with environment variables
try:
    client = MCIClient(
        json_file_path="example.mci.json",
        env_vars={
            "API_KEY": "your-secret-key",
            "BEARER_TOKEN": "bearer-token-123",
            "USERNAME": "demo_user"
        }
    )
except MCIClientError as e:
    print(f"Failed to initialize client: {e}")
    exit(1)

# List all available tools
print("Available tools:")
for tool_name in client.list_tools():
    print(f"  - {tool_name}")

# Get detailed tool information
all_tools = client.tools()
for tool in all_tools:
    print(f"\nTool: {tool.name}")
    print(f"  Title: {tool.annotations.title if tool.annotations else \'N/A\'}")
    print(f"  Description: {tool.description}")

# Filter tools
weather_tools = client.only(["get_weather", "get_forecast"])
print(f"\nWeather tools: {[t.name for t in weather_tools]}")

safe_tools = client.without(["delete_data", "admin_tools"])
print(f"Safe tools: {[t.name for t in safe_tools]}")

# Get tool schema
try:
    schema = client.get_tool_schema("get_weather")
    print(f"\nWeather tool schema: {schema}")
except MCIClientError as e:
    print(f"Error getting schema: {e}")

# Execute a tool
result = client.execute(
    tool_name="get_weather",
    properties={"location": "New York"}
)

if result.result.isError:
    print(f"\nExecution failed: {result.error}")
    if result.metadata:
        print(f"Error metadata: {result.metadata}")
else:
    print(f"\nExecution successful!")
    print(f"Content: {result.result.content[0].text}")
    if result.metadata:
        print(f"Metadata: {result.metadata}")

Template Syntax

MCI supports template placeholders for dynamic value substitution:
  • {{props.fieldName}} - Access properties passed to execute()
  • {{env.VARIABLE_NAME}} - Access environment variables
  • {{input.fieldName}} - Deprecated alias for props (use props instead)
Note: {{input.fieldName}} is supported for backward compatibility but is deprecated. Use {{props.fieldName}} in all new code. Example:
{
  "execution": {
    "type": "http",
    "url": "https://api.example.com/users/{{props.userId}}",
    "headers": {
      "Authorization": "Bearer {{env.API_TOKEN}}"
    }
  }
}
With execution:
result = client.execute(
    "get_user",
    properties={"userId": "12345"}
)
# Resolves to: https://api.example.com/users/12345

Notes

  • All methods are synchronous (blocking) - execution waits for completion
  • Environment variables should be provided during initialization, not at execution time
  • Templates are processed before execution using a simple {{}} placeholder substitution system (not full Jinja2 syntax)
  • HTTP responses are automatically parsed as JSON when possible
  • CLI commands capture both stdout and stderr
  • File paths can be relative or absolute
  • Timeout values are in milliseconds
  • All string fields support template substitution unless explicitly disabled

LiteMcpClient Class

The LiteMcpClient class provides a lightweight integration with MCP (Model Context Protocol) servers using the official mcp package. It allows connecting to MCP tool servers via STDIO (e.g., uvx, npx) and HTTP/SSE endpoints.

Configuration Models

StdioCfg

Configuration for STDIO-based MCP servers (local servers via command-line). Fields:
NameTypeRequiredDescription
typeLiteral["stdio"]YesMust be “stdio”
commandstrYesCommand to run (e.g., “uvx”, “npx”)
argsList[str]NoArguments to pass to the command (default: [])
envDict[str, str]NoEnvironment variables for the server process (default: {})
Example:
from mcipy import StdioCfg

# STDIO configuration for uvx
stdio_cfg = StdioCfg(
    command="uvx",
    args=["mcp-server-memory"],
    env={"API_KEY": "secret"}
)

# STDIO configuration for npx
stdio_cfg = StdioCfg(
    command="npx",
    args=["-y", "@modelcontextprotocol/server-memory"]
)

SseCfg

Configuration for HTTP/SSE-based MCP servers (web-based servers). Fields:
NameTypeRequiredDescription
typeLiteral["http"]YesMust be “http”
urlHttpUrlYesServer URL (e.g., “http://localhost:8000/mcp”)
headersDict[str, str]NoHTTP headers for authentication (default: {})
Example:
from mcipy import SseCfg

# HTTP configuration with authentication
http_cfg = SseCfg(
    url="https://api.example.com/mcp",
    headers={"Authorization": "Bearer token123"}
)

# HTTP configuration without authentication
http_cfg = SseCfg(url="http://localhost:8000/mcp")

ClientCfg

Complete configuration for the LiteMcpClient. Fields:
NameTypeRequiredDescription
serverStdioCfg | SseCfgYesServer connection configuration
request_timeoutOptional[float]NoRequest timeout in seconds (default: 60.0)
Example:
from mcipy import ClientCfg, StdioCfg

# Client configuration with STDIO server
client_cfg = ClientCfg(
    server=StdioCfg(command="uvx", args=["mcp-server"]),
    request_timeout=120.0
)

Initialization

LiteMcpClient(cfg: ClientCfg)

Initialize the LiteMcpClient with configuration. Parameters:
NameTypeRequiredDescription
cfgClientCfgYesClient configuration specifying server type and connection details
Example:
from mcipy import LiteMcpClient, ClientCfg, StdioCfg

cfg = ClientCfg(
    server=StdioCfg(command="uvx", args=["mcp-server-memory"])
)
client = LiteMcpClient(cfg)

Usage

The LiteMcpClient must be used as an async context manager to properly manage the connection lifecycle. Example:
import asyncio
from mcipy import LiteMcpClient, ClientCfg, StdioCfg

async def main():
    cfg = ClientCfg(
        server=StdioCfg(
            command="npx",
            args=["-y", "@modelcontextprotocol/server-memory"]
        )
    )

    async with LiteMcpClient(cfg) as client:
        # List available tools
        tools = await client.list_tools()
        print(f"Available tools: {tools}")

        # Call a tool
        result = await client.call_tool("store_memory", key="test", value="data")
        print(f"Result: {result}")

asyncio.run(main())

Methods

async list_tools() -> List[str]

List all available tools from the MCP server. Returns:
  • List[str] - List of tool names available on the server
Raises:
  • RuntimeError - If session is not initialized (client not used as context manager)
Example:
async with LiteMcpClient(cfg) as client:
    tools = await client.list_tools()
    # Returns: ["store_memory", "retrieve_memory", "list_memories"]

async call_tool(name: str, **arguments: Any) -> Any

Call a tool on the MCP server with the provided arguments. Parameters:
NameTypeRequiredDescription
namestrYesName of the tool to call
**argumentsAnyNoKeyword arguments to pass to the tool
Returns:
  • Any - The tool execution result from the server (typically containing content and metadata)
Raises:
  • RuntimeError - If session is not initialized (client not used as context manager)
Example:
async with LiteMcpClient(cfg) as client:
    # Call tool with arguments
    result = await client.call_tool(
        "store_memory",
        key="user_preference",
        value="dark_mode"
    )
    print(result.content)  # Access result content

Complete Examples

STDIO Example (uvx)

import asyncio
from mcipy import LiteMcpClient, ClientCfg, StdioCfg

async def main():
    cfg = ClientCfg(
        server=StdioCfg(
            command="uvx",
            args=["mcp-server-memory"],
            env={}
        )
    )

    async with LiteMcpClient(cfg) as client:
        tools = await client.list_tools()
        print(f"Available tools: {tools}")

        if "store_memory" in tools:
            await client.call_tool(
                "store_memory",
                key="greeting",
                value="Hello, World!"
            )

asyncio.run(main())

STDIO Example (npx)

import asyncio
from mcipy import LiteMcpClient, ClientCfg, StdioCfg

async def main():
    cfg = ClientCfg(
        server=StdioCfg(
            command="npx",
            args=["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]
        )
    )

    async with LiteMcpClient(cfg) as client:
        tools = await client.list_tools()
        print(f"Filesystem tools: {tools}")

asyncio.run(main())

HTTP Example

import asyncio
from mcipy import LiteMcpClient, ClientCfg, SseCfg

async def main():
    cfg = ClientCfg(
        server=SseCfg(
            url="https://api.githubcopilot.com/mcp/",
            headers={"Authorization": "Bearer YOUR_TOKEN"}
        )
    )

    async with LiteMcpClient(cfg) as client:
        tools = await client.list_tools()
        print(f"GitHub MCP tools: {tools}")

asyncio.run(main())

Error Handling

RuntimeError: Raised when attempting to use methods outside of context manager:
cfg = ClientCfg(server=StdioCfg(command="uvx"))
client = LiteMcpClient(cfg)

# This will raise RuntimeError
await client.list_tools()  # Error: Session not initialized

# Correct usage:
async with client:
    await client.list_tools()  # Works correctly
Connection Errors: Network or process errors are propagated from the underlying MCP client:
try:
    async with LiteMcpClient(cfg) as client:
        tools = await client.list_tools()
except Exception as e:
    print(f"Connection failed: {e}")

Notes

  • The LiteMcpClient uses the official mcp package for MCP protocol communication
  • STDIO transport merges environment variables from the configuration with the current process environment
  • HTTP transport uses Streamable HTTP, the modern replacement for SSE
  • All async operations must be called from within the context manager
  • The client automatically handles connection setup and teardown