For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt, and this page is available as Markdown at /guides/advanced-features/mcp-apps/interactions.md.

Card interactions

Cards can call server tools, send messages to the host conversation, and synchronize model context. Modern.js injects a connected mcpApp, an MCP Apps SDK App instance, into both application components and MF components. Both modes use the same API.

Access mcpApp

Receive mcpApp through component props and import its type with import type { App } from '@modern-js/mcp-apps/react'. Templates declare the prop optional; disable actions when it is unavailable. Reuse the injected instance instead of calling useApp() or creating another App inside the card.

NeedMethodOutcome
Query, calculate, or submit a business operationcallServerTool()Returns the specified tool's result for the card to process and render
Start a follow-up request from the cardsendMessage()Asks the host to add a conversation message; the host handles subsequent model responses
Share selections or filters with the modelupdateModelContext()Updates context for future turns without triggering an immediate model response
Open an external pageopenLink()Asks the host to open a link
Change the card display moderequestDisplayMode()Requests a mode; use the mode actually returned by the host
Send debugging informationsendLog()Sends a log, not a conversation message

callServerTool: call a business tool

Use a tool name from mcp_apps.ts and arguments matching its inputSchema. The host forwards the call to the MCP server; the card does not need a /mcp URL. This component works in both UI modes:

src/components/Sum.tsx
import type { App } from '@modern-js/mcp-apps/react';
import { useState } from 'react';

export default function Sum({ sum, mcpApp }: { sum?: number; mcpApp?: App }) {
  const [value, setValue] = useState<number>();
  const [pending, setPending] = useState(false);
  const [error, setError] = useState<string>();

  async function calculate() {
    if (!mcpApp) return;
    setPending(true);
    setError(undefined);
    try {
      const result = await mcpApp.callServerTool({
        name: 'add_numbers',
        arguments: { a: 2, b: 3 },
      });
      if (result.isError) throw new Error('Calculation failed');
      const output = result.structuredContent;
      if (
        !output ||
        typeof output !== 'object' ||
        !('sum' in output) ||
        typeof output.sum !== 'number'
      ) {
        throw new Error('Invalid calculation result');
      }
      setValue(output.sum);
    } catch (error) {
      setError(error instanceof Error ? error.message : 'Request failed');
    } finally {
      setPending(false);
    }
  }

  return (
    <section>
      <p>{value ?? sum ?? 'Ready'}</p>
      <button type="button" disabled={!mcpApp || pending} onClick={calculate}>
        {pending ? 'Calculating…' : 'Calculate 2 + 3'}
      </button>
      {error && <p role="alert">{error}</p>}
    </section>
  );
}

Handle the returned result in the interaction code and update React state. Do not rely on another host ontoolresult notification to refresh the UI. Business failures can return isError: true, while connection or protocol failures can throw; handle both. Check the business data structure before reading structuredContent, whose type is unknown.

The tool must allow app calls. visibility defaults to ['model', 'app']; ['app'] expresses app-only visibility for hosts to honor. Visibility does not replace server authorization.

sendMessage: request a follow-up in the conversation

Use this for user actions such as explaining a result or analyzing a selection. Call the following function from a button handler and display failures in the card:

import type { App } from '@modern-js/mcp-apps/react';

export async function askForExplanation(mcpApp: App, sum: number) {
  if (!mcpApp.getHostCapabilities()?.message?.text) {
    throw new Error('This host does not support text messages from cards');
  }
  const result = await mcpApp.sendMessage({
    role: 'user',
    content: [{ type: 'text', text: `Explain the calculation result: ${sum}` }],
  });
  if (result.isError) throw new Error('The host rejected the message');
}

A message does not guarantee execution of a specific tool or directly return the model's reply. Use callServerTool() for a specific business operation and sendMessage() to let the model interpret a request and continue the conversation. Avoid automatically sending messages on component render or mount.

updateModelContext: share card state

When users change filters or selected items, provide the current state for subsequent model turns:

import type { App } from '@modern-js/mcp-apps/react';

export async function syncSelection(mcpApp: App, selectedIds: string[]) {
  if (!mcpApp.getHostCapabilities()?.updateModelContext?.structuredContent)
    return;
  await mcpApp.updateModelContext({
    structuredContent: { selectedIds },
  });
}

This does not immediately trigger a model response. Each update replaces the context previously supplied by this card, so send the complete current state you want retained. A subsequent user action can invoke sendMessage() to request analysis. The caller should still handle request failures.

Other capabilities and host differences

  • Request external navigation with mcpApp.openLink({ url: 'https://example.com' }), handling isError and exceptions.
  • Check mcpApp.getHostContext()?.availableDisplayModes before requesting requestDisplayMode({ mode: 'fullscreen' }). Update the UI using the returned mode.
  • Send debug logs with sendLog({ level: 'info', data: 'Calculation completed' }). The host decides how to display or record them.

Host support varies. Inspect getHostCapabilities() and getHostContext() after connection and hide, disable, or provide alternatives for unsupported actions. Verify success, rejection, and failure paths in the target host; the local protocol script does not cover these card-to-host calls.

See the MCP Apps SDK App API for full method signatures and Create a project for host connection steps.