This guide provides detailed usage patterns and examples for working with the MCI Python adapter. If you're new to MCI, start with the Quickstart Guide first.
- Importing the Client
- Creating Tool Schema Files
- Initializing the Client
- Working with Tools
- Execution Types
- Advanced Features
- Complete Example
from mcipy import MCIClientMCI supports both JSON and YAML formats for schema files. Choose the format that best suits your preferences.
Create a file named my-tools.mci.json:
{
"schemaVersion": "1.0",
"metadata": {
"name": "My Tools",
"description": "A collection of useful tools",
"version": "1.0.0"
},
"tools": [
{
"name": "greet_user",
"annotations": {
"title": "User Greeting",
"readOnlyHint": true,
"idempotentHint": true
},
"description": "Generate a personalized greeting message",
"inputSchema": {
"type": "object",
"properties": {
"username": {
"type": "string",
"description": "The user's name"
}
},
"required": ["username"]
},
"execution": {
"type": "text",
"text": "Hello, {{props.username}}! Welcome to MCI."
}
}
]
}Create a file named my-tools.mci.yaml:
schemaVersion: "1.0"
metadata:
name: My Tools
description: A collection of useful tools
version: 1.0.0
tools:
- name: greet_user
annotations:
title: User Greeting
readOnlyHint: true
idempotentHint: true
description: Generate a personalized greeting message
inputSchema:
type: object
properties:
username:
type: string
description: The user's name
required:
- username
execution:
type: text
text: Hello, {{props.username}}! Welcome to MCI.Note: MCI supports both JSON (
.json) and YAML (.yaml,.yml) formats interchangeably.
from mcipy import MCIClient
# Initialize with JSON schema file
client = MCIClient(schema_file_path="my-tools.mci.json")
# Initialize with YAML schema file
client = MCIClient(schema_file_path="my-tools.mci.yaml")client = MCIClient(
schema_file_path="my-tools.mci.json",
env_vars={
"API_KEY": "your-secret-key",
"USERNAME": "demo_user",
"DATABASE_URL": "postgresql://localhost/mydb"
}
)client = MCIClient(
schema_file_path="my-tools.mci.json",
env_vars={"API_KEY": "your-secret-key"}
)Get a list of all available tool names:
tool_names = client.list_tools()
print(f"Available tools: {tool_names}")
# Output: ['greet_user', 'get_weather', 'create_report']Get full tool objects with metadata:
tools = client.tools()
for tool in tools:
title = tool.annotations.title if tool.annotations else tool.name
print(f"- {tool.name}: {title}")
# Output:
# - greet_user: User Greeting
# - get_weather: Get Weather Information
# - create_report: Create ReportExecute a tool with properties:
result = client.execute(
tool_name="greet_user",
properties={"username": "Alice"}
)
# Check the result
if result.result.isError:
print(f"Error: {result.result.content[0].text}")
else:
print(f"Success: {result.result.content[0].text}")Execute without properties (if not required):
result = client.execute(tool_name="get_system_info")# Include only specific tools
weather_tools = client.only(["get_weather", "get_forecast"])
print(f"Weather tools: {[t.name for t in weather_tools]}")# Exclude specific tools
safe_tools = client.without(["delete_data", "admin_tools"])
print(f"Safe tools: {[t.name for t in safe_tools]}")# Include tools with specific tags
api_tools = client.tags(["api", "external"])
# Exclude tools with specific tags
internal_tools = client.withoutTags(["external", "deprecated"])# Get tools from specific toolsets
weather_tools = client.toolsets(["weather"])
api_tools = client.toolsets(["weather", "database", "github"])Retrieve the input schema for a tool:
schema = client.get_tool_schema("greet_user")
print(f"Required properties: {schema.get('required', [])}")
print(f"Properties: {list(schema.get('properties', {}).keys())}")
# Output:
# Required properties: ['username']
# Properties: ['username']MCI supports four execution types: Text, File, CLI, and HTTP. Each type is designed for different use cases.
Return static or templated text directly. Perfect for simple messages, templates, or computed strings.
Schema Example:
{
"name": "generate_welcome",
"description": "Generate a welcome message with current date",
"inputSchema": {
"type": "object",
"properties": {
"username": {
"type": "string",
"description": "User's name"
}
},
"required": ["username"]
},
"execution": {
"type": "text",
"text": "Welcome {{props.username}}! Today is {{env.CURRENT_DATE}}."
}
}Python Usage:
from datetime import datetime
client = MCIClient(
schema_file_path="tools.mci.json",
env_vars={"CURRENT_DATE": datetime.now().strftime("%Y-%m-%d")}
)
result = client.execute(
tool_name="generate_welcome",
properties={"username": "Alice"}
)
print(result.result.content[0].text)
# Output: "Welcome Alice! Today is 2024-01-15."Read and return file contents with optional template substitution. Useful for loading configuration files, templates, or documentation.
Schema Example:
{
"name": "load_config",
"description": "Load a configuration file with template substitution",
"inputSchema": {
"type": "object",
"properties": {
"config_name": {
"type": "string",
"description": "Name of the configuration"
}
},
"required": ["config_name"]
},
"execution": {
"type": "file",
"path": "./configs/{{props.config_name}}.conf",
"enableTemplating": true
}
}File Content (configs/database.conf):
host={{env.DB_HOST}}
port={{env.DB_PORT}}
user={{env.DB_USER}}
database={{props.database_name}}
Python Usage:
client = MCIClient(
schema_file_path="tools.mci.json",
env_vars={
"DB_HOST": "localhost",
"DB_PORT": "5432",
"DB_USER": "admin"
}
)
result = client.execute(
tool_name="load_config",
properties={
"config_name": "database",
"database_name": "production_db"
}
)
print(result.result.content[0].text)
# Output:
# host=localhost
# port=5432
# user=admin
# database=production_dbExecute command-line programs and capture their output. Great for running system commands, scripts, or CLI tools.
Schema Example:
{
"name": "search_files",
"description": "Search for text patterns in files",
"inputSchema": {
"type": "object",
"properties": {
"pattern": {
"type": "string",
"description": "Search pattern"
},
"directory": {
"type": "string",
"description": "Directory to search"
},
"ignore_case": {
"type": "boolean",
"description": "Ignore case when searching"
}
},
"required": ["pattern", "directory"]
},
"execution": {
"type": "cli",
"command": "grep",
"args": ["-r", "-n"],
"flags": {
"-i": {
"from": "props.ignore_case",
"type": "boolean"
}
},
"cwd": "{{props.directory}}",
"timeout_ms": 8000
}
}Python Usage:
client = MCIClient(schema_file_path="tools.mci.json")
result = client.execute(
tool_name="search_files",
properties={
"pattern": "TODO",
"directory": "./src",
"ignore_case": True
}
)
if result.result.isError:
print(f"Error: {result.result.content[0].text}")
else:
print(result.result.content[0].text) # Output from grep commandCLI Configuration Options:
command: The command to execute (e.g., "grep", "python", "node")args: Fixed arguments passed to the commandflags: Dynamic flags based on input propertiestype: "boolean": Include flag only if property is truetype: "value": Include flag with property value (e.g.,--file value)
cwd: Working directory for command executiontimeout_ms: Maximum execution time in milliseconds
Make HTTP requests to APIs with full support for authentication, headers, query parameters, and request bodies.
{
"name": "get_weather",
"description": "Fetch current weather for a location",
"inputSchema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name"
}
},
"required": ["location"]
},
"execution": {
"type": "http",
"method": "GET",
"url": "https://api.example.com/weather",
"params": {
"location": "{{props.location}}",
"units": "metric"
},
"headers": {
"Accept": "application/json"
},
"timeout_ms": 5000
}
}{
"name": "create_report",
"description": "Create a new report via API",
"inputSchema": {
"type": "object",
"properties": {
"title": { "type": "string" },
"content": { "type": "string" }
},
"required": ["title", "content"]
},
"execution": {
"type": "http",
"method": "POST",
"url": "https://api.example.com/reports",
"headers": {
"Content-Type": "application/json"
},
"body": {
"type": "json",
"content": {
"title": "{{props.title}}",
"content": "{{props.content}}",
"timestamp": "{{env.CURRENT_TIMESTAMP}}"
}
},
"timeout_ms": 10000
}
}API Key (Header):
{
"auth": {
"type": "apiKey",
"in": "header",
"name": "X-API-Key",
"value": "{{env.API_KEY}}"
}
}API Key (Query Parameter):
{
"auth": {
"type": "apiKey",
"in": "query",
"name": "api_key",
"value": "{{env.API_KEY}}"
}
}Bearer Token:
{
"auth": {
"type": "bearer",
"token": "{{env.BEARER_TOKEN}}"
}
}Basic Authentication:
{
"auth": {
"type": "basic",
"username": "{{env.USERNAME}}",
"password": "{{env.PASSWORD}}"
}
}OAuth2:
{
"auth": {
"type": "oauth2",
"flow": "clientCredentials",
"tokenUrl": "https://auth.example.com/token",
"clientId": "{{env.CLIENT_ID}}",
"clientSecret": "{{env.CLIENT_SECRET}}",
"scopes": ["read:data"]
}
}from datetime import datetime
client = MCIClient(
schema_file_path="api-tools.mci.json",
env_vars={
"API_KEY": "your-secret-key",
"BEARER_TOKEN": "your-bearer-token",
"CURRENT_TIMESTAMP": datetime.now().isoformat()
}
)
# Execute GET request
weather_result = client.execute(
tool_name="get_weather",
properties={"location": "New York"}
)
if not weather_result.result.isError:
print(f"Weather data: {weather_result.result.content[0].text}")
# Execute POST request
report_result = client.execute(
tool_name="create_report",
properties={
"title": "Q1 Sales Report",
"content": "Sales increased by 15%"
}
)
if not report_result.result.isError:
print(f"Report created: {report_result.result.content[0].text}")Toolsets allow you to organize tools into reusable, modular collections. See the Toolsets Concept Guide for detailed information.
Quick Example:
{
"schemaVersion": "1.0",
"libraryDir": "./mci",
"toolsets": [
{ "name": "weather" },
{
"name": "database",
"filter": "withoutTags",
"filterValue": "destructive"
}
]
}client = MCIClient(schema_file_path="main.mci.json")
# Get tools from specific toolsets
weather_tools = client.toolsets(["weather"])Always check the isError property of execution results:
result = client.execute(tool_name="my_tool", properties={...})
if result.result.isError:
print(f"Error occurred: {result.result.content[0].text}")
# Handle error case
if result.metadata:
print(f"Additional context: {result.metadata}")
else:
print(f"Success: {result.result.content[0].text}")
# Process successful resultYou can create multiple client instances for different schema files:
# Client for API tools
api_client = MCIClient(
schema_file_path="api-tools.mci.json",
env_vars={"API_KEY": "key1"}
)
# Client for CLI tools
cli_client = MCIClient(
schema_file_path="cli-tools.mci.json",
env_vars={"WORKSPACE": "/home/user"}
)Environment variables are the recommended way to handle secrets and configuration:
import os
client = MCIClient(
schema_file_path="tools.mci.json",
env_vars={
"API_KEY": os.getenv("MY_API_KEY"),
"DATABASE_URL": os.getenv("DATABASE_URL"),
"ENVIRONMENT": "production"
}
)Important Security Feature: By default, MCI restricts file and directory access to protect against arbitrary file access vulnerabilities.
When executing file-based tools or CLI tools with a working directory (cwd), MCI validates that all paths are within the directory containing the schema file:
# This works - accessing file in schema directory
client = MCIClient(schema_file_path="/project/tools.mci.json")
result = client.execute("read_config", {"file": "/project/config.json"})
# ✓ Allowed: /project/config.json is in same directory as schema# This fails - accessing file outside schema directory
result = client.execute("read_secret", {"file": "/etc/passwd"})
# ✗ Blocked: Path outside schema directoryYou can allow additional directories using directoryAllowList:
{
"schemaVersion": "1.0",
"directoryAllowList": ["/home/user/data", "./configs"],
"tools": [...]
}Override security settings for individual tools:
{
"name": "read_any_file",
"enableAnyPaths": true,
"execution": {
"type": "file",
"path": "{{props.file_path}}"
}
}Important Notes:
- Tool-level settings override schema-level settings
- Relative paths are resolved relative to the schema directory
enableAnyPathsdisables all path validation - Use with extreme caution- Subdirectories are automatically allowed
Here's a complete example putting it all together:
#!/usr/bin/env python3
"""
Complete MCI example with multiple execution types.
"""
from datetime import datetime
from mcipy import MCIClient
def main():
# Initialize client with environment variables
client = MCIClient(
schema_file_path="./tools.mci.json",
env_vars={
"CURRENT_DATE": datetime.now().strftime("%Y-%m-%d"),
"API_KEY": "demo-api-key-123",
"USERNAME": "demo_user"
}
)
# List all available tools
print("Available tools:")
for tool_name in client.list_tools():
print(f" - {tool_name}")
# Execute text tool
print("\n1. Executing text tool...")
result = client.execute(
tool_name="generate_welcome",
properties={"username": "Alice"}
)
if not result.result.isError:
print(f" Output: {result.result.content[0].text}")
# Execute file tool
print("\n2. Executing file tool...")
result = client.execute(
tool_name="load_config",
properties={"config_name": "database"}
)
if not result.result.isError:
print(f" Config loaded: {len(result.result.content[0].text)} bytes")
# Execute CLI tool
print("\n3. Executing CLI tool...")
result = client.execute(
tool_name="search_files",
properties={
"pattern": "TODO",
"directory": ".",
"ignore_case": True
}
)
if not result.result.isError:
print(f" Found matches: {len(result.result.content[0].text.splitlines())} lines")
# Filter tools
print("\n4. Filtering tools...")
text_tools = client.only(["generate_welcome"])
print(f" Filtered to {len(text_tools)} tools")
print("\n✓ Example completed successfully!")
if __name__ == "__main__":
main()- Concepts - Deep dive into MCI core concepts
- Schema Reference - Complete schema documentation
- API Reference - Detailed API documentation
- MCP Integration - Using MCP servers with MCI
Happy building with MCI! 🚀