Skip to main content
@frontmcp/react includes headless UI components that auto-generate forms from MCP tool/prompt schemas and display results. They render unstyled by default and support custom renderers.

ToolForm

Generates a form from a tool’s inputSchema.
import { ToolForm, useListTools, useCallTool } from '@frontmcp/react';

function ToolUI() {
  const tools = useListTools();
  const [callTool, { data }] = useCallTool(tools[0]?.name ?? '');

  if (!tools.length) return null;

  return (
    <ToolForm
      tool={tools[0]}
      onSubmit={(args) => callTool(args)}
      submitLabel="Execute"
    />
  );
}

Props

PropTypeDefaultDescription
toolToolInfoRequired. Tool definition with inputSchema
onSubmit(args: Record<string, unknown>) => voidRequired. Called with parsed form values
renderField(props: FieldRenderProps) => ReactNodeCustom field renderer
submitLabelstring'Call Tool'Submit button text

Custom Field Rendering

<ToolForm
  tool={tool}
  onSubmit={handleSubmit}
  renderField={({ name, type, required, value, onChange, description }) => (
    <div key={name}>
      <label>{name}{required ? ' *' : ''}</label>
      <input value={value} onChange={(e) => onChange(e.target.value)} />
      {description && <small>{description}</small>}
    </div>
  )}
/>

FieldRenderProps

FieldTypeDescription
namestringField name from schema
typestring'string' | 'number' | 'integer' | 'boolean' | 'enum'
requiredbooleanWhether the field is required
descriptionstring?Schema description
enumValuesstring[]?Enum options (renders <select>)
valuestringCurrent value
onChange(value: string) => voidChange handler

PromptForm

Generates a form from a prompt’s arguments array.
import { PromptForm, useListPrompts, useGetPrompt } from '@frontmcp/react';

function PromptUI() {
  const prompts = useListPrompts();
  const [getPrompt, { data }] = useGetPrompt(prompts[0]?.name ?? '');

  if (!prompts.length) return null;

  return <PromptForm prompt={prompts[0]} onSubmit={(args) => getPrompt(args)} />;
}

Props

PropTypeDefaultDescription
promptPromptInfoRequired. Prompt definition with arguments
onSubmit(args: Record<string, string>) => voidRequired. Called with form values
renderField(props: FieldRenderProps) => ReactNodeCustom field renderer
submitLabelstring'Get Prompt'Submit button text

ResourceViewer

Displays the contents of a ReadResourceResult.
import { ResourceViewer, useReadResource } from '@frontmcp/react';

function ConfigViewer() {
  const { data, loading, error } = useReadResource('app://config');

  return <ResourceViewer data={data} loading={loading} error={error} />;
}

Props

PropTypeDescription
data{ contents?: ResourceContent[] } | nullResource result
loadingbooleanShow loading indicator
errorError | nullShow error message
JSON content (application/json mimeType) is automatically pretty-printed in a <pre> block.

OutputDisplay

Renders any tool/prompt output as formatted JSON or plain text.
import { OutputDisplay, useCallTool } from '@frontmcp/react';

function ToolOutput() {
  const [callTool, { data, loading, error }] = useCallTool('greet');

  return (
    <div>
      <button onClick={() => callTool({ name: 'World' })}>Call</button>
      <OutputDisplay data={data} loading={loading} error={error} />
    </div>
  );
}

Props

PropTypeDescription
dataunknownOutput value — objects are JSON-stringified
loadingbooleanShow loading indicator
errorError | nullShow error message

DynamicRenderer

Recursively renders a ComponentNode tree using the ComponentRegistry.
import { DynamicRenderer } from '@frontmcp/react';

const tree = {
  type: 'Card',
  props: { title: 'Hello' },
  children: [
    { type: 'Text', children: 'World' },
  ],
};

<DynamicRenderer tree={tree} registry={registry} fallback={DefaultComponent} />

Resolution Order

  1. Exact URI match in registry
  2. component://{type} in registry
  3. element://{type} in registry
  4. Fallback component (or <div>)

ComponentRegistry

Maps URI protocols to React components. Used by DynamicRenderer and populated via the provider’s components prop.
import { ComponentRegistry } from '@frontmcp/react';

const registry = new ComponentRegistry();
registry.register('component://Card', CardComponent);
registry.register('element://Badge', BadgeComponent);

// Resolve by short name
const Card = registry.resolve('Card'); // finds component://Card

// List all entries
const entries = registry.list(); // [{ uri, name, description }]

AgentContent

A component that registers itself as an MCP tool. When an agent calls the tool, it renders the args via the render prop. See Agent Components for full details and patterns.
import { AgentContent } from '@frontmcp/react';

<AgentContent
  name="show_weather"
  description="Display weather data"
  render={(data) => <WeatherCard city={data.city} temp={data.temp} />}
  fallback={<p>Waiting for data...</p>}
/>

Props

PropTypeDefaultDescription
namestringRequired. MCP tool name
descriptionstringRequired. Tool description
inputSchemaRecord<string, unknown>{ type: 'object' }JSON Schema for input
render(data: Record<string, unknown>) => ReactNodeRequired. Render function
fallbackReactNodenullShown before first invocation
serverstringTarget a named server

AgentSearch

A headless search component powered by an MCP tool. Registers a tool for delivering results and a resource for the current query. See Agent Components for full details.
import { AgentSearch } from '@frontmcp/react';

<AgentSearch
  toolName="product_search"
  description="Search products"
  placeholder="Search..."
  onResults={setResults}
  renderInput={({ value, onChange, placeholder }) => (
    <input value={value} onChange={(e) => onChange(e.target.value)} placeholder={placeholder} />
  )}
/>

Props

PropTypeDefaultDescription
toolNamestringRequired. MCP tool name
descriptionstringRequired. Tool description
placeholderstringInput placeholder
onResults(results: unknown) => voidRequired. Results callback
renderInput(props: SearchInputRenderProps) => ReactNodeCustom input renderer
serverstringTarget a named server