Search, read, author, and triage plans on plans.devfellowship.com — the
DFL planning system (plans, ADRs/decision records, and the questions/DTQ
surface). This MCP wraps the same REST backend the web UI and the
read-plan/search-plans/publish-plan skills use, so there is one backend
and one visibility policy.
Endpoint
https://plans.mcp.devfellowship.com/mcp
Tools
29
Backing data
The plans REST API (plans.devfellowship.com/api) — plans, versions, ADRs, questions.
Hybrid semantic + keyword search over plans (and optionally ADRs). Results are visibility-filtered to what you can read.
read_plan
Read a plan’s full markdown body + metadata by slug (optionally a specific version). Returns not-found for plans you can’t read.
list_plans
List plans with optional filters (status, source, tag, has_children, has_pending_questions). Returns only readable plans.
list_plan_tasks
List the work tasks bound to a plan — its execution checklist, the read half of set_plan_tasks. Open tasks only by default (done + no_longer_needed hidden); pass include_finished: true for the whole set. The summary always counts every bound task, so you get “27 open of 33” plus a breakdown by status and by stage. Rows carry identifier, status, stage name, points, priority, owner, epic and acceptance criteria, read from work.tasks under your RLS. Sorted by stage → priority → identifier.
list_plans_by_activity
List the plans with activity in a day window — the same rule as the calendar Day board (/calendar?view=day). Activity = the plan row (create, publish, status) plus every related entity (versions, comments, questions and answers, ADRs, child plans, bound tasks and content); the day is a calendar day in tz (default America/Sao_Paulo). Window: date (default today) or from + to (inclusive, max 62 days). mode: activity_on_day (default — any event in the window) or last_activity_on_day (the plan’s last event is in the window: “updated for the last time yesterday”). Filters: owner (me, a user id, an e-mail, or a name such as tainan; a name that matches two people is refused), status (comma list), limit (1–200, default 50). Each row: last activity, the window’s events, bound task counts by status, open and blocking questions, and whether the latest body has a ## Verification section. The start of a daily sweep (skill plans-day-sweep).
Create a new plan (or upsert by slug). Owned by you; visibility defaults to shared. Requires a member+ identity.
publish_plan
Publish (or re-publish) a plan body, creating a new version. Upserts by slug. Requires a member+ identity.
patch_status
Transition a plan’s lifecycle status (draft → fired → executing → done / archived). Gated transitions are blocked while blocking questions are unanswered.
set_links
Replace a plan’s first-class sidebar links (Miro/Figma/GitHub/Epic/docs/… — separate from the markdown body). Replaces the whole list; owner-only; kind auto-detected from the URL. Pass [] to clear.
set_owner
Reassign plans.owner to a canonical Supabase auth uid — by explicit slug list (targeted, repairs a legacy non-uuid owner) or for rows whose owner is NULL. plans.owner must be the auth uid: the readability predicate matches owner = auth.uid()::text, so a non-uuid owner makes a personal plan unreadable by its own owner. Superadmin only.
set_plan_tasks
Bind DevFellowship work tasks (work.tasks) to a plan — the plan’s execution checklist, rendered in the plans-app right sidebar with each task’s status and a done/total counter. Replaces the task list but preserves every other sidebar link. Owner or admin (a checklist is execution state, not sharing). Pass [] to unbind all.
List the comments on a plan — id, version, selection_text, body, created_by, created_at and metadata. Optional version filter. Read-only.
delete_plan_comment
Delete one comment by slug + comment_id. The API allows the comment author or an admin. Find the id with list_plan_comments.
create_plan_comment
Create a comment on a plan — the same plans.plan_comments annotation the web UI writes with select-to-comment. Required: slug, body. Optional: selection_text (the anchor; defaults to (plan) for a plan-wide comment), selection_start, selection_end, version, and metadata. created_by is resolved from your session and is not a settable field; metadata is optional JSON write attribution (max 8 KiB) — for example the requesting human and the channel when a bot writes the comment. Requires a member+ identity.
A plan can embed an artifact that lives in another DFL app — a diagram from
diagrams.devfellowship.com, a document from documents.devfellowship.com, an
image from the media bucket — instead of merely linking it. The plan body holds
an External Entity Reference (EER): a token that points at the artifact and
nothing else.
{{dfl-diagram:<uuid>}} ← legacy alias for {{dfl-entity:diagram:<uuid>}}
type is diagram, document or image. The locator is a UUID for
diagram and document; for image it is a media id or an https:// URL.
Options after the | are k=v pairs separated by ; — mode (live, the
default, or pinned), caption, rev.
Tool
Description
search_entities
Discovery. Find a diagram/document/image across the fleet and get its locator — the only way to obtain the UUID that attach_entity needs, since those artifacts live in other apps. Optional query (omit for most-recently-updated), type, and limit (default 20, max 50). Set include_latest_revision to also resolve each diagram hit’s newest revision id — the rev that pinning requires (at most 10 per call, one extra request each). Scoped to what you can see.
list_plan_entities
List the entities a plan references, with each one’s type, locator, mode and caption. Derived by parsing the plan body, so it is always in sync; returns pointers, not resolved content. Read-only — never creates a version.
attach_entity
Insert an EER token into a plan body without republishing the whole body. Takes slug, type, locator, plus optional mode, rev (the revision to pin a diagram to — see below), caption, and anchor (the text of an existing ## Heading to append under; defaults to an ## Entidades section at the end). Reports anchor_found: false when that heading did not exist and the token went to ## Entidades instead. Idempotent. Owner-gated.
detach_entity
Remove a plan’s reference to one entity (slug, type, locator). Deletes the pointer only — the diagram/document/image itself is untouched. Idempotent. Owner-gated.
List the Discord channels the DevFellowship bot can see, grouped by category, with client-facing ones tagged. The only valid source of a channel_id. Optional query filter and refresh to bypass the backend’s 60s cache.
set_plan_discord_channel
Bind a plan to one Discord channel, so every comment on it is announced there with a link back — or unbind with channel_id: null. Owner-only. Requires confirm_client_exposure: true when the target is client-facing or the plan is personal.
Two modes. With slug: one plan’s questions, grouped by round, with options and answers. Without slug: the cross-plan query over every readable plan. Filters: status (pending|answered|deferred|withdrawn|all, default pending), blocking, include_finished_plans, include_snoozed.
get_question
Resolve ONE question by its UUID — no slug needed. Applies none of the inbox filters, so it finds answered/deferred/withdrawn questions and questions on done or archived plans. Returns the question with its plan_slug, plan_title, options and answer history.
update_question
Edit only question_text/context on the same question UUID. An empty context clears it. Rejects other fields. The plan editor check applies; status, options and answers remain intact.
post_question
Create a structured question on a plan (DTQ). Set blocks_execution to gate the plan’s fire/execute transitions. Requires a member+ identity.
answer_question
Record an answer to a plan question. Select option letters (["A"], or ["A","B"] when multi-select). To answer with free text that rejects every offered option, send the reserved letter ["OTHER"] and put the answer in freeform_notes — that records the question as answered, exactly like a letter does. [] with no notes is a reset back to pending, and []with notes is rejected. The result states the status the server read back, so a reset is never reported as an answer.
withdraw_question
Retire an obsolete question (set status to withdrawn). Safe + idempotent: only OPEN (pending/deferred) questions are withdrawn; answered/already-withdrawn are left intact.
list_global_questions
The cross-plan inbox, each item annotated with its plan slug + title (use for dedup). Same data as list_questions with no slug, and takes the same filters; defaults to OPEN (pending, non-snoozed) questions on unfinished plans.