Skip to content
Tier

Composer sources

Pro

A "Connected sources" section for Composer's @ menu, from your MCP connections. A connected source can be mentioned and says "Connected". One that needs signing in says so; with onSignIn, choosing it starts the sign-in instead of inserting anything, and without it the option says it needs signing in and can't be chosen. An unavailable source stays in the menu with your reason and can't be chosen. Nothing is hidden because it can't be used. Pass what it returns as Composer's mentions, with any others.

Markdown
Version 5.2.0· other versions

This page is for 5.2.0, the current release. An earlier release’s page is the Markdown that release published, so the docs match the version you have installed (candor-lock.json records it).

Not in the docs of 1.3.0, 1.4.0, 1.5.0, 1.5.1, 1.6.0, 1.7.0, 1.8.0, 1.8.1, 1.9.0, 1.9.1, 2.0.0, 2.1.0, 2.2.0, 2.3.0, 2.4.0, 2.5.0, 2.5.1, 2.6.0, 2.6.1, 2.6.2, 2.7.0 and 2.8.0: the page came later, or had another name then.

Docs pages weren’t kept for 1.0.0, 1.0.1, 1.1.0, 1.1.1, 1.2.0 and 1.2.1: they are kept from 1.3.0 on, and before that only llms.txt was published.

Preview

Loading the preview

Install

With the Candor CLI

First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/composer-sources

Brings in: chat, locale, tokens

Usage

TSX · The example above
"use client"

import * as React from "react"
import { Composer } from "@/components/candor/composer"
import { useComposerSources, type ConnectedSource } from "@/components/candor/composer-sources"
import type { EntityRef } from "@/lib/candor/chat"

export default function Example() {
  const [value, setValue] = React.useState("")
  const [refs, setRefs] = React.useState<EntityRef[]>([])
  // As your MCP client reports each connection. A real app starts its sign-in flow in onSignIn.
  const [sources, setSources] = React.useState<ConnectedSource[]>([
    { id: "tracker", name: "Issue tracker", status: "connected", description: "tracker.example.com", entity: { kind: "source", name: "Issue tracker" } },
    { id: "mail", name: "Shared inbox", status: "needs-sign-in" },
    { id: "drive", name: "Team drive", status: { kind: "unavailable", reason: "The drive’s server isn’t answering. Last heard from 20 minutes ago." } },
  ])
  const sourceMentions = useComposerSources(sources, {
    onSignIn: (s) => setSources((all) => all.map((x) => (x.id === s.id ? { ...x, status: "connected", entity: { kind: "source", name: x.name } } : x))),
  })
  return (
    <Composer
      className="max-w-2xl"
      value={value}
      onValueChange={setValue}
      onSubmit={() => setValue("")}
      references={refs}
      onReferencesChange={setRefs}
      placeholder="Type @ to see the connected sources"
      mentions={[{ id: "p1", group: "People", label: "Dana Ortiz", description: "Support lead" }, ...sourceMentions]}
    />
  )
}

Functions

useComposerSources(sources: ConnectedSource[], options?: { /** Called when the person chooses a source that needs signing in. Without it, such a source can't be chosen and says why. */ onSignIn?: ((source: ConnectedSource) => void) | undefined; /** The heading over the section. Defaults to "Connected sources". */ group?: string | undefined; })

Strings

The fixed words, in English by default. Change any of them under composerSources in <LocaleProvider strings={{ … }}>; the table is exported as composerSourcesStrings.

KeyEnglish
groupConnected sources
connectedConnected
signInSign in
needsSignInNeeds sign-in
signInElsewhereNeeds signing in again before it can be used
unavailableUnavailable

Types

ConnectedSource
One source the agent can read through, as your MCP client reports its connection.
{ /** Your id for the connection. */ id: string; /** The name to show, e.g. "Linear", as your app knows it. */ name: string; /** The connection as it stands: "connected", "needs-sign-in" (missing or expired), or unavailable with the reason in your app's words. */ status: "connected" | "needs-sign-in" | { kind: "unavailable"; reason: string; }; /** One line under the name while it can be used, such as the server's host. */ description?: string | undefined; /** What @ inserts for it, as a chip the agent receives as a reference. Without one, "@Name" is typed. */ entity?: EntityRef | undefined; }

Types from other items

The props above take these. Each is defined by another item; import it from the path shown.

EntityRef from @/lib/candor/chat
{ kind: EntityKind; /** The identifier, e.g. "orders.status" or "billing.invoice.due_date". */ name: string; /** A friendlier label when there is one, e.g. "Region". */ label?: string | undefined; /** Where it lives, when more than one place is in scope, e.g. "Shop staging". */ location?: string | undefined; }
EntityKind from @/lib/candor/chat
What kind of thing an entity is: "record", "table", "workflow"… Any string; the app registers each kind's icon and noun (see EntityKindsProvider), and presets cover the kinds of the systems an app commonly works with.
string