# How ChatMCP Implements Thinking Mode and Artifact Display Features

> Discover how ChatMCP implements thinking mode and artifact display by extending Flutter's markdown parser with custom XML tags for expandable panels and interactive file cards.

- Repository: [刀刀/chatmcp](https://github.com/daodao97/chatmcp)
- Tags: deep-dive
- Published: 2026-02-28

---

**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.

```markdown
<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

```

</antThinking>

```

### 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.