Wellington Transport Assistant

Wellington Transport Assistant

Provides tools to search stops, get next departures, and retrieve service alerts from Metlink's real-time public transport data, enabling natural language queries about Wellington transit.

Category
访问服务器

README

Wellington Transport Assistant

A model-powered agent that answers real-time questions about Wellington's public transport. The agent reads live data from Metlink (Wellington's public transport authority), reasons over multiple tool calls, and replies in plain English.

Built with FastMCP, Microsoft Agent Framework, Microsoft Foundry, and Azure Container Apps.

This is a personal project. The code is open source under the MIT license and is designed so anyone can clone the repository and deploy the same setup in their own Azure subscription.


What it does

Ask questions in plain English and get answers from live Metlink data. Some examples:

  • "When is the next bus to Karori from Lambton Quay?"
  • "Is the Johnsonville train line running normally?"
  • "Any disruptions on the Eastbourne ferry today?"
  • "I have a meeting at Te Papa in 25 minutes. Walk or bus from Wellington Station?"

The agent decides which tools to call, in what order, and combines the results into a single readable answer.


Architecture

Architecture diagram

The system has three parts:

  1. An MCP server running on Azure Container Apps. It wraps the Metlink Open Data API and exposes three tools over HTTPS: search_stops, next_departures, and service_alerts.
  2. A language model deployed in Microsoft Foundry. It does the reasoning and the conversation.
  3. An agent that runs on your local machine. It connects to both the model and the MCP server, orchestrates the tool calls, and presents the answer in a chat window or a command line script.

The agent and the MCP server only talk to each other over HTTPS. The MCP server has no knowledge of the model. The model has no knowledge of the underlying Metlink API. That separation means you can swap any piece without touching the others.


Data source

The agent reads its data from Metlink's Open Data API, the official public API for Wellington's bus, train, ferry, and cable car services. The API is free, requires no payment details, and is rate limited rather than billed.

To use it, sign up at https://opendata.metlink.org.nz, fill in a short form describing your use case, and your API key arrives in your dashboard within a few minutes.

The MCP server in this project uses four Metlink endpoints:

Endpoint What it provides
GET /gtfs/stops All stops in the Wellington network (around 3,000 records)
GET /gtfs/routes All routes across bus, train, ferry, and cable car
GET /stop-predictions?stop_id=... Real-time predicted departures for a specific stop
GET /gtfs-rt/servicealerts Current service disruptions and alerts

The static reference data (stops and routes) is cached in memory for 24 hours because it changes rarely. Real-time data (predictions and alerts) is fetched on every request to keep it accurate.


Prerequisites

You need the following before you start:

What Why Where to get it
Azure subscription Hosts the MCP server and the language model https://azure.microsoft.com
Azure CLI installed Used to deploy resources https://learn.microsoft.com/cli/azure/install-azure-cli
Python 3.11 or newer Runs the agent and the MCP server locally https://www.python.org/downloads
uv package manager Manages Python dependencies https://docs.astral.sh/uv/
Metlink API key Lets the MCP server call the Metlink data API. Free. https://opendata.metlink.org.nz
Docker (optional) Only needed if you want to build the image locally. The deploy script builds in the cloud, so you can skip this. https://www.docker.com

You also need a Foundry account with a language model deployed. See the Foundry setup section.


Running the commands

Every command in this README runs in a terminal. If you use Visual Studio Code, open one by clicking Terminal > New Terminal in the top menu (or press Ctrl+`). Any other terminal works too: the macOS Terminal app, Windows Terminal, PowerShell, or your favourite. The Azure CLI behaves the same way in all of them.

Getting started

This is the full step by step walkthrough. Follow the seven steps below in order and you will have a working chat window on your laptop. The whole process takes about 30 minutes the first time, most of which is waiting for Azure to provision resources.

Step 1: Install the prerequisites

Install everything listed in the Prerequisites table above. Then sign in to Azure from your terminal:

az login

Step 2: Clone the repository

git clone https://github.com/sdhilip200/metlink-mcp.git
cd metlink-mcp

All the commands below run from the metlink-mcp folder.

Step 3: Deploy the MCP server to Azure

The repository includes a deploy.sh script that runs the four Azure CLI commands needed to create the resource group, build the Docker image in the cloud, deploy the Container App, and store your Metlink API key as a secret.

# Set your Metlink API key as an environment variable so deploy.sh can read it
export METLINK_API_KEY=your_metlink_key_here

# Run the deploy script
./deploy.sh

This takes about five minutes the first time. When it finishes, it prints a URL similar to:

https://ca-metlink-mcp.<random>.australiaeast.azurecontainerapps.io/mcp

Copy this URL. You will need it in Step 5.

Step 4: Set up the model in Microsoft Foundry

The agent uses a language model deployed in Foundry. Follow the three commands in the Foundry setup section below. They create a Foundry account, deploy a model, and write the endpoint and key into your .env file automatically.

Step 5: Configure your local .env file

cp .env.example .env

Open .env in your editor and fill in the five values:

Variable What to put
METLINK_API_KEY The Metlink API key from Step 1
FOUNDRY_ENDPOINT Filled in automatically by Step 4
FOUNDRY_API_KEY Filled in automatically by Step 4
FOUNDRY_DEPLOYMENT The deployment name you chose in Step 4
MCP_URL The URL you copied at the end of Step 3

Step 6: Install Python dependencies

uv sync --group foundry --prerelease=allow

The --prerelease=allow flag is needed because the Anthropic provider package is still in beta.

Step 7: Run the agent

You have two ways to run the agent.

Option A: Browser chat window (recommended for hand testing)

uv run --group foundry --prerelease=allow streamlit run examples/streamlit_app.py

The chat window opens at http://localhost:8501. Type a question and watch the agent answer.

Option B: Command line with the six demo queries

uv run --group foundry --prerelease=allow python examples/agent.py

The agent runs through the six demo queries one after another and saves the transcript to examples/demo_transcript.md.

That is it. The agent is now answering Wellington transport questions on your laptop using a model deployed in your Azure subscription.


Running the MCP server locally without Azure

If you want to try the agent before deploying anything to Azure, you can run the MCP server on your own laptop:

uv run python -m src.server

Then set MCP_URL=http://localhost:8000/mcp in your .env instead of the Azure URL, and run Step 7. Everything else works the same.


Repository structure

metlink-mcp/
├── README.md                Main documentation, this file
├── LICENSE                  MIT license
├── .gitignore               Files excluded from version control
├── .env.example             Template for your local environment file
├── pyproject.toml           Python dependencies and project metadata
├── uv.lock                  Locked dependency versions for reproducibility
├── Dockerfile               Builds the MCP server container image
├── .dockerignore            Files excluded from the Docker build context
├── deploy.sh                One-command Azure deployment script
│
├── src/                     MCP server source code
│   ├── __init__.py
│   ├── server.py            FastMCP entry point and tool definitions
│   ├── metlink_client.py    HTTP client wrapping the Metlink API
│   ├── models.py            Pydantic models for parsing Metlink responses
│   ├── cache.py             In-memory cache for static reference data
│   └── formatters.py        Converts parsed data into readable text
│
├── examples/                Client examples
│   ├── agent.py             Command-line agent that runs six demo queries
│   └── streamlit_app.py     Local chat user interface
│
├── tests/                   Test suite
│   ├── conftest.py          Shared pytest configuration
│   ├── test_smoke.py        Live API tests
│   ├── test_formatters.py   Unit tests for the formatting functions
│   └── fixtures/            Sample Metlink API responses for testing
│
└── docs/                    Documentation assets
    └── architecture.jpg     Architecture diagram

Deployment

The MCP server runs in Azure Container Apps and scales to zero when idle. It costs nothing when nobody is using it.

Option 1: Use the deploy script (recommended)

The repository includes a deploy.sh script that runs the four required Azure CLI commands in order. To use it:

# Sign in to Azure
az login

# Export your Metlink API key
export METLINK_API_KEY=your_metlink_key_here

# Run the script
./deploy.sh

The script takes about five minutes the first time. When it finishes, it prints the public URL of your MCP server. Copy this URL into your local .env file as the MCP_URL value.

Option 2: Run the commands manually

If you prefer to run each step yourself, the four commands are:

# 1. Create the resource group
az group create --name rg-metlink-mcp --location australiaeast

# 2. Build the image and deploy the container app
az containerapp up \
  --name ca-metlink-mcp \
  --resource-group rg-metlink-mcp \
  --location australiaeast \
  --environment cae-metlink-mcp \
  --source . \
  --ingress external \
  --target-port 8000

# 3. Store the Metlink API key as a secret
az containerapp secret set \
  --name ca-metlink-mcp \
  --resource-group rg-metlink-mcp \
  --secrets metlink-api-key=$METLINK_API_KEY

# 4. Bind the secret and set the scaling rules
az containerapp update \
  --name ca-metlink-mcp \
  --resource-group rg-metlink-mcp \
  --set-env-vars METLINK_API_KEY=secretref:metlink-api-key \
  --min-replicas 0 --max-replicas 1

Step 2 takes about five minutes the first time. It creates an Azure Container Registry, builds the Docker image in the cloud, pushes the image, creates a Container Apps environment, and deploys the app with a public HTTPS URL.

After deployment your MCP server is reachable at a URL similar to:

https://ca-metlink-mcp.<random>.australiaeast.azurecontainerapps.io/mcp

Foundry setup

The agent connects to a language model deployed in Microsoft Foundry. Foundry hosts model families from Anthropic, OpenAI, Meta, Mistral, and others behind a single Azure interface.

To set up a model:

# 1. Create a Foundry account (a Cognitive Services account of kind AIServices)
az cognitiveservices account create \
  --name my-foundry-account \
  --resource-group rg-metlink-mcp \
  --kind AIServices \
  --sku S0 \
  --location eastus2

# 2. Deploy a model on the account. Replace the model details below with the
#    model family you want to use. The Foundry catalogue lists every model
#    available in your region, with their model-name, model-version, and
#    model-format values.
az cognitiveservices account deployment create \
  --name my-foundry-account \
  --resource-group rg-metlink-mcp \
  --deployment-name my-model \
  --model-name <model-name-from-catalogue> \
  --model-version <model-version-from-catalogue> \
  --model-format <model-format-from-catalogue> \
  --sku-name GlobalStandard \
  --sku-capacity 250

# 3. Get the endpoint and key and add them to your .env
ENDPOINT=$(az cognitiveservices account show \
  --name my-foundry-account \
  --resource-group rg-metlink-mcp \
  --query properties.endpoint -o tsv)

KEY=$(az cognitiveservices account keys list \
  --name my-foundry-account \
  --resource-group rg-metlink-mcp \
  --query key1 -o tsv)

echo "FOUNDRY_ENDPOINT=$ENDPOINT" >> .env
echo "FOUNDRY_API_KEY=$KEY" >> .env
echo "FOUNDRY_DEPLOYMENT=my-model" >> .env

A quick note on the bash inside step 3 for anyone new to shell scripting. The command az cognitiveservices account show normally returns a big JSON object. The --query properties.endpoint part tells the CLI to return only that one field, and -o tsv strips the surrounding quotes so you get a clean string. The $(...) wrapper runs the command and captures the result into a variable. The same pattern grabs the API key. The >> then appends each value to your .env file, where the agent reads them later.

The --deployment-name is a name you choose. The --model-name, --model-version, and --model-format values must match an entry in the Foundry catalogue exactly. To see what is available in your region, run az cognitiveservices model list --location eastus2 -o table and pick a model.


Configuration

All configuration lives in your local .env file. The repository includes a .env.example template you can copy.

Variable What it is Example
METLINK_API_KEY Your Metlink Open Data API key (40 character string)
FOUNDRY_ENDPOINT The endpoint URL of your Foundry account https://my-account.cognitiveservices.azure.com
FOUNDRY_API_KEY The API key for your Foundry account (long string)
FOUNDRY_DEPLOYMENT The name of your model deployment in Foundry my-model
MCP_URL The public URL of your deployed MCP server https://ca-metlink-mcp.<random>.australiaeast.azurecontainerapps.io/mcp

The .env file is excluded from version control. It only exists on your local machine.


Testing

The repository includes a small test suite. To run it:

# Unit tests against the fixture data
uv run pytest

# Live tests against the real Metlink API
# (requires METLINK_API_KEY to be set)
uv run pytest -m live

Troubleshooting

Cold start is slow on the first request. Azure Container Apps scales the MCP server to zero when nobody is calling it. The first request after an idle period takes around 10 to 30 seconds to wake the container up. Every request after that is fast.

Streamlit shows a long blank page on first load. The chat window itself takes a few seconds to initialise. If you do not see the input box after 30 seconds, check the terminal for errors.

Agent does not respond and returns a 529 error. This is an "overloaded" response from the upstream model provider. It usually clears within a few minutes. Try again, or switch to a different model in Foundry.

Tool calls fail with a 401 or 403. Your Metlink API key is missing or incorrect. Check the value in your Container App secret and in your local .env.

Deployment fails with "provider not registered". Run these two commands once per subscription to enable the required Azure providers, then try the deployment again:

az provider register -n Microsoft.App
az provider register -n Microsoft.ContainerRegistry

License

MIT. See the LICENSE file for the full text.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选
mcp-server-qdrant

mcp-server-qdrant

这个仓库展示了如何为向量搜索引擎 Qdrant 创建一个 MCP (Managed Control Plane) 服务器的示例。

官方
精选
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选