ptv_mcp

thesammykins/ptv_mcp

3.2

If you are the rightful owner of ptv_mcp 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 PTV MCP Server provides real-time access to Melbourne's public transport data via the Public Transport Victoria (PTV) Timetable API v3, enabling AI assistants to offer comprehensive train information.

Tools
3
Resources
0
Prompts
0

PTV MCP Server šŸš‚

A Model Context Protocol (MCP) server providing real-time access to Melbourne's public transport data via the Public Transport Victoria (PTV) Timetable API v3. This server enables AI assistants to help users with comprehensive Melbourne train information.

šŸš€ Features

Three Powerful Tools:

  • next-train: Find the next train between any two Melbourne stations with real-time departures
  • line-timetable: Get upcoming departures for a specific route and station with platform details
  • how-far: Track approaching trains with real-time vehicle positions and distance estimates

Key Capabilities:

  • šŸš‚ Real-time departure information with platform details and disruption alerts
  • šŸ“ Live vehicle tracking with GPS coordinates, bearing, and ETA calculations
  • šŸ” Intelligent route discovery and validation across Melbourne's train network
  • ⚔ Lightning-fast responses with built-in caching (12-hour TTL for static data)
  • šŸ›”ļø Comprehensive error handling with actionable user messages
  • šŸ“Š Detailed execution metadata for monitoring and debugging

Built with:

  • ⚔ Bun runtime with TypeScript (strict mode)
  • šŸ” HMAC-SHA1 signature authentication per PTV requirements
  • šŸ”„ Automatic retry logic with exponential backoff
  • šŸ“‹ In-memory TTL caching for optimal performance
  • āš™ļø Latest MCP specification compliance

šŸ’» Quick Start

Prerequisites

  • Bun (latest version)
  • PTV Developer Credentials (Developer ID and API Key)

Installation

# Install Bun (if not already installed)
curl -fsSL https://bun.sh/install | bash

# Install from npm (recommended)
npm install @thesammykins/ptv-mcp

# Or clone and setup for development
git clone https://github.com/thesammykins/ptv_mcp.git
cd ptv_mcp
bun install

# Copy environment template
cp .env.example .env
# Edit .env with your PTV credentials

Configuration

Set up your environment variables in .env:

# Required: PTV API credentials
PTV_DEV_ID=your_developer_id_here
PTV_API_KEY=your_api_key_here

# Optional configuration
PTV_BASE_URL=https://timetableapi.ptv.vic.gov.au
HTTP_TIMEOUT_MS=8000
HTTP_MAX_RETRIES=3
CACHE_TTL_HOURS=12
LOG_LEVEL=info

Development

# Start development server with hot reload
bun run dev

# Run tests
bun test

# Type checking
bun run lint

# Format code
bun run format

# Test tools locally
bun run examples/test-tools.ts

MCP Server Usage

# Start MCP server (for Claude Desktop integration)
bun run mcp:dev

🧮 Claude Desktop Integration

Option 1: Use the provided mcp.json (Recommended)

The project includes a ready-to-use mcp.json configuration file:

# Set your PTV credentials as environment variables
export PTV_DEV_ID="your_developer_id_here"
export PTV_API_KEY="your_api_key_here"

# Copy mcp.json to Claude Desktop config directory
cp mcp.json ~/Library/Application\ Support/Claude/claude_desktop_config.json

The mcp.json file uses environment variable substitution for secure credential management:

{
  "mcpServers": {
    "ptv-local": {
      "command": "bun",
      "args": ["run", "src/mcp/server.ts"],
      "cwd": "/path/to/ptv_mcp",
      "env": {
        "PTV_DEV_ID": "${PTV_DEV_ID}",
        "PTV_API_KEY": "${PTV_API_KEY}"
      }
    }
  }
}

Option 2: Manual Configuration

Alternatively, manually add to your Claude Desktop configuration (~/Library/Application Support/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "ptv": {
      "command": "bun",
      "args": ["run", "src/mcp/server.ts"],
      "cwd": "/path/to/ptv_mcp",
      "env": {
        "PTV_DEV_ID": "YOUR_DEVELOPER_ID",
        "PTV_API_KEY": "YOUR_API_KEY"
      }
    }
  }
}

šŸ“¦ Publishing & Release

NPM Package Installation

The PTV MCP server is available as a scoped npm package:

# Install the published package
npm install @thesammykins/ptv-mcp

# Use in your project
const { PtvClient } = require('@thesammykins/ptv-mcp');

Release Process

This project uses automated publishing via GitHub Actions:

  1. Version Update: Update the version in package.json:

    npm version patch  # for bug fixes
    npm version minor  # for new features
    npm version major  # for breaking changes
    
  2. Create Release Tag: Push the version tag to trigger publishing:

    git push origin main --tags
    
  3. Automated Workflow: The GitHub Actions workflow will:

    • Run all tests (must pass)
    • Perform type checking and linting
    • Build the project
    • Publish to npm registry with provenance
    • Create a GitHub release

NPM Registry

Publishing Requirements

  • All tests must pass (bun test)
  • TypeScript compilation must succeed (bun run lint)
  • Build process must complete (bun run build)
  • Version tag format: v*.*.* (e.g., v1.0.0, v1.2.3)
  • NPM_TOKEN secret must be configured in repository settings

šŸ“š Documentation

For AI Agents

  • - Comprehensive guide for AI agents on how to effectively use the PTV MCP tools, including best practices, error handling, and sample interactions

For Developers

  • - System design and module structure
  • - PTV API v3 integration details
  • - Detailed requirements and implementation notes

šŸ› ļø Tool Usage Examples

The PTV MCP supports both Metro and V/Line regional trains - you can query journeys like "Southern Cross to Geelong" alongside metro services.

1. Next Train (next-train)

Find the next train between two stations:

Input:

{
  "origin": "Flinders Street",
  "destination": "South Morang",
  "time": "2024-03-15T09:00:00Z"
}

Response:

{
  "data": {
    "route": {
      "id": 2,
      "name": "Hurstbridge",
      "number": "Hurstbridge"
    },
    "direction": {
      "id": 1,
      "name": "Up"
    },
    "departure": {
      "scheduled": "2024-03-15T09:15:00Z",
      "estimated": "2024-03-15T09:16:00Z",
      "platform": "2",
      "runRef": "run_12345",
      "atPlatform": false,
      "scheduledMelbourneTime": "Fri Mar 15, 8:15 PM",
      "estimatedMelbourneTime": "Fri Mar 15, 8:16 PM",
      "minutesUntilDeparture": 14
    },
    "origin": {
      "id": 1071,
      "name": "Flinders Street",
      "suburb": "Melbourne"
    },
    "destination": {
      "id": 1155,
      "name": "South Morang",
      "suburb": "South Morang"
    },
    "disruptions": [],
    "journey": {
      "changes": 0
    },
    "timing": {
      "currentTime": "Fri Mar 15, 8:01 PM",
      "searchTime": "Fri Mar 15, 8:01 PM",
      "within30MinuteWindow": true
    }
  },
  "metadata": {
    "executionTime": 245,
    "apiCalls": 6,
    "cacheHits": 2,
    "dataFreshness": "2024-03-15T09:00:15Z",
    "routesConsidered": 1,
    "departuresFound": 3,
    "timezone": {
      "systemUTC": "2024-03-15T09:01:00Z",
      "melbourneLocal": "15/03/2024, 8:01:00 pm",
      "isDST": false,
      "offset": "UTC+10 (AEST)"
    }
  }
}

V/Line Regional Example:

{
  "origin": "Southern Cross",
  "destination": "Geelong",
  "time": "2024-03-15T09:30:00Z"
}

2. Line Timetable (line-timetable)

Get upcoming departures for a specific route:

Input:

{
  "stop": "Southern Cross",
  "route": "Belgrave",
  "direction": "outbound",
  "duration": 90
}

Response:

{
  "data": {
    "stop": {
      "id": 1181,
      "name": "Southern Cross",
      "suburb": "Melbourne"
    },
    "route": {
      "id": 4,
      "name": "Belgrave",
      "number": "Belgrave"
    },
    "departures": [
      {
        "scheduled": "2024-03-15T09:12:00Z",
        "estimated": "2024-03-15T09:13:00Z",
        "platform": "8",
        "destination": "Belgrave",
        "atPlatform": true
      },
      {
        "scheduled": "2024-03-15T09:27:00Z",
        "platform": "8", 
        "destination": "Belgrave"
      }
    ],
    "timeWindow": {
      "start": "2024-03-15T09:00:00Z",
      "end": "2024-03-15T10:30:00Z",
      "durationMinutes": 90
    }
  }
}

V/Line Regional Example:

{
  "stop": "Southern Cross",
  "route": "Geelong",
  "direction": "outbound",
  "duration": 120
}

3. How Far (how-far)

Track approaching trains with real-time positions:

Input:

{
  "stop": "Melbourne Central",
  "route": "Craigieburn",
  "direction": "inbound"
}

Response:

{
  "data": {
    "stop": {
      "id": 1120,
      "name": "Melbourne Central", 
      "suburb": "Melbourne",
      "coordinates": {
        "latitude": -37.8103,
        "longitude": 144.9633
      }
    },
    "route": {
      "id": 6,
      "name": "Craigieburn",
      "number": "Craigieburn"
    },
    "direction": {
      "id": 1,
      "name": "City (Flinders Street)"
    },
    "approachingTrains": [{
      "runRef": "run-456",
      "destination": "Flinders Street",
      "distanceMeters": 850,
      "eta": 2.1,
      "accuracy": "realtime",
      "vehicle": {
        "id": "X234",
        "operator": "Metro Trains",
        "description": "X'Trapolis 100",
        "lowFloor": true,
        "airConditioned": true
      },
      "realTimePosition": {
        "latitude": -37.8050,
        "longitude": 144.9633,
        "bearing": 180,
        "lastUpdated": "2024-03-15T09:00:45Z"
      }
    }]
  },
  "metadata": {
    "executionTime": 1250,
    "apiCalls": 4,
    "cacheHits": 1,
    "dataFreshness": "2024-03-15T09:00:50Z",
    "dataSource": "realtime"
  }
}

V/Line Regional Example:

{
  "stop": "Southern Cross",
  "route": "Geelong",
  "direction": "outbound"
}

Note: V/Line trains may have limited real-time vehicle position data, with graceful fallback to schedule-based estimates.

šŸ“ Project Structure

ptv_mcp/
ā”œā”€ā”€ src/
│   ā”œā”€ā”€ config.ts              # Environment configuration
│   ā”œā”€ā”€ mcp/
│   │   └── server.ts           # MCP server entry point
│   ā”œā”€ā”€ ptv/                   # PTV API client
│   │   ā”œā”€ā”€ signing.ts          # HMAC-SHA1 authentication
│   │   ā”œā”€ā”€ http.ts             # HTTP client with retries
│   │   ā”œā”€ā”€ client.ts           # API endpoints
│   │   ā”œā”€ā”€ types.ts            # TypeScript interfaces
│   │   └── cache.ts            # TTL caching
│   └── features/              # Tool implementations
│       ā”œā”€ā”€ next_train/
│       ā”œā”€ā”€ line_timetable/
│       └── how_far/
ā”œā”€ā”€ tests/                  # Unit and integration tests
ā”œā”€ā”€ examples/               # Usage examples
└── docs/                   # Documentation
    ā”œā”€ā”€ plan.md
    ā”œā”€ā”€ architecture.md
    └── apireference.md

šŸ“š Documentation

  • - System design and data flows
  • - PTV API v3 integration details
  • - Development roadmap

āš™ļø Development

Running Tests

# Run all tests
bun test

# Run specific test
bun test tests/signing.test.ts

# Run with coverage
bun test --coverage

Scripts

ScriptDescription
bun run devDevelopment server with hot reload
bun run buildBuild production bundle
bun testRun test suite
bun run lintTypeScript type checking
bun run formatFormat code with Prettier
bun run mcp:devStart MCP server
bun run mcp:validateValidate schemas and types

šŸ”’ Security

  • āš ļø Never commit real API credentials
  • All secrets are loaded from environment variables
  • API keys and signatures are redacted from logs
  • HMAC-SHA1 signature verification for all PTV API requests

šŸ› Troubleshooting

Common Issues

"Invalid signature" errors:

  • Verify your PTV_DEV_ID and PTV_API_KEY are correct
  • Ensure environment variables are properly loaded from .env
  • Check that there are no extra spaces or special characters in credentials

"Stop not found" errors:

  • Check stop names for typos (case insensitive matching supported)
  • Use full stop names: "Flinders Street" not "Flinders St"
  • Try nearby stops or use stop IDs directly for precision

"No departures found":

  • Verify the route services the requested stops
  • Check service hours - some routes don't operate at all times
  • Try broader time windows or different directions

Connection timeouts:

  • The PTV API can be slow during peak times
  • Server automatically retries with exponential backoff
  • Check network connectivity and firewall settings

Tool not found in Claude:

  • Verify MCP server configuration in Claude Desktop
  • Restart Claude Desktop after configuration changes
  • Check server logs for startup errors

Error Codes

CodeDescription
STOP_NOT_FOUNDThe specified stop name was not found
ROUTE_NOT_FOUNDRoute does not service the specified stop
DIRECTION_NOT_FOUNDInvalid direction for the route
NO_DEPARTURESNo upcoming departures found
NO_APPROACHING_TRAINSNo vehicles detected approaching the stop
PTV_API_ERRORUpstream API error or timeout

Getting Help

  • Check the PTV API FAQ
  • Review server logs for detailed error information
  • Open an issue on GitHub with reproduction steps
  • Ensure you're using the latest version

šŸ“¦ Current Status

  • āœ… Environment Setup: Complete with Bun + TypeScript strict mode
  • āœ… Core Architecture: Modular design with clean separation of concerns
  • āœ… PTV API Integration: Full HMAC-SHA1 auth + retry logic + error handling
  • āœ… Tool Implementation: All 3 MVP tools fully functional
  • āœ… Testing: Comprehensive test suite (36 tests - 30 passing, 6 failing on mock data)
  • āœ… Real-time Features: GPS vehicle tracking with Haversine distance calculations
  • āœ… Melbourne Timezone: Complete DST-aware timezone handling utilities
  • āœ… Error Handling: Structured errors with actionable user guidance
  • āœ… Documentation: Complete user + developer + AI agent guides
  • āœ… Claude Desktop Integration: Ready with provided mcp.json configuration
  • āœ… Production Ready: Meets all MVP objectives with enhanced features

šŸ—ļø Development

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes and add tests
  4. Ensure all tests pass (bun test)
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

Architecture Overview

The server follows a clean, layered architecture:

  • MCP Layer (src/mcp/) - Server initialization and tool registration
  • Feature Tools (src/features/) - High-level tool orchestration and business logic
  • PTV Client (src/ptv/) - API authentication, HTTP client, and response caching
  • Types (src/ptv/types.ts) - TypeScript interfaces for all API responses

Key Components

  • Authentication - HMAC-SHA1 signature generation per PTV API requirements
  • HTTP Client - Retry logic, timeout handling, and exponential backoff
  • Caching - TTL-based in-memory cache for stops, routes, and directions
  • Error Handling - Structured error responses with actionable user messages
  • Real-time Data - Live vehicle positions and schedule-based fallbacks

šŸ“„ License

MIT License - see LICENSE file for details

šŸš† Data Attribution

This software uses data from the Public Transport Victoria (PTV) Timetable API.

Users of this software should ensure they comply with the PTV API terms of use and provide appropriate attribution when using PTV timetable data.