npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@thesammykins/ptv-mcp

v0.2.7

Published

MCP server for Public Transport Victoria (PTV) Timetable API v3 - Data licensed under Creative Commons Attribution 3.0 Australia

Downloads

23

Readme

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

  • Package Name: @thesammykins/ptv-mcp
  • Registry: https://www.npmjs.com/package/@thesammykins/ptv-mcp
  • Install Command: npm install @thesammykins/ptv-mcp

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

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

For Developers

🛠️ 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

⚙️ Development

Running Tests

# Run all tests
bun test

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

# Run with coverage
bun test --coverage

Scripts

| Script | Description | |--------|-------------| | bun run dev | Development server with hot reload | | bun run build | Build production bundle | | bun test | Run test suite | | bun run lint | TypeScript type checking | | bun run format | Format code with Prettier | | bun run mcp:dev | Start MCP server | | bun run mcp:validate | Validate 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

| Code | Description | |------|-------------| | STOP_NOT_FOUND | The specified stop name was not found | | ROUTE_NOT_FOUND | Route does not service the specified stop | | DIRECTION_NOT_FOUND | Invalid direction for the route | | NO_DEPARTURES | No upcoming departures found | | NO_APPROACHING_TRAINS | No vehicles detected approaching the stop | | PTV_API_ERROR | Upstream 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.

  • Data Source: Public Transport Victoria (PTV) Timetable API
  • Data Provider: Public Transport Victoria, State Government of Victoria, Australia
  • Data License: Creative Commons Attribution 3.0 Australia
  • Data URL: https://www.ptv.vic.gov.au/footer/data-and-reporting/datasets/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.