Skip to main content
Glama
soil-dev
by soil-dev

loomiomcp

npm CI License: Apache-2.0 Glama

Model Context Protocol server for Loomio. Lets Claude (Desktop, Code, or web Projects via Custom Connector) read and write Loomio discussions, polls, comments and group memberships — and analyse member participation — in plain English. Targets Loomio's b2 API — the canonical surface documented at /help/api2 and the namespace where the controllers live in the open-source repo — as shipped in Loomio 3.8.

Tool catalog

Every read is one upstream call unless the table says otherwise. Every collection returns Loomio's exact total and a scope note naming what was filtered, capped or not visible. The server also ships a ten-line routing guide as MCP instructions, so a client knows which tool answers which kind of question before it reads a single description. The whole catalogue a client downloads at session start (instructions + tools/list for the 24 full-mode tools) is about 36 KB, roughly 9 000 tokens (node scripts/catalog-size.mjs after npm run build); the long-form guidance per tool — inputs, outputs, cost, caveats, exact error texts — is in HOWTO.md.

Reads (always registered)

Tool

Purpose

Upstream calls

check_connection()

Key status, the account the key belongs to, its groups (member / pending / parent), readonly and b3 flags, fixed-wording notes. Call first when unsure what the connector can see.

the health probe (1 authenticated + 1 public GET); its groups body is reused

list_groups()

The connector user's member groups (pending invitations included) with the user's own membership {accepted, admin, delegate, title}, plus each subgroup's parent flagged member: false. Sorted by full_name.

1 (GET /b2/groups)

get_group(id_or_key_or_handle)

One group's full record — privacy, members_can_* permission flags, counters — with member, membership, parent, url. Works for publicly visible groups the user has not joined.

1

list_discussions(group_id, status?, limit?, offset?, description_max_chars?, strip_html?)

A group's discussions, newest activity first, each joined with its thread counters (items_count, replies_count, last_activity_at, locked_at, pinned_at, tags, …) and url. status defaults to open and is always sent. Bodies come as plain text (strip_html, default true; description_format: "text") capped at 1500 chars (description_truncated: true marks a cut).

1

get_discussion(id_or_key, strip_html?, include_items?, items_limit?, items_body_max_chars?)

One discussion with the full body (as stored; strip_html: true for plain text), thread counters, group and users. include_items: true embeds list_thread_items for the thread (same reply budget; thread_items.next_offset says where to page on).

1 (2 with include_items)

list_polls(group_id, status?, limit?, offset?, description_max_chars?, strip_html?)

A group's polls, newest first, as SLIM rows: identity, schedule, hide_results, participation counts, stance_counts + total_score when visible (aligned with poll_options[]), current_outcome, my_stance, url. The per-voter results[] breakdown and the type knobs Loomio left null are get_poll's. status defaults to active.

1

get_poll(id_or_key, strip_html?)

One poll with poll_options, current_outcome, the user's own my_stance, thread counters and url. results_visible / results_hidden_reason apply Loomio's own visibility rule; hidden stance counts are stripped, never zeroed.

1

list_threads(limit?, offset?, group_id?, type?, since?)

Every thread the user can see across all groups, newest activity first — the cheapest "what is new" call. group_id / type / since filter client-side within the page (Loomio's route has no date filter); with since, page until scope.exhausted.

1 (GET /b2/threads)

list_thread_items(topic_id | discussion_id | poll_id, kinds?, limit?, offset?, include_reactions?, body_max_chars?, strip_html?, max_total_chars?)

One thread's structured items (comments, polls, votes, outcomes, edits) with slimmed side-loads; comment bodies, vote reasons and outcome statements come as plain text by default (strip_html). Loomio's route is unpaginated: the thread is fetched once and sliced here, under a reply budget (max_total_chars, default 120000; truncated_by_budget + next_offset). Replaces list_events.

1 with topic_id, 2 otherwise

get_thread_markdown(topic_id | discussion_id | poll_id, max_chars?)

The whole thread rendered to Markdown by Loomio — front matter, body, comments, polls with results tables (Loomio applies vote visibility itself), outcomes. Best single call for a summary.

1 with topic_id, 2 otherwise

search_content(query | author_id, group_id?, types?, tag?, order?)

Full-text search across everything visible; author_id alone lists a user's 20 newest items. Snippets carry **match** emphasis; every hit has a deep-link url and group {id, full_name, handle} (Loomio's "Parent - Subgroup" name). A vote-reason hit on a poll whose results are hidden from the user is dropped from a query search (its existence would confirm the term; scope.hidden_stance_hits_dropped) and kept with snippet: null + snippet_hidden_reason in author mode. Loomio caps results at 20 (capped: true), no paging.

1

get_participation_report(group_ids | group_scope, start_month?, end_month?, delegates_only?, limit?, include_inactive?)

Loomio's participation report for a group set: each user's threads, comments, polls, votes cast vs issued vs missed, outcomes, reactions, total, sorted by total; the top limit rows (default 50, max 500), users with no counted activity dropped unless include_inactive: true (total_users counts all ranked). THE tool for "who is most engaged".

1 for the whole group set

get_user_activity(user_id, group_ids, since?, until?)

One user's counts across groups (month-grained window) with by_group, plus sample_events from one author search.

N + 1 for N groups (4 in flight)

list_memberships(group_id, limit?, offset?)

A group's roster: ids, names, usernames, admin / delegate, title, accepted_at. Member emails only as user_email on a row, and only where the connector's user is a group admin; users[] never carry emails (the connector account's own, which Loomio adds, is removed). A non-member gets an empty list, not a 403 — the connector annotates it.

1 (compact=1)

Writes (registered unless LOOMIO_MCP_READONLY=1)

Tool

Purpose

Upstream calls

create_discussion(title, group_id, …)

Start a thread. Nested {discussion: {…}} body (a flat body silently loses group_id and private). Throws if Loomio's echo lands in another group.

1

update_discussion(id_or_key, …)

Edit title, body (replaced), privacy, comment / reaction / concurrent-poll settings, or add recipients.

1

delete_discussion(id_or_key)

Soft-discard: Loomio blanks the thread and keeps the records; an admin can restore.

1

create_poll(title, poll_type, options, closing_at, group_id | discussion_id | topic_id, …)

Any Loomio 3.8 poll type — proposal, poll, count, check, question, score, ranked_choice, stv, meeting, dot_vote — standalone or inside a discussion. Without closing_at Loomio saves an unopened draft (opened: false + warning); an opening poll is announced to every eligible voter unless notify_on_open: false. A group_id given with a thread reference is cross-checked before anything is written.

1 (2 with discussion_id, or with topic_id + group_id)

update_poll(id_or_key, …)

Edit an open poll: title, details, closing time (the next full hour ends voting within the hour), options to ADD (Loomio's PATCH replaces the set and deletes unlisted options with their votes, so the connector reads the current names first and sends the union), hide_results (tighten only), voters.

1 (2 with options)

delete_poll(id_or_key)

Soft-discard a poll.

1

create_comment(discussion_id | parent_id + parent_type, body, body_format?)

Comment on a thread (discussion_id as numeric id or short key), or reply to a comment, poll, stance or outcome. Send body_format: "html" for HTML bodies (Loomio stores an omitted format as Markdown).

1 (2 with a short key)

update_comment(id, body, body_format?)

Replace a comment's body.

1

delete_comment(id)

Soft-discard a comment.

1

manage_memberships(group_id, emails, remove_absent?)

Invite by email; with remove_absent: true remove everyone not listed. Group admin only. Read SECURITY.md first.

1

Instance-operator tools (b3; registered when LOOMIO_B3_API_KEY is set and not read-only)

Tool

Purpose

Upstream calls

deactivate_user(id)

Deactivate an account instance-wide (Loomio runs it asynchronously).

1

reactivate_user(id)

Reactivate an account and restore the memberships the deactivation revoked.

1

get_user(id | identity_type + uid)

One account by id or linked external identity — email included.

1

list_users(is_admin?)

Every account on the instance — emails included, unpaginated.

1

The b3 secret authenticates the server, not a user: it is validated against ENV['B3_API_KEY'] on the Loomio instance and sees every account. get_user and list_users are therefore for single-tenant deployments only (one organisation per Loomio instance); on a shared instance leave LOOMIO_B3_API_KEY unset.

Deliberately not exposed

  • b3 update / destroy / redact users. Irreversible (destroy and redact delete or scrub personal data for good) and Loomio records no actor identity for b3 calls, so nobody could later tell which agent session did it. Deactivate / reactivate cover the operational need and are reversible.

  • b3 chatbots / webhooks. Group-admin configuration whose serializer returns the webhook URL and secret; nothing an AI caller needs, and a leak surface if it were readable.

  • The participation report's base and countries sections. Instance-wide totals and per-country breakdowns; not answerable per group the way the users section is, and not what members see.

Related MCP server: capsulemcp

Efficiency

Loomio 3.8 exposes aggregates its earlier releases lacked; this connector uses them so every read costs as few upstream calls and bytes as the API allows.

Question

Before (0.0.11)

Now (0.0.12)

"Which groups can you see?"

list_groups probed GET /b2/polls?group_id=N per id: 50–500 calls, blind to groups without polls

1 call on the native GET /b2/groups; parents included; no blind spots

"How active was user X?"

get_user_activity walked every discussion's event stream: ~200 calls, and 0 on Loomio ≥ 3.4 (endpoint removed)

N + 1 calls for N groups on Loomio's participation report + one author search

"Who is most engaged in these groups?"

Not answerable without reconstructing from polls × memberships

get_participation_report: 1 call for the whole group set

"Read / summarise this thread"

list_events per discussion, paginated, bodies in full

get_thread_markdown (1 call, Loomio renders) or get_discussion with include_items (2 calls)

"What is new anywhere?"

list_discussions per group

list_threads: 1 call across every visible group

"Find the thread about …"

Not available

search_content: 1 call, 20 hits with deep links

Payload size is handled the same way:

  • Side-load profiles. Lists send exclude_types=group parent membership reaction translation (the topics root — where the thread counters live — is kept and joined client-side); shows keep the group for its name and privacy; list_threads sends compact minus tag; rosters, search and thread items by bare topic_id use compact=1, while thread items for a thread whose record is already in hand also exclude discussion (no second copy of the opening post). tag is never excluded where topic rows are read: Loomio gates the rows' tags FIELD on it, not just the side-loaded root. Writes never carry these parameters.

  • Slimming. Users become {id, name, username} (+ email only on the b3 tools); groups keep identity, privacy and counters; reactions, attachment and link-preview metadata are dropped unless asked for; list_polls rows leave the per-voter results[] to get_poll.

  • Body caps with explicit flags. description_max_chars (lists, default 1500) and body_max_chars (thread items, default 4000) cap a record's text and mark it *_truncated: true with the original *_chars; 0 omits the field (*_omitted: true), -1 returns everything. An HTML body longer than its cap is first stripped of tag attributes (Loomio stores target / rel on every link and an id on every heading — 17 % of a capped plain body, over half of a link-dense one; href and alt stay) so the capped characters carry content. max_total_chars (thread items, default 120000) budgets the whole reply and hands back next_offset. max_chars on get_thread_markdown (default 60000) caps the whole document from the END with top-level truncated and chars; -1 returns it whole and 0 is refused. get_* return full text.

  • Compact JSON to the model. Tool results are serialised without indentation (measured 10–37 % smaller than pretty-printed over the 3.8.1 fixtures); LOOMIO_MCP_PRETTY_JSON=1 restores indentation for a human reading a stdio session.

  • Exact totals. Every collection surfaces Loomio's meta.total as total, so "how many" never needs a second page.

Example questions

  • "Check the Loomio connection and tell me which groups you can see." → check_connection

  • "What is new in Loomio since yesterday?" → list_threads

  • "Summarise the discussion about the budget." → search_content, then get_thread_markdown

  • "Who are the coordinators of the Finance group?" → list_groups, list_memberships

  • "Rank the members of these three groups by participation this year." → get_participation_report

  • "How active has Ada Example been since March?" → get_user_activity

  • "What was decided in the last five closed proposals?" → list_polls with status: closed

  • "Post a status update in the release thread." → create_comment (writable mode)

HOWTO.md has longer walk-throughs.

Quick start (stdio, local)

LOOMIO_API_KEY=… npx loomiomcp

Add it to your Claude Desktop / Claude Code config the same way you would any stdio MCP server.

Remote (HTTP)

See DEPLOY.md for Cloud Run. The HTTP server also exposes an unauthenticated GET /health that reports whether Loomio still accepts the connector's API key — 200 {"status":"ok","key_status":"valid",…} or 503 with key_status rejected / unreachable. Point an uptime check at it with content match "key_status":"valid" (DEPLOY.md has the recommended setup); a rotated key is otherwise invisible until someone notices every call failing. The check_connection tool reports the same verdict to the AI caller.

Auth

Loomio authenticates by API key sent in an HTTP bearer header:

Authorization: Bearer <API_KEY>

The connector injects it server-side; it never reaches the MCP client. Copy the key from the user's API access page in Loomio (/profile/api_access).

The key is not permanent. Loomio regenerates a user's API key whenever that user's password changes (and Loomio 3.3.1, August 2026, rotated every user's key once). When that happens every call answers 403 {"error":"You are not authorized to access this page."}; the connector recognises that body, says "key rejected — probably rotated" with the remediation, and (HTTP) turns /health red. Fetch the current key from the API access page and update LOOMIO_API_KEY. No API can read another user's key.

Keys passed in the query string (?api_key=…) are rejected — Loomio removed that scheme in July 2026 because URLs are retained in browser history, proxy logs, and monitoring systems. A request carrying its key that way is treated as unauthenticated and 403s.

The optional b3 admin namespace uses the same bearer header with a different secret (validated against ENV['B3_API_KEY'] on the Loomio server, >16 chars). Only relevant if you operate a Loomio instance.

What the connector's user can see

Every read runs as the user whose API key is configured. Loomio ≥ 3.8 lets any authenticated user read publicly visible groups' public threads, so get_group, list_discussions, list_polls, list_threads and search_content reach beyond the user's member groups — but list_groups (Loomio's current_user.groups) and the participation report do not, and list_memberships answers a non-member with an empty list. Instance is_admin widens nothing. Poll results follow Loomio's own rule for that user: an open until_vote poll the user has not voted in has its counts stripped (results_visible: false, results_hidden_reason: "until_vote"), the same rule hides vote reasons in search_content hits (snippet_hidden_reason), and anonymous polls never reveal who voted what.

Loomio compatibility

Tested against Loomio 3.8.1 (TESTED_LOOMIO_VERSION in src/version.ts). Loomio publishes no API compatibility or deprecation policy and ships tags often, so the connector reads the instance's version from the public GET /api/v1/boot/version at startup and logs a one-time loomio.version_drift warning when the major.minor differs; check_connection repeats the warning in its notes. Every outbound request carries User-Agent: loomiomcp/<version> — if your Loomio sits behind a CDN/WAF, allow that user-agent (the connector recognises a WAF 403 and says so instead of blaming the key).

Read-only mode

Set LOOMIO_MCP_READONLY=1 to register only the 14 read tools. All write tools (create_*, update_*, delete_*, manage_*) and the b3 tools are skipped at server-init time, and the client (loomioPost / loomioPatch / loomioDelete) refuses a write before any request is made even if one were reached. This is the mode the Cloud Run deployment runs in.

Docs map

File

When to read

INSTALL.md

"I want to use this locally with Claude Desktop / Code today"

DEPLOY.md

"I want to run this as a remote HTTP/OAuth endpoint"

HOWTO.md

"I want example prompts and use cases"

DESIGN.md

"I want to understand the load-bearing choices"

NOTES-ON-LOOMIO-API.md

"I'm hitting a weird Loomio behaviour, or want the line-by-line endpoint reference"

SECURITY.md

"I'm doing a security review or rotating secrets"

OPTIMIZATIONS.md

"I want to know what each tool costs upstream, and the observability queries"

CONTRIBUTING.md

"I want to add a tool or send a PR"

CHANGELOG.md

"What changed?"

License

Apache-2.0

Available Tools

24 tools
check_connectionA
Read-onlyIdempotent

Call FIRST when unsure whether the connector works or what it can see: 1 health probe, no input. Returns key_status ('valid' | 'rejected' | 'unreachable'), the key's user, its groups[] with member_state, readonly, b3_enabled and notes[].

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (readOnlyHint, openWorldHint, idempotentHint, destructiveHint false), the description details the exact return values: key_status enum, the key's user, groups[] with member_state, readonly, b3_enabled, and notes[]. This adds substantial behavioral context, especially since there is no output schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, densely informative sentence. It front-loads the primary usage instruction ('Call FIRST when unsure...') and then succinctly lists return fields, with no wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple, no-input health probe, the description provides complete context: when to use it, what it returns, and the key statuses. With annotations covering safety and idempotency, and no output schema, nothing essential is missing for an agent to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the baseline is 4. The description confirms 'no input', which is consistent with the empty schema, but naturally there are no parameters to explain further.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('health probe') and resource ('the connector', 'the key'), and clarifies it checks whether the connector works or what it can see. It is clearly distinguishable from all sibling tools, which deal with polls, discussions, comments, and content.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says to call it FIRST when unsure whether the connector works or what it can see, giving clear situational guidance. However, it lacks explicit when-not-to-use guidance or mention of alternatives, though none are really needed for a unique diagnostic.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_commentA

Post a comment in a thread: 1 call (2 when discussion_id is a short key). Required body (+ body_format: 'html' for HTML; Loomio stores an omitted format as Markdown) and a target: discussion_id for a top-level comment, or parent_id + parent_type ('Comment' for a threaded reply; 'Poll' / 'Stance' / 'Outcome'). A new thread: create_discussion.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyYes
parent_idNoComment, Poll, Stance or Outcome id to reply to (needs parent_type).
body_formatNoDefault 'md'; 'html' when `body` is HTML.
parent_typeNoType of parent_id; required with it.
discussion_idNoDiscussion id or short key (+1 call) for a top-level comment; or use parent_id.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover the safety profile (readOnly false, destructive false, openWorld true), and the description adds non-derivable operational context: call cost (1 call, 2 when discussion_id is a short key) and the server-side default that an omitted body_format is stored as Markdown. It does not warn about duplicate posts (idempotentHint=false), which is the main remaining gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action, then packs target rules into one dense sentence with no filler. The telegraphic shorthand ('2 when...', '+1 call') is efficient but slightly compressed relative to plain prose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter mutation tool with no output schema, the description covers purpose, both target paths, the format default, and the sibling alternative. Only the idempotency/duplicate-posting behavior and any required permissions are unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 80% schema coverage the baseline is 3, but the description adds value beyond the schema by mapping parent_type values to intent ('Comment' for a threaded reply; 'Poll'/'Stance'/'Outcome') and by cross-referencing the dependency between parent_id and parent_type in prose.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource ('Post a comment in a thread') and immediately scopes it against siblings by naming create_discussion for new threads. The target variants (top-level vs threaded reply) further pin down what this tool does that create_poll/update_comment do not.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states which parameter combination selects which behavior: discussion_id for a top-level comment, parent_id + parent_type for a reply, and create_discussion for a brand-new thread. An agent can route correctly without opening any schema.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_discussionA

Start a discussion in a group: 1 call. Required title, group_id; optional description (+ description_format: 'html' for HTML), private (omit for the group's default), tags, recipients. Returns id, key, url, topic_id. Check list_discussions for duplicates first; to add to a thread use create_comment.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagsNo
titleYes
privateNotrue = members only, false = public. Default: the group's setting.
group_idYes
descriptionNo
recipient_emailsNoEmails to notify; non-members become guests.
notify_recipientsNofalse = add recipients without emailing them.
recipient_messageNoText for the notification.
description_formatNoDefault 'md'; 'html' when `description` is HTML.
recipient_audienceNo'group' = notify the whole group.
recipient_user_idsNoUser ids to notify.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare non-read-only, non-idempotent, non-destructive, open-world, so the safety profile is covered. The description adds real value beyond that by listing the returned fields (id, key, url, topic_id) despite there being no output schema, and by noting the '1 call' cost and that omitting private falls back to the group default. It does not explicitly state that recipients are emailed by default (notify_recipients semantics), which the schema carries instead.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single dense paragraph that front-loads the action, then parameters, then return values, then routing. Every clause carries information; nothing is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 11-parameter mutation tool with no output schema, the description supplies the return fields and the required/optional split, which fills the biggest gap. It is slightly thin on the recipient-notification behavior and permissions/auth needs, but nothing essential for a correct call is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 64% and the description groups parameters into required (title, group_id) and optional, and clarifies description_format usage and the private default. However, most of that repeats defaults already in the schema, and it says only 'recipients' for the four recipient-related parameters (emails, ids, audience, message, notify flag), leaving the notification surface to the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Start a discussion in a group') and immediately scopes it against siblings by naming create_comment as the tool for threading and list_discussions for dedupe. An agent can distinguish this from create_poll or create_comment without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly tells the agent to check list_discussions for duplicates first and to use create_comment to add to an existing thread. That is a clear when-to-use precondition plus named alternatives, which is exactly what routing guidance should look like.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_pollA

Create a poll: 1 call (2 with discussion_id). Required title, poll_type, options (NO default options; only 'question' takes none) and group_id (standalone) or discussion_id / topic_id (inside a thread). closing_at (ISO-8601, future) is effectively REQUIRED: without it Loomio saves the poll UNOPENED and the result carries opened: false and a warning. An opening poll is announced because notify_on_open defaults to TRUE; pass notify_on_open: false for a quiet create.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagsNoTags for a standalone poll's thread.
titleYes
detailsNo
optionsNoOption names in order. REQUIRED except 'question'; ranked_choice/stv need 2+.
group_idNoGroup of a STANDALONE poll (else only cross-checked).
topic_idNoThread id (`topic_id` on any thread row); no extra call.
anonymousNoPermanent. Needs closing_at; not for count, question, meeting.
max_scoreNoscore: max per option (default 5); meeting: 2.
min_scoreNoscore: min per option (default 0).
poll_typeYes'question' has no options; 'meeting' options are ISO-8601 times; 'stv' takes stv_seats.
stv_seatsNostv: seats to fill.
closing_atNoISO-8601, future. Effectively REQUIRED: omitted = unopened draft.
hide_resultsNoDefault 'off'; anonymous polls force 'until_closed'.
discussion_idNoDiscussion to attach to (id or key; +1 call). Prefer topic_id.
reason_promptNoPrompt above the reason box.
details_formatNoDefault 'md'; 'html' when `details` is HTML.
notify_on_openNoAnnounce (`poll_announced`) on opening; Loomio's default is TRUE.
dots_per_personNodot_vote: points per voter (default 8).
shuffle_optionsNoRandomise option order per voter.
meeting_durationNomeeting: slot minutes. No default through the API.
recipient_emailsNoEmails to invite; non-members become guests.
can_respond_maybeNomeeting: allow 'maybe'. API default is false.
notify_recipientsNoEmail/push the named recipients; SEPARATE from notify_on_open.
recipient_messageNoText for the notification.
recipient_audienceNo'group' = every member (needs announce permission).
recipient_user_idsNoUser ids to invite / notify.
specified_voters_onlyNoOnly the named recipients may vote.
maximum_stance_choicesNoMax options per voter (poll: 1; raise for multi-choice).
minimum_stance_choicesNoMin options per voter (ranked_choice: ranks, default 3).
notify_on_closing_soonNo24h closing reminder; API default is 'nobody'.
show_none_of_the_aboveNoOffer 'none of the above' (poll, ranked_choice).
stance_reason_requiredNoDefault 'optional'; anonymous polls force 'disabled'.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover safety profile, but the description adds critical behaviors beyond them: call count, that omitting closing_at produces an unopened poll with opened:false and a warning, and that notify_on_open defaults to TRUE requiring explicit false for a quiet create. These are meaningful operational disclosures.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four dense sentences front-load the creation summary and required parameters with no filler, using inline code for parameter names. Appropriately sized for a 32-parameter tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the rich schema and annotations, the description covers the critical creation-time behavioral traps (unopened draft, default announcement) and call-count implications. No output schema exists, but the description mentions key result fields, making it complete for an agent's needs.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 94%, so baseline is 3. The description adds operational meaning for requiredness of options/closing_at and the quiet-create toggle, plus the call-count impact of discussion_id, though much of the parameter guidance duplicates existing schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Create') and resource ('poll'), distinguishes standalone vs thread call counts, and names the required fields. Sibling tools are other poll operations (get/update/delete/list), so the creation intent is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear context for when poll creation applies, including standalone vs inside-thread routes and the effectively-required closing_at condition. It does not explicitly name alternatives or when-not-to-use scenarios, so it falls short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_commentA
DestructiveIdempotent

Discard a comment by numeric id: 1 call. Loomio's SOFT delete: the body is blanked and the comment leaves the thread view, but nothing is permanently erased (restorable in Loomio). For a wording fix prefer update_comment.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare destructiveHint=true and idempotentHint=true, but the description adds crucial nuance the annotations cannot: this is a Loomio SOFT delete, the body is blanked, the comment leaves the thread view, and the change is restorable. That materially changes how an agent should reason about irreversibility.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the action, then the soft-delete semantics, then the alternative. No filler; each clause carries distinct information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema, but annotations cover the safety profile and the description covers the rest: action, target, reversibility, and the sibling alternative. An agent has everything needed to call this correctly and to avoid it when updating text instead.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and there is one parameter. The description identifies `id` as a numeric comment identifier, which matches the schema's integer type and clarifies the target entity, but adds no format, range, or lookup detail beyond that. With one trivially typed param, this is adequate but not compensatory.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Discard a comment by numeric `id`') and differentiates from the sibling update_comment as well as the broader delete_* family. An agent can identify the operation without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent: 'For a wording fix prefer update_comment' names the alternative and the condition that selects it. Usage is thereby bounded rather than left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_discussionA
DestructiveIdempotent

Discard a discussion by id_or_key: 1 call. Loomio's SOFT delete: it leaves every list and its text is blanked, but nothing is permanently erased (a group admin can restore it). For a text mistake prefer update_discussion.

ParametersJSON Schema
NameRequiredDescriptionDefault
id_or_keyYesDiscussion id or short key.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only say destructive/idempotent/not-read-only; the description goes well beyond them by disclosing that this is a SOFT delete, that the discussion leaves every list, that its text is blanked, that nothing is permanently erased, and that a group admin can restore it. That reversibility and side-effect detail is exactly what an agent needs before invoking a destructive tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences, front-loaded with the verb and target, then the soft-delete semantics, then the alternative. No filler; every clause carries operational information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter destructive tool with no output schema, the description covers effect (blanked text, removed from lists), reversibility (admin restore), and the sibling alternative. Nothing an agent needs in order to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single parameter is documented there ('Discussion id or short key'), so the schema already carries the semantics. The description references `id_or_key` but adds no format or lookup detail, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Discard') and resource ('a discussion') plus the identifier used to target it. It also distinguishes itself from a sibling ('prefer update_discussion' for text mistakes), so an agent can separate delete from update without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly names the alternative (update_discussion) and the condition selecting it (a text mistake), which is real routing guidance. It lacks broader when-not guidance (e.g., delete vs. archive/lock, or confirm-before-delete norms), so it stops short of fully explicit when/when-not coverage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_pollA
DestructiveIdempotent

Discard a poll by id_or_key: 1 call. Loomio's SOFT delete: the poll and its votes leave the thread view, but nothing is permanently erased (a group admin can restore it). To end voting set closing_at to the next full hour with update_poll; no immediate close exists.

ParametersJSON Schema
NameRequiredDescriptionDefault
id_or_keyYesPoll id or short key.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and idempotentHint=true, so the safety profile is known. The description adds real value by qualifying that destruction: it is a SOFT delete, items leave the thread view but are recoverable by a group admin. It does not explain the response body, but the destructive-scope nuance is the important missing piece and it is supplied.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tightly packed sentences: the action and its soft-delete consequence come first, then the alternative routing. The '1 call' fragment is the only mildly extraneous element.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, and none is needed for a delete. The description covers what is removed, what is recoverable, by whom, and how to achieve the adjacent goal (closing a poll), which is everything an agent needs before invoking it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single parameter is already documented as 'Poll id or short key.' The description only names id_or_key without adding format, accepted-key, or lookup semantics, so it does not exceed the schema baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Discard a poll') plus the identifying parameter, and immediately clarifies the scope of the operation. An agent can distinguish this from delete_comment, delete_discussion, and update_poll without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent away from this tool for a common mis-use case: ending voting is done via update_poll with closing_at, and it notes 'no immediate close exists'. That is a concrete when-not-to-use plus the named alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_discussionA
Read-onlyIdempotent

One discussion by numeric id or short key: 1 call (2 with include_items). Returns the full body, topic_id, counters, url; include_items: true embeds list_thread_items as thread_items (items_limit; next_offset says when to page on). Prose: get_thread_markdown; a group's threads: list_discussions.

ParametersJSON Schema
NameRequiredDescriptionDefault
id_or_keyYesDiscussion id or short key.
strip_htmlNoPlain text instead of HTML; default false.
items_limitNoWith include_items: items to embed (default 200, max 1000).
include_itemsNoAlso embed the thread's items as `thread_items` (+1 call).
items_body_max_charsNoWith include_items: chars per body (default 4000; 0 omits, -1 full).

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, so safety is covered; the description adds genuinely new behavioral context: the call-count budget, the exact return shape (body, topic_id, counters, url), and how embedding items interacts with pagination (next_offset). Only auth/permission expectations and rate limits are left unstated.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Extremely dense but front-loaded: the identifying statement comes first, followed by output shape, optional expansion, and routing. Every clause (call counts, next_offset, sibling pointers) carries information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the burden of describing returns and does so (body, topic_id, counters, url, embedded thread_items, next_offset). It also covers the include_items toggle's cost and paging implication, leaving nothing an agent needs missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all five parameters are already documented there, including strip_html and items_body_max_chars. The description only re-ties items_limit to include_items (which the schema already states), so it adds little beyond the schema baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('One discussion by numeric id or short key') and immediately distinguishes itself from siblings list_discussions and get_thread_markdown. An agent can tell it apart from list_discussions/lookup tools without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent: use get_thread_markdown for prose, list_discussions for a group's threads, and this tool for a single discussion (plus the include_items variant). It also flags the cost tradeoff (1 call vs 2 with include_items) that drives the choice.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_groupA
Read-onlyIdempotent

One group by numeric id, short key or URL handle: 1 call; works for public groups the user has not joined. Returns the full record (members_can_* flags included, billing subscription dropped) plus member, membership, parent, url. 403 'Not authorized to show Group.' = hidden from this user; unknown = 404.

ParametersJSON Schema
NameRequiredDescriptionDefault
id_or_key_or_handleYesGroup numeric id, short key or URL handle.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds substantial behavior beyond the annotations: cost (1 call), visibility rules for unjoined public groups, the exact field set returned (members_can_* included, billing subscription dropped, plus member/membership/parent/url), and error semantics (403 = hidden from user, 404 = unknown). This is exactly the destructive/edge-case context the readOnly/idempotent hints don't cover.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three dense sentences, front-loaded with the identifier forms, then scope, then return shape, then error codes. No filler; every clause carries load-bearing information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description fully covers the return payload and the error taxonomy, plus the non-member visibility nuance. Nothing an agent needs to call and interpret the result is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the description's 'numeric id, short key or URL handle' essentially restates the schema's parameter description. No additional syntax or format detail is added, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific resource (a single group) and the accepted identifier forms (numeric id, short key, URL handle), making it clearly distinguishable from the sibling list_groups ('One group' vs a list). An agent can select it correctly without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear usage context that it 'works for public groups the user has not joined,' which tells the agent this is usable even without membership. It does not explicitly name list_groups as the alternative for multiple groups, so it stops short of full when/when-not routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_participation_reportA
Read-onlyIdempotent

Rank the members of a group set: 1 call returns Loomio's own report, a row per user sorted by total desc. Scope by group_ids (1-50, counted together) or group_scope: 'my'; top limit rows (default 50, max 500), zero-activity users dropped unless include_inactive. Anonymous polls are excluded; a vote counts in the month its counted stance row was created.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoRows after sorting by total desc (1-500). Default 50.
end_monthNoLast month, YYYY-MM. Default: the current month.
group_idsNoGroup ids counted together (1-50); required unless group_scope 'my'.
group_scopeNo'custom' (default) = given group_ids; 'my' = the user's groups.
start_monthNoFirst month, YYYY-MM. Default: 11 months before end_month.
delegates_onlyNoOnly users with an active delegate role. Default false.
include_inactiveNoAlso list users with total 0 (ever-members). Default false.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover safety (readOnly, idempotent, non-destructive), so the description adds genuinely useful behavior beyond them: anonymous polls excluded, zero-activity users dropped unless include_inactive, and the non-obvious counting rule that a vote counts in the month its counted stance row was created. These are real disclosure wins for a reporting tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two dense sentences pack the ranking behavior, scoping options, and counting caveat up front with essentially no filler. The semicolon-chained clauses are information-dense rather than wasteful, though slightly cramped.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description carries return-shape burden: it tells the agent it gets one row per user with a `total` value sorted descending, which is the key information. Full column set is not enumerated, but for a 7-param report this is close to sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents all 7 parameters including ranges and defaults. The description largely restates them ('default 50, max 500', group_ids 1-50) and only marginally adds the 'counted together' relationship, so baseline 3 is warranted.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('rank the members of a group set') and clarifies it returns Loomio's own report, one row per user sorted by `total` desc. It is unambiguous, though it does not explicitly name a sibling such as get_user_activity to differentiate the two activity-style tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains how to scope the report ('group_ids' counted together or 'group_scope: my'), which implies usage, but never states when to choose this tool over alternatives like get_user_activity or get_group. Inclusion rules (include_inactive, zero-activity dropped) give some operational guidance but no true when-to-use framing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_pollA
Read-onlyIdempotent

One poll by numeric id or short key: 1 call. Returns poll (full details, topic_id), poll_options[], current_outcome, my_stance, url; votes as items: list_thread_items with its topic_id. Results gate: results_visible / results_hidden_reason say whether tallies are present; absent counts mean HIDDEN, never zero.

ParametersJSON Schema
NameRequiredDescriptionDefault
id_or_keyYesPoll id or short key.
strip_htmlNoPlain text instead of HTML; default false.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly/openWorld/idempotent/non-destructive), and the description adds behavior annotations cannot: the results-gating fields and the critical gotcha that 'absent counts mean HIDDEN, never zero.' This is exactly the kind of disclosure that prevents misinterpretation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose, then return shape, then sibling routing, then the gating caveat — dense and waste-free. The return-field enumeration is verbose but earned given the absence of an output schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return-value burden and does so fully: it names the key fields, the gating fields, and how to fetch votes. Nothing an agent needs to call and interpret this tool is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters are already documented ('Poll id or short key', 'Plain text instead of HTML; default false'). The description restates the id/key duality but adds no syntax or format detail beyond the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('One poll') and its lookup modes ('by numeric id or short key'), immediately distinguishing it from list_polls, create_poll, and update_poll. An agent knows exactly what it retrieves without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clear context for single-item retrieval and a concrete routing hint for related data ('votes as items: list_thread_items with its topic_id'), which steers the agent to the right sibling for votes. However, it never explicitly contrasts itself with list_polls or states exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_thread_markdownA
Read-onlyIdempotent

The best single call for 'summarise / read this thread': 1 call by topic_id (2 by discussion_id or poll_id; pass exactly one) returns Loomio's server-rendered Markdown of the thread (markdown, chars, truncated). Structured data: list_thread_items. max_chars cuts from the END, so truncated: true means the newest items were dropped.

ParametersJSON Schema
NameRequiredDescriptionDefault
poll_idNoPoll id or short key of a STANDALONE poll (+1 call).
topic_idNoThread id (`topic_id` on any thread row, NOT `id`); no extra call.
max_charsNoCap in chars; default 60000, -1 = all. Cuts the END; `truncated` flags it.
discussion_idNoDiscussion id or short key (+1 call); prefer `topic_id`.

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, so the safety burden is lifted. The description still adds non-obvious behavior: the response is server-rendered Markdown with `markdown`/`chars`/`truncated`, and critically that `max_chars` cuts from the END so `truncated: true` drops newest items. It does not cover auth or rate limits, but for a read tool this is well above the annotation-covered bar.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two dense sentences, front-loaded with the primary use case and no filler. The packed parentheticals ('2 by discussion_id or poll_id; pass exactly one') are information-dense but slightly strain readability, keeping it just short of a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by naming the returned fields and the truncation flag; it also covers all four parameters, the id-selection rule, and the structured-data alternative. An agent has everything needed to call this correctly on the first attempt.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so per-parameter meanings are already documented (baseline 3). The description nevertheless adds a cross-parameter constraint the schema cannot express — 'pass exactly one' of topic_id/discussion_id/poll_id — and reinforces the truncation semantics of max_chars, which is genuine added value.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('read/summarise this thread' returning server-rendered Markdown), and explicitly positions itself as 'the best single call' against the sibling list_thread_items for structured data. An agent can distinguish it from get_discussion and list_thread_items without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use ('for summarise / read this thread'), when to prefer another tool ('Structured data: list_thread_items'), the alternative ids with their cost ('+1 call'; 'prefer topic_id'), and the constraint 'pass exactly one'. Nothing about tool selection is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_user_activityA
Read-onlyIdempotent

One person's participation across groups: 1 call per group + 1. Required user_id (from list_memberships or a participation row) and group_ids. Returns counts, by_group, sample_events (newest items with urls, not a full list). MONTH-GRAINED: since / until widen to whole months; anonymous polls never count; a vote counts in the month its counted stance row was created.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoISO-8601 start, rounded down to its month. Default: all history.
untilNoISO-8601 end (exclusive), rounded out to a whole month. Default: now.
user_idYesLoomio user id.
group_idsYesGroup ids (1-50); 1 call each.

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare this as a safe idempotent read, so the bar is lower, yet the description adds substantial domain behavior: month-graining that widens since/until to whole months, the rule that anonymous polls never count, and the stance-row month attribution rule for votes. It also discloses that sample_events are newest items with urls, not a full list.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose, then required params, then return shape, then the MONTH-GRAINED rules; every clause carries information. It is dense and heavy on terse fragments, but nothing is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a four-parameter read tool with no output schema, the description covers the return fields (counts, by_group, sample_events), the date-windowing semantics, the counting rules, and where inputs are sourced. An agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds meaning beyond the schema by specifying the source of user_id (list_memberships or a participation row) and the month-widening consequence of since/until. The '1 call each' note on group_ids largely restates the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: retrieving one person's participation across groups. The '1 call per group + 1' batching detail is distinctive and helps an agent understand the call pattern. It implies but does not explicitly name the contrast with get_participation_report, so it stops short of full sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It tells the agent where required values come from (user_id from list_memberships or a participation row), which is useful workflow guidance. However, it never says when to prefer this per-user view over the sibling get_participation_report, nor states any exclusions, leaving the when-to-use decision implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_discussionsA
Read-onlyIdempotent

One group's discussions, newest activity first: 1 call. status defaults to 'open'; description_max_chars (default 1500) caps bodies, description_truncated: true marking a cut; strip_html (default true) gives plain text. Every visible group: list_threads; keywords: search_content. Subgroups are excluded.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoPage size, 1-200. Default 50.
offsetNoPage offset. Default 0.
statusNo'open' (default) = unlocked, 'closed' = locked, 'all'.
group_idYes
strip_htmlNoPlain text instead of HTML; default true.
description_max_charsNoChars per `description`; default 1500, 0 omits it, -1 = full.

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover readOnlyHint, idempotentHint, openWorldHint, and destructiveHint=false, so the safety profile is clear. The description adds behavioral details: default status filtering, pagination hints via '1 call', and default strip_html. However, return format and pagination behavior are only partially addressed. Baseline 3 appropriate given annotations carry the core traits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Efficient and front-loaded: the primary purpose and scoping are stated first, followed by parameter defaults and related tools. No wasted words. Could be tightened further but is well structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a list tool with annotations covering safety and schema covering most parameters, the description provides useful defaults and scoping. However, it does not mention pagination behavior (offset/limit interaction) or return structure, and there is no output schema. Adequate but incomplete for an agent needing to call correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 83%, so most parameters are already described. The description adds behavioral nuance for status default, description_max_chars truncation behavior (with description_truncated flag), and strip_html default, which goes beyond schema. This is slightly above baseline but not rich enough for a 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('One group's discussions') and a scope constraint (subgroups excluded). Does not explicitly name the related sibling get_discussion or list_threads, though it does reference list_threads in a different context. Distinguishable from siblings but not maximally so.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Names alternatives: 'Every visible group: list_threads' and 'keywords: search_content', giving clear when-to-use context for related tasks. Lacks explicit when-not or differentiation from get_discussion / list_polls. Adequate but not comprehensive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_groupsA
Read-onlyIdempotent

The connector user's groups, pending invitations included: 1 call, no input. Subgroup parents are appended with member: false. get_group reads one record, even a public group this list omits.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive/openWorld, so safety is covered. The description adds return-shape behavior not in structured fields: pending invitations are included and subgroup parents are emitted with `member: false`. It does not discuss auth requirements or pagination, but adds genuine value beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight clauses, output scope front-loaded, then the call cost, then the sibling contrast. No filler anywhere.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description carries the return-value burden, and it does explain two notable return behaviors. Pagination and ordering are unaddressed, which is a minor remaining gap for a list tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Zero parameters, so the baseline is 4; the description confirms 'no input', which matches the empty schema. Nothing further is needed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific resource (the connector user's groups) with scope detail (pending invitations included) and explicitly distinguishes itself from the sibling get_group, which 'reads one record'. An agent can pick between list_groups and get_group without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The contrast with get_group ('get_group reads one record, even a public group this list omits') gives clear routing guidance for the list-vs-single-record choice. It does not spell out broader when-not-to-use cases, but the key sibling decision is covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_membershipsA
Read-onlyIdempotent

A group's members: 1 call. Returns memberships[] (user_email only where the connector's user is a group admin), users[], total. Use it to resolve a name to a user_id and ALWAYS before manage_memberships with remove_absent. A non-member gets an EMPTY list, not 403: never report it as an empty group.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoPage size, 1-200. Default 50.
offsetNoPage offset. Default 0.
group_idYesGroup id (a non-member gets an empty list, not 403).

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, non-destructive), and the description adds real behavioral nuance beyond them: user_email is only populated when the caller is a group admin, and a non-member receives an empty list rather than 403 — plus an explicit instruction not to misreport that as an empty group. This is exactly the kind of context annotations cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense but front-loaded: scope, return shape, then usage rules, then the empty-list caveat. Nearly every clause earns its place, though the return-shape enumeration is tightly packed and slightly cluttered with backticks.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by naming the returned keys (memberships[], users[], total) and the admin-conditional field, plus the critical empty-list edge case. An agent has everything needed to call and interpret this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, and the schema already documents limit, offset, and the group_id non-member/empty-list behavior. The description's group_id remark largely restates the schema, adding no new syntax or format detail. Baseline 3 applies when the schema carries the parameter burden.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific resource and scope ('A group's members: 1 call') with a clear read verb implied by 'list_memberships'. It is distinguishable from list_groups/get_group, though the differentiation from manage_memberships comes through the usage note rather than the purpose statement itself.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states two use cases: resolving a name to a user_id, and the mandatory pre-step before manage_memberships with remove_absent. Names the sibling tool and the exact condition that requires this call first.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_pollsA
Read-onlyIdempotent

One group's polls, newest first: 1 call. status defaults to 'active' ('closed', 'all'); description_max_chars caps details; strip_html (default true). Slim rows with poll_options[] and stance_counts when visible (trust results_visible). For member activity use get_participation_report, not this plus list_memberships.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoPage size, 1-200. Default 50.
offsetNoPage offset. Default 0.
statusNo'active' (default) = open, 'closed', 'all'.
group_idYes
strip_htmlNoPlain text instead of HTML; default true.
description_max_charsNoChars per `details`; default 1500, 0 omits it, -1 = full.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, so the bar is lower, and the description adds real behavioral detail beyond them: newest-first ordering, slim rows, conditional presence of poll_options[] and stance_counts gated by results_visible, and the effect of strip_html on details. It still doesn't state pagination behavior or total counts, so not a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense and front-loaded, with the scope/ordering statement first and the routing caveat last. The telegraphic fragment style ('1 call', semicolon-joined clauses) is efficient but slightly cryptic and costs a point on readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by describing the row shape (poll_options[], stance_counts, results_visible) and the `details` field. Combined with schema-documented paging and defaults, an agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 83%, so the baseline is 3. The description adds semantic links the schema doesn't make on its own: that description_max_chars caps `details` specifically, and that strip_html controls whether details come back as HTML.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource with scope and ordering: 'One group's polls, newest first: 1 call.' It is immediately distinguishable from siblings like get_poll (single poll), create_poll, and list_groups.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent away from a tempting wrong path: 'For member activity use get_participation_report, not this plus list_memberships.' That is a clear when-not plus a named alternative, though it covers only this one scenario and says nothing about paging or when to prefer get_poll.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_thread_itemsA
Read-onlyIdempotent

One thread as structured items: 1 call by topic_id (2 by discussion_id or poll_id; pass exactly one). Returns items[] in thread order plus the comments, polls, stances (votes), outcomes and users they reference. The whole thread is fetched once and sliced here (limit, offset, kinds) under the max_total_chars budget; next_offset says where to continue.

ParametersJSON Schema
NameRequiredDescriptionDefault
kindsNoItem kinds to keep (e.g. new_comment, stance_created); 'other' = unlisted kinds.
limitNoItems after the kinds filter; default 200, max 1000.
offsetNoItems to skip. Default 0.
poll_idNoPoll id or short key of a STANDALONE poll (+1 call).
topic_idNoThread id (`topic_id` on any thread row, NOT `id`); no extra call.
strip_htmlNoPlain text instead of HTML bodies, reasons, outcomes; default true.
discussion_idNoDiscussion id or short key (+1 call); prefer `topic_id`.
body_max_charsNoChars per `body`; default 4000, 0 omits it, -1 = full.
max_total_charsNoReply budget in chars; default 120000, -1 = none. See next_offset.
include_reactionsNoAlso return emoji `reactions`. Default false.

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, so the bar is lower, but the description adds meaningful behavior: the whole thread is fetched once and sliced locally, `next_offset` signals continuation, and results are budgeted by `max_total_chars`. That pagination model is real context beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two dense sentences that front-load the purpose, then cover the call cost, return shape, pagination, and continuation. Slightly packed, but each clause carries information useful for correct invocation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 10-parameter read tool with annotations and no output schema, the description supplies the return shape (`items[]` plus referenced entities), the slicing parameters, and the continuation pointer. That is sufficient for an agent to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents each of the 10 parameters in detail (including the '+1 call' cost notes). The description adds only the integrated 'pass exactly one' constraint over the id params, which is marginal beyond what the schema provides; baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb+resource ('One thread as structured items') and clarifies the granularity (items[], not a rendered document), which distinguishes it from get_thread_markdown without naming that sibling explicitly. An agent can tell it returns structured thread data rather than a formatted report.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives concrete routing guidance for the id parameters: use `topic_id` for 1 call vs `discussion_id`/`poll_id` for 2 calls, and 'pass exactly one'. This helps an agent pick the efficient path, though it does not explicitly state when to prefer this tool over get_thread_markdown or list_threads.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_threadsA
Read-onlyIdempotent

The cheapest 'what is new across everything I can see': 1 call lists every visible thread, newest activity first (topic_id, type, title, group_id, counters, url; no bodies). group_id / type filter client-side within the page (one group: list_discussions / list_polls). No date filter upstream: pass since and page with offset until scope.exhausted.

ParametersJSON Schema
NameRequiredDescriptionDefault
typeNoKeep only Discussion or Poll threads (client-side).
limitNoThreads per page, default 20, max 100.
sinceNoISO-8601 cutoff on last_activity_at; page until scope.exhausted.
offsetNoThreads to skip. Default 0.
group_idNoOnly this group's threads (client-side; `total` stays instance-wide).

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, non-destructive), yet the description adds real behavioral context: no bodies returned, `group_id`/`type` filtering happens client-side within the page, and `total` stays instance-wide. What it does not fully disclose is what `scope.exhausted` actually contains or how many pages a typical traversal needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the value proposition and return shape, then the caveats; no filler sentences. The parenthetical stacking makes it dense and slightly hard to parse, but nothing is padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return-value burden and does so by listing the key fields and noting the absence of bodies. Combined with the paging loop and client-side filter caveats, an agent has enough to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description goes further by explaining that `group_id`/`type` are client-side filters and that `since`/`offset` drive a page-until-exhausted loop. This adds operational meaning (especially that `total` is not scoped to the filter) beyond the per-parameter schema text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a concrete verb+resource ('lists every visible thread, newest activity first') and enumerates the returned fields, so the agent knows exactly what comes back. It also distinguishes itself from the single-group siblings by naming list_discussions / list_polls as the narrower alternatives.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Positions the tool as 'the cheapest what-is-new across everything I can see' and explicitly routes single-group lookups to list_discussions / list_polls. It even prescribes the paging pattern (pass `since`, page with `offset` until `scope.exhausted`), so when and how to use it is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

manage_membershipsA
Destructive

Invite users to a group by email and optionally REMOVE members not in the list: 1 call; the connector's user must be an admin of THAT group. Default is additive: new addresses are invited, nobody is touched. DANGEROUS: remove_absent: true removes every member whose email is absent, own user included, with no undo: list_memberships first, then confirm the diff with a human.

ParametersJSON Schema
NameRequiredDescriptionDefault
emailsYesAddresses to ensure are members; new ones are invited.
group_idYesGroup id; the connector's user must be its admin.
remove_absentNoDANGEROUS: also revokes every member absent from `emails`, own user included. Default false.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond annotations (which only flag destructive=true, idempotent=false): it names the admin-of-that-group auth requirement, the self-removal hazard ('own user included'), and the irreversibility ('no undo'). This is exactly the safety context an agent needs before a destructive mutation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and default, then the danger. It is dense but each clause earns its place; the '1 call' phrase is slightly superfluous but minor.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 3-param destructive mutation with no output schema, the description covers auth requirements, default vs destructive semantics, self-inclusion, irreversibility, and a recommended pre-check workflow. Nothing an agent needs to invoke it safely is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, and the schema already documents emails ('ensure are members'), group_id (admin requirement), and remove_absent (dangerous/default false). The description largely restates that, so it earns the baseline 3 rather than adding new parameter meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States specific verbs (invite, remove) and resource (group memberships by email), and explicitly contrasts the additive default against the destructive remove mode. An agent can distinguish it from list_memberships without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly tells the agent that the default is additive ('nobody is touched') and that remove_absent:true triggers destructive removal, then prescribes a workflow: call list_memberships first and confirm the diff with a human. When-to-use and when-to-be-careful are both stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_contentA
Read-onlyIdempotent

Keyword search over everything the connector's user can see: 1 call. Pass query (prefix match; !word excludes), author_id alone for 'what did X post', or both. Hard cap: at most 20 results, no paging; capped: true means narrow the search. Stance hits on polls with hidden results are DROPPED from a query search; never use search to probe hidden vote reasons.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagNoOnly threads carrying this tag (exact name).
orderNoauthored_at_desc (default), authored_at_asc, relevance.
queryNoFull-text query (prefix match; `!word` excludes).
typesNoRecord types to include; default all (e.g. ['Outcome']).
group_idNoRestrict to one group (not its subgroups).
author_idNoRestrict to one author; alone = their 20 newest items.

TDQS

A4.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, openWorld and non-destructive, so the safety profile is covered. The description adds genuinely useful behavior the annotations do not: a hard 20-result cap with no paging, the `capped: true` signal, and that stance hits on hidden-result polls are dropped from a query search. That said, it stops short of naming the alternative tool for the capped case, so it is additive but not rich.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Roughly four dense sentences, all front-loaded, with the two most consequential facts (20-result cap, hidden-stance drop) placed where they cannot be missed. No filler or restatement of the tool name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description carries the return-value burden and does so by explaining the `capped: true` marker. With all six parameters fully documented in the schema and the safety profile in annotations, nothing an agent needs to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description earns an extra point by documenting cross-parameter semantics the schema does not: how query, author_id, and their combination compose ('or both') and how the cap interacts with narrowing the search. It omits tag/types/group_id/order, which the schema already covers.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Keyword search over everything the connector's user can see') with the visibility scope made explicit. It also pins down the search modes (query, author_id, both), so an agent can distinguish it from the list_/get_ siblings without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly tells when to use each input ('author_id alone for what did X post', or both), and adds a hard when-not: never use search to probe hidden vote reasons. Both the selection condition and the anti-pattern are given, leaving nothing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_commentA
DestructiveIdempotent

Edit a comment: 1 call. Required numeric id and body (REPLACES the whole text: read it with list_thread_items first), optional body_format. Only the author, or a thread admin where the group allows it, may edit; the thread must be unlocked.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYes
bodyYesNew body; REPLACES the whole text.
body_formatNoOmitted = the STORED format stays; send 'html' when the text is HTML.

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations by disclosing that the body REPLACES the entire text (matching destructiveHint=true), the authorization model, and the thread-lock constraint. Annotations flag safety profile; the description fills in the operational consequences an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the verb and '1 call', then packs replace-semantics, params, and auth into one dense passage. Slightly redundant with schema wording on the body-replacement rule, but no wasted sentences.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no output schema, it covers auth requirements, destructive replace behavior, and prerequisites adequately. Return-value expectations are left implicit, which is acceptable given the tool's simple edit semantics.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67% and the body/body_format descriptions already appear in the schema, so the description largely repeats structured data ('REPLACES the whole text', 'html' example). It adds identification of the undocumented id as 'numeric' and required, but little else beyond the baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Edit a comment') and immediately disambiguates it against the create/delete_comment siblings by describing an in-place edit that REPLACES the whole body. An agent can select it confidently without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear preconditions: author/thread-admin permission, thread must be unlocked, and routes the agent to list_thread_items to read the text before replacing it. No explicit 'use X instead' exclusion, but the context is concrete and actionable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_discussionA
DestructiveIdempotent

Edit a discussion by id_or_key: 1 call. Pass only what changes: title, description (REPLACES the body: read it first, send the whole text), private, allow_* flags, recipients to add. Cannot move a thread or change its tags; a discarded thread cannot be edited.

ParametersJSON Schema
NameRequiredDescriptionDefault
titleNo
privateNotrue = members only; must fit `discussion_privacy_options`.
id_or_keyYesDiscussion id or short key.
descriptionNoNew body; REPLACES the whole description.
allow_commentsNoWhether members may comment.
allow_reactionsNoWhether members may react.
recipient_emailsNoEmails to invite as readers; non-members become guests.
notify_recipientsNofalse = add recipients without emailing them.
recipient_messageNoNotification text; records a visible 'edited' item.
description_formatNoOmitted = the STORED format stays; send 'html' when the text is HTML.
recipient_audienceNo'group' = notify the whole group (needs announce permission).
recipient_user_idsNoUser ids to add as readers and notify.
allow_concurrent_pollsNoAllow several open polls at once.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint and idempotentHint, but the description adds critical specifics beyond them: description fully REPLACES the body (forcing a read-first, send-whole-text workflow), threads cannot be moved, tags cannot be changed, and discarded threads cannot be edited. These negative constraints are exactly the context an agent needs before mutating.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One dense, well-ordered sentence: identification, partial-update rule, the destructive replacement warning, then the impossibility constraints. No filler, and the highest-risk behavior (body replacement) is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 13-parameter mutation tool with no output schema and strong annotation coverage, the description covers the essential behavioral traps. Minor gaps remain around recipient/notify effects and permission requirements, but the core editing contract is complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 92%, so the schema carries most parameter meaning. The description still adds value by grouping the changeable fields ('allow_* flags, recipients to add') and emphasizing the replace-not-merge semantics of description, which the schema only states tersely.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Edit a discussion by id_or_key'), identifies the key parameter, and scopes it as a single call. An agent can distinguish this from create_discussion or update_comment without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Pass only what changes' plus the 'read it first' workflow for description give clear operational context, and the closing sentence lists what the tool cannot do. It stops short of naming a sibling alternative (e.g. update_comment) the way a 5 would, but the usage context is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_pollA
DestructiveIdempotent

Edit an OPEN poll by id_or_key: 1 call (2 with options). Pass only what changes: title, details (REPLACES the text), closing_at (future; opening a draft announces unless notify_on_open is false), options (names to ADD: merged with the current list, so it never removes an option it saw; not atomic), settings. Cannot change poll_type, anonymous, group or tags; a closed poll answers 403.

ParametersJSON Schema
NameRequiredDescriptionDefault
titleNo
detailsNo
optionsNoNames to ADD (+1 call): merged with the stored names, so it never removes an option it saw. Not atomic.
id_or_keyYesPoll id or short key.
max_scoreNoscore: max per option (default 5); meeting: 2.
min_scoreNoscore: min per option (default 0).
stv_seatsNostv: seats to fill.
closing_atNoISO-8601, future; omitted = unchanged. To end voting soon pass the next full hour.
hide_resultsNoCannot leave 'until_closed' once set.
reason_promptNoPrompt above the reason box.
details_formatNoDefault 'md'; 'html' when `details` is HTML.
notify_on_openNoAnnounce (`poll_announced`) on opening; Loomio's default is TRUE.
dots_per_personNodot_vote: points per voter (default 8).
shuffle_optionsNoRandomise option order per voter.
meeting_durationNomeeting: slot minutes. No default through the API.
recipient_emailsNoEmails to invite; non-members become guests.
can_respond_maybeNomeeting: allow 'maybe'. API default is false.
notify_recipientsNoEmail/push the named recipients; SEPARATE from notify_on_open.
recipient_messageNoText for the notification.
recipient_audienceNo'group' = every member (needs announce permission).
recipient_user_idsNoUser ids to invite / notify.
specified_voters_onlyNoOnly the named recipients may vote.
maximum_stance_choicesNoMax options per voter (poll: 1; raise for multi-choice).
minimum_stance_choicesNoMin options per voter (ranked_choice: ranks, default 3).
notify_on_closing_soonNo24h closing reminder; API default is 'nobody'.
show_none_of_the_aboveNoOffer 'none of the above' (poll, ranked_choice).
stance_reason_requiredNoDefault 'optional'; anonymous polls force 'disabled'.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations: discloses that details REPLACES existing text, options are ADD-only and merged (never removes), the merge is not atomic, opening a draft announces a poll, and a closed poll returns 403. These are exactly the destructive/stateful traits an agent needs and the annotations alone (destructiveHint, idempotentHint) do not convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single dense paragraph that is front-loaded with the action and the call-count note, then lists the mutability contract and exclusions. Every sentence carries information; only the count of packed clauses keeps it from being maximally clean.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 27-parameter tool with high schema coverage, a safety profile in annotations, and no output schema, the description supplies the missing behavioral context (overwrite, merge, non-atomicity, 403, announce-on-open). Return values needn't be described since no output schema exists.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 93% schema coverage the baseline is 3, but the description adds real semantic value: 'Pass only what changes', details overwrite behavior, option merge semantics, and future-only closing_at. It clarifies the update-patch contract that the schema type constraints alone don't express.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Edit) and resource (an OPEN poll) with the identifying parameter (id_or_key), and the constraint that it must be open immediately differentiates it from create_poll/delete_poll siblings. An agent can identify the operation without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear when-to-use conditions (only open polls; closed returns 403) and explicit when-not boundaries (cannot change poll_type, anonymous, group, tags). It doesn't name a sibling alternative by name, but the create/delete/update triad is unambiguous from context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 24 tool updatesv0.0.13
    • Addedcheck_connection
    • Changedcreate_comment10 fields changed
      • removedInput schema / properties / body / description
        Removed value: -"Comment body (required)."
      • changedInput schema / properties / body_format / description
        Previous value: -"Format of `body`. Defaults to Loomio's group default when omitted."New value: +"Default 'md'; 'html' when `body` is HTML."
      • addedInput schema / properties / discussion_id / anyOf
        Added value: +[
        +  {
        +    "pattern": "^[A-Za-z0-9_-]+$",
        +    "type": "string"
        +  },
        +  {
        +    "exclusiveMinimum": 0,
        +    "maximum": 9007199254740991,
        +    "type": "integer"
        +  }
        +]
      • changedInput schema / properties / discussion_id / description
        Previous value: -"ID of the discussion to comment on."New value: +"Discussion id or short key (+1 call) for a top-level comment; or use parent_id."
      • removedInput schema / properties / discussion_id / exclusiveMinimum
        Removed value: -0
      • removedInput schema / properties / discussion_id / maximum
        Removed value: -9007199254740991
      • removedInput schema / properties / discussion_id / type
        Removed value: -"integer"
      • addedInput schema / properties / parent_id
        Added value: +{
        +  "description": "Comment, Poll, Stance or Outcome id to reply to (needs parent_type).",
        +  "exclusiveMinimum": 0,
        +  "maximum": 9007199254740991,
        +  "type": "integer"
        +}
      • addedInput schema / properties / parent_type
        Added value: +{
        +  "description": "Type of parent_id; required with it.",
        +  "enum": [
        +    "Discussion",
        +    "Comment",
        +    "Poll",
        +    "Stance",
        +    "Outcome"
        +  ],
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "discussion_id",
        -  "body"
        -]New value: +[
        +  "body"
        +]
    • Addedcreate_discussion
    • Changedcreate_poll39 fields changed
      • changedInput schema / properties / anonymous / description
        Previous value: -"If true, hide voter identities."New value: +"Permanent. Needs closing_at; not for count, question, meeting."
      • addedInput schema / properties / can_respond_maybe
        Added value: +{
        +  "description": "meeting: allow 'maybe'. API default is false.",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / closing_at / description
        Previous value: -"ISO-8601 timestamp at which the poll closes."New value: +"ISO-8601, future. Effectively REQUIRED: omitted = unopened draft."
      • removedInput schema / properties / details / description
        Removed value: -"Optional poll body / context."
      • changedInput schema / properties / details_format / description
        Previous value: -"Format of `details`. Defaults to 'md'."New value: +"Default 'md'; 'html' when `details` is HTML."
      • addedInput schema / properties / discussion_id / anyOf
        Added value: +[
        +  {
        +    "pattern": "^[A-Za-z0-9_-]+$",
        +    "type": "string"
        +  },
        +  {
        +    "exclusiveMinimum": 0,
        +    "maximum": 9007199254740991,
        +    "type": "integer"
        +  }
        +]
      • changedInput schema / properties / discussion_id / description
        Previous value: -"Attach the poll to an existing discussion. When set, group_id is taken from the discussion."New value: +"Discussion to attach to (id or key; +1 call). Prefer topic_id."
      • removedInput schema / properties / discussion_id / exclusiveMinimum
        Removed value: -0
      • removedInput schema / properties / discussion_id / maximum
        Removed value: -9007199254740991
      • removedInput schema / properties / discussion_id / type
        Removed value: -"integer"
      • addedInput schema / properties / dots_per_person
        Added value: +{
        +  "description": "dot_vote: points per voter (default 8).",
        +  "exclusiveMinimum": 0,
        +  "maximum": 9007199254740991,
        +  "type": "integer"
        +}
      • changedInput schema / properties / group_id / description
        Previous value: -"Group the poll belongs to. Required when not attaching to an existing discussion via discussion_id."New value: +"Group of a STANDALONE poll (else only cross-checked)."
      • changedInput schema / properties / hide_results / description
        Previous value: -"Results visibility policy. Defaults to 'off'."New value: +"Default 'off'; anonymous polls force 'until_closed'."
      • addedInput schema / properties / max_score
        Added value: +{
        +  "description": "score: max per option (default 5); meeting: 2.",
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
      • addedInput schema / properties / maximum_stance_choices
        Added value: +{
        +  "description": "Max options per voter (poll: 1; raise for multi-choice).",
        +  "exclusiveMinimum": 0,
        +  "maximum": 9007199254740991,
        +  "type": "integer"
        +}
      • addedInput schema / properties / meeting_duration
        Added value: +{
        +  "description": "meeting: slot minutes. No default through the API.",
        +  "exclusiveMinimum": 0,
        +  "maximum": 9007199254740991,
        +  "type": "integer"
        +}
      • addedInput schema / properties / min_score
        Added value: +{
        +  "description": "score: min per option (default 0).",
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
      • addedInput schema / properties / minimum_stance_choices
        Added value: +{
        +  "description": "Min options per voter (ranked_choice: ranks, default 3).",
        +  "maximum": 9007199254740991,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • changedInput schema / properties / notify_on_closing_soon / description
        Previous value: -"Who Loomio notifies as the closing date approaches. Defaults to 'nobody'."New value: +"24h closing reminder; API default is 'nobody'."
      • changedInput schema / properties / notify_on_closing_soon / enum
        Previous value: -[
        -  "nobody",
        -  "author",
        -  "voters",
        -  "undecided_voters",
        -  "all_members"
        -]New value: +[
        +  "nobody",
        +  "author",
        +  "undecided_voters",
        +  "voters"
        +]
      • addedInput schema / properties / notify_on_open
        Added value: +{
        +  "description": "Announce (`poll_announced`) on opening; Loomio's default is TRUE.",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / notify_recipients / description
        Previous value: -"If false, suppress the initial notification email. Defaults to false."New value: +"Email/push the named recipients; SEPARATE from notify_on_open."
      • changedInput schema / properties / options / description
        Previous value: -"Voting options. `proposal` has built-in agree/disagree/abstain options; for poll / count / score / ranked_choice / meeting / dot_vote you MUST supply your own."New value: +"Option names in order. REQUIRED except 'question'; ranked_choice/stv need 2+."
      • changedInput schema / properties / poll_type / description
        Previous value: -"Poll type. One of: proposal, poll, count, score, ranked_choice, meeting, dot_vote."New value: +"'question' has no options; 'meeting' options are ISO-8601 times; 'stv' takes stv_seats."
      • changedInput schema / properties / poll_type / enum
        Previous value: -[
        -  "proposal",
        -  "poll",
        -  "count",
        -  "score",
        -  "ranked_choice",
        -  "meeting",
        -  "dot_vote"
        -]New value: +[
        +  "proposal",
        +  "poll",
        +  "count",
        +  "score",
        +  "ranked_choice",
        +  "meeting",
        +  "dot_vote",
        +  "check",
        +  "question",
        +  "stv"
        +]
      • addedInput schema / properties / reason_prompt
        Added value: +{
        +  "description": "Prompt above the reason box.",
        +  "type": "string"
        +}
      • addedInput schema / properties / recipient_audience / description
        Added value: +"'group' = every member (needs announce permission)."
      • addedInput schema / properties / recipient_emails / description
        Added value: +"Emails to invite; non-members become guests."
      • changedInput schema / properties / recipient_emails / items / pattern
        Previous value: -"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"New value: +"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
      • addedInput schema / properties / recipient_message / description
        Added value: +"Text for the notification."
      • addedInput schema / properties / recipient_user_ids / description
        Added value: +"User ids to invite / notify."
      • addedInput schema / properties / show_none_of_the_above
        Added value: +{
        +  "description": "Offer 'none of the above' (poll, ranked_choice).",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / shuffle_options / description
        Previous value: -"If true, shuffle option display order."New value: +"Randomise option order per voter."
      • changedInput schema / properties / specified_voters_only / description
        Previous value: -"If true, only users in recipient_user_ids / recipient_emails can vote."New value: +"Only the named recipients may vote."
      • addedInput schema / properties / stance_reason_required
        Added value: +{
        +  "description": "Default 'optional'; anonymous polls force 'disabled'.",
        +  "enum": [
        +    "disabled",
        +    "optional",
        +    "required",
        +    "required_for_disagree_or_block",
        +    "required_for_block"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / stv_seats
        Added value: +{
        +  "description": "stv: seats to fill.",
        +  "exclusiveMinimum": 0,
        +  "maximum": 9007199254740991,
        +  "type": "integer"
        +}
      • addedInput schema / properties / tags
        Added value: +{
        +  "description": "Tags for a standalone poll's thread.",
        +  "items": {
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • removedInput schema / properties / title / description
        Removed value: -"Poll title (required)."
      • addedInput schema / properties / topic_id
        Added value: +{
        +  "description": "Thread id (`topic_id` on any thread row); no extra call.",
        +  "exclusiveMinimum": 0,
        +  "maximum": 9007199254740991,
        +  "type": "integer"
        +}
    • Addeddelete_comment
    • Addeddelete_discussion
    • Addeddelete_poll
    • Addedget_discussion
    • Addedget_group
    • Addedget_participation_report
    • Addedget_poll
    • Addedget_thread_markdown
    • Changedget_user_activity4 fields changed
      • changedInput schema / properties / group_ids / description
        Previous value: -"Groups to scan. Required — pass the result of `list_groups` (or a subset of it) to make the cost explicit. ~1 outbound HTTP request per discussion in scope, plus one list_discussions call per group; ~100-300 calls is typical for a wide scan. Capped at 50 groups per call."New value: +"Group ids (1-50); 1 call each."
      • changedInput schema / properties / since / description
        Previous value: -"ISO-8601 timestamp; ignore events before this time. Rejected if unparseable (so a typo can't silently widen the scan to all history)."New value: +"ISO-8601 start, rounded down to its month. Default: all history."
      • changedInput schema / properties / until / description
        Previous value: -"ISO-8601 timestamp; ignore events at or after this time. Rejected if unparseable."New value: +"ISO-8601 end (exclusive), rounded out to a whole month. Default: now."
      • changedInput schema / properties / user_id / description
        Previous value: -"Loomio user id whose activity to summarise."New value: +"Loomio user id."
    • Changedlist_discussions6 fields changed
      • addedInput schema / properties / description_max_chars
        Added value: +{
        +  "description": "Chars per `description`; default 1500, 0 omits it, -1 = full.",
        +  "maximum": 9007199254740991,
        +  "minimum": -1,
        +  "type": "integer"
        +}
      • removedInput schema / properties / group_id / description
        Removed value: -"ID of the Loomio group whose discussions to list (required)."
      • changedInput schema / properties / limit / description
        Previous value: -"Page size. Loomio defaults to 50."New value: +"Page size, 1-200. Default 50."
      • changedInput schema / properties / offset / description
        Previous value: -"Page offset. Defaults to 0."New value: +"Page offset. Default 0."
      • changedInput schema / properties / status / description
        Previous value: -"Filter by status. 'open' = unlocked, 'closed' = locked, 'all' = every kept discussion. Loomio defaults to 'open'."New value: +"'open' (default) = unlocked, 'closed' = locked, 'all'."
      • addedInput schema / properties / strip_html
        Added value: +{
        +  "description": "Plain text instead of HTML; default true.",
        +  "type": "boolean"
        +}
    • Changedlist_groups3 fields changed
      • removedInput schema / properties / end_id
        Removed value: -{
        -  "description": "Last group_id to probe (inclusive). Defaults to 200. A single call may scan at most 500 ids; use multiple calls for wider ranges.",
        -  "maximum": 10000,
        -  "minimum": 1,
        -  "type": "integer"
        -}
      • removedInput schema / properties / start_id
        Removed value: -{
        -  "description": "First group_id to probe (inclusive). Defaults to 1.",
        -  "maximum": 9007199254740991,
        -  "minimum": 1,
        -  "type": "integer"
        -}
      • removedInput schema / properties / stop_after_consecutive_misses
        Removed value: -{
        -  "description": "Early-exit heuristic: stop probing after this many consecutive 404/403 misses. Saves wall time on sparse id ranges. Defaults to 50.",
        -  "maximum": 500,
        -  "minimum": 1,
        -  "type": "integer"
        -}
    • Changedlist_memberships3 fields changed
      • changedInput schema / properties / group_id / description
        Previous value: -"ID of the Loomio group whose memberships to list (required). The connector's bot user must be an admin (coordinator) of the group — Loomio only returns the member list, including email addresses, to group admins. For a non-admin bot this returns a clear 403 explaining the role requirement; names/usernames/ids (not emails) are still reachable via get_user_activity / list_events."New value: +"Group id (a non-member gets an empty list, not 403)."
      • changedInput schema / properties / limit / description
        Previous value: -"Page size. Loomio defaults to 50."New value: +"Page size, 1-200. Default 50."
      • changedInput schema / properties / offset / description
        Previous value: -"Page offset. Defaults to 0."New value: +"Page offset. Default 0."
    • Changedlist_polls6 fields changed
      • addedInput schema / properties / description_max_chars
        Added value: +{
        +  "description": "Chars per `details`; default 1500, 0 omits it, -1 = full.",
        +  "maximum": 9007199254740991,
        +  "minimum": -1,
        +  "type": "integer"
        +}
      • removedInput schema / properties / group_id / description
        Removed value: -"ID of the Loomio group whose polls to list (required)."
      • changedInput schema / properties / limit / description
        Previous value: -"Page size. Loomio defaults to 50."New value: +"Page size, 1-200. Default 50."
      • changedInput schema / properties / offset / description
        Previous value: -"Page offset. Defaults to 0."New value: +"Page offset. Default 0."
      • changedInput schema / properties / status / description
        Previous value: -"Filter polls by status. Loomio defaults to 'active'."New value: +"'active' (default) = open, 'closed', 'all'."
      • addedInput schema / properties / strip_html
        Added value: +{
        +  "description": "Plain text instead of HTML; default true.",
        +  "type": "boolean"
        +}
    • Addedlist_thread_items
    • Addedlist_threads
    • Changedmanage_memberships4 fields changed
      • changedInput schema / properties / emails / description
        Previous value: -"Email addresses to ensure are members. Each address that isn't already a member is invited / added."New value: +"Addresses to ensure are members; new ones are invited."
      • changedInput schema / properties / emails / items / pattern
        Previous value: -"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"New value: +"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
      • changedInput schema / properties / group_id / description
        Previous value: -"ID of the Loomio group to modify (required). Caller must be a group admin."New value: +"Group id; the connector's user must be its admin."
      • changedInput schema / properties / remove_absent / description
        Previous value: -"DANGEROUS. When true, Loomio REMOVES every existing member whose email is NOT in `emails`. Empty-emails (after dedupe) effectively removes the entire group. Default false. Only set true after reading list_memberships and confirming the diff with a human."New value: +"DANGEROUS: also revokes every member absent from `emails`, own user included. Default false."
    • Addedsearch_content
    • Addedupdate_comment
    • Addedupdate_discussion
    • Addedupdate_poll
  2. 4 tool updatesv0.0.10
    • Removedcreate_discussion
    • Removedget_discussion
    • Removedget_poll
    • Removedlist_events
  3. 12 tool updatesv0.0.6
    • First observedcreate_comment
    • First observedcreate_discussion
    • First observedcreate_poll
    • First observedget_discussion
    • First observedget_poll
    • First observedget_user_activity
    • First observedlist_discussions
    • First observedlist_events
    • First observedlist_groups
    • First observedlist_memberships
    • First observedlist_polls
    • First observedmanage_memberships

TDQS

A3.9/5.0

Scored across 24 tools

Disambiguation4/5

Most tools target clearly distinct resources and actions, but the thread-reading surface (list_threads, list_discussions, list_polls, list_thread_items, get_thread_markdown, get_discussion, get_poll) has enough overlap that an agent may hesitate. The detailed descriptions largely resolve the ambiguity, but not perfectly.

Naming Consistency5/5

All tools use consistent snake_case verb_noun naming (create_poll, list_groups, get_discussion, update_poll, delete_comment, etc.) with no mixed conventions or vague verbs.

Tool Count3/5

24 tools is heavy for the domain and falls into the borderline 16-25 range. While each tool covers a real operation, the set could be consolidated, especially around separate list/read tools for threads, discussions, and polls.

Completeness2/5

CRUD is present for discussions, polls, and comments, but the Loomio decision-making core is incomplete: there is no tool to cast or manage a vote/stance, and group lifecycle operations are missing. Agents cannot fully participate in polls or manage groups end-to-end.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers