This plan outlines the step-by-step implementation of the Model Context Interface (MCI) v1 Python adapter based on PRD.md requirements. The implementation follows DRY, KISS, and modern software engineering principles with a focus on modularity, testability, and maintainability.
File: src/mcipy/enums.py
Define execution types as an enum:
HTTP- HTTP request executionCLI- Command-line executionFILE- File reading executionTEXT- Text template execution
File: src/mcipy/models.py
Define Pydantic models for:
MCISchema- Top-level schema withschemaVersion,metadata,tools[]Metadata- Optional metadata fields (name,description,version,license,authors[])Tool- Individual tool definition withname,title,description,inputSchema,executionExecutionConfig- Base execution configurationHTTPExecutionConfig- HTTP-specific fields (method, url, auth, headers, body, timeout_ms, retries)CLIExecutionConfig- CLI-specific fields (command, args, flags, cwd, timeout_ms)FileExecutionConfig- File-specific fields (path, enableTemplating)TextExecutionConfig- Text-specific fields (text)AuthConfig- Authentication configurations (apiKey, bearer, basic, oauth2)ExecutionResult- Result format withisErrorandcontent/error
Purpose: Provide strong typing, validation, and schema enforcement.
File: src/mcipy/templating.py
Implement a decoupled templating engine with:
Class: TemplateEngine
render_basic(template: str, context: dict) -> str- Basic placeholder substitution ({{props.x}},{{env.Y}})render_advanced(template: str, context: dict) -> str- Advanced templating with loops and control blocks_resolve_placeholder(path: str, context: dict) -> Any- Resolve dot-notation paths (e.g.,props.location)_parse_for_loop(content: str, context: dict) -> str- Parse@for->@endfor_parse_foreach_loop(content: str, context: dict) -> str- Parse@foreach->@endforeach_parse_control_blocks(content: str, context: dict) -> str- Parse@if->@elseif->@else->@endif
Context Structure:
{
"props": {...}, # Properties from execute() call
"env": {...}, # Environment variables
"input": {...} # Alias for props (for backward compatibility)
}File: src/mcipy/executors/base.py
Class: BaseExecutor (Abstract)
execute(config: ExecutionConfig, context: dict) -> ExecutionResult- Abstract method_build_context(props: dict, env_vars: dict) -> dict- Build template context_handle_timeout(timeout_ms: int) -> int- Convert timeout to seconds, apply defaults_format_error(error: Exception) -> ExecutionResult- Standardize error responses
File: src/mcipy/executors/http_executor.py
Class: HTTPExecutor(BaseExecutor)
execute(config: HTTPExecutionConfig, context: dict) -> ExecutionResult_apply_authentication(auth: AuthConfig, request_kwargs: dict) -> None- Apply auth to request_handle_api_key_auth(auth: AuthConfig, request_kwargs: dict) -> None_handle_bearer_auth(auth: AuthConfig, request_kwargs: dict) -> None_handle_basic_auth(auth: AuthConfig, request_kwargs: dict) -> None_handle_oauth2_auth(auth: AuthConfig, request_kwargs: dict) -> None- Fetch token and apply_build_body(body_config: dict, context: dict) -> tuple- Build request body (json/form/raw)_apply_retry_logic(func, retries: dict) -> Any- Implement retry with backoff
Dependencies: requests library
File: src/mcipy/executors/cli_executor.py
Class: CLIExecutor(BaseExecutor)
execute(config: CLIExecutionConfig, context: dict) -> ExecutionResult_build_command_args(config: CLIExecutionConfig, context: dict) -> list- Build full command with args and flags_apply_flags(flags: dict, context: dict) -> list- Convert flags based on type (boolean/value)_run_subprocess(command: list, cwd: str, timeout: int) -> tuple- Execute subprocess
Platform Consideration: Handle Windows/Linux/macOS path and command differences.
File: src/mcipy/executors/file_executor.py
Class: FileExecutor(BaseExecutor)
execute(config: FileExecutionConfig, context: dict) -> ExecutionResult_resolve_path(path: str, context: dict) -> str- Resolve templated path_read_file(path: str) -> str- Read file content_parse_content(content: str, context: dict, parse_placeholders: bool) -> str- Apply templating if enabled
File: src/mcipy/executors/text_executor.py
Class: TextExecutor(BaseExecutor)
execute(config: TextExecutionConfig, context: dict) -> ExecutionResult- Simple implementation that applies templating to text string
File: src/mcipy/executors/__init__.py
Class: ExecutorFactory
get_executor(execution_type: ExecutionType) -> BaseExecutor- Return appropriate executor instance
Purpose: Centralize executor instantiation based on execution type.
File: src/mcipy/parser.py
Class: SchemaParser
parse_file(file_path: str) -> MCISchema- Load and validate JSON fileparse_dict(data: dict) -> MCISchema- Parse dictionary into schema_validate_schema_version(version: str) -> None- Validate schema version compatibility_validate_tools(tools: list) -> None- Validate tool definitions_build_execution_config(execution: dict) -> ExecutionConfig- Build appropriate execution config based on type
Dependencies: Pydantic for validation
File: src/mcipy/tool_manager.py
Class: ToolManager
__init__(schema: MCISchema)get_tool(name: str) -> Tool | None- Retrieve tool by namelist_tools() -> list[Tool]- List all available toolsfilter_tools(only: list[str] | None, without: list[str] | None) -> list[Tool]- Filter tools by inclusion/exclusion
File: src/mcipy/client.py
Class: MCIClient
Initialization:
__init__(json_file_path: str, env_vars: dict | None = None)- Load JSON via
SchemaParser - Store environment variables
- Initialize
ToolManager - Cache executors via
ExecutorFactory
Methods:
tools() -> list[Tool]- Get all available toolsonly(tool_names: list[str]) -> list[Tool]- Filter to include only specified toolswithout(tool_names: list[str]) -> list[Tool]- Filter to exclude specified toolsexecute(tool_name: str, properties: dict) -> ExecutionResult- Execute a toollist_tools() -> list[str]- List available tool namesget_tool_schema(tool_name: str) -> dict- Return tool's input schema
Execute Flow:
- Validate tool exists
- Build context from properties and env_vars
- Get appropriate executor from factory
- Apply templating to execution config
- Execute via executor
- Return structured result (with meta data field)
Error Handling:
- Tool not found →
ExecutionResult(isError=True, error="Tool not found") - Invalid properties →
ExecutionResult(isError=True, error="Invalid input") - Execution error →
ExecutionResult(isError=True, error=<error message>)
Example:
from mcipy import MCIClient
# Initialize adapter with JSON file and environment variables
client = MCIClient(
json_file_path="example.mci.json",
env_vars={"API_KEY": "your-secret-key", "USERNAME": "user"}
)
# List all available tools
all_tools = client.list_tools()
print(f"Available tools: {all_tools}")
# List all available tools
weather_tools = client.list_tools(
only=["get_weather", "get_forecast"]
)
print(f"Only weather tools: {all_tools}")
# Filter to include only specific tools
weather_tools = client.only(["get_weather", "get_forecast"])
# Filter to exclude specific tools
restricted_tools = client.without(["delete_data", "admin_tools"])
# Execute a tool with properties
result = client.execute(
tool_name="get_weather",
properties={"location": "New York", "unit": "celsius"}
)
# Handle result
if result.isError:
print(f"Error: {result.error}")
else:
for content in result.content:
if content.type == "text":
print(content.text)Directory: tests/unit/
Test files:
test_enums.py- Test execution type enumtest_models.py- Test Pydantic models and validationtest_templating.py- Test basic and advanced templatingtest_http_executor.py- Test HTTP executor with mocked requeststest_cli_executor.py- Test CLI executor with mocked subprocesstest_file_executor.py- Test file executor with temp filestest_text_executor.py- Test text executortest_parser.py- Test JSON schema parsingtest_tool_manager.py- Test tool filtering and retrievaltest_adapter.py- Test main adapter API
Directory: tests/integration/
Test files:
test_http_integration.py- Real HTTP calls (or mock server)test_cli_integration.py- Real CLI commandstest_file_integration.py- Real file operationstest_end_to_end.py- Full workflow tests with example JSON
Directory: tests/security/
Test files:
test_env_vars.py- Ensure secrets only from env varstest_injection.py- Test against command injectiontest_path_traversal.py- Test file path security
File: docs/api_reference.md
Document:
MCIAdapterclass and methods- Configuration models
- Execution result format
- Error handling
File: docs/quickstart.md
Include:
- Installation instructions
- Basic usage example
- Tool definition example
- Execution examples for each type
File: docs/schema_reference.md
Document:
- Complete JSON schema structure
- All execution types and their parameters
- Authentication options
- Templating syntax
Directory: examples/
Provide:
http_example.json- HTTP execution examplescli_example.json- CLI execution examplesfile_example.json- File execution examplestext_example.json- Text execution examplesmixed_example.json- Combined examplesexample_usage.py- Python usage examples
File: pyproject.toml
Add required dependencies:
pydantic>=2.0- Data validationrequests>=2.31- HTTP requests- Development dependencies already configured
Update pyproject.toml:
- Version:
1.0.0 - Description and keywords
- Entry points if needed
- Ensure all code has proper type hints
- Run
basedpyrightfor type checking - Run
rufffor linting and formatting - Ensure
codespellpasses
- Shared templating logic in single
TemplateEngineclass - Base executor class for common functionality
- Executor factory for instantiation
- Shared context building and error formatting
- Each executor handles only its execution type
- Clear separation between parsing, templating, and execution
- Simple, focused methods with single responsibilities
- Minimal dependencies (only
pydanticandrequests)
- Type Safety: Pydantic models for all data structures
- Error Handling: Consistent error format across all executors
- Testability: Decoupled components, easy to mock
- Extensibility: Easy to add new execution types via base class
- Security: Environment-only secrets, no credential exposure
- Platform Agnostic: Handle OS differences in CLI executor
- Performance: Lazy loading, caching where appropriate
src/mcipy/
├── __init__.py # Package exports
├── adapter.py # Main MCIAdapter class
├── enums.py # ExecutionType enum
├── models.py # Pydantic models
├── parser.py # SchemaParser class
├── tool_manager.py # ToolManager class
├── templating.py # TemplateEngine class
└── executors/
├── __init__.py # ExecutorFactory
├── base.py # BaseExecutor
├── http_executor.py # HTTPExecutor
├── cli_executor.py # CLIExecutor
├── file_executor.py # FileExecutor
└── text_executor.py # TextExecutor
tests/
├── unit/
│ ├── test_enums.py
│ ├── test_models.py
│ ├── test_templating.py
│ ├── test_http_executor.py
│ ├── test_cli_executor.py
│ ├── test_file_executor.py
│ ├── test_text_executor.py
│ ├── test_parser.py
│ ├── test_tool_manager.py
│ └── test_adapter.py
├── integration/
│ ├── test_http_integration.py
│ ├── test_cli_integration.py
│ ├── test_file_integration.py
│ └── test_end_to_end.py
└── security/
├── test_env_vars.py
├── test_injection.py
└── test_path_traversal.py
docs/
├── api_reference.md
├── quickstart.md
└── schema_reference.md
examples/
├── http_example.json
├── cli_example.json
├── file_example.json
├── text_example.json
├── mixed_example.json
└── example_usage.py
- Stage 1: Establish type system and data models (foundation)
- Stage 2: Implement templating (needed by all executors)
- Stage 3: Build executors (core functionality)
- Stage 4: Create parser and tool manager (JSON handling)
- Stage 5: Implement main adapter API (public interface)
- Stage 6: Write comprehensive tests (quality assurance)
- Stage 7: Create documentation (user enablement)
- Stage 8: Finalize package (distribution ready)
Each stage builds upon previous stages, ensuring dependencies are met before implementation.