dos-travel-advisor

rdwj/dos-travel-advisor

3.1

If you are the rightful owner of dos-travel-advisor and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.

The FastMCP Server Template is a comprehensive solution for deploying Model Context Protocol servers with dynamic capabilities and seamless integration.

FastMCP Server Template

A production-ready MCP (Model Context Protocol) server template with dynamic tool/resource loading, Python decorator-based prompts, and seamless OpenShift deployment.

Features

  • 🔧 Dynamic tool/resource loading via decorators
  • 📁 Resource subdirectories for organizing related resources
  • 📝 Python-based prompts with type safety and FastMCP decorators
  • 🔀 Middleware support for cross-cutting concerns
  • 🏗️ Generator system for scaffolding new components with non-interactive CLI
  • 🔄 Selective updates - patch infrastructure without losing custom code
  • 🚀 One-command OpenShift deployment
  • 🔥 Hot-reload for local development
  • 🧪 Local STDIO and OpenShift HTTP transports
  • 🔐 JWT authentication (optional) with scope-based authorization
  • Full test suite with pytest

Quick Start

Local Development

# Install and run locally
make install
make run-local

# Test with cmcp (in another terminal)
cmcp ".venv/bin/python -m src.main" tools/list

Deploy to OpenShift

# One-command deployment
make deploy

# Or deploy to specific project
make deploy PROJECT=my-project

Project Structure

├── src/
│   ├── core/           # Core server components
│   ├── tools/          # Tool implementations
│   ├── resources/      # Resource implementations (supports subdirectories)
│   │   ├── country_profiles/   # Example: organized by category
│   │   ├── checklists/
│   │   └── emergency_protocols/
│   ├── prompts/        # Python-based prompt definitions
│   └── middleware/     # Middleware implementations
├── tests/              # Test suite
├── .fips-agents-cli/   # Generator templates
├── .template-info      # Template version tracking (for updates)
├── Containerfile       # Container definition
├── openshift.yaml      # OpenShift manifests
├── deploy.sh           # Deployment script
├── requirements.txt    # Python dependencies
└── Makefile           # Common tasks

Development

Adding Tools

Create a Python file in src/tools/. Tools support rich type annotations, validation, and metadata:

from typing import Annotated
from pydantic import Field
from fastmcp import Context
from fastmcp.exceptions import ToolError
from src.core.app import mcp

@mcp.tool(
    annotations={
        "readOnlyHint": True,
        "idempotentHint": True,
        "openWorldHint": False,
    }
)
async def my_tool(
    param: Annotated[str, Field(description="Parameter description", min_length=1, max_length=100)],
    ctx: Context = None,
) -> str:
    """Tool description for the LLM."""
    await ctx.info("Processing request")

    if not param.strip():
        raise ToolError("Parameter cannot be empty")

    return f"Result: {param}"

Best Practices:

  • Use Annotated for parameter descriptions (FastMCP 2.11.0+)
  • Add Pydantic Field constraints for validation
  • Use tool annotations for hints about behavior
  • Always include ctx: Context = None for logging and capabilities
  • Raise ToolError for user-facing validation errors
  • Use structured output (dataclasses) for complex results

See for comprehensive examples and patterns.

Generator examples:

# Simple tool
fips-agents generate tool my_tool \
    --description "Tool description" \
    --async

# Tool with context
fips-agents generate tool search_documents \
    --description "Search through documents" \
    --async \
    --with-context

# Tool with authentication
fips-agents generate tool protected_operation \
    --description "Protected operation" \
    --async \
    --with-auth

# Tool with parameters from JSON file
fips-agents generate tool complex_tool \
    --description "Complex tool with multiple params" \
    --params params.json \
    --with-context

# Advanced tool with all options
fips-agents generate tool advanced_tool \
    --description "Advanced tool example" \
    --async \
    --with-context \
    --with-auth \
    --return-type "dict" \
    --read-only \
    --idempotent

Adding Resources

Resources can be organized in subdirectories for better structure. Create files in src/resources/ or any subdirectory:

Simple resource:

from src.core.app import mcp

@mcp.resource("resource://my-resource")
async def get_my_resource() -> str:
    return "Resource content"

JSON resource with metadata:

from src.core.app import mcp

@mcp.resource(
    "data://config",
    mime_type="application/json",
    description="Application configuration data"
)
async def get_config() -> dict:
    return {"version": "1.0", "features": ["tools", "resources"]}

Resource template (parameterized):

from src.core.app import mcp

@mcp.resource("weather://{city}/current")
async def get_weather(city: str) -> dict:
    """Weather information for a specific city."""
    return {"city": city, "temperature": 22, "condition": "Sunny"}

Organizing resources in subdirectories:

src/resources/
├── country_profiles/
│   ├── __init__.py
│   ├── japan.py          # country-profiles://JP
│   └── france.py         # country-profiles://FR
├── checklists/
│   ├── __init__.py
│   └── travel.py         # travel-checklists://first-trip
└── emergency_protocols/
    ├── __init__.py
    └── passport.py       # emergency-protocols://passport-lost

Generator examples:

# Simple resource
fips-agents generate resource my_resource \
    --description "My resource description" \
    --uri "resource://my-resource" \
    --mime-type "text/plain"

# JSON resource
fips-agents generate resource config_data \
    --description "Application configuration" \
    --uri "data://config" \
    --mime-type "application/json"

# Resource in subdirectory (creates country_profiles/japan.py)
fips-agents generate resource country-profiles/japan \
    --description "Japan country profile" \
    --uri "country-profiles://JP" \
    --mime-type "application/json"

# Resource template with async and context
fips-agents generate resource weather \
    --async \
    --with-context \
    --description "Weather data by city" \
    --uri "weather://{city}/current" \
    --mime-type "application/json"

Subdirectories are automatically discovered by the loader - no manual registration needed!

Creating Prompts

Create Python files in src/prompts/. Prompts support multiple return types, async operations, context access, and metadata:

Basic String Prompt:

from pydantic import Field
from src.core.app import mcp

@mcp.prompt
def my_prompt(
    query: str = Field(description="User query"),
) -> str:
    """Purpose of this prompt"""
    return f"Please answer: {query}"

Async Prompt with Context:

from pydantic import Field
from fastmcp import Context
from src.core.app import mcp

@mcp.prompt
async def fetch_prompt(
    url: str = Field(description="Data source URL"),
    ctx: Context,
) -> str:
    """Fetch data and create prompt"""
    # Perform async operations
    return f"Analyze data from {url}"

Structured Message Prompt:

from pydantic import Field
from fastmcp.prompts.prompt import PromptMessage, TextContent
from src.core.app import mcp

@mcp.prompt
def structured_prompt(
    task: str = Field(description="Task description"),
) -> PromptMessage:
    """Create structured message"""
    return PromptMessage(
        role="user",
        content=TextContent(type="text", text=f"Task: {task}")
    )

Advanced with Metadata:

from pydantic import Field
from src.core.app import mcp

@mcp.prompt(
    name="custom_name",
    title="Human Readable Title",
    description="Custom description",
    tags={"analysis", "reporting"},
    meta={"version": "1.0", "author": "team"}
)
def advanced_prompt(
    data: dict[str, str] = Field(description="Data to process"),
) -> str:
    """Advanced prompt with full metadata"""
    return f"Analyze: {data}"

Generator Examples:

# Basic prompt
fips-agents generate prompt summarize_text \
    --description "Summarize text content"

# Async with Context
fips-agents generate prompt fetch_and_analyze \
    --async --with-context \
    --return-type PromptMessage

# With parameters file
fips-agents generate prompt analyze_data \
    --params params.json --with-schema

# Advanced with metadata
fips-agents generate prompt report_generator \
    --async --with-context \
    --prompt-name "generate_report" \
    --title "Report Generator" \
    --tags "reporting,analysis" \
    --meta '{"version": "2.0"}'

Return Types:

  • str - Simple string prompt (default)
  • PromptMessage - Structured message with role
  • list[PromptMessage] - Multi-turn conversation
  • PromptResult - Full prompt result object

See for comprehensive prompt generation documentation and src/prompts/ for working examples.

Adding Middleware

Create a file in src/middleware/:

from typing import Any, Callable
from fastmcp import Context
from core.app import mcp

@mcp.middleware()
async def my_middleware(
    ctx: Context,
    next_handler: Callable,
    *args: Any,
    **kwargs: Any
) -> Any:
    # Pre-execution logic
    result = await next_handler(*args, **kwargs)
    # Post-execution logic
    return result

Middleware wraps tool execution to add cross-cutting concerns like logging, authentication, rate limiting, caching, etc.

See src/middleware/logging_middleware.py for a working example and src/middleware/auth_middleware.py for a commented authentication pattern.

Generator examples:

# Async middleware
fips-agents generate middleware logging_middleware \
    --description "Request logging middleware" \
    --async

# Sync middleware
fips-agents generate middleware rate_limiter \
    --description "Rate limiting middleware" \
    --sync

Testing

Local Testing (STDIO)

# Run server
make run-local

# Test with cmcp
make test-local

# Run unit tests
make test

OpenShift Testing (HTTP)

# Deploy
make deploy

# Test with MCP Inspector
npx @modelcontextprotocol/inspector https://<route-url>/mcp/

See for detailed testing instructions.

Keeping Projects Updated

This template is actively maintained with improvements to infrastructure, generators, and documentation. You can selectively update your project from template changes without losing your custom code.

Check for Updates

# See what's changed since project creation
fips-agents patch check

This shows available updates organized by category (generators, core, docs, build).

Update Specific Categories

# Update generator templates (safe - your code is untouched)
fips-agents patch generators

# Update core infrastructure (shows diffs, asks for approval)
fips-agents patch core

# Update documentation and examples (safe)
fips-agents patch docs

# Update build and deployment files (shows diffs, asks for approval)
fips-agents patch build

# Preview changes without applying (dry run)
fips-agents patch core --dry-run

Update Everything

# Interactively update all categories
fips-agents patch all

# Skip confirmation prompts (use with caution)
fips-agents patch all --skip-confirmation

What Gets Updated

Automatically updated (no confirmation):

  • .fips-agents-cli/generators/ - Code generator templates
  • docs/ - Documentation files
  • Example files in src/*/examples/

Asks before updating (shows diffs):

  • src/core/loaders.py - Component discovery system
  • src/core/server.py - Server bootstrap code
  • src/*/__ init__.py - Package initialization files
  • Makefile, Containerfile, openshift.yaml - Build files

Never updated (your code is protected):

  • src/tools/*.py - Your tool implementations
  • src/resources/*.py - Your resource implementations
  • src/prompts/*.py - Your prompt definitions
  • src/middleware/*.py - Your middleware implementations
  • tests/ - Your test files
  • README.md, pyproject.toml, .env - Project configuration
  • src/core/app.py, src/core/auth.py, src/core/logging.py - User-customizable core files

Example: Adding New Template Capabilities

Imagine the template adds new authentication capabilities in a future update:

# Check what's new
fips-agents patch check

# Pull in updated generators so you can generate auth-enabled tools
fips-agents patch generators

# Review and apply core infrastructure updates
fips-agents patch core  # Shows diffs, you decide what to apply

# Your existing tools, resources, and prompts remain untouched!

The .template-info file tracks which template version your project was created from, enabling smart updates.

Environment Variables

Local Development

  • MCP_TRANSPORT=stdio - Use STDIO transport
  • MCP_HOT_RELOAD=1 - Enable hot-reload

OpenShift Deployment

  • MCP_TRANSPORT=http - Use HTTP transport (set automatically)
  • MCP_HTTP_HOST=0.0.0.0 - HTTP server host
  • MCP_HTTP_PORT=8080 - HTTP server port
  • MCP_HTTP_PATH=/mcp/ - HTTP endpoint path

Optional Authentication

  • MCP_AUTH_JWT_SECRET - JWT secret for symmetric signing
  • MCP_AUTH_JWT_PUBLIC_KEY - JWT public key for asymmetric
  • MCP_REQUIRED_SCOPES - Comma-separated required scopes

Available Commands

make help         # Show all available commands
make install      # Install dependencies
make run-local    # Run locally with STDIO
make test         # Run test suite
make deploy       # Deploy to OpenShift
make clean        # Clean up OpenShift deployment

Architecture

The server uses FastMCP 2.x with:

  • Dynamic component loading at startup
  • Hot-reload in development mode
  • Python decorator-based prompts with type safety
  • Automatic component registration via decorators (@mcp.tool(), @mcp.resource(), @mcp.prompt(), @mcp.middleware())
  • Middleware for cross-cutting concerns
  • Generator system with Jinja2 templates for scaffolding
  • Support for both STDIO (local) and HTTP (OpenShift) transports

See for detailed architecture information and for generator system documentation.

Requirements

  • Python 3.11+
  • OpenShift CLI (oc) for deployment
  • cmcp for local testing: pip install cmcp

Contributing

We welcome contributions! Please see our for details on how to get started, development setup, and submission guidelines.

License

This project is licensed under the MIT License - see the file for details.