How ChatMCP Implements Thinking Mode and Artifact Display Features

ChatMCP implements thinking mode and artifact display by extending Flutter's markdown parser to recognize custom XML-style tags, transforming <antThinking> reasoning blocks into expandable panels and <antArtifact> references into interactive file cards.

ChatMCP (daodao97/chatmcp) enhances standard markdown rendering for LLM chat interfaces by supporting Anthropic-style custom tags. The implementation uses a specialized parsing layer built on top of Flutter's markdown package to detect and render these non-standard elements as native UI components.

Custom Markdown Tag Architecture

The foundation of ChatMCP's extended markdown support resides in lib/widgets/markdown/tag.dart. This file defines the base parsing infrastructure through two abstract classes that handle XML-style tag detection within markdown streams.

Base Syntax Classes

The TagInlineSyntax and TagBlockSyntax classes provide the regex-based tokenization logic required to identify opening tags, extract attributes, and capture body content. These base classes enable the parser to distinguish between inline elements and block-level containers, passing structured node data to specialized widget builders while maintaining clean separation between parsing and presentation layers.

Thinking Mode Implementation

ChatMCP processes reasoning content through the <antThinking> tag system implemented in lib/widgets/markdown/widgets/think.dart. This file contains the complete implementation chain including syntax recognition, AST node definition, widget construction, and UI interaction logic.

Tag Syntax and Content Capture

When the parser identifies an opening <antThinking> delimiter, it initiates a content buffer that accumulates tokens until encountering the closing </antThinking> tag. The system captures the inner content as raw markdown, preserving formatting syntax for nested rendering.

<antThinking>
Analyzing the user's request to determine the appropriate tool...
The user wants to calculate a sum, so I should use the calculator function.

```python
def calculate():
    return 42

### UI Widget Behavior

The thinking widget renders as an expandable panel titled **"Thinking…"** with a loading spinner indicator. By default, the panel displays in a collapsed state showing only the header and spinner. Users can tap to expand the panel, revealing the inner text rendered as a nested markdown block with full syntax highlighting support.

## Artifact Display System

For file and code artifact management, ChatMCP utilizes the self-closing `<antArtifact>` tag defined in `lib/widgets/markdown/widgets/artifact.dart`. Unlike the thinking tag, artifacts carry metadata attributes and render as discrete reference cards rather than expandable text containers.

### Self-Closing Tag Format

The artifact tag uses XML self-closing syntax with three primary attributes: `title` for the display name, `hash` for unique identification, and `closed` to indicate the generation state.

```markdown
<antArtifact title="Generated Python Script" hash="abc123" closed="true" />

Card Rendering and State Management

The artifact widget renders as a compact card displaying the title alongside a unique hash identifier. When the closed="true" attribute is present, the card shows a green checkmark and remains collapsed by default, indicating the artifact generation is complete. Users can tap the card to trigger a preview action, opening the full content in a dedicated view without cluttering the main conversation thread.

Integration and Parsing Flow

The integration between base syntax classes and feature-specific widgets follows a consistent visitor pattern across both features. The TagBlockSyntax implementation in lib/widgets/markdown/tag.dart performs initial regex-based detection, while feature-specific files handle node instantiation.

For thinking blocks, the parser constructs a ThinkNode containing the raw markdown string buffer. Artifact tags parse immediately as self-closing elements, creating ArtifactNode instances with extracted title, hash, and closed boolean properties. Both nodes resolve to their respective Flutter widgets through the markdown visitor pattern, ensuring type-safe rendering pipelines.

Summary

  • ChatMCP extends Flutter markdown through custom tag parsing classes defined in lib/widgets/markdown/tag.dart
  • Thinking mode uses <antThinking> tags parsed by lib/widgets/markdown/widgets/think.dart to show collapsible reasoning panels with spinners and nested markdown support
  • Artifact display employs <antArtifact> tags handled in lib/widgets/markdown/widgets/artifact.dart to generate preview cards with metadata attributes and tap-to-preview functionality
  • Both features use XML-style syntax with proper opening/closing tags for thinking blocks and self-closing format for artifacts
  • The architecture separates syntax recognition from UI rendering through dedicated node classes (ThinkNode, ArtifactNode) and widget implementations

Frequently Asked Questions

What markdown syntax triggers the thinking mode in ChatMCP?

ChatMCP recognizes the <antThinking> XML-style tag to trigger thinking mode. Content wrapped between <antThinking> and </antThinking> renders as a collapsible panel with a "Thinking…" header and spinner animation, supporting nested markdown formatting including code blocks within the reasoning text.

How does ChatMCP display generated code artifacts?

ChatMCP displays artifacts through the <antArtifact> self-closing tag with title, hash, and closed attributes. The system renders these as interactive cards in lib/widgets/markdown/widgets/artifact.dart, showing the title with a green checkmark when closed, and allowing tap-to-preview functionality for full content examination.

Where is the custom markdown parsing logic located?

The custom markdown parsing infrastructure resides in lib/widgets/markdown/tag.dart, which defines TagInlineSyntax and TagBlockSyntax base classes. Feature-specific implementations extend these classes in lib/widgets/markdown/widgets/think.dart for thinking mode and lib/widgets/markdown/widgets/artifact.dart for artifact display.

Can users interact with the thinking panels?

Yes, thinking panels implemented in lib/widgets/markdown/widgets/think.dart support user interaction through expand and collapse gestures. The panels default to a collapsed state showing only the "Thinking…" header and spinner, while tapping reveals the full reasoning content with preserved markdown formatting.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →