Atlas / MCP servers / forumone / @forumone/throughline

@forumone/throughlineBLOCK

mcp/forumone/throughline
Verdict
BLOCK
Grade
F
Trust score
36 /100
Exposed tools
79 59r · 19w · 1d
Transport
—
License
MIT
Stars
0
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

A conversational content management framework. Exposes Payload CMS as a set of MCP tools so marketers can operate websites through Claude rather than a traditional admin UI.

Documentation

Full documentation lives at docs/ — getting-started tutorials, conceptual explanations of the architecture, how-to guides, per-package reference, and operations docs. Start at docs/README.md.

Status

1.0. Releases publish under latest, and a snapshot of every merge to main under next. 0.x is closed; its source stays on the v0 branch. See docs/roadmap.md for phase status, and Upgrading from 0.x to 1.0 to move a site.

Packages

Three published packages, released together at one version:

  • @forumone/throughline — throughline(), which registers the suite, and each part on its own subpath: publishing, approvals, the audit log, components, integrations, email, editorial reports, media, the field kit, and background jobs on Inngest or Payload Jobs
  • @forumone/throughline-design-system — the component contract and manifest, its lint, and the manifest's Payload blocks, rendering and admin components
  • @forumone/create-throughline — the scaffolder (pnpm create @forumone/throughline my-site), with the brand-neutral reference design system a new project starts from

Internal, non-published config packages:

  • @forumone/throughline-tsconfig — shared TypeScript configs
  • @forumone/throughline-eslint-config — shared ESLint flat config
  • @forumone/throughline-prettier-config — shared Prettier config

Using in a client project

The fastest path is the scaffolder:

pnpm create @forumone/throughline my-client-site

It asks a small set of questions and produces a pnpm monorepo with Payload, the suite registered by throughline(), and an Inngest endpoin

Read from source at commit 4fefe9156715OBSERVED · 2026-10-07
Advertisement
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code
claude mcp add throughline-tsconfig --env APPROVAL_TOKEN_SECRET=${APPROVAL_TOKEN_SECRET} --env INNGEST_EVENT_KEY=${INNGEST_EVENT_KEY} --env PAYLOAD_SECRET=${PAYLOAD_SECRET} --env RESEND_API_KEY=${RESEND_API_KEY} -- npx -y @forumone/[email protected]
claude-desktop
{
  "mcpServers": {
    "throughline-tsconfig": {
      "command": "npx",
      "args": [
        "-y",
        "@forumone/[email protected]"
      ],
      "env": {
        "APPROVAL_TOKEN_SECRET": "${APPROVAL_TOKEN_SECRET}",
        "INNGEST_EVENT_KEY": "${INNGEST_EVENT_KEY}",
        "PAYLOAD_SECRET": "${PAYLOAD_SECRET}",
        "RESEND_API_KEY": "${RESEND_API_KEY}"
      }
    }
  }
}
03

Exposed tools (79)

59 read · 19 write · 1 destructive. Blast radius: 1 tool can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.

ToolRiskDescription
2readTwo columns
3readThree columns
4readFour columns
Customread
FakereadFake integration
autoreadMedia\
build_landing_pagereadCompose a landing page from design-system blocks for a goal and an audience, as a draft.
centerreadCenter-aligned
checkwriteWhether a document would publish right now, without publishing it: every check
check_slugreadWhether a URL slug is free in a collection, before creating or renaming a document. Normalises it the way the slug field will (lowercase, hyphens, no accents), and if it is taken says by which document, including one in the trash, and suggests the first free alternative.
compactreadSmall vertical margin
compose_sectionreadFor a section no component fits: checks a composed section
create_draftwriteCreates a new draft of a content type from the fields
defaultreadStandard vertical margin
describe_content_typereadWhat a content type is made of, before creating or editing one: every field an author may set, with its type, limits, whether it is required, a select\
design_guidereadThe design system, for choosing and filling blocks. With
draft_postwriteWrite a new post (or another article-like content type) from a topic and notes, as a draft.
edit_blockswriteChanges the blocks in one blocks field of a draft —
findreadFinds content to work on or link to. With a query across every content type, or within one
find_anti_patternreadScans a proposed composition for known design anti-patterns (multiple Heroes, Hero at the bottom of a page, etc.). Returns matches with explanation and suggested alternatives. Use before publishing to surface editorial issues.
find_content_needing_attentionreadLists published content that needs a review, by check: pages not revised within their threshold, pages missing a meta description or image, images in use without alt text, and any other checks the site configures. Each result names the document, why it is listed, and its admin link. Use for
find_relatedreadLooks up something a document links to — an author, a client, a taxonomy term, an image — by a few letters of its name, to get the id a field needs. Images come back with their alt text and dimensions. Which kinds exist is in each field\
getreadReads content. With
get_approval_statusreadReturns the current status of an approval request including who decided, when, and any notes. Read-only; no audit record is written.
get_change_historyreadReturns the complete chronological history of actions on a single document, including diffs. Use to answer
get_content_calendarreadOne month of the content calendar: scheduled publishes, past publishes and events, by day in the site\
get_contractreadReturns the full contract for a named component, including intent, composition rules, content fields, variants, tokens, accessibility requirements, examples, and anti-examples.
get_documentwriteReads one document in the shape the write tools accept: the fields an author may set, relationships as ids, and blocks with their ids. The latest draft by default; pass draft: false for the published version. Also its status and its admin and preview links.
get_integration_statuswriteDetailed status for a single integration instance — including its last sync time, last error, and current configuration metadata (config values themselves are admin-only and not returned).
get_publish_statuswriteReturns the current publishability of a document without actually publishing: a dry run of every check
get_ready_to_publishwriteTake an existing draft through every publishing check and, with your go-ahead, publish or request approval.
get_recent_failuresreadRecent failed operations across all MCP servers. Use for
get_tokensreadReturns the design tokens a component consumes plus the configurable token-backed props and their allowed values.
get_variantsreadReturns the available variants for a component, with descriptions and guidance about when to use each.
insert_blockwriteAdds one block to a blocks field of a draft —
inversereadDark background
largereadOversized display treatment
lgreadLarge
linkedreadEntire card is clickable
list_componentsreadReturns the list of components available in the design system. Use this to discover what components exist before composing content.
list_integration_typesreadLists the integration plugins available in this deployment. Use when answering
list_integrationswriteLists configured integration instances and their last-sync status. Use to answer
list_job_failuresreadBackground jobs that ran out of retries, and healthchecks that failed, most recent first: what failed, when, the error, and the run id to find it in the job runner. Use for
list_my_requestsreadReturns approval requests the current user has submitted, optionally filtered by status. Use to answer
list_my_workreadWhat is waiting on somebody: documents with unpublished changes, newest first, and scheduled publishes, soonest first, each with its admin link. These are the dashboard\
list_pending_approvalsreadReturns pending approval requests routed to one of the caller
mdreadMedium (default)
move_blockwriteMoves one block within its blocks field: to the start, to the end, or after another block. Checked against the composition rules, which care about order.
oddreadTakes a bare string.
primaryreadStandard background
publishwriteTakes a document live, or changes what is live.
query_auditreadGeneral-purpose audit log query. Filter by collection, document, actor, action, server, date range, or failure-only. Returns chronologically ordered results, most recent first. Use when you need a custom view of system activity that doesn
remove_blockdestructiveRemoves one block from a draft
request_approvalreadKicks off the approval workflow for a document that requires approval before publishing. Provide a clear changesSummary explaining what changed and why; approvers see this in their notifications. Returns the approval ID, expiration time, and the list of approvers who were notified.
respond_to_approvalreadRecords an approver
rollbackreadRolls a document back to a prior version from Payload
save_draftwriteSaves a draft. Without
save_recipewriteSaves a recipe as a draft, or updates a draft one by id. Refused if it does not pass validate_recipe, or if the recipe is approved (an approved recipe does not change: save a new one). A person approves it in the admin; until then no page using it can be published.
schedule_publishwriteSchedules a future publish. Validates the document would currently pass the preflight pipeline (composition, accessibility, required fields, embargo, approval), then stores
search_contentreadFinds documents by a few letters of their title, across every collection the admin
secondaryreadSubtle grey background
smreadSmall
spaciousreadLarge vertical margin
splitreadText on one side, media on the other
squareread1:1
startwriteLeft-aligned
staticreadNo link; presentational only
suggest_for_intentreadGiven a natural-language description of what the author wants to accomplish, returns ranked component recommendations with reasoning. Optionally accepts the existing page context so duplicate Heroes / composition conflicts surface as warnings on the suggestions.
test_integrationreadCalls the integration
trigger_syncwriteRuns a real sync of one integration now, exactly as the admin\
unpublishreadUnpublishes a published document by reverting it to draft. Use when content needs to be removed from the public site without deleting it. Fires content/page.unpublished so revalidation and integrations can react.
update_blockwriteChanges fields of one block in a draft, by the block
update_draftwriteChanges fields of a document\
validate_compositionreadValidates a proposed page layout against the design system
validate_recipereadChecks a recipe — { contract, tree } — against the design system as it is now, without saving it. Returns every problem with its path in the tree and what to do instead. Run it until it returns none, then save_recipe.
what_changed_in_rangereadSummarized activity over a time range, grouped by action type, actor, and target collection. Use for
who_changed_whatreadA user
xlreadExtra large
xsreadExtra small
04

Trust audit

BLOCKgrade F · trust 36/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.

LayerWhat it checksResult
L0Provenance & inventoryFAIL
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfaceWARN
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (3 observation(s))
Network
declared (7 observation(s))
Shell
none-observed
Dependencies
not all pinned
Secrets in source
found

Findings (25)

HIGHInventory / provenance · inv.suspicious_name · CWE-1104
apps/playground/src/payload.config.ts
payload.config.ts
Why it matters. member named after an attack tool
Fix. remove or justify
HIGHInventory / provenance · inv.suspicious_name · CWE-1104
packages/create-throughline/src/templates/base/apps/web/src/payload.config.ts.template
payload.config.ts.template
Why it matters. member named after an attack tool
Fix. remove or justify
HIGHInventory / provenance · inv.suspicious_name · CWE-1104
packages/throughline/bin/payload-cli.d.mts
payload-cli.d.mts
Why it matters. member named after an attack tool
Fix. remove or justify
HIGHInventory / provenance · inv.suspicious_name · CWE-1104
packages/throughline/bin/payload-cli.mjs
payload-cli.mjs
Why it matters. member named after an attack tool
Fix. remove or justify
HIGHHard-coded secrets · secret.db_uri · CWE-798, CWE-321
apps/playground/.env.example:1
DATABASE_URI=postgres://postgres:postgres@localhost:5433/throughline_playground
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
packages/create-throughline/src/templates/base/apps/web/playwright.config.ts:37
url: `http://127.0.0.1:${String(site.port)}${site.home}`,
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
packages/create-throughline/src/templates/base/apps/web/playwright.config.ts:56
baseURL: site.baseURL ?? `http://127.0.0.1:${String(site.port)}`,
MEDIUMHard-coded secrets · secret.db_uri · CWE-798, CWE-321
.github/workflows/scaffold.yml:33
DATABASE_URI: postgres://ci:ci@localhost:5432/ci
MEDIUMHard-coded secrets · secret.db_uri · CWE-798, CWE-321
docs/getting-started/scaffolding-a-project.md:47
# DATABASE_URI=postgres://postgres:dev@localhost:5432/throughline
MEDIUMHard-coded secrets · secret.db_uri · CWE-798, CWE-321
packages/create-throughline/src/scaffold-migrations.test.ts:206
const DIRECT = 'postgres://u:[email protected]/neondb'
MEDIUMHard-coded secrets · secret.db_uri · CWE-798, CWE-321
packages/create-throughline/src/scaffold-migrations.test.ts:207
const POOLED = 'postgres://u:[email protected]/neondb'
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
packages/throughline/src/access/coreCollections.test.ts:23
secret: 'test-secret-test-secret-test-secret',
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
packages/throughline/src/access/coreCollections.test.ts:75
secret: 'test-secret-test-secret-test-secret',
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
packages/throughline/src/editorial/calendar/calendar.integration.test.ts:54
secret: 'test-secret-test-secret-test-secret',
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
packages/throughline/src/editorial/health/health.integration.test.ts:72
secret: 'test-secret-test-secret-test-secret',
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
packages/throughline/src/editorial/palette/search.integration.test.ts:48
secret: 'test-secret-test-secret-test-secret',
MEDIUMFilesystem / path · mcp.destructive_tools · CWE-22, CWE-59
remove_block
Why it matters. 1 tool(s) can delete or overwrite
Fix. prefer a read-only mode or scoped tokens; the page states the blast radius
LOWInventory / provenance · inv.hidden_file · CWE-1104
.prettierignore
.prettierignore
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWInventory / provenance · inv.hidden_file · CWE-1104
.prettierrc.json
.prettierrc.json
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWInventory / provenance · inv.suspicious_name · CWE-1104
docs/spec/C2-design-contract.md
C2-design-contract.md
Why it matters. member named after an attack tool
Fix. remove or justify
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
packages/create-throughline/src/templates/base/apps/web/scripts/lib/target.ts:1
import { resolveDatabaseConnection } from '../../src/lib/database'
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
packages/design-system/src/testing/blockInvariants.test.ts:20
'../../../create-throughline/reference-ds/src/components',
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
packages/design-system/src/testing/checkBlockProps.test.ts:101
const bin = path.resolve(here, '../../bin/check-block-props.mjs')
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
packages/design-system/src/testing/checkBlockProps.test.ts:177
const bin = path.resolve(here, '../../bin/check-block-props.mjs')
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
packages/design-system/src/testing/checkBlockProps.test.ts:186
dir = await mkdtemp(path.join(here, '../../.tmp-check-block-props-'))

Gates applied: no_behavioural_pass.

Audited 2026-10-07 · audit v0.4.1 · source sha 4fefe9156715full audit observations/trust-audit/mcp-server/forumone__throughline.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-074fefe9156715BLOCKF36first audit
06

Questions

What tools does @forumone/create-throughline expose?

79 in total: 59 read-only, 19 that write, and 1 that can delete or overwrite (remove_block). Every one is listed on this page with its risk.

Is @forumone/create-throughline safe to connect to an agent?

No — not without reading the findings first. The audit graded it F (36/100) and found 5 critical or high issues in the source. Each one is listed on this page with the file and line it is on. Separately from the audit: 1 of its tools can destroy data, so scope the token you give it to what you actually need.

What credentials does @forumone/create-throughline need?

It reads APPROVAL_TOKEN_SECRET, INNGEST_EVENT_KEY, PAYLOAD_SECRET and RESEND_API_KEY from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How current is this page?

The grade is for one exact copy of the source (4fefe9156715), read on 2026-10-07. The repository is watched and re-audited when it changes.

Advertisement