Agent SDK
Use the web embed widget
Ship a working web agent quickly with EmcyChat from react-embed, then layer in same-user identity and host context.
@emcy/agent-sdk/react-embed is the fastest way to put an Emcy agent into a web app.
Use it when:
- you want a working embed quickly
- you are fine with Emcy owning the widget UI
- you do not need a fully custom transcript, dock, or systems panel
Install#
npm install @emcy/agent-sdkMinimal example#
import { EmcyChat } from "@emcy/agent-sdk/react-embed";
export function SupportPanel() {
return (
<div style={{ height: 640 }}>
<EmcyChat
apiKey="emcy_sk_xxxx"
agentId="ag_xxxxx"
mode="inline"
title="Support Agent"
/>
</div>
);
}Same-user embedded auth#
If one of the agent's attached MCP servers requires user-scoped OAuth, pass the current host user through userIdentity and scope the embed to the current host session with appSessionKey.
import { EmcyChat } from "@emcy/agent-sdk/react-embed";
export function BillingAssistant() {
return (
<div style={{ height: 640 }}>
<EmcyChat
apiKey={process.env.NEXT_PUBLIC_EMCY_API_KEY!}
agentId={process.env.NEXT_PUBLIC_BILLING_AGENT_ID!}
mode="inline"
title="Billing Agent"
appSessionKey={session.id}
userIdentity={{
subject: session.user.id,
email: session.user.email,
organizationId: session.organizationId,
displayName: session.user.name,
}}
/>
</div>
);
}Use appSessionKey so the embed does not accidentally reuse persisted MCP auth or resumed conversation state across logout/login boundaries.
Common props#
The most common embed props are:
apiKeyagentIdserviceUrlmodetitleappSessionKeyuserIdentityappContextclientTools
Add client tools#
Even with the widget, you can expose client-side actions to the agent.
const clientTools = {
refreshInvoices: {
description: "Refresh the invoice list shown in the current page.",
parameters: {},
execute: async () => {
await refetchInvoices();
return { success: true };
},
},
openInvoice: {
description: "Open a specific invoice in the current app.",
parameters: {
invoiceId: {
type: "string",
description: "Invoice id to open.",
required: true,
},
},
execute: async ({ invoiceId }) => {
router.push(`/invoices/${invoiceId}`);
return { success: true, invoiceId };
},
},
};
<EmcyChat
apiKey="emcy_sk_xxxx"
agentId="ag_xxxxx"
clientTools={clientTools}
/>Add app context#
appContext is the right place for lightweight runtime hints about the current page.
<EmcyChat
apiKey="emcy_sk_xxxx"
agentId="ag_xxxxx"
appContext={{
currentSurface: "invoice-detail",
hostRefreshInstruction:
"After any successful invoice mutation, call refreshInvoices before you answer.",
}}
/>Use appContext for dynamic, page-specific hints.
Use the agent system prompt for durable product rules.
Inline mode vs floating mode#
Use:
mode="inline"for dashboards, settings pages, or side panels- floating mode for support-widget style integrations
If your assistant needs to be deeply integrated into the surrounding product chrome, move to custom React UI instead of forcing the widget to behave like a bespoke shell.
Production checklist#
- add all production domains to the agent's allowed origins
- pass
userIdentityfor same-user OAuth-backed MCP flows - pass
appSessionKeyfor correct auth and conversation scoping - keep
clientToolssmall and explicit - test the same agent both in the playground and in the embed
When to move beyond the widget#
Use a custom UI when you need:
- a docked assistant
- your own transcript and systems panels
- branded approvals and input requests
- app-native mobile layout
- assistant state woven into product chrome
