Skip to main content

MCI Structure

This document explains the structural organization of MCI projects, including entry files, toolsets, MCP server caching, and basic templating patterns.

Entry Files

MCI projects start with one or more entry files located in the root of your project directory. These are the main schema files that define your tool collections.

Single Entry File

The simplest structure uses a single entry file:
my-project/
├── mci.json           # Main entry file
├── mci/               # Toolsets directory (optional)
│   └── weather.mci.json
└── src/               # Your application code
Example: mci.json
{
  "schemaVersion": "1.0",
  "metadata": {
    "name": "My Application Tools"
  },
  "tools": [
    {
      "name": "main_tool",
      "description": "Primary tool for the application",
      "execution": {
        "type": "text",
        "text": "Main application output"
      }
    }
  ]
}

Multiple Entry Files

You can have multiple entry files, each creating a specific set of tools for different purposes:
my-project/
├── api-tools.mci.json         # API-related tools
├── dev-tools.mci.json         # Development tools
├── production-tools.mci.json  # Production-only tools
├── mci/
│   ├── database.mci.json
│   ├── logging.mci.json
│   └── monitoring.mci.json
└── src/
Example: Multiple contexts for different environments api-tools.mci.json:
{
  "schemaVersion": "1.0",
  "metadata": {
    "name": "API Tools"
  },
  "toolsets": [{ "name": "database" }, { "name": "logging" }],
  "tools": [
    {
      "name": "api_health_check",
      "execution": {
        "type": "http",
        "url": "https://api.example.com/health"
      }
    }
  ]
}
dev-tools.mci.json:
{
  "schemaVersion": "1.0",
  "metadata": {
    "name": "Development Tools"
  },
  "toolsets": [
    { "name": "database" },
    { "name": "logging" },
    { "name": "monitoring" }
  ],
  "tools": [
    {
      "name": "run_tests",
      "execution": {
        "type": "cli",
        "command": "pytest",
        "args": ["--verbose"]
      }
    }
  ]
}
Key Points:
  • Each entry file is independent and creates its own set of tools
  • Entry files can share toolsets from the ./mci directory
  • Use multiple entry files to organize tools by environment, team, or purpose
  • No limit on the number of entry files (1, 3, 10, or more)
  • Each entry file must be loaded separately by the client; multiple entry files are not automatically merged and each requires its own MCIClient instance.

Automatic .env File Loading

MCI automatically loads environment variables from .env and .env.mci files when loading your MCI schema. This provides a convenient way to manage environment-specific configuration without manually setting variables. Automatic Detection:
  • When you run any MCI command (run, list, validate, etc.), MCI looks for environment files in:
    1. The project root directory (same location as your mci.json or mci.yaml)
    2. The ./mci directory
File Priority:
  • MCI prioritizes .env.mci files (MCI-specific configs) over .env files (general configs)
  • Important: When .env.mci files exist, .env files are not loaded at all
  • This allows you to keep MCI-specific environment variables separate from general project variables
Loading Behavior:
  • If .env.mci files exist: Only .env.mci files are loaded
    1. ./mci/.env.mci - Library MCI-specific configs
    2. Project root .env.mci - Project MCI-specific configs (higher priority)
  • If no .env.mci files exist: .env files are loaded instead
    1. ./mci/.env - Library general defaults
    2. Project root .env - Project-level configs (higher priority)
  • Then: System environment variables and explicit env_vars override all file-based configs
Full Precedence Order (lowest to highest):
  1. File-based configs (.env.mci files if they exist, otherwise .env files)
    • From ./mci/ directory first
    • Then from project root
  2. System environment variables (set via export or shell config)
  3. Environment variables passed via CLI or code (highest priority)
Example .env file:
# .env or .env.mci file in project root
API_KEY=your-api-key-here
BASE_URL=https://api.example.com
DEBUG=false

# Comments are supported
# Blank lines are ignored

# Export keyword is optional (automatically stripped)
export OPTIONAL_VAR=value
Example directory structure:
my-project/
├── .env.mci               # MCI-specific variables (if present, .env ignored)
├── .env                   # General project variables (only if .env.mci absent)
├── mci.json               # Your MCI schema
└── mci/
    ├── .env.mci           # Library MCI-specific (if present, ./mci/.env ignored)
    ├── .env               # Library defaults (only if ./mci/.env.mci absent)
    └── weather.mci.json   # Your toolsets
Example: Using .env.mci files
# Scenario 1: Only .env.mci files present
# ./mci/.env.mci
API_KEY=mci-library-key
LIBRARY_VAR=lib-value

# .env.mci (project root)
API_KEY=mci-project-key    # Overrides ./mci/.env.mci
MCI_SPECIFIC=mci-value

# Result: MCI will use:
# API_KEY=mci-project-key (from root .env.mci)
# LIBRARY_VAR=lib-value (from ./mci/.env.mci)
# MCI_SPECIFIC=mci-value (from root .env.mci)
Example: Using .env files (no .env.mci)
# Scenario 2: Only .env files present
# ./mci/.env
API_KEY=default-key
LIBRARY_VAR=lib-value

# .env (project root)
API_KEY=project-key        # Overrides ./mci/.env
PROJECT_VAR=proj-value

# Result: MCI will use:
# API_KEY=project-key (from root .env)
# LIBRARY_VAR=lib-value (from ./mci/.env)
# PROJECT_VAR=proj-value (from root .env)
Notes:
  • .env files are completely optional - MCI works fine without them
  • No error if .env files are missing
  • Use .env.mci for MCI-specific configurations to keep them completely separate from general project configs
  • When .env.mci exists, .env is ignored (not merged)
  • You can disable auto-loading by setting auto_load_dotenv=False when using the MCI library programmatically
  • .env files should NOT be committed to version control if they contain secrets

Toolsets Directory

Toolsets are stored in the ./mci directory by default. This can be customized using the libraryDir field.

Default Structure

my-project/
├── main.mci.json      # Entry file
└── mci/               # Default toolsets directory
    ├── weather.mci.json
    ├── database.mci.json
    ├── github.mci.json
    └── monitoring.mci.json

Custom Library Directory

You can use a different directory name:
{
  "schemaVersion": "1.0",
  "libraryDir": "./toolsets", // Custom directory
  "toolsets": [{ "name": "weather" }]
}
my-project/
├── main.mci.json
└── toolsets/          # Custom toolsets directory
    └── weather.mci.json

Nested Toolset Organization

Organize toolsets in subdirectories:
my-project/
└── mci/
    ├── external/
    │   ├── github.mci.json
    │   ├── slack.mci.json
    │   └── weather.mci.json
    ├── internal/
    │   ├── database.mci.json
    │   ├── logging.mci.json
    │   └── monitoring.mci.json
    └── mcp/            # MCP cache (auto-generated)
        ├── filesystem.mci.json
        └── memory.mci.json
Loading nested toolsets:
{
  "toolsets": [
    { "name": "external/github" },
    { "name": "external/weather" },
    { "name": "internal/database" }
  ]
}

MCP Tools Cache

When you register MCP servers in your schema, MCI automatically caches the tools in a special mcp subdirectory within your toolsets directory.

Cache Location

my-project/
├── main.mci.json
└── mci/
    ├── weather.mci.json      # Regular toolset
    ├── database.mci.json     # Regular toolset
    └── mcp/                  # MCP cache directory
        ├── filesystem.mci.json
        ├── github.mci.json
        └── memory.mci.json

How It Works

  1. Register MCP Server in your entry file:
{
  "schemaVersion": "1.0",
  "mcp_servers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"]
    }
  }
}
  1. First Load: MCI connects to the MCP server, fetches all tools, and saves them to ./mci/mcp/filesystem.mci.json
  2. Subsequent Loads: MCI uses the cached file instead of connecting to the server (much faster)
  3. Cache File Example (./mci/mcp/filesystem.mci.json):
{
  "schemaVersion": "1.0",
  "metadata": {
    "name": "filesystem MCP Server",
    "description": "Auto-generated toolset from MCP server"
  },
  "expiresAt": "2024-02-15T10:30:00Z",
  "tools": [
    {
      "name": "read_file",
      "description": "Read contents of a file",
      "execution": {
        "type": "mcp",
        "serverName": "filesystem",
        "toolName": "read_file"
      }
    },
    {
      "name": "write_file",
      "description": "Write content to a file",
      "execution": {
        "type": "mcp",
        "serverName": "filesystem",
        "toolName": "write_file"
      }
    }
  ]
}

Cache Management

Expiration: Caches expire after a configurable number of days (default: 30):
{
  "mcp_servers": {
    "filesystem": {
      "command": "npx",
      "args": ["..."],
      "config": {
        "expDays": 7 // Refresh every 7 days
      }
    }
  }
}
Manual Refresh: Delete cache files to force re-fetch:
rm -rf ./mci/mcp/
Git Ignore: Add MCP cache to .gitignore:
mci/mcp/

Basic Templating

MCI supports templating in all schema files using the {{}} syntax. This allows dynamic values from environment variables and provides default fallbacks.

Environment Variable Templating

Syntax: {{env.VARIABLE_NAME}}
{
  "tools": [
    {
      "name": "api_call",
      "execution": {
        "type": "http",
        "url": "{{env.API_BASE_URL}}/users",
        "auth": {
          "type": "apiKey",
          "in": "header",
          "name": "X-API-Key",
          "value": "{{env.API_KEY}}"
        }
      }
    }
  ]
}

Default Values with Pipe Operator

Syntax: {{env.VARIABLE_NAME|'default_value'}} The pipe operator (|) allows you to specify a default value if the environment variable is not set:
{
  "tools": [
    {
      "name": "connect_db",
      "execution": {
        "type": "cli",
        "command": "psql",
        "args": [
          "-h",
          "{{env.DB_HOST|'localhost'}}",
          "-p",
          "{{env.DB_PORT|'5432'}}",
          "-U",
          "{{env.DB_USER|'postgres'}}",
          "-d",
          "{{env.DB_NAME|'myapp'}}"
        ]
      }
    }
  ]
}
Without environment variables:
  • {{env.DB_HOST|'localhost'}}"localhost"
  • {{env.DB_PORT|'5432'}}"5432"
  • {{env.DB_USER|'postgres'}}"postgres"
With environment variables set:
  • {{env.DB_HOST|'localhost'}}"production.db.example.com"
  • {{env.DB_PORT|'5432'}}"3306"
Note: This allows any amount of vars (but keep it under 5, please): {{env.DB_HOST|env.EXTERNAL_DB_HOST|'localhost'}}

MCI File Templating Examples

Example 1: API Configuration with Defaults

{
  "schemaVersion": "1.0",
  "tools": [
    {
      "name": "fetch_users",
      "execution": {
        "type": "http",
        "method": "GET",
        "url": "{{env.API_URL|'https://api.example.com}}/users'",
        "headers": {
          "Authorization": "Bearer {{env.API_TOKEN}}",
          "Accept": "application/json"
        },
        "timeout_ms": "{{env.REQUEST_TIMEOUT|'5000'}}"
      }
    }
  ]
}

Example 2: CLI Tools with Environment Defaults

{
  "schemaVersion": "1.0",
  "tools": [
    {
      "name": "deploy_app",
      "execution": {
        "type": "cli",
        "command": "{{env.DEPLOY_TOOL|'kubectl'}}",
        "args": [
          "apply",
          "-f",
          "{{env.CONFIG_PATH|'./k8s/deployment.yaml'}}",
          "--namespace",
          "{{env.NAMESPACE|'default'}}"
        ],
        "cwd": "{{env.PROJECT_ROOT|'.'}}"
      }
    }
  ]
}

Example 3: MCP Server with Template Defaults

{
  "schemaVersion": "1.0",
  "mcp_servers": {
    "filesystem": {
      "command": "{{env.MCP_RUNNER|'npx'}}",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "{{env.WORKSPACE_PATH|'/tmp'}}"
      ],
      "env": {
        "LOG_LEVEL": "{{env.LOG_LEVEL|'info'}}",
        "MAX_FILE_SIZE": "{{env.MAX_FILE_SIZE|'10485760'}}"
      }
    }
  }
}

Example 4: Toolset Reference with Filtering

{
  "schemaVersion": "1.0",
  "libraryDir": "{{env.TOOLSETS_DIR|'./mci'}}",
  "toolsets": [
    {
      "name": "weather",
      "filter": "only",
      "filterValue": "get_weather,get_forecast"
    },
    {
      "name": "database",
      "filter": "withoutTags",
      "filterValue": "destructive"
    }
  ]
}

Template Usage in Different Contexts

1. Entry Files - Use templates in the main schema:
{
  "libraryDir": "{{env.MCI_LIB|'./mci'}}",
  "directoryAllowList": [
    "{{env.DATA_DIR|'./data'}}",
    "{{env.CONFIG_DIR|'./config'}}"
  ]
}
2. Toolset Files - Cannot use libraryDir or top-level config, but can use templates in tool definitions:
{
  "schemaVersion": "1.0",
  "tools": [
    {
      "name": "process_data",
      "execution": {
        "type": "file",
        "path": "{{env.TEMPLATE_PATH|'./templates'}}/report.txt"
      }
    }
  ]
}
3. MCP Servers - Use templates for credentials and paths:
{
  "mcp_servers": {
    "api_service": {
      "type": "http",
      "url": "{{env.MCP_URL|'http://localhost:8000/mcp}}'",
      "headers": {
        "Authorization": "Bearer {{env.MCP_TOKEN}}"
      }
    }
  }
}

Best Practices

1. Use Descriptive Entry File Names

✓ Good:
  - api-tools.mci.json
  - dev-environment.mci.json
  - production-monitoring.mci.json

✗ Avoid:
  - tools.json
  - config.json
  - my-stuff.json

2. Organize Toolsets by Domain

mci/
├── apis/
│   ├── github.mci.json
│   ├── weather.mci.json
│   └── slack.mci.json
├── databases/
│   ├── postgres.mci.json
│   └── redis.mci.json
└── utilities/
    ├── logging.mci.json
    └── monitoring.mci.json

3. Use Environment Variables for Secrets

{
  "tools": [
    {
      "execution": {
        "type": "http",
        "auth": {
          "type": "apiKey",
          "value": "{{env.API_KEY}}" // ✓ Good
          // "value": "sk-1234567890"  // ✗ Never hardcode secrets
        }
      }
    }
  ]
}

4. Provide Sensible Defaults

{
  "execution": {
    "type": "cli",
    "command": "{{env.PYTHON_BIN|'python3'}}", // ✓ Default to python3
    "timeout_ms": "{{env.TIMEOUT|'30000'}}" // ✓ Default timeout
  }
}

5. Document Your Entry Files

{
  "schemaVersion": "1.0",
  "metadata": {
    "name": "Production API Tools",
    "description": "Tools for production API operations. Requires API_KEY and DB_URL env vars.",
    "version": "2.1.0",
    "authors": ["Platform Team"]
  }
}

Summary

  • Entry Files: Main schema files in your project root that define tool collections
  • Multiple Entry Files: Use as many as needed for different environments or purposes
  • Toolsets Directory: Default is ./mci, customizable via libraryDir
  • MCP Cache: Auto-generated in ./mci/mcp/ when MCP servers are registered
  • Templating: Use {{env.VAR}} for environment variables, {{env.VAR|default}} for defaults
  • Organization: Group toolsets by domain, use descriptive names, and document your schemas