Signal, beacon and spec MCP tools
Reference for search_signals, get_signal, get_signal_source, create_signal, list_beacons, get_beacon, list_specs, get_document_markdown, get_spec_delivery and get_history.
nima's pipeline MCP tools let an agent read the Signal, Beacon, Spec, PR, Closed pipeline and file new evidence into it. Ten tools cover it: nine are read-only and one, create_signal, writes. Each is a loopback call to a REST route, so the same guards, scopes, throttling and workspace scoping apply as for a direct API call.
On for every workspace. list_specs, get_document_markdown and get_spec_delivery read documents, whose routes are declared under the plan feature documents; a workspace whose plan lacks it can get 403 INSUFFICIENT_PERMISSIONS with details.feature set to documents. Handle that response. get_signal_source needs an owner or admin.
Pipeline tools at a glance
The table lists each tool, the scope its token needs, the REST route it calls and whether it writes. To connect a client, see the MCP server overview. The routes are documented in Signals, Beacons, Specs and Events.
| Tool | Scope | Route | Reads or writes |
|---|---|---|---|
search_signals | signals:read | GET /v1/signals | Read |
get_signal | signals:read | GET /v1/signals/{id} | Read |
get_signal_source | sources:read | GET /v1/signals/{id}/source | Read (live call to the source system) |
create_signal | signals:write | POST /v1/signals | Write |
list_beacons | signals:read | GET /v1/beacons | Read |
get_beacon | signals:read | GET /v1/beacons/{id} | Read |
list_specs | documents:read | GET /documents | Read |
get_document_markdown | documents:read | GET /documents/{id}/markdown | Read |
get_spec_delivery | documents:read | GET /documents/{id}/delivery | Read |
get_history | signals:read | GET /v1/events | Read |
Every id these tools take is a UUID returned by another tool. Do not invent one. Input is validated strictly: an unknown key or a value outside its range comes back as a tool result with isError: true and Invalid arguments, not as a protocol error. The list tools (search_signals, list_beacons, list_specs) return trimmed summaries. The detail tools return the full record.
get_signal_source needs sources:read, which only an owner or admin can grant. The other scopes can be granted by any member. See Scopes and permissions.
search_signals tool
search_signals returns one page of the workspace's signals, filtered and sorted, as trimmed summaries. Use it to find what people reported, then get_signal for the full text of one.
/v1/signalssignals:readMCP toolsearch_signalssearchstringFull-text query, up to 200 characters. It matches the signal's content, preview, extracted intent and PM notes, and its extracted stakeholders and product areas.
searchModeenumword (default) requires a whole word: "fracti" does not match "fractional". prefix matches words that start with the term.
statusenumOne status: pending, processing, extracting, classified, ready, merged, dismissed, failed or resolved. ready means fully classified. classified is legacy: current signals go from extracting to ready. resolved means the spec the signal fed shipped. The tool takes a single value, not a list. The enum also lists a deprecated waiting_for_response that new signals never carry.
classificationenumOne of bug, feature_request, spec_drift, customer_feedback, performance, documentation, question, noise.
sourceenumThe integration the signal arrived from: slack, github, manual, hubspot, web_performance, granola, posthog, sentry, linear, clickup or webhook.
impactenumlow, medium or high.
sortByenumpriority (default), newest or volume. volume is the number of duplicates folded in.
pageinteger1-based. Defaults to 1. Keep the filters and limit unchanged while paging.
limitinteger1 to 50. Defaults to 20. The REST route allows 100; the tool does not.
Each row carries 13 fields: id, preview, status, classification, impact, origin (internal, external or customer), source, sourceCount, priorityScore, extractedStakeholder, extractedProductArea, createdAt and updatedAt. The response also carries the pagination envelope described in Pagination.
Paging stops at 3000 rows. A request whose page and limit reach past row 3000 fails with a validation error naming maxOffset: 3000; narrow the filters instead of paging deeper. Signals folded into a duplicate never appear in the list, so status=merged returns an empty page.
The tool does not expose the REST route's filter parameter, grouped, inSpec, sortOrder or groupBy. It has no way to filter by date range or by account.
get_signal tool
get_signal returns one signal in full, by id.
/v1/signals/{id}signals:readMCP toolget_signaliduuidrequiredA signal id from search_signals.
The result is the complete signal: the full content (not just the preview), status, classification, impact, origin, source, sourceChannel, extractedIntent, extractedStakeholder, extractedProductArea, priorityScore, pmNotes, verdict, dismissReason, linked entities, and sourceDocument. sourceDocument.available says whether a fuller original exists that get_signal_source can fetch. When it is false, only the stored excerpt exists.
get_signal_source tool
get_signal_source fetches the original document behind a signal, live from its source system, using the workspace's own integration: the whole Slack thread, the full GitHub PR or issue discussion, the HubSpot record, the Granola meeting note, the PostHog or Sentry issue, the Linear issue with its comments. nima stores only the excerpt that produced the signal, so call this only when the surrounding context matters.
Each source also trims what it returns: a HubSpot record section is cut at 16,000 characters and its email thread at 50 messages of up to 4,000 characters each; a Sentry issue keeps its last 15 stack frames; a PostHog issue's latest event is cut at 12,000 bytes of JSON.
/v1/signals/{id}/sourcesources:readMCP toolget_signal_sourceiduuidrequiredA signal id from search_signals.
cursorstringThe nextCursor from the previous page of the same signal. Opaque.
partenumsummary (default) returns the document as nima's producer saw it. full asks for everything the source has, for example a Granola meeting transcript.
The caller must be an owner or admin. The tool is annotated openWorldHint: true because it reaches an external system, and it sits on the soft rate-limit tier (300 requests per 10 seconds). Fetch one signal at a time.
The result carries these fields:
| Field | Meaning |
|---|---|
availability | live (fetched now), stored (manual, webhook and web-performance signals: nima is the source) or unavailable |
reason | Set when availability is unavailable; see the list below |
url, title | Deep link and title in the source system, set whenever known |
format, content | markdown or text, and the document body (null when unavailable) |
ingestedAt, fetchedAt | When nima captured the excerpt and when this call fetched the document |
changedSinceIngest | true or false when nima can tell whether the source changed; null when it cannot (always null for stored content) |
nextCursor | Pass it back as cursor for the next page; null on the last page |
duplicates | Up to 50 signals merged into this one, each with its own original |
A page is about 40,000 bytes of content. Follow nextCursor until it is null to read a long document.
An unavailable result carries one reason:
missing_reference: the signal predates source references, so there is nothing to rebuild the fetch from.integration_disconnected: the workspace disconnected the integration.integration_mismatch: the integration was reconnected to a different workspace, portal or installation than the signal names.not_found_at_source: the document was deleted, expired or merged away upstream.access_denied_at_source: nima's bot left the channel, the app was uninstalled or the token lost access.rate_limited: the source system throttled the call. Retry later.source_error: the source system failed.workspace_pending_deletion: the workspace is in its 7-day deletion hold and nothing is fetched.source_terms_pending: the source's full document is switched off (Granola transcripts).
Stored content from a manual or webhook signal may already have been rewritten by extraction. It is not guaranteed to be the verbatim original.
create_signal tool
create_signal files one piece of raw feedback (a bug, a request, a complaint, an observation) into the workspace so it enters the pipeline. nima classifies it and extracts from it asynchronously, so the call returns at once with the signal in pending status.
/v1/signalssignals:writeMCP toolcreate_signalcontentstringrequiredThe feedback in the reporter's own words, 1 to 10,000 characters. Include what happened, who said it and why it matters.
sourceLabelstringWhere it came from, for example customer call or support ticket 412. Up to 100 characters. Defaults to manual.
stakeholdersstring[]People or accounts affected. Up to 10 items of up to 80 characters each.
productAreasstring[]Product areas touched. Up to 10 items of up to 80 characters each.
The result is the created signal as JSON, with its id and status of pending. The signal's source is manual, and your sourceLabel is stored as its channel.
Two things to design around. create_signal is not idempotent: calling it twice with the same text creates two signals, and there is no idempotency key. nima never merges signals automatically, so both stay in the pipeline. And the tool is annotated destructiveHint: false, idempotentHint: false, so a client may ask for confirmation. It sits on the soft rate-limit tier. Do not file something you are not sure is real: it enters the same queue as customer evidence and can seed a beacon.
list_beacons tool
list_beacons returns one page of the workspace's beacons, ranked clusters of related signals and the unit a PM decides on.
/v1/beaconssignals:readMCP toollist_beaconsstatusenumOne of forming, ready, held, promoted, dismissed. ready means enough evidence to act on. The tool takes one value, not a list.
searchstringUp to 200 characters, matched against title and summary. A beacon key such as BCN-142 finds that beacon.
sortByenumrank (default, highest first), newest or evidence (most member signals first).
pageinteger1-based. Same 3000-row paging cap as search_signals.
limitinteger1 to 50. Defaults to 20.
Each row carries 16 fields: id, key (BCN-<n>, sequential per workspace and never reused), title, summary, status, rankScore (0 to 100), rankBreakdown, evidenceCount, sourceCounts, stakeholderCount, latestEvidenceAt, promotedSpecId, disposition, autoPromotedAt, createdAt and updatedAt.
rankBreakdownholds the four terms of the rank, each with its normalizedvalueand coefficient, plusscoreandcomputedAt. The terms are severity (0.35), reach (0.30), weight (0.20) and recency (0.15). It isnulluntil the first ranking pass. See How nima decides.dispositionisfixwhen nima's placement judge called the ask a plain defect,decidewhen a person has to choose, andnullon a beacon a person grouped by hand.promotedSpecIdis set only whenstatusispromoted. Pass it toget_document_markdownorget_spec_delivery.autoPromotedAtis set only when nima promoted the beacon itself. Automatic promotion is off for workspaces unless the nima team enables it, so it isnullfor most.
get_beacon tool
get_beacon returns one beacon in full, by id.
/v1/beacons/{id}signals:readMCP toolget_beaconiduuidrequiredA beacon id from list_beacons.
The result is the whole beacon record: everything list_beacons returns plus heldReason (set only when held), formedAt, pmNotes and previewSignalIds. previewSignalIds lists at most 3 member signal ids, highest priority first. It is not the full member list, and no MCP tool returns the full list. Read the three with get_signal, or search for more with search_signals. accountRollup (the attributed accounts and ARR at stake, omitted when it could not be computed) is also returned.
list_specs tool
list_specs returns one page of documents, specs by default. A spec is the technically grounded document an AI coding agent executes.
/documentsdocuments:readMCP toollist_specssearchstringUp to 200 characters, matched against titles.
statusenumThe spec stage: draft, in_review, approved, in_progress or shipped.
typeenumspec (default), epic or document. The tool defaults to spec; the REST route with no type returns every kind.
pageinteger1-based. Defaults to 1.
pageSizeinteger1 to 50. Defaults to 20. Note the name: documents use pageSize, signals and beacons use limit.
Each row carries id, title, type, status, cardId (the ticket the spec became, or null), ticket (that ticket's PREFIX-N key), prCount, prState (the furthest any linked PR reached: merged, open or closed, null when none), beaconId, beaconKey, signalCount, createdAt and updatedAt, plus a specMetadata object holding generation, status, priority, effort, ownerId and dueDate.
When specMetadata.generation is present, the spec came from a nima spec-generation run. Its stage is researching, deciding or writing while the run is going, and the body is empty or partial: it is not abandoned. A stage of failed means the run gave up and the body will not change on its own.
get_document_markdown tool
get_document_markdown returns one document, usually a spec, rendered as Markdown, in windows you page through.
/documents/{id}/markdowndocuments:readMCP toolget_document_markdowniduuidrequiredA document id from list_specs.
offsetintegerWhere the window starts. Take it from pagination.nextOffset. Defaults to 0.
limitintegerMaximum window size, 1 to 12,000. Defaults to 8,000. Offsets and sizes count UTF-16 code units, and one extra unit may be added so an emoji is not split.
The result carries id, title, markdown (the window), version, updatedAt, status (null for a plain document), cardId, generationStage and pagination with offset, limit, totalCharacters and nextOffset. Follow nextOffset until it is null to read the whole body. The tool takes no version input, but version is returned on every window: keep it unchanged across windows, and if it changes, restart at offset 0. A generationStage of researching, deciding or writing means the draft is partial; failed means the run gave up.
get_spec_delivery tool
get_spec_delivery says where one spec is in Spec, PR, Closed: its status, the ticket it became, and up to 20 pull requests linked to that ticket with each one's latest drift check.
/documents/{id}/deliverydocuments:readMCP toolget_spec_deliveryiduuidrequiredA spec id from list_specs.
The result carries these parts:
status: the spec stage, ornull.card:id,ticket(PREFIX-N),title,boardId,columnandisDone(the card sits in a done column).nullwhen the spec was never promoted to a ticket. An unpromoted spec returnscard: nulland no pull requests.pullRequests: up to 20, most recently updated first. Each hasid,number,title,state(open,closedormerged),authorLogin,repoFullName,mergedAt,updatedAtanddrift.drift, per pull request:nullwhen that PR was never checked. Otherwisestatus(pending,analyzing,completedorfailed),hasDrift(the verdict),sections,matchStrategy(card_linkorfile_path: how the PR was tied to the spec),commitShaandcheckedAt. Each entry insectionshassectionRef,verdict(aligned,driftedornot_addressed),summary,prdExcerptandrelevantFiles.sectionsis empty until the check completes.
The top-level latestDrift field is deprecated. It is only the newest of the per-PR verdicts; read pullRequests[].drift instead. See Delivery: Spec to PR to Closed.
get_history tool
get_history returns the recorded event history of one signal, beacon, spec, pull request or ticket, newest first, including events on the things it flowed into. For a signal, that means its beacon, spec and PR.
/v1/eventssignals:readMCP toolget_historysubjectKindenumrequiredWhat the id refers to: signal, beacon, spec, pr or ticket.
subjectIduuidrequiredThe subject's id.
limitintegerMaximum events, 1 to 200. Defaults to 50.
The result carries subjectKind, subjectId, title (the nima-authored title, such as a beacon or spec title or PR #n, or null when the subject no longer exists) and events. Each event has id, type, subjectKind, subjectId, viaLineage (true when the event is on a downstream subject matched through lineage), actorKind and occurredAt.
Events carry ids, types and timestamps only. Their payloads are hidden on purpose, because they can hold question text or a person's reason. The history is workspace-wide, not limited to what the caller watches, which is why it needs signals:read rather than a watch scope. The event types are listed in Events.
What the pipeline MCP tools cannot do
The pipeline MCP tools read the pipeline and file signals. They do not steer it. No MCP tool promotes, holds, dismisses, edits or merges a beacon, removes signals from a beacon, dismisses or merges a signal, or answers a spec's open question. The MCP tools also have no structured filter: search_signals and list_beacons take only the flat parameters above.
See The loop for how a beacon becomes a spec. The web app cannot do these either: it is an admin panel, and links nima sends to a beacon or spec open the Integrations page.