React Capability Interface Protocol
RCIP exposes typed React application capabilities to AI assistants, UI agents, and tools. Your application controls live context, input/output validation, availability, policy, confirmation, and execution. Consumers invoke declared actions without DOM scraping. The core is framework-neutral; React bindings connect contracts to live behavior.
Documentation · Quick start · React starter · Interactive demo · API reference · Source
Optional Assist and Explorer provide a ready-made conversation UI and read-only capability inspector. No model service, credentials, or remote transport is bundled. The hosted demo uses a clearly labeled deterministic adapter and needs no account.
| What you are building | How RCIP helps |
|---|---|
| A React AI assistant or UI agent | Discover the capabilities and application context the host chooses to expose. |
| React tool calling or function calling | Map a consumer's tool request to client.invoke; validate its input and run existing application behavior. |
| Browser agents interacting with a React app | Use semantic actions with live availability, application policy, and human confirmation. Your integration connects the agent to the RCIP client. |
| An application tool registry | Share typed capability contracts across assistants, command palettes, and other consumers. |
A model/provider adapter remains application-owned. RCIP does not automatically connect an arbitrary browser agent or generate application actions from the DOM. See React agents and semantic capabilities.
An in-app agent or agentic UI can share these application capabilities with frontend tools and browser-automation consumers. Browser use is a valid use case: a custom integration can translate an agent's requests into RCIP discovery and invocation today. Generic cross-page discovery is future work, separate from the existing in-process client.
Run the standalone React starter to explore reads, writes, validation, and host approval without a backend.
RCIP addresses application-tooling problems also explored by the Model Context Protocol (MCP) and WebMCP. It provides an in-process capability runtime with React bindings. Direct MCP and WebMCP adapters are planned and are not included in this release. An existing MCP or WebMCP client needs an integration to invoke RCIP.
Compare RCIP, MCP, WebMCP, AG-UI, and A2UI.
HiNivaas uses RCIP to expose bounded current-view facts and authorized Finance navigation. The Finance case study explains those contracts and their limits. Try the independent interactive demo to explore discovery, invocation, layout changes, and host confirmation.
React already gives people a visual interface, but external tools usually have to scrape labels, inspect DOM structure, or depend on application-specific API knowledge. RCIP lets the application publish the meaning it is willing to expose while keeping execution inside trusted product code.
live semantic snapshot
scopes + context + capabilities
│
▼
assist / translator / tool ─► RcipClient
│
▼
schema → availability → policy → confirmation
│
▼
existing React binding
│
▼
validated application outcome
The integration has four deliberate steps: declare stable product intent, bind existing behavior, let tools discover the live surface, and invoke only through the validated client boundary.
npm install @binaried/rcipRCIP 2 implements protocol 1.0 and supports React 18 and React 19.
@binaried/rcip/core: framework-neutral definitions, runtime, and types.@binaried/rcip/react: React provider and host binding hooks.@binaried/rcip/explorer: optional read-only capability registry UI.@binaried/rcip/assist: optional Assist hook, dot, and floating panel.@binaried/rcip: convenient combined core and React exports.
import {
RCIP_PROTOCOL_VERSION,
createRcipRuntime,
defineRcipApplication,
defineRcipCapability,
defineRcipScope,
} from '@binaried/rcip/core'
const todos = defineRcipScope({
id: 'todos',
title: 'Todos',
description: 'The user task area.',
})
const createTodo = defineRcipCapability<
{ title: string },
{ id: string; title: string }
>({
id: 'todos.create',
title: 'Create todo',
description: 'Create one task.',
usage: {
whenToUse: 'Use when the user explicitly asks to add one task.',
examples: [
{ description: 'Add a grocery task.', input: { title: 'Buy milk' } },
],
},
scopeIds: [todos.id],
effect: 'write',
inputSchema: {
type: 'object',
properties: { title: { type: 'string', minLength: 1 } },
required: ['title'],
additionalProperties: false,
},
outputSchema: {
type: 'object',
properties: {
id: { type: 'string' },
title: { type: 'string' },
},
required: ['id', 'title'],
additionalProperties: false,
},
})
const definition = defineRcipApplication({
protocolVersion: RCIP_PROTOCOL_VERSION,
application: {
id: 'example.todos',
name: 'Todos',
description: 'Example task application.',
},
scopes: [todos],
capabilities: [createTodo],
})
export const runtime = createRcipRuntime(definition, {
policy({ capability, confirmed }) {
if (capability.effect === 'read' || confirmed) {
return { decision: 'allow' }
}
return { decision: 'confirm' }
},
})import {
RcipProvider,
useRcipCapability,
useRcipContext,
} from '@binaried/rcip/react'
function TodoFeature() {
useRcipContext({
activeScopeIds: ['todos'],
primaryScopeId: 'todos',
})
useRcipCapability(createTodo, {
execute: ({ title }) => saveTodo(title),
getAvailability: () => ({
available: userCanCreateTodo(),
}),
})
return <TodoScreen />
}
export function App() {
return (
<RcipProvider runtime={runtime}>
<TodoFeature />
</RcipProvider>
)
}Definitions describe a stable contract. Bindings connect that contract to live application state. The runtime validates availability, input, host policy, confirmation, execution, and output before returning a structured outcome.
A tool receives RcipClient, never the host controller.
import type { RcipClient } from '@binaried/rcip/core'
export async function listAvailableActions(client: RcipClient) {
return client.listCapabilities({
context: 'current',
availableOnly: true,
})
}
export async function invokeCreateTodo(
client: RcipClient,
title: string,
) {
return client.invoke({
capabilityId: 'todos.create',
input: { title },
})
}Tools own their model/provider integration and API transport. Only trusted
application code calls runtime.host.resolveConfirmation.
The SDK ships a provider-neutral Assist tool that collapses to a status dot and expands into a draggable floating panel. The host passes its runtime and a consumer-owned asynchronous callback. RCIP supplies the current snapshot, conversation, and prior outcomes; the callback returns either a message or one bounded batch of capability invocations.
import { RcipAssist, type RcipAssistDecide } from '@binaried/rcip/assist'
import '@binaried/rcip/assist/styles.css'
const decide: RcipAssistDecide = async (request, { signal }) => {
const response = await fetch('/api/assist', {
method: 'POST',
body: JSON.stringify(request),
signal,
})
return response.json()
}
<RcipAssist
runtime={runtime}
decide={decide}
mode="interactive"
/>Use mode="read-only" when the callback may discover and invoke only read
capabilities. Interactive mode still goes through runtime availability, schema,
host policy, and trusted host confirmation. The headless useRcipAssist hook is
available for consumers that want a different UI.
The polished default interaction keeps Assist small without making it mouse only: click/tap starts or stops voice input, double-click opens the panel, long-press opens it on touch, Enter opens it from a keyboard, and Space toggles voice input. The built-in voice source is intentionally a one-second simulation that captures nothing and invokes nothing.
Applications can replace the simulation with a consumer-owned voice adapter and ordered processors. This makes audio → transcription → text refinement → Assist an explicit, cancellable pipeline rather than model-specific SDK behavior.
import type { RcipAssistInputPipeline } from '@binaried/rcip/assist'
const inputPipeline: RcipAssistInputPipeline = {
voice: browserVoiceAdapter,
processors: [transcribeOnYourServer, refineOnYourServer],
}
<RcipAssist {...props} inputPipeline={inputPipeline} />Composer text uses the same processor chain. A final text value is submitted to
the existing decision flow; null consumes the input, and an untransformed
audio value fails safely. See
Assist and input pipelines.
The package ships one generic tool: a live, read-only registry dashboard.
import { RcipCapabilityExplorer } from '@binaried/rcip/explorer'
import '@binaried/rcip/explorer/styles.css'
<RcipCapabilityExplorer client={runtime.client} />It displays every registered capability and highlights capabilities relevant to
the current semantic context. It never invokes capabilities or observes tool
execution state. CSS custom properties prefixed with --rcip-explorer- support
consumer theming.
npx --yes npm@11.16.0 ci
RCIP_PILOT_PORT=4176 npm run devThe standalone pilot contains a normal Todos/Profile UI, a consumer-owned Control Panel, the packaged Assist and Explorer tools, and a server-side optional model adapter with deterministic fallback. It does not require any HiNivaas service.
Validation commands:
npm run check
npm run test:e2e
npm run check:starter
npm audit- Protocol 1.0
- Security model
- Tool author guide
- Assist and input pipelines
- Migrating from v1
- Published-package health checks
- Release runbook
- Contributing
- Security reporting
- Changelog
Apache-2.0