MCP tool reference
Every tool the Clinical Terminal MCP server exposes: health-tech vendors, the hospitals and health systems that buy from them, the people who run both, and the signals moving between them, plus the few tools that publish a page. To connect a client first, start with the setup guide.
Each entry lists the tool’s parameters, an example arguments object, the fields that come back and the errors it can return. Access comes with a Landscape subscription, which covers every tool here except the two Analysis tools; those need an enterprise key.
Start here
Two tools answer most first questions. Reach for these before chaining anything.
For a question about one company, get_vendor_dossier takes a name and returns the profile, the hospital customers with the verbatim quote each was evidenced by, current products and recent signals — in one call, instead of four.
For a question about a market, find_vendors_for_problem takes a buyer problem in plain words and routes it to one of the KLAS Revenue Cycle segments, then returns that segment’s vendors ranked by traction.
One habit worth forming: an empty result here means not covered, never does not exist. Several tools say so explicitly in their response rather than handing back a bare empty list.
How responses work
- Every tool returns one text content block holding JSON. Most responses are pretty-printed; get_vendor_dossier, get_provider and get_persona return compact JSON.
- A missing key means unknown. Null and empty fields are dropped from every row rather than sent as null, so never read an absent field as zero or false.
- A response longer than 50,000 characters is cut off and ends with … [truncated at 50000 chars — narrow your query with filters or a smaller limit]. The two dossier tools keep to their own smaller budgets instead and list what they trimmed in meta.truncated.
- Arguments are validated against each tool’s schema before it runs. A wrong type, an out-of-range number or an unknown enum value is rejected with a validation error, so the tool-specific errors below are the ones a well-formed call can still hit.
- Numeric limits accept any number in range and are rounded down to a whole number.
Companies & vendors
The published health-tech vendors, their products, and their own websites. Coverage is uneven: nearly every vendor has a logo and a summary, fewer have a product catalog, so a thin result means thin data rather than a thin company.
get_vendor_dossier
The fastest path to any single-vendor question. One call by name returns the profile, hospital customers with their evidence quotes, current products, recent signals, ownership and what we know of the vendor’s website — instead of chaining a search, a fetch, a product lookup and a signal query.
Ask it: “Give me the dossier on Waystar.”
| Name | Type | Description |
|---|---|---|
| vendor required | string | A vendor name (“Waystar”), vendor id or numeric slug. A unique near-miss spelling is corrected automatically. 1–200 characters. |
{
"vendor": "Waystar"
}One object. Each section can independently be replaced by an unavailable marker (see errors).
| vendor | The vendor profile, as get_vendor returns it. |
| customers[] | Up to 10 customer relationships, strongest evidence first, with the evidence quote, evidence tier and citable article. |
| products[] | Up to 5 current products. |
| signals[] | Up to 5 recent signals, one per source article. |
| ownership[] | Acquisitions in either direction. Omitted when none are on file. |
| funding | Funding and M&A news we hold. roundsTracked is always false: this is news, not a round history. |
| siteMap | Pages we know on the vendor’s website, by category, with freshness. |
| meta | The query, the resolved vendor, spellingCorrected when a typo was fixed, and truncated listing anything trimmed to fit the budget. |
- Ambiguous name — Returns candidates[] (up to 5, each with id, name and domain) instead of a dossier. Call again with the id you meant.
- Unknown vendor — Entity not found: "<id>". followed by how to pass an id: the id from search_vendors, a numeric slug, or a terminalId. A vendor name is not an id.
- A section failed — That section becomes { unavailable: true, reason }; the rest of the dossier still comes back. Retry, or use the section’s own tool.
search_vendors
Find vendors by name, domain or category. Multi-word queries match on all words, then top up with looser any-word matches; results rank exact name matches first, then by how much news a company is generating.
Ask it: “Which vendors work in denials management?”
| Name | Type | Description |
|---|---|---|
| query required | string | Matched against name, domain and categories; multi-word phrases work. 1–200 characters. |
| limit optional | integer | Maximum results, 1–50. Default 20. |
{
"query": "denials management",
"limit": 10
}An array of vendors, best match first.
| id | Vendor id — pass it to get_vendor. |
| name | Vendor name. |
| domain | The vendor’s web domain. |
| summary | Company summary. |
| logoUrl | Permanent logo URL. |
| companyType | Always vendor. |
- No match — Returns { results: [], note } instead of an array. The note is the coverage contract: a miss means Clinical Terminal does not cover the vendor, not that it does not exist.
get_vendor
The full profile once you have an id or numeric slug. There is no vendor score on this server — the denial/appeals/prebill scores were retired from every read path on 2026-08-04 and are never returned.
| Name | Type | Description |
|---|---|---|
| id required | string | Vendor id from search_vendors, or the numeric slug. A vendor name is not an id. |
{
"id": "100000001"
}One vendor object.
| id, name, domain | Identity. |
| slug | Numeric terminalId, as a string. |
| summary, logoUrl | Company summary and logo URL. |
| categories[] | KLAS segment slugs, rolled up from the products this vendor sells. |
| foundedYear, headquarters | Company basics, when known. |
| ceoName, ceoTitle | The current CEO, when known. |
- Unknown or unpublished id — Vendor not found.
find_vendors_for_problem
Capability discovery through the KLAS segment index — the same taxonomy the app routes vendor discovery through. Routing is deterministic, never a model guess. Vendors rank by tracked hospital relationships, then news volume, then products in the segment.
Ask it: “Which vendors do ambient clinical documentation?”
| Name | Type | Description |
|---|---|---|
| problem required | string | A buyer problem or capability in plain words, or an exact segment name from list_segments. At least 2 characters. |
| limit optional | integer | Maximum vendors, 1–25. Default 10. |
{
"problem": "denials management",
"limit": 10
}An object with status: "ok" and the segment it routed to.
| segmentId, segmentName, segmentGroup | The segment the problem routed to. |
| matchMethod | How it routed: exact, alias or substring. |
| vendors[] | Ranked vendors: id, name, terminalId, domain, summary, logoUrl, up to 5 productNames in the segment, productsInSegment, customerEdges and signalCount. |
- Could not route the phrase — Returns status: "no_route" with segmentMenu[]. Pick the closest segment and call again with its exact name.
- Reading customerEdges — It is an ordinal traction signal, not an audited customer count. Corroborate with get_relationships before citing a number.
list_segments
Every KLAS Revenue Cycle segment with live vendor and product counts — the index behind the tool above. A zero count means no published product evidence yet, not an empty market.
None — call it with an empty arguments object.
{}An array of every segment, including empty ones.
| id | Segment slug. |
| name | Display name — pass it to find_vendors_for_problem. |
| group, description | The segment’s group and what it covers. |
| vendorCount, productCount | Vendors and active products tagged with the segment. |
search_products
Search what vendors actually sell. Defaults to current products, because a large share of the catalog is discontinued; status always comes back so you can tell the difference.
| Name | Type | Description |
|---|---|---|
| query optional | string | Matched against product name and description. 1–200 characters. |
| vendor_id optional | string | Restrict to one vendor’s catalog. |
| include_inactive optional | boolean | Also return discontinued products. Default false. |
| limit optional | integer | Maximum results, 1–50. Default 20. |
{
"query": "prior authorization",
"limit": 20
}An array of products, by vendor name then product name.
| id | Product id — pass it to get_product. |
| vendorId, vendorName | The vendor that sells it. |
| name | Product name. |
| productType | service, software, platform, module or device. |
| status | active or inactive. |
| description | Product description. |
| rcmSegments[] | KLAS segment slugs the product is tagged with. |
- Empty array — Usually means the vendor is not catalogued, not that it sells nothing.
get_product
One product in full, with the vendor it belongs to.
| Name | Type | Description |
|---|---|---|
| id required | string | Product id from search_products. |
{
"id": "prod_8f2k1"
}One product object, with the same fields as a search_products row.
- Unknown id — Product not found.
get_vendor_pages
A vendor’s own website as data — the pages we have crawled and classified. Filter by category to jump straight to the page worth reading.
| Name | Type | Description |
|---|---|---|
| vendor required | string | Vendor name, id or numeric slug. 1–200 characters. |
| category optional | enum | One of homepage, about, leadership, contact, news, careers, blog, legal, product, pricing, customers, integrations, demo, resources, other. Omit for every page. |
| include_dead optional | boolean | Also return pages that no longer resolve. Default false. |
| limit optional | integer | Rows to return, 1–100. Default 50. |
| offset optional | integer | Rows to skip, for paging. Default 0. |
{
"vendor": "Waystar",
"category": "customers",
"limit": 25
}One object.
| vendor | The resolved vendor: id, name, terminalId. |
| pages[] | Each page: page_id (pass it to get_page_content), url, classification, scraped (whether we hold its text), and isDead when it no longer resolves. |
| pagesKnown, pagesReturned | Live pages we hold, and rows in this response. |
| scrapedCount, deadPages | Pages we hold text for, and pages that no longer resolve. |
| lastCrawledAt | When content was last fetched — the freshness stamp. |
| note | Why a result is empty or partial, and how to page on. |
- Ambiguous name — Returns candidates[] instead of pages.
- Unknown vendor — Entity not found: "<id>". followed by how to pass an id: the id from search_vendors, a numeric slug, or a terminalId. A vendor name is not an id.
- Unpublished vendor — Its website corpus is not available on this server.
- No crawl yet — An empty list with a note saying we have not mapped the site — absence of data on our side, not absence of pages on theirs.
- Corpus tools switched off — An error saying the website-corpus tools are temporarily disabled; every other tool is unaffected.
get_page_content
Read the text of one of those pages: product copy, case studies and bios rather than a guess from the URL. It arrives inside an explicit untrusted-content fence, because it is verbatim third-party marketing — evidence to quote, never instructions to follow.
| Name | Type | Description |
|---|---|---|
| page_id required | string | A page_id from get_vendor_pages. A URL or a vendor name is not a page_id. |
{
"page_id": "pg_3k9x2"
}One object.
| page_id, url, classification | Which page this is. |
| vendor | The published vendor that owns the page. |
| scraped | Whether we hold its text. |
| title, content | When scraped: the title, and Markdown up to 10,000 characters inside a BEGIN/END UNTRUSTED WEBSITE CONTENT fence. |
| truncated | True when the content was cut at a paragraph boundary. |
| scrapedAt | When the text was fetched. |
- Not scraped — Not an error: scraped: false with a note to fetch the URL directly.
- Unknown page_id — An error naming the id and where page_ids come from.
- Page of an unpublished vendor — Its content is not available here.
get_my_context
The organizations you have been working with in Clinical Terminal chat, most recent first. This is what lets an assistant resolve “that vendor” or “my target” across sessions instead of asking you again.
Ask it: “What was I looking at last time?”
None — call it with an empty arguments object.
{}One object.
| recentEntities[] | Up to 25, most recent first: tid (usable with get_relationships or get_vendor_dossier), name, type, lastSeenAt and seenCount. |
| updatedAt | When the chat memory last changed. |
- No chat history — Plain text, not JSON: no chat memory yet, or the key has no linked user.
Providers
The buy side: US hospitals, health systems, FQHCs, rural health clinics, ASCs, imaging centers, physician groups, skilled nursing and home health.
get_provider_segments
Start any provider-market question here. Every segment with its entity count, its trailing-7-day signal volume, and the signed change against the week before. All segment keys come back, including the quiet ones, so you never have to guess whether a segment exists.
Ask it: “Which parts of the provider market moved this week?”
None — call it with an empty arguments object.
{}An array with one row per provider segment, zero-filled.
| providerType | Segment key — pass it to search_providers. |
| count | Provider entities in the segment. |
| signals7d, signals7dPrior | Signal rows in the last 7 days, and days 8–14. |
| delta | The signed change between the two. |
- Reading signal counts — They count article-by-entity rows, not distinct articles, and are non-zero only for hospital and health-system segments.
search_providers
The provider counterpart to vendor search — by name, segment, state, health system or size. Names collide heavily in this data, so filter by state or size when you can.
| Name | Type | Description |
|---|---|---|
| query optional | string | Provider name or fragment; multi-word phrases work. 1–200 characters. |
| provider_type optional | enum | A segment key from get_provider_segments, such as health_system, acute_care, critical_access, fqhc or asc. |
| state optional | string | A two-letter code or a full state name (“TX” or “Texas”). |
| health_sys_id optional | string | Only members of one health system — a healthSysId from a result. |
| min_beds optional | integer | Minimum staffed beds, 1–5000. Drops providers with no bed count, such as clinics. |
| sort optional | enum | size (most beds first), name, or signal_recency (newest news first). Defaults to relevance with a query, name without. |
| limit optional | integer | Maximum results, 1–50. Default 20. |
{
"query": "Baylor Scott",
"state": "TX",
"sort": "size",
"limit": 10
}An array of providers.
| id, terminalId | Either one works with get_provider. |
| name, city, state | Identity and location. |
| providerSubtype, companyType | Segment key, and the coarse type it derives from. |
| staffedBeds | Bed count, for hospitals and health systems. |
| healthSysId | The parent health system, for a system-to-members lookup. |
| LinkedIn URL. | |
| lastSignalAt | Most recent news detection, for hospitals and health systems. |
- Unrecognised state — Unknown state: "<state>". with the list of valid codes.
search_service_lines
Hospitals and health systems that run a clinical department — cardiology, oncology, neurology, orthopedics and 41 more — each with the evidence that says so: staff job titles naming the department, and sections of the provider’s own website. Use it instead of search_providers for any department question; that tool matches names only. This is a floor, not an inventory: a provider missing from the list may still run the department.
Ask it: “Which hospitals in Texas run a cardiology program?”
| Name | Type | Description |
|---|---|---|
| service_line required | enum | The department key, such as cardiology, oncology, neurology, orthopedics, obgyn, behavioral, imaging or emergency. |
| state optional | string | A two-letter code or a full state name (“TX” or “Texas”). |
| cities optional | string[] | Only providers in these cities; needs state. A metro is several cities, so list the suburbs too, such as ["Houston", "Sugar Land", "The Woodlands"]. Case, “St” versus “Saint” and punctuation don’t matter. |
| level optional | enum | hospital (individual facilities), system (health-system parents) or any. A system’s beds are its system-wide total. Default hospital. |
| provider_type optional | enum | One segment, such as acute_care, critical_access or childrens. |
| min_beds optional | integer | Minimum staffed beds, 1–5000. Drops providers with no bed count. |
| min_evidence optional | enum | strong keeps only a dedicated website section or 2+ staff titles; any also includes single mentions. Default any. |
| include_unclassified optional | boolean | Return providers with no recorded segment, shown with a null providerType. Most are real hospitals and regional systems; a few are universities or payers, so check the name. false withholds and counts them. Default true. |
| limit optional | integer | Maximum providers, 1–50. Default 25. |
{
"service_line": "oncology",
"state": "TX",
"cities": [
"Houston",
"Sugar Land",
"The Woodlands",
"Katy"
],
"limit": 25
}One object: the line, the providers largest first, and counters that explain every provider not returned.
| line | The department key and its label. |
| results[].terminalId, openInGetProvider | Pass terminalId to get_provider as id when openInGetProvider is true. When it is false, the provider is not in the provider directory yet (mostly unclassified rows), so cite the row’s own evidence instead. |
| results[].name, city, state, providerType, isSystem, beds, website | The provider. beds is null when unknown. |
| results[].evidence | strength (strong or some), titles (headcount and up to 3 verbatim titles) and website (tier 1–3, pages, share of the site, up to 3 URLs). |
| providersWithLine | Every provider with evidence for the line. |
| droppedUnclassified, droppedByFilter, droppedNoCity, droppedNoCard, droppedBySize | Why each provider read was not returned. droppedNoCity counts providers with no city on record, which a cities filter cannot match. |
| truncated | The scan cap stopped the sweep. Narrow by state. |
| asOf | When the nightly build last ran. |
- Unrecognised state — Unknown state: "<state>". with the list of valid codes.
- cities without state — cities needs state — city names repeat across states, so pass both.
- An empty list — No provider with evidence for the department matched. That means none recorded, not none exist — read the counters.
get_provider
One provider in depth: profile, health-system context including parent and largest members, technology relationships with verbatim evidence quotes, recent signals, and the clinical departments we hold evidence for. Each section says which kind of empty it is.
| Name | Type | Description |
|---|---|---|
| id required | string | Provider id or terminalId from search_providers. A name is not an id. |
{
"id": "100245871"
}One compact object, kept within a 20,000-character budget.
| provider | The profile, as a search_providers row. |
| system | The health system, its true member count, and up to 10 largest members. Omitted when the provider has no system. |
| edges | Up to 10 technology relationships, strongest evidence first. |
| signals | Up to 5 recent signals, one per source article. |
| serviceLines | Clinical departments, strongest evidence first — each with its label, strength, staff title headcount and website tier. An absent department is unknown, not missing. |
| meta | The resolved provider, a coverageNote for non-hospital providers, and truncated listing anything trimmed. |
- Unknown id — Provider not found: "<id>". — search first; names are not ids.
- A section is unavailable — { status: "unavailable", reason }: a source was down. Retry.
- A section is not tracked — { status: "not_tracked_for_this_provider_type", reason }: relationships and signals are linked for hospitals and health systems only today, so for other providers this is unknown, not zero.
People
People with a current role at any hospital, health system, or published vendor, investor, payor or association, plus the alumni trail behind them.
get_persona
Research a role the way you would research a company. Real job titles with counts, how many people we track and at what kind of employer, duties quoted verbatim from real job postings, typical KPIs, buying role, and what people in the role say they care about — grounded in the census rather than in generic knowledge.
Ask it: “What does a CDI nurse actually do all day?”
| Name | Type | Description |
|---|---|---|
| query required | string | A role in plain words (“CDI nurse”, “VP of revenue cycle”) or an exact personaId. 1–200 characters. |
{
"query": "VP of revenue cycle"
}One object with status: "ok".
| personaId, label | The seniority-by-department group it resolved to. |
| roleDefinition | What the role is. |
| titleVariants[] | Real job titles held, with counts. |
| census | How many people we track, and at which employer types. |
| responsibilities[], kpis[], buyingRole | What the role does and is measured on. |
| jdQuotes | Quotes from real job postings, fenced as untrusted text. |
| aggregated | What people in the role say they care about. Withheld below an anonymity floor, and note says why. |
- No match — status: "no_route" with personaMenu[]. Pick the closest personaId and call again.
- More than one match — status: "ambiguous" with candidates[]. Call again with one of them; never guess.
search_people
Find people by name, employer or job title, or everyone at one organization. Every result holds a current role at a visible organization and lists the person’s other current roles. Pass at least one of query, organization_id or department.
| Name | Type | Description |
|---|---|---|
| query optional | string | Matched against name, employer and job title. 1–200 characters. |
| organization_id optional | string | Only people currently at this organization. |
| vendor_id optional | string | Older name for organization_id. Pass one or the other. |
| department optional | enum | One of clinical, operations, general, finance, recruiting, customer_success, marketing, engineering, legal, data, product, sales, security, design, editorial, research. |
| role optional | enum | Seniority: c_suite, vp, director, or executive for all three. Does not count as a filter on its own. |
| limit optional | integer | Maximum results, 1–50. Default 20. |
{
"query": "revenue cycle",
"role": "executive",
"limit": 10
}An array of people, one row per person, showing the most senior role that matched.
| id | Person id — pass it to get_person. |
| name, jobTitle, organization | Who, and the role shown. |
| positionLevel | Seniority: CEO, President, C_Suite, VP, Director, … |
| functionalDepartment | Department of that role. |
| personaId | <level>_<department>, such as c_suite_ceo. An absent value means the role is unclassified, not junior. |
| headline, imageUrl, linkedin | Profile headline, photo and LinkedIn. |
| otherCurrentRoles[] | Up to 5 other visible roles, most senior first. |
| otherCurrentRolesHidden | Other roles at employers we cannot name. |
- No filter — Provide at least one of query, organization_id, or department.
- organization_id and vendor_id disagree — An error asking for one of them.
- People held back — A second text block after the results counts people who matched but whose roles are at organizations not published here. Treat it as a coverage gap.
get_person
One profile in full: title, employer, other current roles, past roles, headline, headshot and LinkedIn.
| Name | Type | Description |
|---|---|---|
| id required | string | Person id from search_people, or a slug. |
{
"id": "Xk29fPq7LmN3"
}One person object with the fields of a search_people row, plus:
| pastRoles[] | Up to 25 closed roles, newest departure first, with employer, title and dated start and end. |
| pastRolesWithheld | Past employers we cannot name. |
- Not found — Person not found. Also returned for a person with no current role at a visible organization.
search_alumni
The departures side of the graph. Anchor on a vendor and get each person’s past role with a dated departure, plus every current role they hold, most senior first. Current employers are named when published and counted when not.
Ask it: “Who left Epic in the last year and where did they land?”
| Name | Type | Description |
|---|---|---|
| vendor_id required | string | A published vendor’s id or numeric slug. A name is not an id. |
| left_after optional | date | YYYY-MM-DD. Only people who left on or after this date. |
| role optional | enum | Seniority of the past role: c_suite, vp, director or executive. |
| department optional | string | Department of the past role, such as sales or engineering. |
| limit optional | integer | Maximum people, 1–50. Default 25. |
{
"vendor_id": "100000001",
"left_after": "2025-09-01",
"role": "executive"
}One object.
| vendor | The anchor vendor. |
| results[] | Newest departure first: the person, their pastRole at the vendor with dates, and every currentRoles[] entry, with customer evidence for vendor employers. |
| totalMatched | Everyone with a past role at the vendor, before filters. |
| _dropped* counters | Why matched people are missing, by reason. |
- Unknown or unpublished vendor — Vendor not found: "<id>". — pass an id from search_vendors.
- Undated departures — Excluded when left_after is set, and counted in the drop counters.
search_retirements
Executives who will retire or have retired, each with the last day, a confidence and who said so. Editor-confirmed retirements (a published story) come first; after them, people whose own LinkedIn profile says they have retired, marked low confidence. Every row is backed by a sourced claim, and the list grows as retirements are recorded.
Ask it: “Which health-system CEOs have announced they are retiring?”
| Name | Type | Description |
|---|---|---|
| status optional | enum | announced (last day still ahead), completed, or any. Default any. |
| seat optional | string | A seat such as ceo, cfo, cno or cio. |
| since optional | date | YYYY-MM-DD. Only last days on or after this date; rows with no last day are excluded. |
| min_confidence optional | enum | high returns editor-confirmed retirements only; low or any also returns LinkedIn self-reports. Default any. |
| limit optional | integer | Maximum people, 1–50. Default 25. |
{
"status": "announced",
"seat": "ceo"
}One object.
| results[] | Announced first (soonest last day first), then completed, editor-confirmed before self-reported: the person, organization, seat, lastDay, status, confidence, the reporting source and every claims entry. |
| retirementsRecorded | Every retirement on record. |
| droppedByFilter, droppedNoPhoto, droppedBySize | Why rows are missing; droppedBySize above zero means narrow the query or lower limit. |
| organizationHidden | People returned with the organization left blank because it is not published. |
| note | What the list does and does not cover. |
- Empty results — No matching retirements are recorded yet — not an error.
Signals
What the market did lately — news, funding, leadership changes.
search_signals
Recent market signals, newest first. Filter by text, by the entity a signal came from, by type, by source format, or by a detection window.
Ask it: “Show me every funding round in revenue cycle since May.”
| Name | Type | Description |
|---|---|---|
| query optional | string | Matched against title and summary. 1–200 characters. |
| entity_id optional | string | Only signals about this entity. |
| origin_entity_type optional | enum | vendor, provider (includes hospitals), hospital, investor or organization. |
| signal_type optional | string | An exact, case-sensitive category such as Funding / Investment or Leadership Change. |
| source_type optional | enum | The source format, such as news_article, press_release, linkedin_post, sec_filing or job_posting. |
| detected_after optional | date | ISO date or UTC datetime. On or after. |
| detected_before optional | date | ISO date or UTC datetime. On or before; a bare date includes the whole day. |
| sort optional | enum | importance or recency. Accepted, but results currently always come back newest first. Default recency. |
| distinct_articles optional | boolean | One row per article instead of one per article and linked entity. Default false. |
| limit optional | integer | Maximum rows, 1–50. Default 20. |
{
"signal_type": "Funding / Investment",
"detected_after": "2026-05-01",
"distinct_articles": true,
"limit": 50
}An array of signals, newest first.
| id, articleId | Row id, and the article it came from — group on articleId to count stories. |
| title, summary, sourceUrl | The story. |
| detectedAt | When we detected it. |
| topics[], categories[] | What it is about. Prefer these to signalType. |
| originEntityId, originEntityType | Which entity the row is about. |
| linkedEntityCount | How many entities the article names. |
| urgency, painPoint, salesAngle | Machine-written sales analysis. |
- Empty array — Nothing matched; there is no coverage note on this tool.
Graph
Who runs what. This is the only place hospitals are addressable as an anchor.
resolve_hospital
Turn a hospital name into the id the relationship lookup accepts. Resolution only, not a profile — it returns ranked candidates so you can pick the right St. Mary’s before you ask about edges.
| Name | Type | Description |
|---|---|---|
| query required | string | Hospital name or part of one. 1–200 characters. |
| state optional | string | A two-letter state code. Full names are not accepted here. |
| limit optional | integer | Maximum candidates, 1–20. Default 10. |
{
"query": "Massachusetts General",
"state": "MA",
"limit": 5
}An array of candidates, largest by staffed beds first.
| terminalId | The preferred get_relationships input. |
| id | Also accepted by get_relationships. |
| name, city, state | Which hospital this is. |
| hospitalType, staffedBeds | Type and size, to tell same-named hospitals apart. |
- Empty array — No hospital matched.
get_relationships
Company-to-company edges touching an entity, with provenance: source, evidence quote, evidence tier, a citable article and when it was first seen. The anchor can be a vendor or a hospital, which is what makes “what does this hospital run” answerable.
Ask it: “What technology does Mass General run?”
| Name | Type | Description |
|---|---|---|
| entity_id required | string | A vendor or hospital id, numeric slug or terminalId. Not a name. |
| edge_type optional | string | A relationship type such as CUSTOMER_OF or INVESTED_IN; case-insensitive. |
| limit optional | integer | Maximum edges, 1–200. Default 50. |
{
"entity_id": "100000001",
"edge_type": "CUSTOMER_OF",
"limit": 100
}An array of edges, active first. When some were withheld it is instead { relationships, withheld, note }.
| edgeType, relationshipLabel | The type to filter on, and its plain-English form. |
| label | The organization on the other end. |
| sourceId, targetId | terminalIds of the two ends. |
| evidenceSnippet, evidenceTier | The supporting quote, and its strength: 1 case study, 2 customer list, 3 logo or passing mention. |
| evidenceNamesLabel | Whether the quote actually names the other organization. |
| topArticleUrl | An article to cite. |
| firstSeenAt, lastConfirmedAt | When the edge was first and last seen. |
| corroborated, corroborationQuote | Independent corroboration, when checked. |
- Unknown id — Entity not found: "<id>". followed by how to pass an id: the id from search_vendors, a numeric slug, or a terminalId. A vendor name is not an id.
- Withheld edges — Counted in withheld: the other organization is unpublished and cannot be named. Say “at least” when counting.
Publishing
The only tools here that write. Everything above is read-only.
publish_page
Publish a page your assistant composed — a market analysis, a vendor write-up, an article — as a hosted page on clinicalterminal.com, styled like the product and stamped with its publish date. Unlisted by default: only someone with the link can read it. A public page gets a keyword URL, a sitemap listing and a Markdown twin for other agents.
| Name | Type | Description |
|---|---|---|
| title required | string | Page title, 1–200 characters. Be specific. |
| body_html required | string | The page body only — what goes inside <body>, using the allowed tags and .ct-* classes. Up to 256 KB. |
| summary required | string | One sentence, up to 500 characters: the meta description and list subtitle. |
| citations optional | array | Up to 50 { label, url } sources, rendered in the page footer. Default []. |
| source_tools optional | string[] | Which tools on this server produced the data. Default []. |
| visibility optional | enum | unlisted (unguessable link, not indexed) or public (indexable). Use public only when the user asks for a discoverable page. Default unlisted. |
| page_type optional | enum | comparison, analysis or article: the visual register. Guessed from the title when omitted. |
| artifact_id optional | string | Omit to create a page. Pass an existing id to update it in place at the same URL; visibility and page_type are then ignored. |
{
"title": "Texas acute-care hospitals: Q3 news activity",
"summary": "Twelve Texas systems drove most provider news this quarter.",
"body_html": "<h1>Texas acute-care activity</h1><p>Baylor Scott and White led signal volume.</p>",
"page_type": "analysis"
}One object.
| url | The page URL — give it to the user exactly as returned. |
| artifact_id | For later updates or revocation. |
| visibility | public or unlisted. |
| published_at, byte_size | When, and how large. |
| markdown_url | Public pages only: the agent-readable twin. |
| revision, note | On an update: the revision number and a note that readers see it within a minute. |
- Rejected HTML — Sending <!doctype>, <html>, <head>, <body>, <style>, <script> or <link>, an inline style or id, an event handler, or an image from an unapproved host is rejected with an error naming each offender. Nothing is silently stripped.
- Too large — body_html over 262,144 bytes. Cut sections rather than truncating.
- Daily quota — 20 publishes per key per UTC day, updates included, shared with publish_comparison.
- Storage quota — 200 live pages per key. Revoking one frees a slot.
- Update of an unknown id — No live page with that artifact_id is published under this account.
publish_comparison
The same mechanics, shape and quota as publish_page, with guidance tuned for a vendor comparison, and page_type defaulting to comparison. A comparison assembled in a chat window dies in the scrollback; this is the version you can send to someone.
| Name | Type | Description |
|---|---|---|
| title required | string | Page title, 1–200 characters — “Waystar vs Adonis — denials, 400-bed IDN” beats “Vendor Comparison”. |
| body_html required | string | The page body only. Same allowed tags and .ct-* classes as publish_page. |
| summary required | string | One sentence, up to 500 characters. |
| citations optional | array | Up to 50 { label, url } sources. Default []. |
| source_tools optional | string[] | Which tools produced the data, such as get_vendor_dossier. Default []. |
| visibility optional | enum | unlisted or public. Default unlisted. |
| page_type optional | enum | comparison, analysis or article. Default comparison. |
| artifact_id optional | string | Pass an existing id to update in place. |
{
"title": "Waystar vs Adonis: denials, 400-bed IDN",
"summary": "Waystar has broader confirmed hospital traction; Adonis is newer with regional references.",
"body_html": "<h1>Waystar vs Adonis</h1><p>Waystar leads on confirmed customers.</p>",
"citations": [
{
"label": "Waystar case study",
"url": "https://www.waystar.com/case-studies/"
}
],
"source_tools": [
"get_vendor_dossier",
"get_relationships"
]
}The same object as publish_page.
- Every publish_page error — Applies here too, against the same shared quota.
list_my_comparisons
Everything published under your key, newest first. This is your exposure audit — the one place to check what of yours is publicly readable.
| Name | Type | Description |
|---|---|---|
| limit optional | integer | How many to return, 1–50. Default 20. |
| include_revoked optional | boolean | Include revoked pages, flagged. Set false for live pages only. Default true. |
{
"limit": 10,
"include_revoked": false
}{ ok: true, artifacts }, newest first.
| artifact_id, title, summary | Which page. |
| url | The page URL; dead once revoked. |
| visibility | public (indexable) or unlisted (link only). |
| revoked | True once taken down. |
| published_at, byte_size | When, and how large. |
| view_count_approx | Approximate page loads — not analytics. |
revoke_comparison
Take a published page offline. The body is deleted rather than hidden and the URL stops working within about a minute. Permanent: republishing produces a new URL. Works for pages from either publish tool.
| Name | Type | Description |
|---|---|---|
| artifact_id required | string | The id a publish tool or list_my_comparisons returned. |
{
"artifact_id": "waystar-vs-adonis-denials-k3f9x2"
}{ ok: true, artifact_id }. One stored-page slot is freed.
- Unknown, not yours, or already revoked — The same answer for all three, so ids cannot be probed.
Brand kit
Clinical Terminal's own press kit, as data. For an assistant that is designing something about us rather than asking about the market.
get_brand_kit
The same kit that lives at clinicalterminal.com/pressrelease, returned as data. An assistant that calls it first uses the real marks; one that does not tends to invent a red.
Ask it: “Design a LinkedIn banner in Clinical Terminal's brand”
None — call it with an empty arguments object.
{}One object.
| assets[] | Every logo, wordmark, avatar, banner and cover: absolute url, kind, format, theme, pixel size and transparency. |
| colors[] | The brand colors as hex, each with its role. |
| fonts[] | The typefaces, their roles and where to get them. |
| usage, principles[] | Do and don’t rules, and one-line brand rules. |
| readMe | How to read the payload. Quote values exactly. |
Analysis
Ad-hoc SQL across the warehouse. These two need an enterprise key; every other tool on this page does not.
describe_schema
The column inventory for an allowed dataset, so an assistant can author correct SQL instead of guessing at table shapes.
| Name | Type | Description |
|---|---|---|
| dataset optional | enum | knowledge_graph, clinical_ai_design or analytics. Default knowledge_graph. |
| table optional | string | Restrict to one table. |
{
"dataset": "knowledge_graph",
"table": "providers"
}{ dataset, columns }, ordered by table then column position.
| columns[] | Each column’s table name, column name and data type. |
- Any failure — Never an error response: columns comes back empty with an error field. An unknown table returns an empty list with no error.
run_analysis_sql
A read-only query for analysis the fixed tools cannot express. One statement, writes rejected, a LIMIT 1000 added when you give none, and capped at 5 GiB scanned.
| Name | Type | Description |
|---|---|---|
| sql required | string | One SELECT or WITH query against the allowed datasets. |
| params optional | object | Named parameters, referenced as @name in the SQL. |
{
"sql": "SELECT provider_subtype, COUNT(*) AS n FROM `clinical-ai-design.knowledge_graph.providers` WHERE state = @st GROUP BY 1 ORDER BY n DESC",
"params": {
"st": "TX"
}
}{ ok, rows, bytesProcessed }.
- Any rejection — Never an error response: ok: false with an error naming the rule — multiple statements, anything but SELECT/WITH, a write keyword anywhere in the text, a dataset or project outside the allowlist, or a scan estimated over 5 GiB.
Limits & errors
These apply to every tool, before it runs. Tool-specific errors are listed on each entry above.
| Code | What it means |
|---|---|
| 401 | No authorization header was sent. |
| 403 | Invalid or revoked key, a lapsed Landscape subscription, or over the monthly quota. The response says which. |
| 429 | Per-minute rate limit. Retry after the interval the response names. |
The monthly cap is the control that actually binds. The per-minute limit is counted per server instance and the service scales out, so treat the stamped number as a floor rather than a promise.