Documentation Index
Fetch the complete documentation index at: https://usemci.dev/llms.txt
Use this file to discover all available pages before exploring further.
Basic Usage
This guide covers the essential patterns for working with the MCI Python adapter, from client initialization to tool execution and error handling.
Importing the Client
from mcipy import MCIClient
MCI 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.
Initializing the Client
Basic Initialization
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")
With Environment Variables
client = MCIClient(
schema_file_path="my-tools.mci.json",
env_vars={
"API_KEY": "your-secret-key",
"USERNAME": "demo_user",
"DATABASE_URL": "postgresql://localhost/mydb"
}
)
Backward Compatibility
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 Report
Execute 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']
Execution Types
MCI supports four execution types: Text, File, CLI, and HTTP. Each type is designed for different use cases.
Text Execution
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."
File Execution
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_db
CLI Execution
Execute 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 command
CLI Configuration Options:
command: The command to execute (e.g., “grep”, “python”, “node”)
args: Fixed arguments passed to the command
flags: Dynamic flags based on input properties
type: "boolean": Include flag only if property is true
type: "value": Include flag with property value (e.g., --file value)
cwd: Working directory for command execution
timeout_ms: Maximum execution time in milliseconds
HTTP Execution
Make HTTP requests to APIs with full support for authentication, headers, query parameters, and request bodies.
Basic GET Request
{
"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
}
}
POST Request with JSON Body
{
"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
}
}
Authentication Types
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"]
}
}
Python Usage Example
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}")
Advanced Features
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"])
Error Handling
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 result
Multiple Clients
You 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
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"
}
)
Security: Path Restrictions
Important Security Feature: By default, MCI restricts file and directory access to protect against arbitrary file access vulnerabilities.
Default Behavior
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 directory
Allowing Specific Directories
You 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
enableAnyPaths disables all path validation - Use with extreme caution
- Subdirectories are automatically allowed
Complete Example
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()