Model Context Protocol MCP 17-Lesson Learning Path: End-to-End Workflow Explained

The Model Context Protocol (MCP) 17-lesson learning path in rohitg00/ai-engineering-from-scratch provides a progressive curriculum that takes you from basic tool registry definition to secure, production-ready MCP implementations, with Lesson I7 specifically focusing on argument validation and secure execution.

This repository contains a comprehensive hands-on course structured across 17 sequential lessons. Each lesson builds upon the previous to create a fully functional MCP-enabled application, culminating in robust argument validation and audit logging capabilities.

Overview of the 17-Lesson Curriculum

The learning path is defined in learning-paths/model-context-protocol.json and spans from foundational tool registries to deployment strategies. While Lessons I1 through I6 establish the basic infrastructure—creating JSON Schema registries, implementing tool functions like read_file, and building the client-side function-calling loop—Lesson I7 serves as the critical security gate.

By the time you reach I7, you have a live MCP server exposing tools via the list_tools RPC. I7 adds the argument-validation layer that ensures every tool call is well-formed, safe, and conforms to the MCP specification before execution.

The 7-Step End-to-End Workflow

The complete pipeline implemented across the learning path follows this reproducible sequence:

  1. Define a Tool Registry — Create a JSON Schema description in phases/11-llm-engineering/14-model-context-protocol/code/tools.json that describes every tool's parameters and return types.

  2. Implement Tool Functions — Write concrete server-side implementations (e.g., read_file, run_shell) that perform the actual business logic.

  3. Register All Tools — Load the registry into the MCP server so clients can discover capabilities via the list_tools JSON-RPC method.

  4. Build the Function-Calling Loop — Implement client code in client_loop.py that repeatedly asks the LLM for a plan, inspects responses for tool calls, and dispatches them to the server.

  5. Validate Arguments (Lesson I7) — Before invoking any tool, validate arguments against JSON Schema definitions, reject malformed requests, and sanitize inputs to enforce Non-Negotiable Security Rules (e.g., blocking absolute paths and shell injection).

  6. Run the Demo — Execute a scripted interaction showing the model discovering a tool, calling it with validated arguments, and receiving typed responses for context augmentation.

  7. Collect Evidence — Automatically record request/response traces to phases/11-llm-engineering/14-model-context-protocol/outputs/gate_trace.json for later audit and conformance testing.

Deep Dive into Lesson I7: Argument Validation & Secure Execution

Lesson I7, documented in phases/11-llm-engineering/14-model-context-protocol/docs/en.md, implements the security and type-safety layer. This lesson transforms a prototype into a production-grade system through eight specific technical steps:

Step 1: Load the Tool Registry

The validation process begins by loading tools.json and extracting each tool's JSON Schema payload to create validator instances.

Step 2: Schema Validation on Incoming Calls

For every incoming call_tool RPC, the system uses a JSON Schema validator (compatible with jsonschema.Draft7Validator) to verify that the arguments object matches the expected schema defined in the registry.

Step 3: Structured Error Handling

If validation fails, the server returns a structured error object with error.code = "INVALID_ARGUMENTS" and logs the event for audit purposes, preventing malformed data from reaching tool implementations.

Step 4: Input Sanitization

Upon successful validation, free-text fields undergo sanitization—control characters are stripped, length limits are enforced, and path arguments are checked against security policies in sanitizer.py.

Step 5: Tool Dispatch

Sanitized arguments are dispatched to concrete implementations (e.g., read_file in code/read_file.py) only after passing all validation gates.

Step 6: MCP-Compliant Response Packaging

The tool's return value is packaged into an MCP-compliant response structure with a result field and transmitted back to the client through server.py.

Step 7: Context Augmentation

The client appends the result to the model's context via model_context.append(result), enabling the LLM to reference the tool output in its next generation step.

Step 8: Trace Logging

The complete request/response pair is recorded in gate_trace.json by tracing.py, ensuring reproducibility and compliance auditing.

Code Implementation: From Registry to Validation

The following snippets illustrate the validation workflow implemented in Lesson I7:

Loading and Preparing Validators


# tools/registry.py

import json, jsonschema

with open("phases/11-llm-engineering/14-model-context-protocol/code/tools.json") as f:
    registry = json.load(f)

validators = {
    name: jsonschema.Draft7Validator(spec["parameters"])
    for name, spec in registry["tools"].items()
}

Validating Incoming Tool Calls


# server.py

def call_tool(name: str, arguments: dict):
    validator = validators.get(name)
    if not validator:
        raise MCPError("UNKNOWN_TOOL", f"{name} not registered")

    errors = list(validator.iter_errors(arguments))
    if errors:
        return {
            "error": {
                "code": "INVALID_ARGUMENTS",
                "message": "; ".join(e.message for e in errors),
            }
        }

    safe_args = {k: v.strip() if isinstance(v, str) else v for k, v in arguments.items()}
    return dispatch_tool(name, safe_args)

Dispatching to Concrete Implementations


# dispatcher.py

def dispatch_tool(name, args):
    if name == "read_file":
        return {"result": read_file(args["path"])}
    # Additional tool dispatches...

Client-Side Function-Calling Loop


# client_loop.py

while not done:
    response = model.generate(context)
    if response.contains_tool_call():
        tool_name, args = response.extract_call()
        result = mcp_server.call_tool(tool_name, args)
        if "error" in result:
            context.append(result["error"]["message"])
        else:
            context.append(result["result"])

Summary

  • The Model Context Protocol 17-lesson learning path provides a progressive curriculum from basic tool definitions to secure execution environments.

  • Lesson I7 specifically implements argument validation using JSON Schema validation against tools.json, input sanitization, and structured error responses with INVALID_ARGUMENTS codes.

  • Key files include validator.py for schema checking, server.py for dispatch, client_loop.py for orchestration, and gate_trace.json for audit trails.

  • The workflow ensures type safety, security, and reproducibility by validating all tool calls before execution and logging complete request/response cycles.

Frequently Asked Questions

What is the Model Context Protocol (MCP) 17-lesson learning path?

The MCP 17-lesson learning path is a structured educational curriculum in rohitg00/ai-engineering-from-scratch that teaches developers how to build MCP servers and clients. It progresses from basic JSON Schema tool registries (Lesson I1) through function-calling loops (I4) to advanced argument validation (I7) and deployment strategies (I8-I17), providing hands-on experience with the complete MCP specification.

How does Lesson I7 validate tool arguments in the MCP workflow?

Lesson I7 validates tool arguments by loading JSON Schema definitions from tools.json and using jsonschema.Draft7Validator to check incoming RPC calls in validator.py. If arguments fail validation, it returns an INVALID_ARGUMENTS error code; if they pass, it sanitizes inputs (stripping control characters and enforcing path constraints) before dispatching to the actual tool implementation in read_file.py or similar modules.

What files are critical for understanding the MCP end-to-end workflow?

The critical files are: learning-paths/model-context-protocol.json (lesson manifest), phases/11-llm-engineering/14-model-context-protocol/code/tools.json (schema registry), code/validator.py (argument validation), code/server.py (dispatch logic), code/client_loop.py (client orchestration), and outputs/gate_trace.json (audit logging). The workflow is also summarized in site/data.js (lines 2094-2133).

Why is argument validation necessary in MCP implementations?

Argument validation is necessary because MCP servers expose tool capabilities to LLMs that may generate hallucinated or malicious parameters. By enforcing JSON Schema constraints in Lesson I7, the system prevents path traversal attacks, shell injection, and type mismatches before they reach execution contexts, ensuring the Non-Negotiable Security Rules are maintained in production environments.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →