Nazar Mammedov

Software Engineer

Building an MCP Server for Resume Generation: A Practical Guide

6 min read
|
Poster of Boston Code and Coffee talk for MCP tool development.

Introduction to Model Context Protocol (MCP)

Model Context Protocol (MCP) is an open standard introduced by Anthropic in November 2024 that revolutionizes how AI models interact with external tools and data sources. Created by David Soria Parra and Justin Spahr-Summers, MCP solves a critical problem in AI system integration: the M×N integration challenge.

The M×N Problem

Without MCP, connecting M different AI models to N different tools requires M×N separate integrations. This creates exponential complexity as systems scale. MCP simplifies this by establishing a common protocol where each component connects once to the standard, reducing the complexity to M+N connections.

Foundation and Architecture

MCP is built on JSON-RPC 2.0, providing a robust foundation for communication between AI models and external resources. The protocol defines three core components:

1. Tools - Functions and tasks that the AI can execute (e.g., generating documents, sending emails)

2. Resources - Data and information sources the AI can access (e.g., certificate lists, skill databases)

3. Prompts - Predefined prompt templates that guide the AI's behavior for specific tasks

Building a Resume Generation MCP Server

Let's explore a practical implementation: an MCP server that helps with job applications by generating resumes and cover letters, accessing professional data, and sending emails.

Project Structure

├── mcp_server.py          # Main MCP server implementation
├── generator.py           # Resume/cover letter generation logic
├── mailer.py             # Email functionality
├── config.py             # Configuration and paths
├── data/
│   ├── certificates.json  # Professional certifications
│   ├── skills.json       # Technical skills database
│   └── smtp-config.json  # Email configuration
└── templates/
    ├── template_resume.docx
    └── template_cover_letter.docx

Understanding the MCP Server Implementation

Installing Dependencies

Before building your MCP server, you'll need to install the required packages. This project uses Python for the server implementation and npm for MCP tooling.

Python Dependencies:

pip install mcp
pip install fastmcp
pip install python-docx
pip install docxtpl

Or install all at once from a requirements file:

pip install mcp fastmcp python-docx docxtpl

Node.js/npm Dependencies (for debugging and testing):

npm install -g @modelcontextprotocol/inspector

The MCP Inspector is a crucial development tool that provides a web interface for testing your MCP server before integrating it with Claude Desktop.

Optional: Using uv (Python Package Manager):

The project uses uv, a fast Python package installer and resolver. Install it with:

pip install uv

Or on Windows via PowerShell:

powershell -c "irm https://astral.sh/uv/install.ps1 | iex"

Once installed, uv can manage your Python environment and dependencies more efficiently than traditional pip.

Setting Up the Server

The server initialization uses FastMCP, a Python library that simplifies MCP server creation:

from mcp.server.fastmcp import FastMCP
from mcp.types import Icon

mcp = FastMCP(
    name="resume-generator",
    icons=[
        Icon(
            src=str(config.ICONS_DIR / "icon.png"),
            mimeType="image/png",
            sizes=["48x48"],
        )
    ],
)

This creates a named MCP server with visual identification, making it recognizable in client interfaces like Claude Desktop.

Implementing Tools

Tools are the executable functions that Claude can call. Here's how the resume generation tool is implemented:

@mcp.tool()
def create_resume(json_string: str) -> str:
    """
    Generate a Word resume from JSON string using the generate_resume() function.

    Args:
        json_string: JSON content as a string.
    Returns:
        Path to the generated Word file.
    """
    output_path = generate_resume(json_string)
    return output_path

The @mcp.tool() decorator registers this function as an MCP tool. When Claude needs to create a resume, it can:

  1. Prepare the resume data in JSON format
  2. Call this tool with the JSON string
  3. Receive the path to the generated Word document

The actual document generation happens in generator.py:

def generate_resume(json_string: str, template_path: str = config.RESUME_TEMPLATE) -> str:
    # Parse the JSON data
    context = json.loads(json_string)
    
    # Load the Word template
    doc = DocxTemplate(template_path)
    
    # Render the template with the context data
    doc.render(context)
    
    # Create output filename based on job title
    job_title = context.get("job_title", "resume").replace(" ", "-")
    output_filename = f"{config.FULL_NAME}-{job_title}-resume.docx"
    output_path = os.path.join(config.OUTPUT_DIR, output_filename)
    
    # Save the document
    doc.save(output_path)
    
    return output_path

This function uses the docxtpl library to populate a Word template with dynamic data, allowing for consistent formatting while customizing content for each job application.

Email Integration Tool

The email tool demonstrates how MCP can integrate with external services:

@mcp.tool("send_email")
def send_email(subject: str, body: str, recipient: str, html: bool = False) -> str:
    """
    Sends an email to recipients defined in the JSON config.

    Args:
        subject (str): Email subject
        body (str): Email content
        recipient (str): Email of the recipient
        html (bool): Whether body is HTML

    Returns:
        str: Success or error message
    """
    return mail_send(subject, body, recipient, html)

This tool enables Claude to send application materials directly to recruiters or hiring managers, streamlining the job application workflow.

Implementing Resources

Resources provide read-only access to data sources. Here's how the certificates resource is implemented:

@mcp.resource(
    uri="resource://certificates",
    name="certificates",
    description="Returns a list of certificates from the certs.json file",
    mime_type="application/json",
)
def list_certificates() -> dict:
    """Return a list of certificates from certs.json"""
    if not os.path.exists(config.CERT_FILE):
        return {"error": "Certificate file not found."}

    with open(config.CERT_FILE, "r", encoding="utf-8") as f:
        data = json.load(f)

    return {"resources": data}

The @mcp.resource() decorator registers this as a data resource with:

  • URI: A unique identifier (resource://certificates)
  • Name: Human-readable identifier for Claude
  • Description: Explains what data this resource provides
  • MIME type: Indicates the data format

When Claude needs to reference your certifications while creating a resume, it can access this resource to retrieve the complete list without hardcoding the data.

Implementing Prompts

Prompts are predefined templates that guide Claude's behavior for specific tasks:

@mcp.prompt()
def job_analysis_prompt() -> str:
    """Creates a prompt to analyze the job description"""
    return f"Follow these instructions to analyze the job: \
            - Create an analysis of the job description I paste and identify the most important parts \
            - Research on the Internet what are the most important things to know when applying for work at the company \
            - Create an assessment of my likelihood of success in being hired for the job"

This prompt provides a consistent framework for job analysis, ensuring that Claude follows the same analytical approach for every job description.

Configuration Management

The config.py file centralizes all configuration using Python's pathlib:

from pathlib import Path

FULL_NAME = "Jons Myth"

BASE_DIR = Path(__file__).parent.resolve()
TEMPLATES_DIR = BASE_DIR / "templates"
DATA_DIR = BASE_DIR / "data"
OUTPUT_DIR = BASE_DIR / "output"

This approach ensures that all file paths are relative to the project directory, making the codebase portable across different systems.

Connecting the MCP Server to Claude

Step 1: Configure Claude Desktop

Edit the Claude Desktop configuration file located at:

  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

Step 2: Add Your MCP Server

Add your server configuration to the mcpServers section:

{
  "mcpServers": {
    "resume-generator": {
      "command": "uv",
      "args": [
        "--directory",
        "C:/www/boston-code-coffee/mcp/fastmcp",
        "run",
        "mcp_server.py"
      ]
    }
  }
}

This configuration tells Claude Desktop to:

  1. Use the uv command (a Python package runner)
  2. Set the working directory to your project folder
  3. Run the mcp_server.py file

Step 3: Restart Claude Desktop

After saving the configuration file, restart Claude Desktop. Your MCP server will be available, and you'll see the resume-generator icon in the interface.

Step 4: Verify Connection

You can verify the connection by asking Claude to:

  • List available certificates: Claude will call the list_certificates() resource
  • Create a resume: Claude will use the create_resume() tool
  • Analyze a job: Claude will use the job_analysis_prompt() template

Using the Inspector Tool

The project includes an inspector tool for debugging:

npx @modelcontextprotocol/inspector uv --directory "C:/www/boston-code-coffee/mcp/fastmcp" -- run mcp_server.py

This launches a web interface where you can:

  • Test tool invocations
  • Inspect resource responses
  • Debug JSON-RPC messages
  • Verify server configuration

Practical Workflow Example

Here's how a typical job application workflow works with this MCP server:

  1. Job Analysis: User shares a job description. Claude uses the job_analysis_prompt() to structure its analysis and researches the company online.

  2. Resume Adaptation: Claude accesses the certificates and skills resources to understand your background, then creates tailored resume data in JSON format.

  3. Document Generation: Claude calls create_resume() with the JSON data, generating a professionally formatted Word document.

  4. Cover Letter Creation: Following similar steps, Claude generates a personalized cover letter using create_cover_letter().

  5. Email Delivery: Optionally, Claude can use send_email() to send the application materials directly to the hiring manager.

Best Practices and Considerations

Error Handling

Always include robust error handling in your tools:

try:
    context = json.loads(json_string)
except json.JSONDecodeError as e:
    raise ValueError(f"Invalid JSON: {e}")

Security

  • Store sensitive credentials (like SMTP passwords) in configuration files that are excluded from version control
  • Use app-specific passwords for email services
  • Validate all input data before processing

Scalability

  • Keep tools focused on single responsibilities
  • Use resources for read-only data access
  • Cache frequently accessed data when appropriate

Conclusion

Model Context Protocol represents a significant advancement in AI integration architecture. By standardizing how AI models interact with tools and data, MCP enables developers to build more maintainable, scalable, and interoperable AI-powered applications.

The resume generation server demonstrates MCP's practical applications: combining document generation, data access, and external service integration into a cohesive system that augments the job application process. As MCP adoption grows, we can expect to see increasingly sophisticated AI assistants that seamlessly integrate with our digital workflows.

Whether you're building developer tools, business automation systems, or specialized AI assistants, MCP provides the foundation for creating powerful, extensible AI integrations that scale efficiently as your needs grow.

Resources

  • #MCP
  • #Model-Context-Protocol
  • #AI
  • #Anthropic
  • #Claude
  • #Python
  • #FastMCP
  • #Resume-Generation

Hello! How can I help you today?

Virtual Chat
  • Hello! My name is VirtuBot. I am a virtual assistant representing Nazar. You can ask me questions as if I am Nazar.
    4:23 PM
    Tell me about yourself?
Powered by NazarAI