{"id":34562,"date":"2026-07-30T10:05:08","date_gmt":"2026-07-30T08:05:08","guid":{"rendered":"https:\/\/www.angulararchitects.io\/?p=34562"},"modified":"2026-07-30T10:49:23","modified_gmt":"2026-07-30T08:49:23","slug":"mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses","status":"publish","type":"post","link":"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/","title":{"rendered":"MCP Apps in Angular with CopilotKit: Rich Chat Interfaces Instead of Text Responses"},"content":{"rendered":"<div class=\"wp-post-series-box series-agentic-angular wp-post-series-box--expandable\">\n\t\t\t<input id=\"collapsible-series-agentic-angular6a6cac96dde72\" class=\"wp-post-series-box__toggle_checkbox\" type=\"checkbox\">\n\t\n\t<label\n\t\tclass=\"wp-post-series-box__label\"\n\t\t\t\t\tfor=\"collapsible-series-agentic-angular6a6cac96dde72\"\n\t\t\ttabindex=\"0\"\n\t\t\t\t>\n\t\t<p class=\"wp-post-series-box__name wp-post-series-name\">\n\t\t\tThis is post 10 of 10 in the series <em>&ldquo;Agentic UI with Angular&rdquo;<\/em>\t\t<\/p>\n\t\t\t<\/label>\n\n\t\t\t<div class=\"wp-post-series-box__posts\">\n\t\t\t<ol>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/understanding-ag-ui-the-standard-for-agentic-user-interfaces\/\">Understanding AG-UI: The Standard for Agentic User Interfaces<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-the-sdk-for-typescript\/\">AG-UI in Practice: The SDK for TypeScript<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/\">AG-UI End to End: Connecting Server and Client<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/implementing-ag-ui-with-angular\/\">Agentic UI with Angular, CopilotKit, and AG-UI<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/a2ui-how-ai-generates-dynamic-uis-at-runtime\/\">A2UI: How AI Generates Dynamic UIs at Runtime<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/integrating-a2ui-with-ag-ui-in-angular\/\">Integrating A2UI with AG-UI and CopilotKit in Angular<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/custom-catalogs-in-a2ui-your-own-components-for-ai-generated-uis\/\">Custom Catalogs in A2UI: Your Own Components for AI-Generated UIs<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/how-i-made-my-a2ui-dashboard-300-times-faster\/\">A2UI with a DSL: Controllable Dashboards Optimized for Performance<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/agentic-ui-with-mcp-apps-tool-results-as-interactive-widgets\/\">Agentic UI with MCP Apps: Tool Results as Interactive Widgets<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><span class=\"wp-post-series-box__current\">MCP Apps in Angular with CopilotKit: Rich Chat Interfaces Instead of Text Responses<\/span><\/li>\n\t\t\t\t\t\t\t<\/ol>\n\t\t<\/div>\n\t<\/div>\n<p>In the <a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/agentic-ui-with-mcp-apps-tool-results-as-interactive-widgets\/\">previous article<\/a>, we laid the foundations of MCP and MCP Apps: MCP connects agents with external tools, and MCP Apps lifts their results from plain text to the level of interactive user interfaces. Using a minimal, VanillaJS-based demo, we saw how a host loads an app into a secured iframe and communicates with it via the <code>postMessage<\/code> API \u2013 abstracted by the <code>App<\/code> object and the <code>AppBridge<\/code>. From establishing the connection, through the exchange of tool parameters, results, and host context, all the way to the orderly teardown, we walked through the entire lifecycle.<\/p>\n<p>We now apply this foundation to a complete case study. This time, a real MCP server, a language model, the agent framework Mastra, and the AG-UI protocol come into play. The goal is to connect a business partner's MCP server to our flight portal and present its results with the help of an MCP App.<\/p>\n<p>\ud83d\udcc2 <a href=\"https:\/\/github.com\/angular-architects\/flights42\/tree\/copilotkit\">Source code<\/a> (branch: <em>copilotkit<\/em>)<\/p>\n<p>The readme shows how to start the example including the backend and the MCP server.<\/p>\n<h2>Integrating an MCP Server with MCP Apps<\/h2>\n<p>Having clarified the basic mechanics of MCP Apps with the first example, we now want to apply our knowledge to a larger case study with a language model and an MCP server. The idea is to connect the MCP server of a business partner specialized in hotel bookings to our flight portal. This way, our customers can inquire not only about flights but also about hotels in the destination city:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/07\/mcp-apps-chat.png\" alt=\"\" \/><\/p>\n<h3>Providing an MCP Server<\/h3>\n<p>The implementation of the MCP server isn't the focus of this article. For better understanding, however, I still want to take a brief look at our Node.js implementation. When using other server frameworks, the approach is very similar.<\/p>\n<p>An object of type <code>McpServer<\/code> from the MCP SDK represents the server itself:<\/p>\n<pre><code class=\"language-ts\">import { McpServer } from &#039;@modelcontextprotocol\/sdk\/server\/mcp.js&#039;;\n\n[...]\n\nconst server = new McpServer({\n  name: &#039;Flights42 Hotels MCP Server&#039;,\n  version: &#039;1.0.0&#039;,\n});<\/code><\/pre>\n<p>The name and the version are merely metadata. Consumers can use them to avoid possible version conflicts.<\/p>\n<p>With the function <code>registerAppTool<\/code> from the MCP Apps SDK, we register a tool with the <code>McpServer<\/code>:<\/p>\n<pre><code class=\"language-ts\">import {\n  registerAppTool,\n} from &#039;@modelcontextprotocol\/ext-apps\/server&#039;;\n\n[...]\n\nexport const HOTELS_RESOURCE_URI = &#039;ui:\/\/hotels\/results.html&#039;;\n\nregisterAppTool(\n  server,\n  &#039;findHotels&#039;,\n  {\n    title: &#039;Find Hotels&#039;,\n    description:\n      &#039;Find three demo hotels for a city. Use this when the user asks for hotels in a specific city.&#039;,\n    inputSchema: findHotelsInputSchema,\n    outputSchema: findHotelsResultSchema,\n    _meta: {\n      ui: {\n        resourceUri: HOTELS_RESOURCE_URI,\n      },\n    },\n  },\n  async (input) =&gt; {\n    const result = findHotels(findHotelsInputSchema.parse(input));\n    const hotels = result.hotels;\n    return {\n      content: [{ type: &#039;text&#039;, text: `${hotels.length} hotels found` }],\n      structuredContent: result,\n    };\n  },\n);<\/code><\/pre>\n<p>As usual, an id, a name, a description, and schemas for parameters and return value define the tool. The schema description here, too, is done as usual via Zod:<\/p>\n<pre><code class=\"language-ts\">export const findHotelsInputSchema = z.object({\n  city: z.string().trim().min(1).describe(&#039;The city to search hotels for.&#039;),\n});\n\nexport const findHotelsResultSchema = z.object({\n  city: z.string(),\n  hotels: z.array(hotelSchema),\n});<\/code><\/pre>\n<p>In addition, <code>registerAppTool<\/code> also takes the implementation of the tool. This receives an object of type <code>findHotelsInputSchema<\/code>, searches for hotels, and returns a result with a <code>structuredContent<\/code> of type <code>findHotelsResultSchema<\/code>. Additionally, the return value contains a piece of textual information.<\/p>\n<p>The decisive point for MCP Apps, however, is the registration of a <code>resourceUri<\/code> in the tool's metadata. This URI points to an MCP resource that delivers the app's HTML file. The server registers this resource with the function <code>registerAppResource<\/code>:<\/p>\n<pre><code class=\"language-ts\">import {\n  registerAppResource,\n  RESOURCE_MIME_TYPE\n} from &#039;@modelcontextprotocol\/ext-apps\/server&#039;;\n\n[...]\n\nconst htmlPath = resolve(distDir, &#039;index.html&#039;);\n\nregisterAppResource(\n  server,\n  &#039;Flights42 Hotel Results&#039;,\n  HOTELS_RESOURCE_URI,\n  {\n    description: &#039;Hotel results rendered as an interactive MCP App.&#039;,\n  },\n  async () =&gt; {\n    const html = await readFile(htmlPath, &#039;utf8&#039;);\n\n    return {\n      contents: [\n        {\n          uri: HOTELS_RESOURCE_URI,\n          mimeType: RESOURCE_MIME_TYPE, \n            \/\/ text\/html;profile=mcp-app\n          text: html,\n          [...]\n        },\n      ],\n    };\n  },\n);<\/code><\/pre>\n<p>In addition, we make the <code>McpServer<\/code> accessible via HTTP through an Express server. The complete source code of the server can be found in the article's repository (<a href=\"https:\/\/github.com\/angular-architects\/flights42\/blob\/copilotkit\/mcp-server\/src\/server.ts\">mcp-server\/src\/server.ts<\/a>).<\/p>\n<h3>Direct Access with the MCP Inspector<\/h3>\n<p>The MCP Inspector application allows us to interact directly with an MCP server. This includes retrieving metadata about tools, retrieving resources, and executing tools:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/07\/mcp-inspector.png\" alt=\"\" \/><\/p>\n<p>The inspector can be started without prior installation using the command <code>npx @modelcontextprotocol\/inspector<\/code>. Afterwards, you enter the address of the MCP server and connect.<\/p>\n<p>With our MCP server, you find the app's <code>resourceUri<\/code> in the metadata of the find-hotels tool. If you then retrieve the associated resource, you arrive at its HTML.<\/p>\n<h3>Integrating MCP Apps into the Backend<\/h3>\n<p>For an agent to pick up the tools of an MCP server, that server must be registered with it. With most agent frameworks, specifying the address of the MCP server is enough for this.<\/p>\n<p>The agent framework Mastra that we use, for example, offers an <code>MCPClient<\/code> object with which you can retrieve metadata about all offered tools of an MCP server. These tools can be registered with the agent just like local tools:<\/p>\n<pre><code class=\"language-ts\">import { MCPClient } from &#039;@mastra\/mcp&#039;;\n[...]\n\nconst hotelsMcpTools = await new MCPClient({\n      id: &#039;hotels-mcp-client&#039;,\n      servers: { hotels: { url: new URL(&#039;http:\/\/127.0.0.1:3002\/mcp&#039;) } },\n    }).listTools();\n\nexport const ticketingAgent = new Agent({\n  id: &#039;ticketingAgent&#039;,\n  tools: {\n    [...],\n    ...hotelsMcpTools,\n  },\n});<\/code><\/pre>\n<h3>MCP Apps via AG-UI<\/h3>\n<p>To point the client to an existing MCP App via AG-UI, the server sends a message of type <code>ACTIVITY_SNAPSHOT<\/code>:<\/p>\n<pre><code class=\"language-json\">{\n  &quot;type&quot;: &quot;ACTIVITY_SNAPSHOT&quot;,\n  &quot;messageId&quot;: &quot;0145bd3d-fb17-4d72-907a-9b2a1d9fad63&quot;,\n  &quot;activityType&quot;: &quot;mcp-apps&quot;,\n  &quot;content&quot;: {\n    &quot;serverHash&quot;: &quot;&quot;,\n    &quot;serverId&quot;: &quot;hotels&quot;,\n    &quot;resourceUri&quot;: &quot;ui:\/\/hotels\/results.html&quot;,\n    &quot;toolInput&quot;: {\n      &quot;city&quot;: &quot;Paris&quot;\n    },\n    &quot;result&quot;: {\n      &quot;content&quot;: [\n        {\n          &quot;type&quot;: &quot;text&quot;,\n          &quot;text&quot;: &quot;{ \\&quot;city\\&quot;: \\&quot;Paris\\&quot;, \\&quot;hotels\\&quot;: [...] }&quot;\n        }\n      ],\n      &quot;structuredContent&quot;: {\n        &quot;city&quot;: &quot;Paris&quot;,\n        &quot;hotels&quot;: [\n          {\n            &quot;id&quot;: &quot;grand-palace&quot;,\n            &quot;name&quot;: &quot;Grand Palace Paris&quot;,\n            &quot;sterne&quot;: 5,\n            &quot;imageUrl&quot;: &quot;http:\/\/127.0.0.1:3002\/assets\/hotels\/grand-palace.svg&quot;\n          },\n          {\n            &quot;id&quot;: &quot;skyline-suites&quot;,\n            &quot;name&quot;: &quot;Skyline Suites Paris&quot;,\n            &quot;sterne&quot;: 4,\n            &quot;imageUrl&quot;: &quot;http:\/\/127.0.0.1:3002\/assets\/hotels\/skyline-suites.svg&quot;\n          },\n          {\n            &quot;id&quot;: &quot;biz-hotel&quot;,\n            &quot;name&quot;: &quot;Biz Hotel Paris&quot;,\n            &quot;sterne&quot;: 3,\n            &quot;imageUrl&quot;: &quot;http:\/\/127.0.0.1:3002\/assets\/hotels\/biz-hotel.svg&quot;\n          }\n        ]\n      }\n    }\n  }\n}<\/code><\/pre>\n<p>The important thing here is the <code>activityType<\/code>. Because of the value <code>mcp-apps<\/code>, the client recognizes that this is information for an MCP App. In this case, the <code>content<\/code> node contains the reference to the resource, the parameters sent to the tool, and the result.<\/p>\n<p>Hint: The <code>ExtendedMastraAgent<\/code> (<a href=\"https:\/\/github.com\/angular-architects\/flights42\/blob\/copilotkit\/libs\/ag-ui-server\/extended-mastra-agent.ts\">libs\/ag-ui-server\/extended-mastra-agent.ts<\/a>) used in our demo application contains a bit of logic that, after a tool call, sends such an activity snapshot, provided an MCP App is linked to the respective tool.<\/p>\n<p><div style=\"\nmargin: 8px 0;\npadding: 22px;\nborder: 1px solid #e5e7eb;\nborder-radius: 14px;\nbackground: #f8fafc;\n\">NOTE<\/p>\n<h3 style=\"margin-top:0\">Agentic UI with Angular<\/h3>\n<p>If you don't just want to use MCP Apps, AG-UI, and agents in isolation but combine them into a solid architecture:<br \/>\nIn my book Agentic UI with Angular, I cover the underlying patterns and trade-offs in depth.<\/p>\n<p><a href=\"https:\/\/agentic-angular.com\/\"><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/04\/cover.png\" width=\"400\" alt=\"Cover of the eBook Agentic UI with Angular\" style=\"cursor:pointer !important\"><\/a><\/p>\n<p><a style=\"cursor:pointer !important\" href=\"https:\/\/agentic-angular.com\/\">Learn more about the eBook \u2192<\/a>\n<\/div>\n<\/p>\n<h3>CopilotKit's MCP Apps Renderer<\/h3>\n<p>To display the received activity snapshot in the client, we need an activity renderer. CopilotKit ships such a renderer for MCP Apps. It lives in the secondary entry point <code>@copilotkit\/angular\/mcp-apps<\/code> and is set up in <a href=\"https:\/\/github.com\/angular-architects\/flights42\/blob\/copilotkit\/src\/app\/app.config.ts\">app.config.ts<\/a> with the function <code>provideMCPApps<\/code>:<\/p>\n<pre><code class=\"language-ts\">\/\/ src\/app\/app.config.ts\n\nimport { provideCopilotKit } from &#039;@copilotkit\/angular&#039;;\nimport { provideMCPApps } from &#039;@copilotkit\/angular\/mcp-apps&#039;;\n\nimport { mcpAppsConfig } from &#039;.\/mcp-apps.config&#039;;\n\n[...]\n\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    [...],\n\n    provideCopilotKit({\n      [...]\n    }),\n\n    provideMCPApps(mcpAppsConfig),\n\n    [...]\n  ],\n};<\/code><\/pre>\n<h3>Configuring the Host Information<\/h3>\n<p>The configuration passed to <code>provideMCPApps<\/code> is typed with <code>MCPAppsConfig<\/code>. Above all, it defines the <code>hostInfo<\/code> and the <code>hostContext<\/code> \u2013 the key parameters that we discussed in the first part in the context of the first demo application:<\/p>\n<pre><code class=\"language-ts\">\/\/ src\/app\/mcp-apps.config.ts\n\nimport type { MCPAppsConfig } from &#039;@copilotkit\/angular\/mcp-apps&#039;;\n\nexport const mcpAppsConfig: MCPAppsConfig = {\n  hostInfo: { name: &#039;Flights42 MCP Host&#039;, version: &#039;1.0.0&#039; },\n  hostContext: {\n    displayMode: &#039;inline&#039;,\n    theme: &#039;light&#039;,\n    styles: {\n      variables: {\n        &#039;--color-ring-primary&#039;: &#039;#3f51b5&#039;,\n      },\n    },\n  },\n};<\/code><\/pre>\n<h3>The Proxy in the Backend<\/h3>\n<p>This leaves the question of how the requests originating from the widget reach the MCP server. In principle, this could happen directly from the browser \u2013 provided the MCP server sets the appropriate CORS headers. CopilotKit, however, assumes a proxy in the backend: the requests travel over the AG-UI endpoint that is already in place; the MCP server's address and any credentials thus remain a backend detail. This proxy task is handled by the <code>MCPAppsMiddleware<\/code> from the package <code>@ag-ui\/mcp-apps-middleware<\/code>. For this, our AG-UI route (<a href=\"https:\/\/github.com\/angular-architects\/flights42\/blob\/copilotkit\/ai-server\/src\/mastra\/routes\/ag-ui-route.ts\">ag-ui-route.ts<\/a>) declares the hotels MCP server's configuration exactly once:<\/p>\n<pre><code class=\"language-ts\">\/\/ ai-server\/src\/mastra\/routes\/ag-ui-route.ts\n\nimport {\n  MCPAppsMiddleware,\n  type MCPClientConfig,\n} from &#039;@ag-ui\/mcp-apps-middleware&#039;;\n\n[...]\n\nconst HOTELS_MCP_SERVER: MCPClientConfig = {\n  type: &#039;http&#039;,\n  url: &#039;http:\/\/127.0.0.1:3002\/mcp&#039;,\n  serverId: &#039;hotels&#039;,\n};\n\nconst mcpAppsProxy = new MCPAppsMiddleware({\n  mcpServers: [HOTELS_MCP_SERVER],\n});<\/code><\/pre>\n<p>The server-side route handler then checks whether the incoming run carries a widget request. If so, the run goes through the middleware \u2013 without an agent and thus without a language model. All other runs go to the agent as before:<\/p>\n<pre><code class=\"language-ts\">const agent = getExtendedLocalAgent({\n  [...]\n});\n\nconst middleware = isProxiedMcpRequest(parsed.input.forwardedProps)\n  ? mcpAppsProxy\n  : undefined;\n\n[...]\n\nawait streamAgentEvents(sse, agent, parsed.input, { middleware });<\/code><\/pre>\n<p>For this, the function <code>streamAgentEvents<\/code> accepts an optional <code>middleware<\/code> parameter and then subscribes to <code>middleware.run(input, agent)<\/code> instead of <code>agent.run(input)<\/code>.<\/p>\n<p>Important for the overall picture: the MCP server's tools remain registered at agent level \u2013 as shown above \u2013 and continue to be executed on the server during the run. In this setup, the middleware serves solely as a proxy for the <code>resources\/read<\/code> and <code>tools\/call<\/code> requests initiated by the widget.<\/p>\n<h3>Rendering Activities<\/h3>\n<p>Since we use CopilotKit in headless mode, we have to take care of rendering the activities ourselves. When iterating over the messages of the chat history, we therefore check whether an <code>activity<\/code> is present for the current message. If so, we display it with the helper component <code>app-copilot-activity<\/code>.<\/p>\n<pre><code class=\"language-html\">&lt;!-- \n  src\/app\/domains\/shared\/ui-assistant\/chat-messages\/chat-messages.html \n--&gt;\n\n[...]\n@for (view of views(); track view.id) {\n\n  [...]\n\n  @if (view.activity) {\n    @let activity = view.activity;\n    &lt;article class=&quot;msg {{ view.variant }}&quot;&gt;\n      &lt;div class=&quot;avatar&quot;&gt;{{ view.avatar }}&lt;\/div&gt;\n      &lt;div&gt;\n        &lt;div class=&quot;bubble&quot; [class.bubble--a2ui]=&quot;activity.isSurface&quot;&gt;\n          &lt;app-copilot-activity\n            [message]=&quot;activity.message&quot;\n            [agentId]=&quot;agentId()&quot; \/&gt;\n        &lt;\/div&gt;\n        &lt;div class=&quot;meta&quot;&gt;&lt;\/div&gt;\n      &lt;\/div&gt;\n    &lt;\/article&gt;\n  }\n\n  [...]\n\n}\n\n[...]<\/code><\/pre>\n<p>When this text was written, there was no ready-made component for headless mode for visualizing activities yet. That's why <code>app-copilot-activity<\/code>, as the <code>app-<\/code> prefix reveals, is a self-written component.<\/p>\n<p>It takes the current message as well as the <code>agentId<\/code> and derives the view to display from them in a <code>computed<\/code>:<\/p>\n<pre><code class=\"language-ts\">\/\/ src\/app\/domains\/shared\/util-copilotkit\/activity\/copilot-activity.ts\n\n[...]\n\n@Component({\n  selector: &#039;app-copilot-activity&#039;,\n  imports: [NgComponentOutlet],\n  template: `\n    @let view = rendered();\n    @if (view) {\n      &lt;ng-container *ngComponentOutlet=&quot;view.component; inputs: view.inputs&quot; \/&gt;\n    }\n  `,\n  [...]\n})\nexport class CopilotActivity {\n  private readonly copilotKit = inject(CopilotKit);\n\n  readonly message = input.required&lt;ActivityMessage&gt;();\n  readonly agentId = input.required&lt;string&gt;();\n\n  protected readonly rendered = computed(() =&gt;\n    toRenderActivity(\n      this.message(),\n      this.copilotKit.activityMessageRenderConfigs(),\n      this.agentId(),\n      this.copilotKit.getAgent(this.agentId()),\n    ),\n  );\n}<\/code><\/pre>\n<p>The list <code>activityMessageRenderConfigs()<\/code> includes not only the configurations registered by the application but also the shipped renderers \u2013 among them the MCP Apps renderer set up via <code>provideMCPApps<\/code>. It fetches the app's HTML through the proxy discussed earlier and routes the widget's further requests there as well. The <code>serverId<\/code> from the activity snapshot indicates which of the MCP servers configured at the proxy is meant \u2013 only the backend knows the server's URL.<\/p>\n<p>The actual selection of the renderer is handled by the function <code>toRenderActivity<\/code>:<\/p>\n<pre><code class=\"language-ts\">export function toRenderActivity(\n  message: ActivityMessage,\n  configs: readonly RenderActivityMessageConfig[],\n  agentId: string,\n  agent: AbstractAgent | undefined,\n): RenderedActivity | null {\n  const matches = configs.filter(\n    (candidate) =&gt; candidate.activityType === message.activityType,\n  );\n\n  const config =\n    matches.find((candidate) =&gt; candidate.agentId === agentId) ??\n    matches.find((candidate) =&gt; candidate.agentId === undefined) ??\n    configs.find((candidate) =&gt; candidate.activityType === &#039;*&#039;);\n\n  if (!config) {\n    return null;\n  }\n\n  const parsed = config.content.safeParse(message.content);\n  if (!parsed.success) {\n    [...]\n    return null;\n  }\n\n  return {\n    component: config.component,\n    inputs: {\n      activityType: message.activityType,\n      content: parsed.data,\n      message,\n      agent,\n    },\n  };\n}<\/code><\/pre>\n<p>The selection follows the logic that CopilotKit uses internally in its <code>CopilotChatMessageView<\/code> component: among the renderers with a matching <code>activityType<\/code> \u2013 <code>mcp-apps<\/code> in our case \u2013 one registered for the concrete <code>agentId<\/code> wins first; after that, an agent-independent entry comes into play, and as a last resort a wildcard renderer with the <code>activityType<\/code> <code>&#039;*&#039;<\/code>. The function then validates the snapshot's content with the schema stored in the renderer and returns the component along with its inputs, which the template displays via <code>*ngComponentOutlet<\/code>.<\/p>\n<h2>Summary<\/h2>\n<p>MCP standardizes the connection of tools to agents, and MCP Apps lifts this idea to the level of the user interface: instead of a tool result in textual form, the user receives an interactive, tailored interface. An MCP App is a standalone web application that the MCP server provides as a resource and to which a tool's metadata points via a <code>resourceUri<\/code>. The host loads the app into a secured iframe and communicates with it via the <code>postMessage<\/code> API \u2013 abstracted by the <code>App<\/code> object on the app side and the <code>AppBridge<\/code> on the host side.<\/p>\n<p>Via the host context, the host prescribes theming and layout; conversely, the app reports its space requirements so that no scrollbar arises. The lifecycle spans from initialization, through the exchange of tool parameters and results, all the way to the orderly teardown with <code>teardownResource<\/code> and <code>close<\/code>. In a real-world setup with a language model, the MCP server registers tool and resource together, the agent integrates the tools like local tools, and after a tool call AG-UI transports an <code>ACTIVITY_SNAPSHOT<\/code> to the client, which an activity renderer picks up and displays as an MCP App. The accompanying widget does not connect to the MCP server directly; it routes resource and tool requests through the AG-UI agent to a server-side proxy based on the <code>MCPAppsMiddleware<\/code>.<\/p>\n<p><div style=\"\nmargin: 8px 0;\npadding: 22px;\nborder: 1px solid #e5e7eb;\nborder-radius: 14px;\nbackground: #f8fafc;\n\"><\/p>\n<h3 style=\"margin-top:0\">Interested in production-ready Agentic UI architectures?<\/h3>\n<p>In my workshop, we dig into AG-UI, A2UI, MCP Apps, HITL patterns, and modern Angular architectures for real-world agentic systems.<\/p>\n<p><a href=\"https:\/\/www.angulararchitects.io\/en\/training\/agentic-ai-with-angular-architecture-patterns\/\"><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/05\/sujet-workshop-en.png\" width=\"400\" alt=\"Workshop: Agentic AI with Angular \u2013 AG-UI, A2UI, MCP Apps & HITL patterns\" style=\"cursor:pointer !important\"><\/a><\/p>\n<p><a style=\"cursor:pointer !important\" href=\"https:\/\/www.angulararchitects.io\/en\/training\/agentic-ai-with-angular-architecture-patterns\/\">See all details \u2192<\/a>\n<\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is post 10 of 10 in the series &ldquo;Agentic UI with Angular&rdquo; Understanding AG-UI: The Standard for Agentic User Interfaces AG-UI in Practice: The SDK for TypeScript AG-UI End to End: Connecting Server and Client Agentic UI with Angular, CopilotKit, and AG-UI A2UI: How AI Generates Dynamic UIs at Runtime Integrating A2UI with AG-UI [&hellip;]<\/p>\n","protected":false},"author":25,"featured_media":34552,"comment_status":"open","ping_status":"open","sticky":true,"template":"","format":"standard","meta":{"_acf_changed":false,"_price":"","_stock":"","_tribe_ticket_header":"","_tribe_default_ticket_provider":"","_ticket_start_date":"","_ticket_end_date":"","_tribe_ticket_show_description":"","_tribe_ticket_show_not_going":false,"_tribe_ticket_use_global_stock":"","_tribe_ticket_global_stock_level":"","_global_stock_mode":"","_global_stock_cap":"","_tribe_rsvp_for_event":"","_tribe_ticket_going_count":"","_tribe_ticket_not_going_count":"","_tribe_tickets_list":"[]","_tribe_ticket_has_attendee_info_fields":false,"footnotes":""},"categories":[18],"tags":[],"class_list":["post-34562","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","post_series-agentic-angular"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>MCP Apps in Angular with CopilotKit: Rich Chat Interfaces Instead of Text Responses - ANGULARarchitects<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"MCP Apps in Angular with CopilotKit: Rich Chat Interfaces Instead of Text Responses - ANGULARarchitects\" \/>\n<meta property=\"og:description\" content=\"This is post 10 of 10 in the series &ldquo;Agentic UI with Angular&rdquo; Understanding AG-UI: The Standard for Agentic User Interfaces AG-UI in Practice: The SDK for TypeScript AG-UI End to End: Connecting Server and Client Agentic UI with Angular, CopilotKit, and AG-UI A2UI: How AI Generates Dynamic UIs at Runtime Integrating A2UI with AG-UI [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/\" \/>\n<meta property=\"og:site_name\" content=\"ANGULARarchitects\" \/>\n<meta property=\"article:published_time\" content=\"2026-07-30T08:05:08+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-07-30T08:49:23+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/07\/sujet-2.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"628\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Manfred Steyer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/07\/sujet-2.jpg\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Manfred Steyer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/\"},\"author\":{\"name\":\"Manfred Steyer\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/f3de69c1e2bdb5ba04d8d2f5f998b81a\"},\"headline\":\"MCP Apps in Angular with CopilotKit: Rich Chat Interfaces Instead of Text Responses\",\"datePublished\":\"2026-07-30T08:05:08+00:00\",\"dateModified\":\"2026-07-30T08:49:23+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/\"},\"wordCount\":1556,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/07\/ChatGPT-Image-Jul-30-2026-09_59_18-AM.png\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/\",\"name\":\"MCP Apps in Angular with CopilotKit: Rich Chat Interfaces Instead of Text Responses - ANGULARarchitects\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/07\/ChatGPT-Image-Jul-30-2026-09_59_18-AM.png\",\"datePublished\":\"2026-07-30T08:05:08+00:00\",\"dateModified\":\"2026-07-30T08:49:23+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/#primaryimage\",\"url\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/07\/ChatGPT-Image-Jul-30-2026-09_59_18-AM.png\",\"contentUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/07\/ChatGPT-Image-Jul-30-2026-09_59_18-AM.png\",\"width\":1672,\"height\":941},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.angulararchitects.io\/en\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"MCP Apps in Angular with CopilotKit: Rich Chat Interfaces Instead of Text Responses\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#website\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/\",\"name\":\"ANGULARarchitects\",\"description\":\"AngularArchitects.io\",\"publisher\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.angulararchitects.io\/en\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\",\"name\":\"ANGULARarchitects\",\"alternateName\":\"SOFTWAREarchitects\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg\",\"contentUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg\",\"width\":644,\"height\":216,\"caption\":\"ANGULARarchitects\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/github.com\/angular-architects\",\"https:\/\/www.linkedin.com\/company\/angular-architects\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/f3de69c1e2bdb5ba04d8d2f5f998b81a\",\"name\":\"Manfred Steyer\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/8778dfb353992fa3a0d909beee085a088891e5bfce65cdb3631801da527cf11b?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/8778dfb353992fa3a0d909beee085a088891e5bfce65cdb3631801da527cf11b?s=96&d=mm&r=g\",\"caption\":\"Manfred Steyer\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"MCP Apps in Angular with CopilotKit: Rich Chat Interfaces Instead of Text Responses - ANGULARarchitects","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/","og_locale":"en_US","og_type":"article","og_title":"MCP Apps in Angular with CopilotKit: Rich Chat Interfaces Instead of Text Responses - ANGULARarchitects","og_description":"This is post 10 of 10 in the series &ldquo;Agentic UI with Angular&rdquo; Understanding AG-UI: The Standard for Agentic User Interfaces AG-UI in Practice: The SDK for TypeScript AG-UI End to End: Connecting Server and Client Agentic UI with Angular, CopilotKit, and AG-UI A2UI: How AI Generates Dynamic UIs at Runtime Integrating A2UI with AG-UI [&hellip;]","og_url":"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/","og_site_name":"ANGULARarchitects","article_published_time":"2026-07-30T08:05:08+00:00","article_modified_time":"2026-07-30T08:49:23+00:00","og_image":[{"width":1200,"height":628,"url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/07\/sujet-2.jpg","type":"image\/jpeg"}],"author":"Manfred Steyer","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/07\/sujet-2.jpg","twitter_misc":{"Written by":"Manfred Steyer","Est. reading time":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/#article","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/"},"author":{"name":"Manfred Steyer","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/f3de69c1e2bdb5ba04d8d2f5f998b81a"},"headline":"MCP Apps in Angular with CopilotKit: Rich Chat Interfaces Instead of Text Responses","datePublished":"2026-07-30T08:05:08+00:00","dateModified":"2026-07-30T08:49:23+00:00","mainEntityOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/"},"wordCount":1556,"commentCount":0,"publisher":{"@id":"https:\/\/www.angulararchitects.io\/en\/#organization"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/07\/ChatGPT-Image-Jul-30-2026-09_59_18-AM.png","inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/","url":"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/","name":"MCP Apps in Angular with CopilotKit: Rich Chat Interfaces Instead of Text Responses - ANGULARarchitects","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/#primaryimage"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/07\/ChatGPT-Image-Jul-30-2026-09_59_18-AM.png","datePublished":"2026-07-30T08:05:08+00:00","dateModified":"2026-07-30T08:49:23+00:00","breadcrumb":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/#primaryimage","url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/07\/ChatGPT-Image-Jul-30-2026-09_59_18-AM.png","contentUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/07\/ChatGPT-Image-Jul-30-2026-09_59_18-AM.png","width":1672,"height":941},{"@type":"BreadcrumbList","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/mcp-apps-in-angular-with-copilotkit-rich-chat-interfaces-instead-of-text-responses\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.angulararchitects.io\/en\/"},{"@type":"ListItem","position":2,"name":"MCP Apps in Angular with CopilotKit: Rich Chat Interfaces Instead of Text Responses"}]},{"@type":"WebSite","@id":"https:\/\/www.angulararchitects.io\/en\/#website","url":"https:\/\/www.angulararchitects.io\/en\/","name":"ANGULARarchitects","description":"AngularArchitects.io","publisher":{"@id":"https:\/\/www.angulararchitects.io\/en\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.angulararchitects.io\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.angulararchitects.io\/en\/#organization","name":"ANGULARarchitects","alternateName":"SOFTWAREarchitects","url":"https:\/\/www.angulararchitects.io\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/","url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg","contentUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg","width":644,"height":216,"caption":"ANGULARarchitects"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/github.com\/angular-architects","https:\/\/www.linkedin.com\/company\/angular-architects\/"]},{"@type":"Person","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/f3de69c1e2bdb5ba04d8d2f5f998b81a","name":"Manfred Steyer","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/8778dfb353992fa3a0d909beee085a088891e5bfce65cdb3631801da527cf11b?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/8778dfb353992fa3a0d909beee085a088891e5bfce65cdb3631801da527cf11b?s=96&d=mm&r=g","caption":"Manfred Steyer"}}]}},"_links":{"self":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/34562","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/users\/25"}],"replies":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/comments?post=34562"}],"version-history":[{"count":7,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/34562\/revisions"}],"predecessor-version":[{"id":34582,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/34562\/revisions\/34582"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media\/34552"}],"wp:attachment":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media?parent=34562"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/categories?post=34562"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/tags?post=34562"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}