BingMCP
by luljaj
README.md
# BingMCP
BingMCP is a FastMCP server that gives an LLM live access to useful
Binghamton University campus data. It supports local stdio clients and
Streamable HTTP clients, including Baxter or another MCP-compatible frontend.
The server discovers the existing tools from `tools/*/tool.py` at startup.
No API credentials are required for the public campus data sources.
## Current tools
- `get_laundry_availability(building: str)` — current washer and dryer state
- `get_bus_locations()` — live bus positions and arrival estimates
- `get_dining_status(hall: str)` — current Bearcat Dining resident-hall or
retail hours/status; retail support is hours only
- `get_dining_menu(hall: str, date?: str)` — normalized dining menus
- `get_parking_availability(day?: str, lot?: str)` — official weekday parking
availability estimates from TAPS; not a live occupancy feed
- `get_gym_capacity()` — East Gym occupancy and open/closed status
- `get_available_library_rooms(library?: str, category?: str)` — currently
available study rooms
- `get_bengaged_events(limit?: int, offset?: int, search?: str)` — upcoming
B-Engaged events
- `test_tool(message: str)` — the existing protocol smoke-test tool
Every tool returns a structured result. When an upstream source is unavailable,
the tool returns:
```json
{
"status": "unavailable",
"reason": "..."
}
```
## Bearcat Dining integration
The dining tools use Binghamton’s current Bearcat Dining provider through the
official [Dine On Campus Binghamton site](https://dineoncampus.com/Binghamton),
not the retired Sodexo integration.
The adapter dynamically resolves the Binghamton site and dining-location IDs,
so it is resilient to provider-side ID changes. It reads:
- public site metadata and dining locations;
- weekly schedules for current hall hours and open/closed status;
- meal periods and per-period menu data, including stations, items, portions,
calories, dietary filters, nutrients, and allergens.
Supported resident halls and aliases include Hinman, CIW
(College-in-the-Woods), C4 (Chenango Champlain), and Appalachian/ACC.
Dining-hours status also resolves current Bearcat Dining retail locations such
as Starbucks, B3, Chick-n-Bap, Dunkin', Panera Bread, The Quiet Cup, and
Bearcat Express. Retail locations intentionally support hours/status only;
`get_dining_menu` remains resident-hall-only.
`get_dining_menu` accepts these date formats:
- `YYYY-MM-DD`
- `MM-DD-YYYY`
- `MM/DD/YYYY`
- `YYYY/MM/DD`
The public API base URL and site slug can be overridden for testing with
`BEARCAT_DINING_API_URL` and `BEARCAT_DINING_SITE_SLUG`.
## Project layout
```text
BingMCP/
server.py
cache.py
run.sh
requirements.txt
test_dining.py
test_parking.py
test_mcp.py
test_tools.py
tools/
bus/tool.py
dining/tool.py
events/tool.py
gym/tool.py
laundry/tool.py
library/tool.py
parking/tool.py
test_tool/tool.py
```
## Requirements and setup
- Python 3.10+
```bash
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
```
Or use the helper script:
```bash
./run.sh
```
## Running the server
### stdio (default)
```bash
python server.py
```
Use stdio for local MCP clients that launch the server as a subprocess.
### Streamable HTTP
```bash
python server.py --transport http
# or
./run.sh --transport http
```
The HTTP server listens on `localhost:8000` and exposes MCP at:
```text
http://localhost:8000/mcp
```
For a frontend, run the backend with `--transport http`. If tools appear stale
or the endpoint returns 404, stop any older process still using port 8000 and
start the server again.
## Testing
Run the deterministic Bearcat adapter contract tests:
```bash
python -m unittest -v test_dining.py
```
Run the deterministic parking adapter contract tests:
```bash
python -m unittest -v test_parking.py
```
To test the full MCP protocol over HTTP, start the server in one terminal and
run this in a second terminal:
```bash
python server.py --transport http
python test_mcp.py
```
`test_mcp.py` discovers the registered tools and calls each endpoint, including
Bearcat retail hours, parking availability, and the smoke-test tool.
`test_tools.py` is the live upstream smoke test;
it calls the external campus APIs and therefore depends on network access and
the current operating hours of each service.
## Other data sources
- Laundry: LaundryView
- Bus: ETA Spot
- Gym: `https://binggym.com/api/gym`
- Library: Binghamton LibCal
- Events: B-Engaged mobile events endpoint
- Parking: [Binghamton TAPS parking availability](https://www.binghamton.edu/services/transportation-and-parking/parking/parking-availability/)
Each source has its own in-memory TTL and background refresh interval in
`cache.py`. A tool fetch registers the requested key with the server; later
calls are served from memory while the server refreshes that key before its
TTL expires. Concurrent calls for the same uncached key share one upstream
request, so the API is not queried once per MCP request. The events tool uses
the same server-lifetime approach with a full upcoming-event snapshot that is
refreshed every 15 minutes.
Current cache policy:
| Source | Cache TTL | Background refresh |
| --- | ---: | ---: |
| Bus | 20 seconds | 15 seconds |
| Laundry | 45 seconds | 30 seconds |
| Gym | 2 minutes | 90 seconds |
| Library | 1 minute | 45 seconds |
| Dining | 5 minutes | 4 minutes |
| Parking | 15 minutes | 12 minutes |
The cache is process-local and is cleared when the server restarts. Only keys
that have been requested are refreshed, avoiding polling unused buildings,
room categories, or menu dates.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues