Skip to content

APIs

Componecat exposes two programmatic surfaces — a REST API for scripts and integrations, and an MCP server for AI agents. They share the same authorization model, so a token’s access means the same thing on either one. The examples below use the hosted host, https://app.componecat.ai; substitute your own instance’s host if you self-host.

The REST API at /api/rest/v1 is the programmatic surface for CI/CD pipelines, scripts, and external systems. It’s authenticated with a personal access token and covers the core catalog operations — browsing, search, and the mutations behind everything you can create or change.

https://app.componecat.ai/api/rest/v1

Catalog search takes the same query language the UI does — pass the expression as q to GET /catalog/search:

/api/rest/v1/catalog/search?q=lifecycle:production AND NOT tag:deprecated

Each search result carries the entity’s custom field values as fields, in the same shape an entity’s detail returns, so an export can page through search instead of fetching every entity one by one.

A semantic clause works here too — q=kind:component ~"issues customer refunds" — and each result then carries its relevance, the similarity to the clause text. For an organization without search by meaning (no embedding model, or a plan that doesn’t include it) the request fails with 400 and the problem’s code is SemanticSearchUnavailable; if the model is set up but fails or times out, the request fails with 503 and the code SemanticSearchFailed — safe to retry.

An entity’s current scorecard results — score, attained level, and a per-rule pass/fail breakdown — are available alongside its other sub-resources:

GET /api/rest/v1/catalog/{id}/scorecards

Scorecards themselves — the standards, not just the results — are a resource too: list them, read one’s definition (scope, rules, weights), or pull its rollup report (distribution, breakdown by team/kind/ladder level, per-rule failure counts, and the score trend, matching the app’s Report tab):

GET /api/rest/v1/scorecards
GET /api/rest/v1/scorecards/{id}
GET /api/rest/v1/scorecards/{id}/report

This surface is read-only, the same as the MCP scorecard tools — defining a standard is done from the organization-settings UI.

An entity’s impact analysis — its blast radius across your dependency relationship kinds — is another sub-resource:

GET /api/rest/v1/catalog/{id}/impact-analysis?direction=upstream&kindKeys=depends-on,calls&maxDepth=5

All parameters are optional. kindKeys (comma-separated or repeated) names the relationship kinds to follow; without it, every kind marked as a dependency kind is followed, and the request returns 422 with the code NO_DEPENDENCY_KIND if there is none. direction is downstream (the default), upstream or both, and maxDepth is 1–50 (default 10). Each entity in the response carries its depth, the kindKeys it was reached by, and the relationshipIds reaching it. The older kindKey parameter still works and is added to kindKeys.

The relationship graph around an entity, and the paths connecting two entities, are sub-resources too:

GET /api/rest/v1/catalog/{id}/graph?kinds=depends-on,calls&direction=both&maxDepth=3&filter=lifecycle:production
GET /api/rest/v1/catalog/{id}/paths/{targetId}?kinds=depends-on&direction=outbound&maxDepth=6&maxPaths=3

They return the same data as the GraphQL traverseGraph and findPaths queries described below. kinds (comma-separated or repeated) names the relationship kinds to follow — omit it to follow every kind — and direction is outbound (the default), inbound or both. For /graph, maxDepth is 1–50 (default 5) and filter is a query language expression; the response lists nodes (each with its depth, the root first), edges, and truncated. For /paths, maxDepth is 1–20 (default 10) and maxPaths 1–20 (default 5); the response lists paths, shortest first, each with its length, nodes and edges. Every edge carries the relationship’s relationshipId, relationshipKindKey, its stored sourceEntityId and targetEntityId, description, source (how it was asserted), confidence, provenanceRef, assertedAt, lastObservedAt and attributes.

These three endpoints answer bad input with a problem-details body: 400 for an invalid direction or a maxDepth / maxPaths outside its range, 422 for an unknown relationship kind, an invalid filter, or a path whose two ends are the same entity, and 404 for an entity that doesn’t exist.

The wiki is available under /wiki, gated by the wiki access category: list pages (filter by title text with q, or by a reference such as @platform or $kind:service with ref), read, create, update and delete a page by its slug, list a page’s references, and find the pages that reference a catalog object:

GET /api/rest/v1/wiki/pages?q=on-call&ref=@platform
POST /api/rest/v1/wiki/pages
GET /api/rest/v1/wiki/pages/conventions/service-tiers
PATCH /api/rest/v1/wiki/pages/conventions/service-tiers
DELETE /api/rest/v1/wiki/pages/conventions/service-tiers
GET /api/rest/v1/wiki/pages/conventions%2Fservice-tiers/references
GET /api/rest/v1/wiki/referencing?targetType=TEAM&targetId={id}
GET /api/rest/v1/wiki/source
POST /api/rest/v1/wiki/source/sync

A page’s tags are a list of references, each exactly one reference such as $kind:service or @platform; a create or update with any other tag returns 422 with the code WIKI_TAG_INVALID. Deleting a page moves it to Trash.

To avoid overwriting someone else’s edit, send the page’s updatedAt from the read your change is based on as expectedUpdatedAt in the PATCH body (or the updateWikiPage input over GraphQL). If the page has changed since, nothing is saved and the request returns 409 with the code WIKI_PAGE_CONFLICT and the page’s currentUpdatedAt; read the page again and reapply the change (over GraphQL, wikiPageById(id) finds the page even if it was renamed meanwhile). Without expectedUpdatedAt the update applies to the current version. Either way, an update or delete that races another save of the same page returns the same 409 rather than overwriting it; repeat the request.

A slug’s / can be sent plain or encoded as %2F. Encode it on the /references route, and when reading a page whose slug ends in /references (/wiki/pages/api%2Freferences): sent plain, that path lists the references of page api instead.

While the wiki is sourced from a git repository it is read-only: page writes return 409 with the code WIKI_EXTERNALLY_MANAGED, and the pages should be edited in the repository instead. POST /wiki/source/sync queues a sync from the repository and returns 202; read GET /wiki/source for the outcome. When a sync is already running nothing new is queued, and the response’s status is already_running instead of queued. It returns 404 when the wiki has no git source, and 409 with the code WIKI_SYNC_PAUSED while Documentation Syncing is turned off on the wiki’s integration.

The full endpoint reference is the OpenAPI document, published for tooling and SDK generation and readable without a token. It lists every endpoint and describes every request and response field, the search filters, and the shape of custom field values:

https://app.componecat.ai/api/rest/v1/openapi.json

Teams carry externalId and externalSource when they’re synced from another system — for an Atlassian team, externalId is its Atlassian team id — so a script can map a Componecat team to its counterpart. See Team sync.

POST /teams/{id}/reassign-entities moves catalog entities from the team in the path to toTeamId: every entity it owns, or only those in entityIds, up to 5,000 per call. Only organization admins can call it, and the key needs write access to both teams and entities. It’s all-or-nothing: if any listed entity isn’t owned by the team, nothing moves and the response is 422. The response counts the moved entities and, in descriptorManagedCount, those defined in a componecat.yaml whose owner: may set the owner back on the next scan.

The web app itself runs on the GraphQL API at /api/graphql, and it carries a few reads the other surfaces don’t yet have. The main ones are graph traversal and path finding: traverseGraph returns the subgraph reachable from one entity — every entity reached, with its hop count from the start, and every relationship followed — in a single request, instead of a chain of one-hop lookups.

query {
traverseGraph(
root: { ref: "component://payments/checkout-api" }
kinds: ["depends-on", "provides-api-for"]
direction: OUTBOUND
maxDepth: 3
filter: "lifecycle:production"
) {
truncated
nodes { depth entity { id displayName ref } }
edges {
source { id }
target { id }
kind { key }
relationship { id description source confidence }
}
}
}
Argument Meaning
root The starting entity, as exactly one of id or ref (kind://namespace/name).
kinds Relationship kind keys to follow. Omit it to follow every kind your organization defines; an unknown key is an error.
direction OUTBOUND follows relationships from source to target (what the entity depends on), INBOUND from target to source (what depends on it), BOTH either way. Defaults to OUTBOUND.
maxDepth Hops from the root, 1–50. Defaults to 5; values outside the range are clamped.
filter A query language expression. Only entities matching it are returned or traversed through, so anything reachable only through a non-matching entity is left out. The root is always returned.

Each node’s depth is its shortest hop count from the root (the root is 0). Each edge carries the stored relationship, so its description, source, and confidence come with it. Deleted entities are skipped, and traversal never crosses into another organization. A result holds at most 2,000 entities and 10,000 relationships; when a larger graph hits either cap the walk stops at that depth, the response holds what was reached so far, and truncated is true, rather than failing. Lower maxDepth or name fewer kinds to fit; a filter narrows which entities are returned and expanded but does not reduce the relationships examined against the edge cap, so truncated can be true with fewer than 10,000 relationships in the response.

subgraph returns the graph of a set of entities you already have — a page of search results, a collection’s items — rather than a neighborhood: the entities you name, and every relationship whose source and target are both among them. It is what the catalog and collection graph views draw. Leave entityIds out and it returns the graph of the whole catalog — every entity in your organization, in display-name order — which is what the Graph page draws.

query {
subgraph(
entityIds: ["<uuid>", "<uuid>", "<uuid>"]
kinds: ["depends-on"]
) {
truncated
nodes { entity { id displayName ref } }
edges { source { id } target { id } kind { key } relationship { id } }
}
}
Argument Meaning
entityIds The entities to include. Nodes come back in this order, each with depth 0; duplicates are returned once, and an id that is deleted or not in your organization is left out rather than reported. Omit it for every entity in your organization, ordered by display name.
kinds Relationship kind keys whose relationships to include. Omit it to include every kind; an unknown key is an error. Naming kinds narrows the edges, never the nodes.

The caps are the same as traverseGraph’s: at most 2,000 entities (ids past the first 2,000 are dropped; without entityIds, the catalog is cut after the first 2,000 in display order) and 10,000 relationships, with truncated set to true when either is hit.

findPaths answers how two entities are connected: the paths from one entity to another across the relationship kinds you choose, shortest first.

query {
findPaths(
from: { ref: "component://payments/checkout-api" }
to: { ref: "component://payments/ledger-db" }
kinds: ["depends-on", "provides-api-for"]
direction: OUTBOUND
maxDepth: 6
maxPaths: 3
) {
length
nodes { displayName ref }
edges {
source { ref }
target { ref }
kind { key }
relationship { description source confidence }
}
}
}
Argument Meaning
from, to The two entities, each as exactly one of id or ref. They must be different entities.
kinds Relationship kind keys a path may follow. Omit it to allow every kind your organization defines; an unknown key is an error.
direction Which way each hop follows its relationship, from from toward to: OUTBOUND from source to target, INBOUND from target to source, BOTH either way. Defaults to OUTBOUND.
maxDepth Longest path to return, in hops, 1–20. Defaults to 10; values outside the range are clamped, and longer paths are never returned.
maxPaths Most paths to return, 1–20. Defaults to 5; values outside the range are clamped.

Each path lists its edges in order from from to to, and the nodes along it, from first. Paths are simple — no entity appears twice in one — and two paths that differ in any hop, even only in a relationship’s kind, are distinct. The shortest path comes first; paths of the same length are compared hop by hop — first by the relationship kind’s display order (then its key, when two kinds share a display order), then by the name of the entity the hop reaches, compared case-sensitively. Each path’s type is TraversalPath. Each edge keeps its stored source and target, so with INBOUND or BOTH a hop can run from an edge’s target to its source. When the entities aren’t connected within maxDepth the result is an empty list, not an error. Paths never pass through a deleted entity or cross into another organization. In an extremely dense graph the search works within the same size caps as traverseGraph and returns the paths it found within them, so fewer paths than maxPaths may come back and the first path returned may not be the shortest that exists; lower maxDepth or name fewer kinds to narrow it.

impactAnalysis is the GraphQL form of impact analysis: an entity’s blast radius across your dependency relationship kinds.

query {
impactAnalysis(
entity: { ref: "component://payments/ledger-db" }
direction: UPSTREAM
maxDepth: 4
) {
kinds { key }
truncated
entities {
depth
entity { displayName ref }
kinds { key }
reachedVia { source { ref } target { ref } relationship { id } }
}
}
}
Argument Meaning
entity The entity to analyze, as exactly one of id or ref.
kindKeys Relationship kind keys to follow. Omit it to follow every kind your organization marks as a dependency kind; with none marked the query fails with the code NO_DEPENDENCY_KIND. An unknown key is an error.
kindKey Deprecated: a single kind key, added to kindKeys.
direction DOWNSTREAM follows relationships from source to target, UPSTREAM from target to source, BOTH either way. Defaults to DOWNSTREAM.
maxDepth Hops from the entity, 1–50. Defaults to 10; values outside the range are clamped.

entities lists every entity reached, nearest first, without the analyzed entity itself. Each one’s depth is its shortest hop count; its kinds are the relationship kinds that reach it at that distance, in display order, and reachedVia holds those relationships. The result’s kinds lists the kinds that were followed. Impact analysis runs on the same traversal as traverseGraph, so the same scoping and the same size caps apply, and truncated means the same.

similarEntities is “more like this”: the entities whose meaning is closest to the one you name, nearest first, never including the entity itself. It needs search by meaning for the organization — a plan that includes it and an embedding model; see Turning on search by meaning.

query {
similarEntities(entityId: "8a7c3f4e-1d2b-4c5a-9e6f-0b1c2d3e4f5a", limit: 5) {
relevance
entity { displayName ref kind { key } }
}
}
Argument Meaning
entityId The entity to find neighbors for. An unknown or deleted entity fails with NOT_FOUND.
limit How many entities to return. Defaults to 10, and never more than your instance’s semantic result limit.

relevance is the cosine similarity to the entity (−1 to 1, higher is closer), and only entities at or above the instance’s similarity threshold come back. An entity that was created moments ago may return an empty list until background indexing has embedded it. For an organization without search by meaning the query fails with the code SEMANTIC_SEARCH_UNAVAILABLE; ask semanticSearchAvailable (a Boolean!) first to know whether the caller’s organization has it. searchCatalog items also carry relevance when the query has a semantic clause; when the embedding model fails or times out while reading the clause, searchCatalog returns a queryError with code SEMANTIC_SEARCH_FAILED.

relevantDocumentation finds the documentation sections whose meaning is closest to a question, nearest first, each with the entity it documents. It needs search by meaning too.

query {
relevantDocumentation(text: "how do we rotate the payment gateway key", limit: 5) {
relevance
snippet
section { title sectionType }
entity { displayName ref }
}
}
Argument Meaning
text The question or topic, in plain language.
entityId Optional. Search only this entity’s documentation. An unknown or deleted entity fails with NOT_FOUND.
limit How many sections to return. Defaults to 10, at most 50, and never more than your instance’s semantic result limit.

relevance is the cosine similarity between the text and the section, and only sections at or above the instance’s similarity threshold come back. snippet is the passage around the text when the section contains it word for word, otherwise the passage around the longest word of the text (four or more characters) that the section contains, and otherwise the section’s opening. A section edited moments ago may be missing until background indexing has embedded it. For an organization with no embedding model the query fails with SEMANTIC_SEARCH_UNAVAILABLE; when the embedding model fails or times out, it fails with SEMANTIC_SEARCH_FAILED.

The Model Context Protocol server at /api/mcp is the surface built for AI agents — a tool catalog plus a browsable entity resource tree, with OAuth device flow authorization. Its search_catalog tool takes the same query language as the UI and the REST API, so an agent can express an entire question in one call — including a semantic clause, which lets an agent search by what a component does rather than what it’s called. When your organization has an embedding model, two more tools start from a plain-language description: find_relevant_entities returns the best-matching entities, and find_relevant_documentation returns the best-matching documentation sections. The wiki tools — list_wiki_pages, get_wiki_page, create_wiki_page, update_wiki_page, and get_guides_for, which finds the guides for a target written in the reference syntax — are gated by the wiki access category. See Connect AI agents for the full walkthrough.

https://app.componecat.ai/api/mcp

Catalogs are private and organization-scoped, so every surface requires authentication.

  • Personal access tokens — bearer tokens you create in your access-token settings. Used by the REST API and by non-interactive MCP clients.
  • OAuth device flow — the standard flow for interactive MCP agents, with dynamic client registration and automatic authorization-server discovery.

Tokens are scoped: you grant read or write access per resource category (catalog entities, teams, schema, wiki), and can scope a token to specific entities. Grant the least access that does the job.