# FronyBoard (pypi · fronyboard)

Project tracker for AI agents: roadmap, periods, tasks and a validation gate, in one SQLite file

- Trust score: 71/100 (medium)
- Change this week: +2
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-09-20

## Components

- pypi · `fronyboard`: 71/100 (this document), [markdown](https://verifymcp.io/servers/cafelatte1-fronyboard/fronyboard.md), [page](https://verifymcp.io/servers/cafelatte1-fronyboard/fronyboard)

## Channel facts

- Registry: `pypi`
- Package: `fronyboard`
- Version: `0.39.0`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-09-20.

- **Supply Chain Security**: 100/100
  - No malware found by supply-chain analysis.
  - No known CVEs affecting this package version or its production dependencies.
  - Runs hatchling.build at install time, a recognised native-build step with no shell scripting around it.
  - 4 of 39 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 45/100
  - Source repository is publicly reachable at the declared URL.
  - Provenance check failed: no build-provenance attestation is published.
  - Clear OSI-approved license (MIT).
  - Actively maintained (last published 3 days ago).
  - Disclosure check failed: no security disclosure policy was found in the source repository.
- **Schema Quality & AI Usability**: 64/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 4074 tokens (~214/item across 19 items; 19 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 33/100
  - Stability check failed: the tool surface changed between 0.29.0 and 0.39.0: 1 tool removals, 1 breaking changes, 0 additions.
- **Tool Coverage**: 67/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 0% of tool parameters carry a description.
- **Tool Safety**: 100/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - We read all 19 captured tool definition(s), and no name or description among them implies an irreversible operation.
  - An AI judge read all 20 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a current MCP spec version (2026-07-28).

## Install

### How do I install the FronyBoard MCP server?

FronyBoard runs locally as a PyPI package, launched with uvx fronyboard. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add cafelatte1-fronyboard -- uvx fronyboard
```

### Cursor

```json
{
  "mcpServers": {
    "cafelatte1-fronyboard": {
      "command": "uvx",
      "args": [
        "fronyboard"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "cafelatte1-fronyboard": {
      "command": "uvx",
      "args": [
        "fronyboard"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add cafelatte1-fronyboard -- uvx fronyboard
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "cafelatte1-fronyboard": {
      "type": "local",
      "command": [
        "uvx",
        "fronyboard"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add cafelatte1-fronyboard --command uvx --arg fronyboard
```

### Hermes

```yaml
mcp_servers:
  cafelatte1-fronyboard:
    command: "uvx"
    args: ["fronyboard"]
```

### Netclaw

```json
{
  "McpServers": {
    "cafelatte1-fronyboard": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "fronyboard"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add cafelatte1-fronyboard -t stdio -c uvx -a fronyboard
```

### Other

```json
{
  "mcpServers": {
    "cafelatte1-fronyboard": {
      "command": "uvx",
      "args": [
        "fronyboard"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-09-20 (score 71, +1)

- [functional] Package version: 0.32.1 → 0.39.0

### 2026-09-18 (score 70, +1)

No change was recorded against any check on this day. Stability & Change Management went from 22 to 26.

### 2026-09-17 (score 69, 0)

- [security regression] Stability: fail → unverified
- [security regression] Tool safety: pass → unverified
- [functional regression] Capabilities: pass → unverified
- [functional regression] Tool coverage: 100 → unverified
- [functional] Package version: 0.38.0 → 0.39.0

### 2026-09-16 (score 69, +1)

- [security regression] Stability: fail → unverified
- [security regression] Tool safety: pass → unverified
- [functional regression] Schema quality: 189 → 214
- [functional regression] Capabilities: pass → unverified
- [functional regression] Tool coverage: 100 → unverified
- [functional] Package version: 0.34.1 → 0.38.0

### 2026-09-15 (score 68, +15)

- [security improvement] Malware scan: unverified → pass

### 2026-09-14 (score 53, −16)

- [security regression] Malware scan: pass → unverified
- [security regression] Stability: 0.17 → fail
- [functional improvement] Schema quality: 4050 → 3607
- [functional] Package version: 0.32.1 → 0.34.1
- [functional] Package version: 0.32.1 → 0.33.1
- [functional] Package version: 0.32.1 → 0.33.0

### 2026-09-13 (score 69, +1)

No change was recorded against any check on this day. Stability & Change Management went from 13 to 17. That category is still filling its 30-day observation window: 4 days of observed history at the previous scan, 5 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-12 (score 68, +29)

- [security improvement] Injection markers: unverified → pass
- [functional improvement] Tool coverage: unverified → 100
- [functional improvement] Stability: unverified → 0.13
- [functional improvement] MCP protocol: unverified → pass

## MCP tools (19)

### `create_project` (~145 tokens)

Register a new project — once per codebase, before any planning happens.

\`key` is the task-id prefix (2-5 uppercase letters, e.g. DLY); `description` is one
line saying what the project is, in the user's language (shown on the dashboard cards);
\`repo` is where its code lives (owner/name or a URL). Status starts as active.

A fresh project holds nothing yet: set_overview (year) -> upsert_milestone (quarter)
\-> open_period must run before create_task will accept a task.

Input parameters:

- `description`
- `key` (string, required)
- `name`
- `repo`

### `update_project` (~146 tokens)

Update a project's own fields — pass at least one of name, description, repo, status.
The key (and with it the task id prefix) never changes, and nothing here touches the
roadmap, periods or tasks. `name` and `description` follow create_project's language rule.

\`status`: active | paused | archived. paused only changes the badge; archived hides the
project from list_projects and refuses every other mutation until it is set back to
active. Archived is as far as removal goes — there is no hard delete.

Input parameters:

- `description`
- `key` (string, required)
- `name`
- `repo`
- `status`

### `list_projects` (~112 tokens)

List every project (key, name, description, repo, status, meta) — how to find out
which keys exist. Archived ones are left out unless `include_archived` is set.

Each entry carries a `summary`: its open periods, task counts by status and
\`last_activity` (the newest task update). No milestones or task detail: get_roadmap
for the plan, get_status for per-period progress, list_tasks for the tasks.

Input parameters:

- `include_archived` (boolean)

### `get_roadmap` (~94 tokens)

Read a project's plan as written: yearly overviews (goal, now, target, checklist),
quarterly milestones, and the names of its periods.

Goals only, no counts — get_status for progress and the current period, list_tasks for
the tasks themselves. Timestamps (`meta`) are left out unless `include_meta` is set.

Input parameters:

- `include_meta` (boolean)
- `key` (string, required)

### `set_overview` (~227 tokens)

Create or replace a year's overview: the one-line yearly `goal`, plus the three
blocks the dashboard shows for the current year — `now` (what is being worked on),
\`target` (what that work is meant to reach) and `checklist` (the concrete steps to get
there, ticked off as they land). A year needs an overview before upsert_milestone will
add a quarter to it.

\`year` is YYYY. All prose here is in the user's language. `now` and `target` are one
short line each. `checklist` items are strings (not done yet) or {text, done} maps,
in display order. Calling it again
replaces the whole overview — resend the checklist to keep it; use set_check to tick a
single item. Quarterly goals belong in upsert_milestone, not here.

Input parameters:

- `checklist`
- `goal` (string, required)
- `key` (string, required)
- `now`
- `target`
- `year` (string, required)

### `set_check` (~94 tokens)

Tick or untick one item of a year's overview checklist: `index` is its 0-based
position in get_roadmap's `checklist`, `done` the new state. Returns the updated
overview. To add, remove or reword items use set_overview.

Input parameters:

- `done` (boolean)
- `index` (integer, required)
- `key` (string, required)
- `year` (string, required)

### `upsert_milestone` (~120 tokens)

Create or update a quarterly milestone — a year's goal for one quarter.

\`year` is YYYY (its overview must exist), `quarter` is Q1-Q4, `goal` is one line in the
user's language, `status` is planned | active | done (open_period flips planned to
active, close_period sets done).
Omitted fields keep their current value.

Input parameters:

- `goal`
- `key` (string, required)
- `quarter` (string, required)
- `status`
- `year` (string, required)

### `open_period` (~80 tokens)

Start working in a quarter: opens its period and flips a planned milestone to active.
Required before create_task will accept that period.

\`period` is YYYYQn (e.g. 2026Q3) and its roadmap milestone must already exist —
upsert_milestone first.

Input parameters:

- `key` (string, required)
- `period` (string, required)

### `close_period` (~145 tokens)

Close a period (YYYYQn) and record its retrospective — call when its work is over.

Refuses while any task is still todo or in_progress. Stores `result_markdown` as the
period's `result` and marks the milestone done.

The retrospective is written in the user's language, stays under ~30 lines and holds
judgment and reasons only — summary vs goal, what landed and what did not, carried-over tasks
(old id -> new id), lessons.
Calling it again on a closed period rewrites the retrospective and changes nothing else.

Input parameters:

- `key` (string, required)
- `period` (string, required)
- `result_markdown` (string, required)

### `get_retrospective` (~63 tokens)

Read a closed period's (YYYYQn) retrospective — the `result` markdown close_period
wrote. Errors while the period is still open; get_status says which ones are closed.

Input parameters:

- `key` (string, required)
- `period` (string, required)

### `create_task` (~430 tokens)

Create a task — one issue/branch-sized unit of work — with status todo.

The id is assigned from the project-global sequence and never reused. `period` is
YYYYQn and must be open; nothing else has to exist first.

\`title` is a short English imperative ("Add multi-select status filter") — it is what
every reader sees, so it has to say the whole thing.

\`content` is optional: one line, at most 300 characters, English. It answers **why this
task exists** — the pressure that made it necessary, the reading you chose where the
spec allowed several, or the scope you deliberately left out. It is written now, before
the work, so it cannot describe the result; what proves the work done is `check`, which
transition_task takes when you finish. Do not restate the title here: a note that only
rephrases it tells the next agent nothing. Line breaks are folded into spaces; a longer
text is rejected, not cut. Rationale beyond one line goes in the commit.

\`tags` are free-form labels ("frontend", "bug", "infra"): up to 8 per task, 24
characters each, no commas. Reuse the wording already in use on the project
(list_tasks shows it) instead of coining a new spelling for the same thing.

\`depends_on` lists the task ids this one builds on — the *earlier* work whose result it
needs, or the task that handed it this scope. Full ids, other projects allowed. It
points backwards only: there is no forward list, so a task never has to be updated
because a later one appeared. It is a pointer, not a lock — nothing is blocked, and
\`list_tasks` / `get_status` merely flag the entries not yet done as `waiting_on`.

Input parameters:

- `content`
- `depends_on`
- `key` (string, required)
- `period` (string, required)
- `tags`
- `title` (string, required)

### `update_task` (~250 tokens)

Update a task's fields — everything except status, which is transition_task.
\`branch` records the working branch name; `content` replaces the one-line note
(same rule as create_task: one line, at most 300 characters). `check` corrects the
proof recorded at completion and is only accepted on a task that is already done.

\`tags` replaces the whole label list — pass the tags the task should end up with,
not just the new ones. `depends_on` likewise replaces the whole predecessor list.

Omitted fields are left as they are. To remove an optional field pass an empty value:
\`content=""`, `branch=""`, `tags=[]`, `depends_on=[]`, `check=""` (title cannot be removed).

\`task_id` is the full id including the project prefix, e.g. DLY-042 — the project
is derived from that prefix, so `key` may be omitted (if given it must match).

Input parameters:

- `branch`
- `check`
- `content`
- `depends_on`
- `key`
- `tags`
- `task_id` (string, required)
- `title`

### `transition_task` (~343 tokens)

Move a task to a new status: todo | in_progress | done | blocked | cancelled. The
only tool that changes status — title, content and tags are update_task.

\`task_id` is the full id, e.g. DLY-042; the project is derived from that prefix, so
\`key` may be omitted (if given it must match). Call when work starts (in_progress,
ideally with the branch name) and when it finishes (done); the server stamps
started_at and completed_at itself.

\`done` requires `check`: one line, at most 300 characters, saying **what proves the work
done** — the command you ran and what it printed ("uv run pytest -q: 96 passed"), or the
observable a reader can go and see ("GET /healthz returns 200 on the deployed host").
You are the only one who can write it; by the next session the run is gone and all that
is left is your word. A restatement of the title proves nothing, so do not write one.
get_status shows it beside the finished task, and reopening a task drops it.

\`cancelled` is the soft delete — there is no hard one: the record is kept but hidden
from queries by default, and `reason` is required. Use blocked for work that may
resume, cancelled for work that will not happen. Transitioning a cancelled task to
any other status restores it.

Input parameters:

- `branch`
- `check`
- `key`
- `reason`
- `status` (string, required)
- `task_id` (string, required)

### `list_tasks` (~250 tokens)

List one project's tasks, optionally narrowed by period, status, tags or recency.
get_status already lists the open ones; use this for done or cancelled tasks, a closed
period, or a tag cut. get_task when you know the id, search_tasks for text across
projects.

\`period` is YYYYQn (all periods, closed ones included, when omitted), `status` is one of
todo | in_progress | done | blocked | cancelled. `tags` narrows to the tasks carrying
\*all* of the given labels; pass one tag to match on it alone, and call again per tag
when you want the union. `updated_since` keeps tasks touched after a duration ("24h",
"7d") or ISO timestamp. A row carries `waiting_on` (the ids from its `depends_on` not yet
done) only when there are any. Cancelled tasks are excluded unless `include_cancelled`
is set or `status` is 'cancelled'.

Input parameters:

- `include_cancelled` (boolean)
- `key` (string, required)
- `period`
- `status`
- `tags`
- `updated_since`

### `get_status` (~222 tokens)

The resume: everything an agent needs to pick a project up cold, in one call. The
latest year's overview (goal / now / target / checklist); per period its milestone goal
and status, task counts by status, whether it is closed, and `open_tasks` — every
todo / blocked / in_progress task with its title, tags, branch, one-line content and
\`waiting_on`; and `recent_done` — the ten most recently finished tasks across every period, newest
first, each with its content, its `check` and when it completed. Closed periods are
included.

\`recent_done` is what the project already has, in the words of whoever built it, and
\`check` is what they said proves it. Both are claims: confirm against the code before
building on one. Older finished work and cancelled tasks are list_tasks; the plan as
written is get_roadmap.

Call it once at the start of a session; there is nothing to poll for afterwards.

Input parameters:

- `key` (string, required)

### `get_task` (~90 tokens)

Read one task in full by id (DLY-042) — the project comes from the prefix, so no key
is needed. Returns the record with its period. Use this instead of list_tasks whenever
you already know the id; search_tasks when you only know a word from it. The record also
carries `waiting_on` when it applies.

Input parameters:

- `task_id` (string, required)

### `search_tasks` (~199 tokens)

Find tasks by text across all projects, with the dashboard's rules: case-insensitive
substring over project key, task id, title and content (not branch or tags); a
matching project key returns all of its tasks. Closed periods are included; cancelled
tasks only with `include_cancelled` (or `status='cancelled'`).

Hits are compact, ordered by project, then in_progress -> blocked -> todo
\-> done -> cancelled, then id; `match` says which field hit; a task's one-line `content`
is included when it has one. `key` narrows to one project, `limit` (default 20) caps the
hits while `count` still reports the total. Follow up with get_task for the full record.

Input parameters:

- `include_cancelled` (boolean)
- `key`
- `limit` (integer)
- `query` (string, required)
- `status`

### `recent_activity` (~198 tokens)

What changed recently and who did it: the tool calls recorded in tools.jsonl,
newest first — `ts`, `tool`, `caller` (key:<name> / session:<user> / oauth:… / stdio / local),
\`project`, `task` and `args` (argument names; prose fields appear as `<name>_len`);
\`ok: false` marks a rejected call. This is the mutation history; task records
themselves keep only timestamps.

\`since` is a duration ("24h" default, "7d", "90m") or an ISO timestamp; `key` narrows
to one project; `limit` caps the rows (default 50) while `count` reports the total.
Read-only calls are dropped unless `writes_only=False`.

Input parameters:

- `key`
- `limit` (integer)
- `since`
- `writes_only` (boolean)

### `validate` (~67 tokens)

Check a project's stored data against the FronyBoard schema and rules, returning
errors and warnings.

Rarely needed on its own — every mutation runs this same gate and refuses to write when
it fails. Use it after the store was edited outside these tools.

Input parameters:

- `key` (string, required)

## Diagnostics

Captured diagnostic sections: Provenance, Install scripts, Dependencies. The full working is on the page: https://verifymcp.io/servers/cafelatte1-fronyboard/fronyboard#diagnostics

## Score history

- 2026-09-20: 71
- 2026-09-19: 70
- 2026-09-18: 70
- 2026-09-17: 69
- 2026-09-16: 69
- 2026-09-15: 68
- 2026-09-14: 53
- 2026-09-13: 69
- 2026-09-12: 68
- 2026-09-11: 39
- 2026-09-10: 52
- 2026-09-09: 39
- 2026-09-08: 51

## Common questions

### What is the FronyBoard MCP server?

FronyBoard is an MCP server listed in the public MCP registry as io.github.Cafelatte1/fronyboard. Project tracker for AI agents: roadmap, periods, tasks and a validation gate, in one SQLite file. This page covers its PyPI package (fronyboard).

### Is the FronyBoard MCP server safe to use?

FronyBoard scores 71 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 20 September 2026. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the FronyBoard MCP server expose?

FronyBoard exposes 19 tools: create_project, update_project, list_projects, get_roadmap, set_overview, and 14 more. Their descriptions and schemas cost roughly 3,275 tokens of context every time the server is loaded.

### Is the FronyBoard MCP server still maintained?

FronyBoard is still listed as active in the MCP registry. We last reached this channel on 20 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

### What licence is the FronyBoard MCP server under?

FronyBoard declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.

## Links

- PyPI project: https://pypi.org/project/fronyboard/
- Socket report: https://socket.dev/pypi/package/fronyboard
- Repository: https://github.com/Cafelatte1/FronyBoard
- Changelog RSS feed: https://verifymcp.io/servers/cafelatte1-fronyboard/fronyboard.xml
- Changelog JSON feed: https://verifymcp.io/servers/cafelatte1-fronyboard/fronyboard.json
- HTML version of this page: https://verifymcp.io/servers/cafelatte1-fronyboard/fronyboard
