work
Project management: projects, epics, deliveries, tasks, business units, and member placement against the work schema.
| Endpoint | https://work.mcp.devfellowship.com/mcp |
| Tools | 34 |
| Backing data | work schema (projects, epics, deliveries, tasks, business units, placements). |
Projects
Section titled “Projects”| Tool | Description |
|---|---|
create_project | Create a new project. |
delete_project | Delete a project. This will fail if the project has associated epics. |
get_project | Get a specific project by ID with its epics. |
list_projects | List all projects with optional filters. |
update_project | Update an existing project. |
| Tool | Description |
|---|---|
create_epic | Create a new epic. ⚠️ An epic cannot be shown on a plan — the plans-app renders bound tasks only. Bind the epic’s tasks instead. |
delete_epic | Delete an epic. This will fail if the epic has associated deliveries or tasks. |
get_epic | Get a specific epic by ID with its deliveries and tasks. |
list_epics | List all epics with optional filters. |
update_epic | Update an existing epic. |
Deliveries
Section titled “Deliveries”| Tool | Description |
|---|---|
create_delivery | Create a new delivery. |
delete_delivery | Delete a delivery. |
get_delivery | Get a specific delivery by ID with its epic and tasks. |
list_deliveries | List all deliveries with optional filters. |
update_delivery | Update an existing delivery. |
| Tool | Description |
|---|---|
create_task | Create a new task. Requires a context package (why/what) and a stage_id (spec / design / execution / review / decision / qa) — a task without a stage is invisible on the board. If it belongs to a plan, also call set_plan_tasks on the plans MCP — see the callout above. |
delete_task | Delete a task. |
get_task | Get a specific task by ID with its epic and delivery. |
list_tasks | List all tasks with optional filters. |
update_task | Update an existing task. |
Business Units
Section titled “Business Units”| Tool | Description |
|---|---|
create_business_unit | Create a new business unit. Requires finance/admin/owner role. |
delete_business_unit | Delete a business unit by ID. Requires finance/admin/owner role. |
get_business_unit | Get a specific business unit by ID. Requires finance/admin/owner role. |
list_business_units | List all business units with optional filters. Requires finance/admin/owner role. |
update_business_unit | Update an existing business unit. Requires finance/admin/owner role. |
Placements
Section titled “Placements”| Tool | Description |
|---|---|
create_placement | Record a DFL fellow placement (job/freelance/internal) in work.placements. Resolve the member_id first via lookup_member on the learn endpoint. |
create_member_label_alias | Map a raw speaker/label string to a member by upserting into work.member_label_aliases. |
Meetings
Section titled “Meetings”| Tool | Description |
|---|---|
merge_meetings | Dedup a duplicate recurring-meeting cluster by merging a skeleton meeting into a canonical meeting, then removing the skeleton. Lossless on duplicate-date collisions: it never drops a transcription-bearing occurrence in favor of an empty one. For a date both meetings share, it compares transcripts on both sides — if the canonical occurrence is empty but the skeleton one carries a real transcript, it re-parents the skeleton occurrence onto the canonical and deletes the empty canonical duplicate (the real transcript survives). If both carry transcripts it reports a conflicts entry, keeps both, and does not remove the skeleton row (skeleton_meeting_removed: false, manual review). Empty skeleton duplicates of an existing canonical date are dropped; skeleton occurrences on a new date are re-parented. Other meeting_id child rows (participants/concepts/expertise/tools/underlines) are re-parented onto the canonical, guarding the work.meeting_participants unique constraint. The skeleton row is removed only when there are zero unresolved conflicts. Transcriptions live per-occurrence so nothing is concatenated and the canonical survives. It also preserves the work.meetings.template field: if the canonical is null/"default" and the skeleton carries a non-default template (e.g. "weekly_leaders"), the canonical is updated to the skeleton’s template (carry the more-specific value forward; never downgrade). Pass dry_run: true first to preview the change without writing. |
set_meeting_recurrence_time | Set the time-of-day window (recurrence_start_time / recurrence_end_time) on a single recurring meeting series in work.meetings, so its recurring occurrences render at the right hour on the /meetings time-grid. Times are 24h wall-clock "HH:MM" or "HH:MM:SS" (Postgres time). The meeting must already be a recurring series (is_recurring = true); recurrence_day_of_week is set separately. Returns the updated row. |
set_meeting_template | Set the UI template (work.meetings.template) on a single meeting. The template selects which structured-underline UI the dfl-learn /meetings view renders — the weekly-leaders structured form is gated on template = "weekly_leaders". Allowed values: "default" | "weekly_leaders" (mirrors the dfl-learn UnderlineTemplate enum); unknown values are rejected. Returns the updated row. Primary use: restore a meeting’s template after a dedup-merge collapsed it to "default". |
Meeting series data-ops
Section titled “Meeting series data-ops”| Tool | Description |
|---|---|
list_meeting_series | Read-only discovery of recurring series parents (work.meetings with is_recurring = true), so dedup targets can be found without psql. Filters: created_after / created_before (ISO-8601), title_contains, fireflies_calendar_id_contains, limit. Each result carries id, title, fireflies_calendar_id, meeting_date, created_at plus occurrence accounting (occurrence_count, occurrences_with_transcript, occurrences_with_transcript_id); include_occurrences: true adds the per-occurrence rows (id, date, status, has_transcript, fireflies_transcript_id). Transcript text is never returned — it is tens/hundreds of KB per occurrence. Sorted by created_at. |
remove_meeting_series | Remove one recurring series parent, promoting its occurrences to standalone (“avulsa”) meetings first so the cascade can never eat a transcript. occurrence_policy: promote_real_discard_empty (default — promote occurrences carrying transcript text or a Fireflies transcript id, delete the empty materializer placeholders), promote_all, or require_empty (pure safety mode). Guards, all of which abort rather than guess: occurrences with transcript text but no fireflies_transcript_id (unverifiable); occurrences whose transcript id already exists on a meetings row (skipped, not re-inserted — the partial unique uq_meetings_fireflies_transcript_id, which also makes the tool idempotent); rows in meeting_participants / meeting_concepts / meeting_expertise / meeting_tools / meeting_transcript_segments / meeting_underlines referencing the parent or its occurrences (use merge_meetings, which knows how to re-parent them); and a post-promotion assert that every surviving occurrence has a standalone counterpart before anything is deleted. Promoted rows get is_recurring: false, fireflies_calendar_id: null (deliberately detached), the parent’s title, and a meeting_date rebuilt from the occurrence date plus the parent’s time-of-day. Refuses a non-recurring meeting unless allow_non_recurring: true. Returns counts (total_occurrences / promoted / discarded / already_present, which must balance), the created standalone ids, and n8n_webhook_inserts. |
promote_occurrence_to_standalone | Promote one work.meeting_occurrences row to a standalone meeting and detach/delete the occurrence — the generic primitive underneath remove_meeting_series. Optional title_override; keep_occurrence: true creates the standalone but leaves the occurrence in place (copy-then-review, and the escape hatch for an occurrence whose transcript has no id or that still has participant/underline rows attached). Same unique/transcript/cascade guards; insert-and-confirm happens before any delete. |
Weekly updates
Section titled “Weekly updates”Read-only. What one member did in the last N days, per source, with a daily text ready to paste. Mirrors the Weekly updates page of dfl-learn (/weekly-updates).
| Tool | Description |
|---|---|
get_weekly_updates | member_id? (default: you), days 1–14 (Brasília calendar days, today included). Sections: tasks moved to done / dev_completed (work.tasks.status_timestamps), tasks in progress, merged PRs (review_request.review_requests.merged_at, by created_by), Core Daily lines (resolved per meeting: segment attribution, then the top alias, then the exact name; any ambiguity leaves the line out), plans whose status changed (plans app, with your own session). Returns unavailable[] and truncated[] per source and daily_text in the Bom dia / Ontem / Hoje / No blockers format, one line per item, with no PR numbers, repos, task identifiers or links. Everything runs on your JWT; no service role. |