Skip to main content
Glama
justinmclean

Podlings MCP

by justinmclean
README.md
# Podlings MCP

A small dependency-free MCP server for working with Apache Software Foundation Incubator `podlings.xml` data.

It exposes tools to:

- load podling metadata from a URL or local XML file
- list podlings with optional filtering
- list current, graduated, and retired podlings
- fetch details for a specific podling
- return basic Incubator summary statistics
- return mentor-count coverage statistics
- analyze podling starts and active population over time
- analyze yearly completion counts
- analyze graduation rate over time
- analyze graduation and retirement duration over time
- inspect podling reporting cadence and upcoming reporting periods

If `source` is omitted, the server defaults to `https://incubator.apache.org/podlings.xml`.

The default ASF podlings XML source is cached locally for 24 hours. Set `PODLINGS_MCP_CACHE_DIR` to override the cache directory.

## Requirements

- Python 3.12+

## Install

```bash
python3 -m pip install .
```

For development tools:

```bash
python3 -m pip install -e .[dev]
```

## Run

After installation, run the stdio MCP server with:

```bash
podlings-mcp
```

For local development without installing first, you can still run:

```bash
python3 server.py
```

The server uses `stdio`, so it is intended to be launched by an MCP client.
It accepts standard JSON-RPC 2.0 request objects and non-empty batches, ignores notifications, and returns structured JSON-RPC errors for malformed input, invalid request shapes, unknown methods, and invalid MCP tool parameters.

## Test

```bash
python3 -m unittest discover -s tests -v
```

The tests cover parser behavior, tool functions, error cases, and a small end-to-end MCP `stdio` exchange.

## Developer Commands

```bash
make format
make check-format
make test
make coverage
make lint
make typecheck
make check
```

Formatting and linting use `ruff`, including `make check-format` for CI-style format verification, and type checking uses `mypy`. See [docs/architecture.md](./docs/architecture.md) for the current module layout.

## Example MCP client config

```json
{
  "mcpServers": {
    "podlings": {
      "command": "podlings-mcp"
    }
  }
}
```

The package also keeps `apache-podlings-mcp` as a backwards-compatible command alias.

## Concepts and Defaults

- `sponsor_type` defaults to `incubator` across the filtering and analytics tools.
- `completed` means podlings that reached an end state: `graduated` or `retired`.
- Count and rate timeline tools use podling `enddate` to place outcomes into a year.
- Duration timeline tools use both `startdate` and `enddate` to calculate months to graduate or retire.
- `completed_podlings_by_year` returns both lists by default, and the `graduated_podlings_by_year` and `retired_podlings_by_year` tools are convenience wrappers over that same lookup.
- `reporting_schedule` is schedule-aware, not submission-aware: it answers cadence, due-this-month, and expected-period questions from `podlings.xml` scheduling metadata only.

## Tools

### `list_podlings`

List podlings from `podlings.xml`.

Arguments:

- `source`: URL or local file path
- `status`: optional exact status filter
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`
- `search`: optional case-insensitive name/description/champion search
- `limit`: optional max number of results to return

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `list_current_podlings`

List podlings with `status="current"`.

Arguments:

- `source`: URL or local file path
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`
- `search`: optional case-insensitive name/description/champion search
- `limit`: optional max number of results to return

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `list_graduated_podlings`

List podlings with `status="graduated"`.

Arguments:

- `source`: URL or local file path
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`
- `search`: optional case-insensitive name/description/champion search
- `limit`: optional max number of results to return

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `list_retired_podlings`

List podlings with `status="retired"`.

Arguments:

- `source`: URL or local file path
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`
- `search`: optional case-insensitive name/description/champion search
- `limit`: optional max number of results to return

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `get_podling`

Return a single podling by name.

Arguments:

- `source`: URL or local file path
- `name`: podling name

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `podling_stats`

Return summary statistics for a `podlings.xml` source.

Arguments:

- `source`: URL or local file path
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

The stats include sponsor classification so you can distinguish:

- `incubator`: sponsored by the Incubator
- `project`: sponsored by another ASF project/PMC
- `unknown`: no sponsor value was found

### `mentor_count_stats`

Return mentor coverage and mentor-count distribution stats for a `podlings.xml` source.

Arguments:

- `source`: URL or local file path
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `raw_podlings_xml_info`

Return source metadata and a small preview of parsed records for troubleshooting.

Arguments:

- `source`: URL or local file path

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `graduation_rate_over_time`

Return yearly graduation and retirement counts plus graduation rate based on podling `enddate`.

Arguments:

- `source`: URL or local file path
- `start_year`: optional inclusive start year filter
- `end_year`: optional inclusive end year filter
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `podlings_started_over_time`

Return yearly podling start counts based on `startdate`.

Arguments:

- `source`: URL or local file path
- `start_year`: optional inclusive start year filter
- `end_year`: optional inclusive end year filter
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `started_podlings_by_year`

Return the podlings that started in a specific year.

Arguments:

- `source`: URL or local file path
- `year`: required year to inspect
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `active_podlings_by_year`

Return yearly active-podling counts based on lifecycle span.

Arguments:

- `source`: URL or local file path
- `start_year`: optional inclusive start year filter
- `end_year`: optional inclusive end year filter
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `active_podlings_in_year`

Return the podlings that were active during a specific year.

Arguments:

- `source`: URL or local file path
- `year`: required year to inspect
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `completion_rate_over_time`

Return yearly completion rate using completed outcomes divided by active population.

Arguments:

- `source`: URL or local file path
- `start_year`: optional inclusive start year filter
- `end_year`: optional inclusive end year filter
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `completion_count_over_time`

Return yearly completed podling counts based on `enddate`, split into graduated and retired outcomes.

Arguments:

- `source`: URL or local file path
- `start_year`: optional inclusive start year filter
- `end_year`: optional inclusive end year filter
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `completed_podlings_by_year`

Return the podlings that completed in a specific year, split into graduated and retired outcomes.

Arguments:

- `source`: URL or local file path
- `year`: required year to inspect
- `status`: optional filter, `graduated` or `retired`
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `completed_podlings_in_range`

Return the podlings that completed within an inclusive year range.

Arguments:

- `source`: URL or local file path
- `start_year`: required inclusive start year
- `end_year`: required inclusive end year
- `status`: optional filter, `graduated` or `retired`
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `graduated_podlings_by_year`

Return the podlings that graduated in a specific year.

Arguments:

- `source`: URL or local file path
- `year`: required year to inspect
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `retired_podlings_by_year`

Return the podlings that retired in a specific year.

Arguments:

- `source`: URL or local file path
- `year`: required year to inspect
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `graduation_time_over_time`

Return yearly time-to-graduate stats in months based on podling `startdate` and `enddate`, including average, median, and percentile views.

Arguments:

- `source`: URL or local file path
- `start_year`: optional inclusive start year filter
- `end_year`: optional inclusive end year filter
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `time_to_retirement_over_time`

Return yearly time-to-retirement stats in months based on podling `startdate` and `enddate`, including average, median, and percentile views.

Arguments:

- `source`: URL or local file path
- `start_year`: optional inclusive start year filter
- `end_year`: optional inclusive end year filter
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

### `reporting_schedule`

Return reporting cadence and expected reporting periods for current podlings, or for a specific named podling.

Arguments:

- `source`: URL or local file path
- `name`: optional exact podling name lookup
- `as_of_date`: optional ISO date used for schedule evaluation, defaults to today
- `report_month`: optional reporting month in `YYYY-MM` format; defaults to the active reporting cycle derived from `as_of_date`
- `due_this_month`: optional boolean filter
- `sponsor_type`: optional sponsor type filter, defaults to `incubator`

`source` is optional and defaults to the ASF Incubator `podlings.xml` URL.

## Usage Examples

These examples show natural-language requests an MCP client can answer with the tools below.

### Current Podling Review Workflow

Use these when preparing for a regular review of the active Incubator podling roster:

- "Show me the current Incubator-sponsored podlings."
- "Summarize the current Incubator podlings, including how many have descriptions, sponsors, champions, and mentors listed."
- "Which current podlings have unusually low mentor coverage?"
- "Give me the full podlings.xml record for PodlingFoo."

This gives reviewers a quick view of the active roster, basic metadata coverage, and mentor coverage without needing to inspect `podlings.xml` directly.

### Reporting Workflow

Use these when preparing the monthly IPMC reporting cycle:

- "Which podlings are due to report this month?"
- "Which podlings are due in the 2026-05 reporting cycle?"
- "When is PodlingFoo next expected to report?"
- "Show me the reporting cadence for current Incubator-sponsored podlings."

This gives the IPMC a schedule-oriented view based on `podlings.xml` reporting metadata without needing a separate Clutch-style workflow.
When `report_month` is omitted, the tool treats the current cycle as running through the third Wednesday of the month, then rolls forward to the next month's cycle.

### Cohort And Lifecycle Review

Use these when trying to understand how a group of podlings moved through incubation over time:

- "How many Incubator-sponsored podlings started each year from 2020 onwards?"
- "Which podlings started in 2022?"
- "Show the active podling count by year from 2020 to 2025."
- "Which podlings were active during 2023?"

This connects yearly trends to the specific podlings behind those trends.

### Completion And Graduation Review

Use these when reviewing graduation and retirement outcomes for a period:

- "Show yearly Incubator podling completions since 2020, split into graduations and retirements."
- "What was the graduation rate for completed podlings each year from 2020 to 2025?"
- "Which podlings completed between 2023 and 2024?"
- "Which podlings retired in 2023?"

This is useful for turning trend charts into a concrete list of podlings to discuss.

### Duration Trend Review

Use these when reviewing how long podlings take to reach terminal outcomes:

- "How long did graduated podlings take to graduate each year, including median and percentile timings?"
- "Show retirement timing by year for podlings that retired after 2020."
- "What is the average and median time to retirement for recent retired podlings?"

This separates completion volume from time-to-outcome trends.

### Source Troubleshooting Workflow

Use these when a local XML file or alternate URL does not produce the expected results:

- "Inspect `/path/to/podlings.xml` and show me the source metadata plus a few parsed records."
- "List the first 10 normalized podling records from `/path/to/podlings.xml`."
- "In `/path/to/podlings.xml`, show me the parsed record for ExampleOne."
- "Using `/path/to/podlings.xml`, show yearly completion counts from 2020 onwards."

This helps separate source-loading issues from filtering or analytics questions.

## Source examples

- ASF URL: `https://incubator.apache.org/podlings.xml`
- Local file: `/path/to/podlings.xml`

## Notes

- Remote sources are fetched with Python's standard library.
- XML parsing targets the ASF Incubator `podlings.xml` structure directly.
- Tools that accept `sponsor_type` default to `incubator`.
- Valid `sponsor_type` values are `incubator`, `project`, and `unknown`.

TDQS

B3/5.0

Scored across 22 tools

Disambiguation3/5

Several tools have overlapping purposes (e.g., active_podlings_by_year vs active_podlings_in_year, graduated_podlings_by_year vs list_graduated_podlings). Descriptions help but some ambiguity remains, causing potential misselection.

Naming Consistency3/5

Naming follows a mostly verb_noun pattern but mixes conventions like 'active_podlings_by_year' and 'list_graduated_podlings'. Inconsistent use of 'list_' vs direct nouns and suffixes like '_over_time' vs '_by_year'.

Tool Count3/5

22 tools is on the higher side for a focused domain. While each tool serves a specific filtering or statistics purpose, the count feels slightly bloated and could be reduced by combining some similar ones.

Completeness4/5

The tool set covers listing, filtering, statistics (counts, rates, timing), and reporting schedule. Minor gaps exist (e.g., no tool for podling mentors by podling), but overall it provides a comprehensive read-only surface.

Maintenance

ActivityInactive
ResponsivenessNo issues