Sign inSign up

phonhay103/maitabi

By phonhay103

•Updated about 10 hours ago

Maitabi CLI + MCP server: bus tours, trekking tours, calendars (unofficial).

Image
0

364

phonhay103/maitabi repository overview

⁠Maitabi (Python)

Search Maitabi (まいたび — 毎日新聞旅行 / 毎日あるぺん号) from one package: mountain bus tours (bus.maitabi.jp), general travel and trekking tours, and departure calendars (www.maitabi.jp). It ships as a CLI, an MCP server, and three agent skills — all driven by the same eight actions.

Unofficial client. Not affiliated with 毎日新聞旅行.

InterfaceUse it whenStart with
CLIyou want commands, scripts, or JSON for jquvx maitabi --help
MCP serveryou want the tools inside an MCP clientuvx maitabi mcp
Skillsyou want an agent to know the workflowsnpx skills add phonhay103/maitabi -g

⁠Install

uv tool install maitabi     # installs the `maitabi` command on your PATH
uv tool upgrade maitabi     # later, to update it
maitabi --version           # confirm which version is running

Nothing installed? uvx maitabi ... runs the same published version on demand, e.g. uvx maitabi bus search-tours --month 11.

⁠Quick start (CLI)

# Mountain bus tours
maitabi bus search-tours --month 11 --area 18 --pretty

# General trekking tours
maitabi general search-tours --travel-type 1 --keyword '富士山' --year-month 2026-11

# One tour in full
maitabi bus get-tour-detail --course-no 14241

# Monthly departure matrix
maitabi general get-calendar --year 2026 --month 11 --travel-type 1

Every data command accepts --pretty and --output FILE.

⁠Output contract

Search commands return one envelope; every item carries a detail_url:

{
  "count": 191,
  "page": 1,
  "items": [
    {
      "course_no": 14241,
      "course_cd": "S104C21",
      "date": "2026年09月12日(土)",
      "title": "立山室堂ライン往復ツアー",
      "price": "15,500円",
      "status": "受付中",
      "detail_url": "https://bus.maitabi.jp/detail.html?course_no=14241&year=2026&month=9"
    }
  ],
  "query": { "departure": 1, "month": 11, "page": 1 }
}
  • count is the upstream total for the query, before the client-side price/availability filters; items can be shorter on the current page.
  • count and page are null when upstream does not report them; items is always a list.
  • Batch detail (--course-no 14241,8518) returns the same envelope with page: null; a single course returns the detail object itself.
  • Filter options, district groups, and the calendar return their own objects — a list of one would add indexing without information.
  • status is domain-native: a Japanese string for bus, a numeric code for general (1/2 bookable, 3 closed).
  • Errors are always {"error": ..., "detail": ...}, never a partial envelope.

The contract only grows: new fields appear, existing ones are never renamed or removed within a major version.

⁠Tools (7)

Full parameter reference (MCP args, CLI flags, defaults, endpoints): docs/TOOL_CATALOG.md⁠ — generated from the code, so it cannot drift.

⁠Mountain bus (api.bus.maitabi.jp)
MCP toolCLIWhat it does
bus_list_filtersmaitabi bus list-filtersfilter options, lodges, tour counts (cascading)
bus_list_district_groupsmaitabi bus list-district-groupsarea/district groups + counts
bus_list_filter_mastermaitabi bus list-filter-masterone master list (--kind style|bus_sheet|return_day|district), small payload
bus_search_toursmaitabi bus search-tourssearch tours and lodge packages
bus_get_tour_detailmaitabi bus get-tour-detailfull itinerary by course_no (single or batch)
⁠General tours & calendar (www.maitabi.jp)
MCP toolCLIWhat it does
general_search_toursmaitabi general search-tourssearch by travel_type 1-5, keyword, dates, categories
general_get_tour_detailmaitabi general get-tour-detailitinerary, conditions, every departure + booking link
general_get_calendarmaitabi general get-calendarmonthly departure matrix

⁠One deliberate exception to "API only"

www.maitabi.jp publishes no tour-detail API — api/v1 serves only category_search and calendar/{year}/{month}, and api.bus.maitabi.jp only knows mountain-bus courses. So general_get_tour_detail reads the rendered detail page, in a way that keeps the fragile surface small:

  • the tour record itself (title, description, price, statuses) comes from a JSON literal the page embeds (const detailData = {...}), parsed as JSON — no prose is scraped;
  • only three <table> elements are read from the markup: itinerary, travel conditions, and the departure/price matrix. Columns are matched by their Japanese headers, not by position.

If the page ever loses that structure the tool returns an error naming source_url instead of a hollow object, and the offline fixtures in tests/fixtures/ fail first.

⁠MCP server

One executable, one subcommand. mcp speaks stdio by default, or sse / streamable-http:

uvx maitabi mcp                                  # stdio — what MCP clients expect
uvx maitabi mcp --transport streamable-http --port 8000
docker run -i --rm phonhay103/maitabi mcp        # same thing in a container

Client configuration (mcpServers key):

{
  "mcpServers": {
    "maitabi": {
      "command": "uvx",
      "args": ["maitabi", "mcp"]
    }
  }
}

Docker variant:

{
  "mcpServers": {
    "maitabi": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "phonhay103/maitabi:latest", "mcp"]
    }
  }
}

Local checkout, no install:

{
  "mcpServers": {
    "maitabi": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/maitabi", "maitabi", "mcp"]
    }
  }
}

Tools are named <domain>_<command>: bus_* reads api.bus.maitabi.jp, general_* reads www.maitabi.jp.

⁠Agent skills

npx skills add phonhay103/maitabi -g     # all three
npx skills add phonhay103/maitabi --list # inspect first
  • maitabi-cli — terminal workflows and JSON piping.
  • maitabi-mcp — how to call the already-connected tools: which tool, in what order, how to read results.
  • maitabi-bus-extractor — raw HTTP/curl for both hosts, standalone. No CLI, no MCP.

⁠Rate limits

HostLimitApplies to
www.maitabi.jp60 requests/min per IPgeneral tours + calendar
api.bus.maitabi.jpnone observed at normal usagemountain bus tours

When the cap is hit, the result is {"error": "Rate limited by www.maitabi.jp ...", "retry_hint": "wait ~60s and retry manually"}. There is no auto-retry. Narrow --day ranges help, since each day fans out into a parallel request (bounded at 5).

⁠Exit codes

CodeMeaning
0Success
1Upstream/network error (payload contains error, incl. rate limiting)
2Input error (bad flag value or failed validation)

⁠Development

make install        # uv sync
make dev            # MCP server over stdio
make test           # offline suite (no network)
make smoke          # live check against the production API
make catalog        # regenerate docs/TOOL_CATALOG.md + skill reference copies
make catalog-check  # what CI runs — fails on stale generated files
make docker-build   # 2-stage image (Python 3.14)
make build          # wheel + sdist

Architecture, in one paragraph: parameters live once in core/inputs.py; endpoint logic lives in services/; registry.py declares one Action per capability (domain, MCP tool name, CLI command, input model, service, endpoint, docs); both adapters and the catalog are generated from that table, so the CLI, the MCP schema, and the documentation cannot disagree. See AGENTS.md⁠.

Tag summary

Content type

Image

Digest

sha256:fdb7a5deb…

Size

69.3 MB

Last updated

about 10 hours ago

docker pull phonhay103/maitabi