#
tokens: 48031/50000 54/62 files (page 1/2)
lines: off (toggle) GitHub
raw markdown copy
This is page 1 of 2. Use http://codebase.md/adamsmaka/flutter-mcp?page={x} to view the full context.

# Directory Structure

```
├── .dockerignore
├── .github
│   └── workflows
│       ├── build-executables.yml
│       └── publish-pypi.yml
├── .gitignore
├── .pypirc.template
├── .python-version
├── build.spec
├── CHANGELOG.md
├── CLAUDE.md
├── context7-installation-analysis.md
├── docker
│   ├── docker-compose.yml
│   └── Dockerfile
├── docs
│   ├── api-reference.md
│   ├── CLIENT-CONFIGURATIONS.md
│   ├── CONTRIBUTING.md
│   ├── DEVELOPMENT.md
│   ├── planning
│   │   ├── context7-marketing-analysis.md
│   │   ├── flutter-mcp-project-summary.md
│   │   ├── IMPLEMENTATION_SUMMARY.md
│   │   ├── ingestion-strategy.md
│   │   ├── initial-vision.md
│   │   ├── project-summary.md
│   │   ├── project-tasks.csv
│   │   ├── README-highlights.md
│   │   └── task-summary.md
│   ├── PUBLISHING.md
│   ├── README.md
│   ├── token-counting-analysis.md
│   ├── token-management-implementation.md
│   ├── TOOL-CONSOLIDATION-PLAN.md
│   ├── truncation-algorithm.md
│   └── VERSION_SPECIFICATION.md
├── ERROR_HANDLING.md
├── examples
│   ├── token_management_demo.py
│   └── truncation_demo.py
├── LICENSE
├── MANIFEST.in
├── npm-wrapper
│   ├── .gitignore
│   ├── bin
│   │   └── flutter-mcp.js
│   ├── index.js
│   ├── package.json
│   ├── publish.sh
│   ├── README.md
│   └── scripts
│       └── install.js
├── pyproject.toml
├── QUICK_FIX.md
├── README.md
├── RELEASE_GUIDE.md
├── scripts
│   ├── build-executables.sh
│   ├── publish-pypi.sh
│   └── test-server.sh
├── setup.py
├── src
│   └── flutter_mcp
│       ├── __init__.py
│       ├── __main__.py
│       ├── cache.py
│       ├── cli.py
│       ├── error_handling.py
│       ├── logging_utils.py
│       ├── recovery.py
│       ├── server.py
│       ├── token_manager.py
│       └── truncation.py
├── tests
│   ├── __init__.py
│   ├── test_integration.py
│   ├── test_token_management.py
│   ├── test_tools.py
│   └── test_truncation.py
└── uv.lock
```

# Files

--------------------------------------------------------------------------------
/.python-version:
--------------------------------------------------------------------------------

```
3.13

```

--------------------------------------------------------------------------------
/npm-wrapper/.gitignore:
--------------------------------------------------------------------------------

```
# Node modules
node_modules/

# npm debug logs
npm-debug.log*

# IDE
.vscode/
.idea/

# OS
.DS_Store
Thumbs.db

# Build artifacts
*.tgz
```

--------------------------------------------------------------------------------
/.pypirc.template:
--------------------------------------------------------------------------------

```
# PyPI configuration template
# Copy this file to ~/.pypirc and update with your credentials
# DO NOT commit this file with real credentials!

[distutils]
index-servers =
    pypi
    testpypi

[pypi]
username = __token__
password = pypi-<your-token-here>

[testpypi]
repository = https://test.pypi.org/legacy/
username = __token__
password = pypi-<your-test-token-here>
```

--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------

```
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
.venv/
venv/
ENV/
env/

# Testing
.pytest_cache/
.coverage
htmlcov/
.tox/
.nox/

# Git
.git/
.gitignore

# Documentation (except needed files)
docs/planning/

# Development
.env
.env.local
*.log
*.swp
.DS_Store

# IDE
.vscode/
.idea/
*.sublime-*

# Build artifacts
build/
dist/
*.egg-info/
.eggs/

# Cache
.cache/
.mypy_cache/
.ruff_cache/
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
venv/
ENV/
env.bak/
venv.bak/
.venv
pip-log.txt
pip-delete-this-directory.txt
.env

# Virtual environments
bin/
include/
lib/
lib64/
share/
pyvenv.cfg

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
*.manifest

# Unit test / coverage
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# IDEs
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store

# Project specific
.uv/
*.log
dump.rdb
redis-data/

# MCP
mcp-inspector-data/
inspiration/
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
docs/README.md
```

--------------------------------------------------------------------------------
/npm-wrapper/README.md:
--------------------------------------------------------------------------------

```markdown
# flutter-mcp

Stop hallucinated Flutter code. Get real docs, instantly.

Flutter MCP provides AI coding assistants with real-time access to Flutter/Dart documentation, eliminating outdated or incorrect API suggestions.

## Quick Start

```bash
# One-time usage (no installation)
npx flutter-mcp

# Or install globally
npm install -g flutter-mcp
flutter-mcp
```

## Claude Desktop Setup

Add to your `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "flutter-docs": {
      "command": "npx",
      "args": ["flutter-mcp"]
    }
  }
}
```

That's it! No configuration needed.

## Features

✅ **Real-time documentation** - Always up-to-date Flutter/Dart APIs  
✅ **500+ pre-indexed widgets** - Instant access to common Flutter components  
✅ **Smart search** - Fuzzy matching finds what you need  
✅ **Pub.dev integration** - Package docs and examples included  
✅ **Zero config** - Works out of the box  

## Advanced Usage

```bash
# HTTP mode for web clients
flutter-mcp --http --port 3000

# SSE mode for streaming
flutter-mcp --sse --port 3000

# Update Python backend
flutter-mcp --install
```

## Requirements

- Node.js 16+
- Python 3.8+
- pip (Python package manager)

## What it does

This wrapper:
1. Checks for Python 3.8+ installation
2. Installs the `flutter-mcp-server` Python package if needed
3. Runs the Flutter MCP Server

## Documentation

For full documentation, visit: https://github.com/flutter-mcp/flutter-mcp

## License

MIT
```

--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------

```markdown
# Flutter MCP: Give Your AI Real-Time Flutter Superpowers 🚀

**A real-time MCP server providing Flutter/Dart documentation and pub.dev package info to AI assistants — supports ALL 50,000+ packages on demand.**

Stop fighting with hallucinated widgets and deprecated APIs. Flutter MCP connects your AI assistant to real-time documentation, ensuring the Flutter code it generates actually works.

<p align="center">
  <a href="https://www.npmjs.com/package/flutter-mcp"><img src="https://img.shields.io/npm/v/flutter-mcp.svg" alt="npm version"></a>
  <a href="https://www.npmjs.com/package/flutter-mcp"><img src="https://img.shields.io/npm/dm/flutter-mcp.svg" alt="npm downloads"></a>
</p>

<p align="center">
  <img src="https://img.shields.io/badge/Flutter-02569B?style=for-the-badge&logo=flutter&logoColor=white" alt="Flutter">
  <img src="https://img.shields.io/badge/Dart-0175C2?style=for-the-badge&logo=dart&logoColor=white" alt="Dart">
  <img src="https://img.shields.io/badge/Python-3776AB?style=for-the-badge&logo=python&logoColor=white" alt="Python">
  <img src="https://img.shields.io/badge/MCP-Protocol-green?style=for-the-badge" alt="MCP">
</p>

<p align="center">
  <a href="#-quick-start">Quick Start</a> •
  <a href="#-demo">Demo</a> •
  <a href="#-features">Features</a> •
  <a href="#-how-it-works">How it Works</a> •
  <a href="#-contributing">Contributing</a>
</p>

## 🎬 Demo

<p align="center">
  <img src="https://github.com/flutter-mcp/flutter-mcp/assets/demo.gif" alt="Flutter MCP Demo" width="800">
</p>

**See it in action**: From `npx flutter-mcp` to getting real-time Flutter documentation in 20 seconds.

## The Problem: Your AI is Stuck in 2021

<table>
<tr>
<td width="50%" align="center">

### 😡 Without Flutter MCP

```dart
// User: "How do I use Riverpod to watch a future?"

// AI generates (outdated):
final userProvider = FutureProvider((ref) async {
  return fetchUser();
});

// WRONG! Missing autoDispose, family, etc.
```

**Result**: Deprecation warnings, confused debugging, time wasted on Google

</td>
<td width="50%" align="center">

### ✅ With Flutter MCP

```dart
// User: "How do I use @flutter_mcp riverpod:^2.5.0 to watch a future?"

// AI generates (using v2.5.1 docs):
final userProvider = FutureProvider.autoDispose
  .family<User, String>((ref, userId) async {
    return ref.watch(apiProvider).fetchUser(userId);
});

// Correct, version-specific, actually works!
```

**Result**: Code works immediately, you ship faster

</td>
</tr>
</table>

## 🚀 Quick Start

### Installation

Get started in seconds with npm:

```bash
# One-line usage (no installation required)
npx flutter-mcp

# Or install globally
npm install -g flutter-mcp
flutter-mcp
```

That's it! No Python setup, no configuration, no complexity. The server automatically installs dependencies and starts running.

> **📢 For MCP SuperAssistant Users**: Use `npx flutter-mcp --transport http --port 8000` to enable HTTP transport!

### Alternative Installation Methods

<details>
<summary><strong>🐍 Python Package (pip)</strong></summary>

If you prefer using Python directly:

```bash
# Install from GitHub (PyPI package coming soon)
pip install git+https://github.com/adamsmaka/flutter-mcp.git

# Run the server
flutter-mcp-server start
```

</details>

<details>
<summary><strong>🔧 Install from Source</strong></summary>

For development or customization:

```bash
# Clone the repository
git clone https://github.com/adamsmaka/flutter-mcp.git
cd flutter-mcp

# Create virtual environment
python3 -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install in development mode
pip install -e .

# Run the server
flutter-mcp-server start
```

</details>

<details>
<summary><strong>🐳 Docker</strong></summary>

For containerized deployments:

```bash
# Docker image coming soon
# Run with Docker (once published)
# docker run -d -p 8000:8000 ghcr.io/adamsmaka/flutter-mcp:latest

# For now, use local development setup instead
pip install git+https://github.com/adamsmaka/flutter-mcp.git
```

</details>

<details>
<summary><strong>🎯 Single Executable (Coming Soon)</strong></summary>

```bash
# Download for your platform
curl -L https://github.com/flutter-mcp/flutter-mcp/releases/latest/flutter-mcp-macos -o flutter-mcp
chmod +x flutter-mcp
./flutter-mcp
```

No Python, no pip, just download and run!

</details>

### Requirements

- **Node.js 16+** (for npm/npx)
- Python 3.10+ is auto-detected and used by the npm package
- That's it! Built-in SQLite caching means no external dependencies

### 2. Add to Your AI Assistant

<details open>
<summary><strong>Claude Desktop</strong></summary>

Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "flutter-docs": {
      "command": "npx",
      "args": ["flutter-mcp"]
    }
  }
}
```

Or if you installed globally:

```json
{
  "mcpServers": {
    "flutter-docs": {
      "command": "flutter-mcp"
    }
  }
}
```

Restart Claude Desktop after saving. The server will automatically install dependencies on first run.

</details>

<details>
<summary><strong>Claude Code (claude.ai/code)</strong></summary>

Create a `.mcp.json` file in your Flutter project root:

```json
{
  "mcpServers": {
    "flutter-docs": {
      "command": "npx",
      "args": ["flutter-mcp"]
    }
  }
}
```

Then run Claude Code in your project directory:
```bash
cd your-flutter-project
claude
```

Flutter MCP will automatically provide documentation for all packages in your `pubspec.yaml`.

**Alternative: Global npm install**

If you installed globally with `npm install -g flutter-mcp`:

```json
{
  "mcpServers": {
    "flutter-docs": {
      "command": "flutter-mcp"
    }
  }
}
```

**Important:** Don't use the `--dangerously-skip-permissions` flag when running Claude Code, as it prevents MCP servers from being loaded.

</details>

<details>
<summary><strong>Cursor / Windsurf</strong></summary>

In Settings → MCP Servers, add:

```json
{
  "flutter-docs": {
    "command": "npx",
    "args": ["flutter-mcp"]
  }
}
```

</details>

<details>
<summary><strong>MCP SuperAssistant</strong></summary>

MCP SuperAssistant requires HTTP transport. Configure it with:

1. Start the server with HTTP transport:
```bash
npx flutter-mcp --transport http --port 8000
```

2. In MCP SuperAssistant, add a new server:
   - **Name**: Flutter MCP
   - **URL**: `http://localhost:8000`
   - **Type**: HTTP MCP Server

3. The server will now be available in your MCP SuperAssistant client.

</details>

<details>
<summary><strong>VS Code + Continue</strong></summary>

In your `.continuerc.json`:

```json
{
  "models": [
    {
      "provider": "claude",
      "mcp_servers": {
        "flutter-docs": {
          "command": "npx",
          "args": ["flutter-mcp"]
        }
      }
    }
  ]
}
```

</details>

### 3. Start the Server (Optional for Testing)

<details>
<summary>Manual server control and transport options</summary>

```bash
# Default STDIO mode (for Claude Desktop)
npx flutter-mcp

# HTTP transport (for MCP SuperAssistant)
npx flutter-mcp --transport http --port 8000

# SSE transport
npx flutter-mcp --transport sse --port 8080

# Custom host binding
npx flutter-mcp --transport http --host 0.0.0.0 --port 3000

# If installed globally
flutter-mcp-server --transport http --port 8000
```

**Transport Options:**
- Default (no flag) - STDIO for Claude Desktop and most MCP clients
- `--transport http` - For HTTP-based clients like MCP SuperAssistant
- `--transport sse` - For Server-Sent Events based clients
- `--port PORT` - Port for HTTP/SSE transport (default: 8000)
- `--host HOST` - Host to bind to (default: 127.0.0.1)

Note: When configured in Claude Desktop, the server starts automatically using STDIO transport.

</details>

### 3. Use It!

Flutter MCP now features simplified tools following Context7's successful pattern - just 2 main tools instead of 5!

#### 🎯 New Simplified Usage (Recommended)

The AI assistant can now use Flutter MCP more intelligently:

```
# Universal search
"Search for Flutter animation widgets"
"Find state management packages" 
"Look for HTTP clients in pub.dev"

# Smart documentation fetching
"Show me Container widget documentation"
"Get the docs for provider package"
"Explain dart:async Future class"
```

#### 💫 Natural Language Support

Your AI will automatically detect Flutter/Dart content and fetch relevant docs:

```
"How do I implement infinite scroll with infinite_scroll_pagination?"
"Show me dio interceptors for auth tokens"
"What's the difference between bloc and riverpod?"
```

#### 🔧 Legacy Support

The `@flutter_mcp` mentions still work for backward compatibility:

```
"Explain @flutter_mcp freezed code generation"
"Show me all @flutter_mcp get_it service locator patterns"
```

### 🎯 Version-Specific Documentation (NEW!)

Get documentation for specific package versions using familiar pub.dev syntax:

```
# Exact versions
"Show me @flutter_mcp provider:6.0.5 breaking changes"
"How does @flutter_mcp riverpod:2.5.1 AsyncNotifier work?"

# Version ranges
"Compare @flutter_mcp dio:^5.0.0 vs @flutter_mcp dio:^4.0.0"
"What's new in @flutter_mcp bloc:>=8.0.0?"

# Special keywords
"Try @flutter_mcp get:latest experimental features"
"Is @flutter_mcp provider:stable production ready?"
```

See [Version Specification Guide](docs/VERSION_SPECIFICATION.md) for details.

## 📚 Available Tools

### 🎯 NEW: Simplified Tools (Context7-style)

Flutter MCP now provides just 2 main tools, making it easier for AI assistants to use:

### 1. `flutter_search` - Universal Search

Search across Flutter/Dart documentation and pub.dev packages with intelligent ranking.

```json
{
  "tool": "flutter_search",
  "arguments": {
    "query": "state management",
    "limit": 10  // Optional: max results (default: 10)
  }
}
```

Returns multiple options for the AI to choose from, including Flutter classes, Dart libraries, pub packages, and concepts.

### 2. `flutter_docs` - Smart Documentation Fetcher

Get documentation for any Flutter/Dart identifier with automatic type detection.

```json
{
  "tool": "flutter_docs",
  "arguments": {
    "identifier": "Container",              // Auto-detects as Flutter widget
    "topic": "examples",                    // Optional: filter content
    "max_tokens": 10000                     // Optional: limit response size
  }
}
```

Supports various formats:
- `"Container"` - Flutter widget
- `"material.AppBar"` - Library-qualified class
- `"provider"` - pub.dev package
- `"dart:async.Future"` - Dart core library

### 3. `flutter_status` - Health Check (Optional)

Monitor service health and cache statistics.

```json
{
  "tool": "flutter_status",
  "arguments": {}
}
```

---

### 📦 Legacy Tools (Deprecated but still functional)

The following tools are maintained for backward compatibility but internally use the new simplified tools:

<details>
<summary>View legacy tools</summary>

#### `get_flutter_docs` (Use `flutter_docs` instead)
```json
{
  "tool": "get_flutter_docs",
  "arguments": {
    "class_name": "Container",
    "library": "widgets"
  }
}
```

#### `get_pub_package_info` (Use `flutter_docs` instead)
```json
{
  "tool": "get_pub_package_info",
  "arguments": {
    "package_name": "provider",
    "version": "6.0.5"
  }
}
```

#### `search_flutter_docs` (Use `flutter_search` instead)
```json
{
  "tool": "search_flutter_docs",
  "arguments": {
    "query": "material.AppBar"
  }
}
```

#### `process_flutter_mentions` (Still functional)
```json
{
  "tool": "process_flutter_mentions",
  "arguments": {
    "text": "I need help with @flutter_mcp riverpod state management"
  }
}
```

#### `health_check` (Use `flutter_status` instead)
```json
{
  "tool": "health_check",
  "arguments": {}
}
```

</details>

## 🎯 Features

- **✨ NEW: Simplified Tools**: Just 2 main tools instead of 5 - following Context7's successful pattern
- **📦 Real-Time Documentation**: Fetches the latest docs for any pub.dev package on-demand
- **🎯 Version-Specific Docs**: Request exact versions, ranges, or use keywords like `latest`/`stable`
- **🚀 Zero Configuration**: Automatically detects packages from your `pubspec.yaml`
- **⚡ Lightning Fast**: Intelligent caching means instant responses after first fetch
- **🔒 100% Private**: Runs locally - your code never leaves your machine
- **🎨 Smart Context**: Provides constructors, methods, examples, and migration guides
- **♾️ Unlimited Packages**: Works with all 50,000+ packages on pub.dev
- **🤖 AI-Optimized**: Token limiting and smart truncation for efficient LLM usage

## 💡 How It Works

Flutter MCP is a local MCP server (think of it as a "RAG sidecar" for Flutter) built on the battle-tested Python MCP SDK. It enhances your AI with real-time documentation:

```mermaid
graph LR
    A[Your Prompt] --> B[AI Assistant]
    B --> C{Flutter/Dart Content?}
    C -->|Yes| D[Query Flutter MCP]
    D --> E[Check Local Cache]
    E -->|Hit| F[Return Cached Docs]
    E -->|Miss| G[Fetch from pub.dev]
    G --> H[Process & Cache]
    H --> F
    F --> I[Enhanced Context]
    I --> J[AI Generates Accurate Code]
    C -->|No| J
```

### The Magic Behind the Scenes

1. **MCP Integration**: Your AI assistant automatically detects when you're asking about Flutter/Dart packages
2. **Smart Detection**: No special syntax required - just mention package names naturally
3. **Lightning Cache**: First request fetches from pub.dev (1-2 seconds), subsequent requests are instant
4. **Context Injection**: Documentation is seamlessly added to your AI's knowledge before it responds
5. **Privacy First**: Everything runs locally - your code and queries never leave your machine

### Performance Notes

- ⚡ **First Query**: 1-2 seconds (fetching from pub.dev)
- 🚀 **Cached Queries**: <50ms (from local SQLite cache)
- 💾 **Cache Duration**: 24 hours for API docs, 12 hours for packages
- 🧹 **Auto-Cleanup**: Expired entries cleaned on access

### Error Handling

If documentation isn't available or a fetch fails, Flutter MCP gracefully informs your AI, preventing it from generating incorrect or hallucinated code based on missing information. Your AI will let you know it couldn't find the docs rather than guessing.

## 📊 What Gets Indexed

When you request a package, Flutter MCP extracts:

- ✅ **API Documentation**: Classes, methods, properties with full signatures
- ✅ **Constructors**: All parameters, named arguments, defaults
- ✅ **Code Examples**: From official docs and README files
- ✅ **Migration Guides**: Breaking changes and upgrade paths
- ✅ **Package Metadata**: Dependencies, platform support, versions

## 🛠️ Advanced Usage

<details>
<summary><strong>Debug Commands</strong></summary>

```bash
# Run with debug logging
DEBUG=true npx flutter-mcp

# Check server status and cache info
flutter-mcp-server --help
```

Note: Cache is automatically managed by the server. Cached documentation expires after 24 hours (API docs) or 12 hours (packages).

</details>

<details>
<summary><strong>Docker Deployment</strong></summary>

For production or team use:

```bash
# Run the server (Docker image coming soon)
# docker run -d -p 8000:8000 --name flutter-mcp ghcr.io/adamsmaka/flutter-mcp:latest

# Check logs
docker logs -f flutter-mcp
```

</details>

## 🛠️ Troubleshooting

<details>
<summary><strong>Error: spawn flutter-mcp ENOENT</strong></summary>

This error means the system cannot find the `flutter-mcp` command. Solutions:

1. **Use npx (recommended):**
```json
{
  "mcpServers": {
    "flutter-docs": {
      "command": "npx",
      "args": ["flutter-mcp"]
    }
  }
}
```

2. **Install globally first:**
```bash
npm install -g flutter-mcp
# Then use:
{
  "mcpServers": {
    "flutter-docs": {
      "command": "flutter-mcp"
    }
  }
}
```

3. **Check Node.js installation:**
```bash
node --version  # Should be 16+
npm --version   # Should be installed
```

</details>

<details>
<summary><strong>MCP server failed to start</strong></summary>

1. Check if Node.js 16+ is installed: `node --version`
2. Try running manually to see errors: `npx flutter-mcp`
3. The npm package will auto-install Python dependencies on first run
4. Check if Python 3.8+ is available: `python3 --version`
5. View detailed logs: `DEBUG=true npx flutter-mcp`

</details>

<details>
<summary><strong>Documentation not found errors</strong></summary>

- Some very new packages might not have documentation yet
- Private packages are not supported
- Try using the package name exactly as it appears on pub.dev

</details>

<details>
<summary><strong>Cannot connect from MCP client</strong></summary>

Different MCP clients require different transport protocols:

1. **Claude Desktop**: Uses STDIO transport (default)
   - No port/URL needed
   - Just use: `npx flutter-mcp`

2. **MCP SuperAssistant**: Requires HTTP transport
   - Start with: `npx flutter-mcp --transport http --port 8000`
   - Connect to: `http://localhost:8000`

3. **Custom clients**: May need SSE transport
   - Start with: `npx flutter-mcp --transport sse --port 8080`
   - SSE endpoint: `http://localhost:8080/sse`

If connection fails:
- Verify the correct transport mode for your client
- Check if the port is already in use
- Try binding to all interfaces: `--host 0.0.0.0`
- Ensure Node.js and npm are properly installed

</details>

## 📱 Client Configurations

Need help configuring your MCP client? We have detailed guides for:
- Claude Desktop
- MCP SuperAssistant  
- Claude Code
- VS Code + Continue
- Custom HTTP/SSE clients
- Docker configurations

**[→ View all client configuration examples](docs/CLIENT-CONFIGURATIONS.md)**

## 🤝 Contributing

We love contributions! This is an open-source project and we welcome improvements.

**[→ Read our Contributing Guide](CONTRIBUTING.md)**

### Quick Ways to Contribute

- 🐛 **Report bugs** - [Open an issue](https://github.com/flutter-mcp/flutter-mcp/issues)
- 💡 **Suggest features** - [Start a discussion](https://github.com/flutter-mcp/flutter-mcp/discussions)
- 📖 **Improve docs** - Even fixing a typo helps!
- 🧪 **Add tests** - Help us reach 100% coverage
- 🌐 **Add translations** - Make Flutter MCP accessible globally
- ⭐ **Star the repo** - Help others discover Flutter MCP

### 🚀 What's New & Coming Soon

**Recently Released:**
- ✅ **Simplified Tools**: Reduced from 5 tools to just 2 main tools (Context7-style)
- ✅ **Smart Detection**: Auto-detects Flutter widgets, Dart classes, and pub packages
- ✅ **Token Limiting**: Default 10,000 tokens with smart truncation
- ✅ **Topic Filtering**: Focus on specific sections (examples, constructors, etc.)

**On our roadmap:**
- 📚 Stack Overflow integration for common Flutter questions
- 🎯 Natural language activation: "use flutter docs" pattern
- 🌍 Offline mode for airplane coding
- 🚀 Hosted service option for teams

Want to help build these features? [Join us!](CONTRIBUTING.md)

## ❤️ Spread the Word

Help other Flutter developers discover AI superpowers:

<p align="center">
<a href="https://twitter.com/intent/tweet?text=Just%20gave%20my%20AI%20assistant%20Flutter%20superpowers%20with%20%40flutter_mcp!%20Real-time%20docs%20for%20any%20pub.dev%20package.%20No%20more%20outdated%20code!%20%23Flutter%20%23AI&url=https://github.com/flutter-mcp/flutter-mcp">
  <img src="https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Fgithub.com%2Fflutter-mcp%2Fflutter-mcp" alt="Tweet">
</a>
</p>


Add the badge to your project:

```markdown
[![Flutter MCP](https://img.shields.io/badge/Enhanced%20by-Flutter%20MCP-blue)](https://github.com/flutter-mcp/flutter-mcp)
```

## 📄 License

MIT © 2024 Flutter MCP Contributors

## 🏗️ Built With

- **[Python MCP SDK](https://github.com/modelcontextprotocol/python-sdk)** - The most popular MCP implementation (14k+ stars)
- **[FastMCP](https://github.com/modelcontextprotocol/fastmcp)** - High-level Python framework for MCP servers
- **SQLite** - Built-in caching with zero configuration
- **npm/npx** - Simple one-line installation and execution
- **BeautifulSoup** - Robust HTML parsing
- **httpx** - Modern async HTTP client

---

<p align="center">
  <strong>Ready to give your AI Flutter superpowers?</strong>
  <br><br>
  <a href="#-quick-start">Get Started</a> • 
  <a href="https://github.com/flutter-mcp/flutter-mcp/issues">Report Bug</a> • 
  <a href="https://github.com/flutter-mcp/flutter-mcp/discussions">Request Feature</a>
  <br><br>
  Made with ❤️ by the Flutter community
</p>

```

--------------------------------------------------------------------------------
/CLAUDE.md:
--------------------------------------------------------------------------------

```markdown
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

This is a Flutter/Dart documentation MCP (Model Context Protocol) server project designed to provide AI assistants with seamless access to Flutter and Dart documentation. Following Context7's proven approach, the project uses on-demand web scraping with Redis caching to ensure users always get the most current documentation while maintaining fast response times.

## Key Architecture Components

1. **MCP Server**: FastMCP server with on-demand documentation fetching
2. **Redis Caching**: Fast in-memory cache for processed documentation
3. **Web Scraping**: Respectful fetching from api.flutter.dev and api.dart.dev
4. **Pub.dev API**: Official API for package documentation
5. **Processing Pipeline**: Parse → Enrich → Clean → Cache (Context7-style)
6. **Rate Limiting**: 2 requests/second to respect server resources

## Development Commands

```bash
# Project setup (using uv package manager)
uv init mcp-server-flutter-docs
cd mcp-server-flutter-docs
uv add "mcp[cli]" httpx redis beautifulsoup4 structlog

# Start Redis (required for caching)
redis-server  # In a separate terminal

# Development server with MCP Inspector
mcp dev server.py

# Run the server
uv run server.py

# Alternative with traditional Python
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
pip install "mcp[cli]" httpx redis beautifulsoup4 structlog
python server.py
```

## Core Implementation Guidelines

1. **On-Demand Fetching**: Fetch documentation only when requested, like Context7
2. **Redis Caching**: Cache processed docs with appropriate TTLs (24h for APIs, 12h for packages)
3. **Smart URL Resolution**: Pattern matching to resolve queries to documentation URLs
4. **Rate Limiting**: RateLimiter class ensuring 2 requests/second max
5. **Error Handling**: Graceful fallbacks when documentation isn't found
6. **User Agent**: Always identify as "Flutter-MCP-Docs/1.0" with GitHub URL

## Transport and Distribution

- **Primary Transport**: STDIO for local Claude Desktop integration
- **Configuration Path**: `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Distribution Size**: <10MB lightweight package
- **Dependencies**: Redis required (local or external service)
- **Distribution Methods**: PyPI package, npm package, Docker image
- **Versioning**: Semantic versioning (MAJOR.MINOR.PATCH)

## Implementation Timeline

1. **MVP (4 hours)**: Basic server with Flutter API docs
2. **Week 1**: Add pub.dev support, search functionality
3. **Week 2**: Polish, documentation, and launch
4. **Future**: Stack Overflow, cookbook, version-specific docs
```

--------------------------------------------------------------------------------
/docs/CONTRIBUTING.md:
--------------------------------------------------------------------------------

```markdown
# Contributing to Flutter MCP 🎉

First off, **thank you** for considering contributing to Flutter MCP! 🙏 This is an open-source community project, and it's people like you who make it possible to give AI assistants real-time Flutter superpowers. Whether you're fixing a typo, reporting a bug, or adding a major feature, every contribution matters!

## 🌟 Ways to Contribute

There are many ways to contribute to Flutter MCP, and we value them all:

### 🐛 Report Bugs

Found something broken? [Open an issue](https://github.com/adamsmaka/flutter-mcp/issues/new?template=bug_report.md) and help us squash it!

### 💡 Suggest Features

Have an idea to make Flutter MCP even better? [Start a discussion](https://github.com/adamsmaka/flutter-mcp/discussions/new?category=ideas) or [open a feature request](https://github.com/adamsmaka/flutter-mcp/issues/new?template=feature_request.md)!

### 📖 Improve Documentation

Even the smallest documentation fix helps! Whether it's fixing a typo, clarifying instructions, or adding examples - documentation is crucial.

### 🧪 Write Tests

Help us maintain quality by adding tests. We aim for high test coverage to ensure Flutter MCP stays reliable.

### 🌐 Add Translations

Make Flutter MCP accessible to developers worldwide by helping with translations.

### ⭐ Spread the Word

Star the repo, share it with your Flutter community, write a blog post, or tweet about your experience!

### 💻 Write Code

Fix bugs, implement features, optimize performance - dive into the code and make Flutter MCP better!

## 🚀 Getting Started

### Prerequisites

Before you begin, ensure you have:

- Python 3.10 or higher
- Redis installed and running
- Git for version control
- A GitHub account

### Development Setup

1. **Fork the repository**

   Click the "Fork" button at the top right of the [Flutter MCP repository](https://github.com/adamsmaka/flutter-mcp).

2. **Clone your fork**

   ```bash
   git clone https://github.com/YOUR-USERNAME/flutter-mcp.git
   cd flutter-mcp
   ```

3. **Set up the development environment**

   ```bash
   # Create a virtual environment
   python -m venv venv

   # Activate it
   source venv/bin/activate  # On Windows: venv\Scripts\activate

   # Install dependencies in development mode
   pip install -e ".[dev]"
   ```

4. **Start Redis**

   ```bash
   # macOS
   brew services start redis

   # Linux
   sudo systemctl start redis

   # Docker
   docker run -d -p 6379:6379 --name flutter-mcp-redis redis:alpine
   ```

5. **Run the development server**

   ```bash
   # Run with MCP Inspector for debugging
   mcp dev src/flutter_mcp/server.py

   # Or run directly
   python -m flutter_mcp.server
   ```

For more detailed setup instructions, check out our [Development Guide](DEVELOPMENT.md).

## 📋 Before You Submit

### 🎨 Code Style Guidelines

We use Python's standard style guidelines with a few preferences:

- **Black** for code formatting (line length: 88)
- **isort** for import sorting
- **Type hints** for all public functions
- **Docstrings** for all classes and public methods

Run the formatters before committing:

```bash
# Format code
black src/ tests/

# Sort imports
isort src/ tests/

# Check types
mypy src/

# Run linter
ruff check src/ tests/
```

### 🧪 Testing Guidelines

All code changes should include tests:

```bash
# Run all tests
pytest

# Run with coverage
pytest --cov=flutter_mcp

# Run specific test file
pytest tests/test_server.py

# Run tests in watch mode
pytest-watch
```

We aim for at least 80% test coverage. Write tests that:

- Cover both happy paths and edge cases
- Are isolated and don't depend on external services
- Use mocks for Redis and external API calls
- Have descriptive names that explain what they test

### 📝 Commit Messages

We follow the [Conventional Commits](https://www.conventionalcommits.org/) specification:

```
feat: add support for package version constraints
fix: handle rate limiting from pub.dev API
docs: update Redis installation instructions
test: add tests for cache expiration
refactor: extract documentation parser into separate module
```

## 🔄 Pull Request Process

### 1. Create a Feature Branch

```bash
git checkout -b feature/your-feature-name
# or
git checkout -b fix/issue-description
```

### 2. Make Your Changes

- Write clean, readable code
- Add tests for new functionality
- Update documentation if needed
- Ensure all tests pass

### 3. Commit Your Changes

```bash
git add .
git commit -m "feat: add amazing new feature"
```

### 4. Push to Your Fork

```bash
git push origin feature/your-feature-name
```

### 5. Open a Pull Request

1. Go to the [Flutter MCP repository](https://github.com/adamsmaka/flutter-mcp)
2. Click "Compare & pull request"
3. Fill out the PR template:
   - Describe what changes you made
   - Link any related issues
   - Include screenshots if relevant
   - Check all the boxes in the checklist

### 6. Code Review

- Be patient and respectful during review
- Respond to feedback constructively
- Make requested changes promptly
- Ask questions if something isn't clear

## 🐛 Reporting Bugs

Found a bug? Help us fix it by providing detailed information:

1. **Search existing issues** first to avoid duplicates
2. **Use the bug report template** when creating an issue
3. **Include**:
   - Flutter MCP version (`flutter-mcp --version`)
   - Python version (`python --version`)
   - OS and version
   - Steps to reproduce
   - Expected behavior
   - Actual behavior
   - Error messages/logs
   - Screenshots if applicable

## 💡 Requesting Features

Have an idea? We'd love to hear it!

1. **Check existing issues and discussions** first
2. **Use the feature request template**
3. **Explain**:
   - The problem you're trying to solve
   - Your proposed solution
   - Alternative solutions you've considered
   - How it benefits other users

## 🤝 Community Guidelines

### Our Code of Conduct

We're committed to providing a welcoming and inclusive environment. By participating, you agree to:

- **Be respectful** - Treat everyone with respect
- **Be constructive** - Provide helpful feedback
- **Be inclusive** - Welcome newcomers and help them get started
- **Be patient** - Remember that everyone is volunteering their time
- **Be professional** - Keep discussions focused and productive

### Getting Help

- 💬 **Discord**: Join our [Flutter MCP Discord](https://discord.gg/flutter-mcp)
- 🤔 **Discussions**: Ask questions in [GitHub Discussions](https://github.com/adamsmaka/flutter-mcp/discussions)
- 📧 **Email**: Reach out to [email protected]

## 🏆 Recognition

We believe in recognizing our contributors!

### All Contributors

We use the [All Contributors](https://allcontributors.org/) specification to recognize everyone who helps make Flutter MCP better. Contributors are automatically added to our README.

### Types of Contributions We Recognize

- 💻 Code
- 📖 Documentation
- 🎨 Design
- 💡 Ideas & Planning
- 🧪 Testing
- 🐛 Bug Reports
- 👀 Code Reviews
- 📢 Evangelism
- 🌍 Translation
- 💬 Answering Questions
- 🚧 Maintenance
- 🔧 Tools
- 📦 Packaging

## 📚 Additional Resources

- [Development Guide](DEVELOPMENT.md) - Detailed development setup
- [Architecture Overview](docs/ARCHITECTURE.md) - How Flutter MCP works
- [API Reference](docs/API.md) - Server API documentation
- [Testing Guide](docs/TESTING.md) - How to write effective tests

## 🎯 Current Priorities

Check our [Project Board](https://github.com/adamsmaka/flutter-mcp/projects) for current priorities. Good first issues are labeled with [`good first issue`](https://github.com/adamsmaka/flutter-mcp/labels/good%20first%20issue).

### Quick Wins for New Contributors

- Fix typos or improve documentation clarity
- Add missing tests for existing functionality
- Improve error messages
- Add code examples to documentation
- Help triage issues

## 🚢 Release Process

We use semantic versioning and release regularly:

- **Patch releases** (x.x.1) - Bug fixes, documentation updates
- **Minor releases** (x.1.0) - New features, non-breaking changes
- **Major releases** (1.0.0) - Breaking changes (rare)

Releases are automated through GitHub Actions when maintainers tag a new version.

---

<p align="center">
  <strong>Ready to contribute?</strong>
  <br><br>
  Remember: no contribution is too small! Whether you're fixing a typo or adding a major feature, you're helping make AI + Flutter development better for everyone.
  <br><br>
  <strong>Thank you for being awesome! 🎉</strong>
  <br><br>
  Made with ❤️ by the Flutter MCP community
</p>

```

--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------

```python
"""Flutter MCP Server test suite."""
```

--------------------------------------------------------------------------------
/src/flutter_mcp/__main__.py:
--------------------------------------------------------------------------------

```python
#!/usr/bin/env python3
"""Main entry point for Flutter MCP Server executable"""

if __name__ == "__main__":
    from .cli import main
    main()
```

--------------------------------------------------------------------------------
/src/flutter_mcp/__init__.py:
--------------------------------------------------------------------------------

```python
"""Flutter MCP Server - Real-time Flutter/Dart documentation for AI assistants."""

__version__ = "0.1.0"
__author__ = "Flutter MCP Team"
__email__ = "[email protected]"

from .server import mcp, main

__all__ = ["mcp", "main"]
```

--------------------------------------------------------------------------------
/docker/docker-compose.yml:
--------------------------------------------------------------------------------

```yaml
version: '3.8'

services:
  flutter-mcp:
    build:
      context: ..
      dockerfile: docker/Dockerfile
    container_name: flutter-mcp-server
    environment:
      - PYTHONUNBUFFERED=1
    volumes:
      # Mount source code for development
      - ../src:/app/src:ro
      # Persist cache between restarts
      - cache-data:/app/.cache
    stdin_open: true
    tty: true
    restart: unless-stopped
    ports:
      - "8000:8000"

volumes:
  cache-data:
```

--------------------------------------------------------------------------------
/npm-wrapper/publish.sh:
--------------------------------------------------------------------------------

```bash
#!/bin/bash
# Script to publish the npm wrapper package

echo "Publishing @flutter-mcp/server to npm..."

# Check if logged in to npm
if ! npm whoami &> /dev/null; then
    echo "Error: Not logged in to npm. Please run 'npm login' first."
    exit 1
fi

# Clean any previous builds
rm -rf node_modules package-lock.json

# Install dependencies
echo "Installing dependencies..."
npm install

# Run prepublish script
npm run prepublishOnly

# Publish to npm
echo "Publishing to npm..."
npm publish --access public

echo "✅ Published successfully!"
echo ""
echo "Users can now install with:"
echo "  npx @flutter-mcp/server"
```

--------------------------------------------------------------------------------
/.github/workflows/publish-pypi.yml:
--------------------------------------------------------------------------------

```yaml
name: Publish to PyPI

on:
  push:
    tags:
      - 'v*'
  workflow_dispatch:

jobs:
  build-and-publish:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.11'
    
    - name: Install build dependencies
      run: |
        python -m pip install --upgrade pip
        pip install build twine
    
    - name: Build package
      run: python -m build
    
    - name: Check package
      run: twine check dist/*
    
    - name: Publish to PyPI
      if: startsWith(github.ref, 'refs/tags/v')
      env:
        TWINE_USERNAME: __token__
        TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
      run: |
        twine upload dist/*
```

--------------------------------------------------------------------------------
/QUICK_FIX.md:
--------------------------------------------------------------------------------

```markdown
# Quick Fix for MCP SuperAssistant Users

## For Users Who Already Installed from Source

1. **Pull the latest changes**:
```bash
cd flutter-mcp  # or wherever you cloned it
git pull
```

2. **Reinstall with new features**:
```bash
pip install -e .
```

3. **Start with HTTP transport**:
```bash
flutter-mcp start --transport http --port 8000
```

4. **Configure MCP SuperAssistant**:
- URL: `http://localhost:8000`
- Type: HTTP MCP Server

That's it! The HTTP transport support is now available.

## Alternative: Direct GitHub Install

If you haven't cloned the repo:
```bash
pip install git+https://github.com/flutter-mcp/flutter-mcp.git
flutter-mcp start --transport http --port 8000
```

## Troubleshooting

If `flutter-mcp` command not found:
```bash
python -m flutter_mcp.cli start --transport http --port 8000
```

Or from the source directory:
```bash
cd src
python -m flutter_mcp start --transport http --port 8000
```
```

--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------

```markdown
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.1] - 2025-06-28

### Fixed
- Fixed HTTP and SSE transport modes that were failing with FastMCP API errors
  - Removed incorrect `sse_params` parameter usage 
  - Removed `get_asgi_app()` call that doesn't exist in FastMCP
  - FastMCP now handles HTTP transport internally without uvicorn

### Changed
- Removed uvicorn dependency as it's no longer needed (FastMCP handles HTTP transport internally)

## [0.1.0] - 2025-06-22

### Added
- Initial release of Flutter MCP Server
- Real-time Flutter and Dart documentation fetching
- pub.dev package documentation support
- SQLite caching for performance
- Multiple transport modes: stdio, HTTP, SSE
- Rich CLI interface with progress indicators
```

--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
# Flutter MCP Server Docker Image
# Build from project root: docker build -f docker/Dockerfile -t flutter-mcp .
FROM python:3.11-slim

# Install system dependencies
RUN apt-get update && apt-get install -y \
    git \
    && rm -rf /var/lib/apt/lists/*

# Set working directory
WORKDIR /app

# Copy project files
COPY pyproject.toml setup.py ./
COPY src ./src
COPY docs/README.md LICENSE ./

# Install Python dependencies
RUN pip install --no-cache-dir -e .

# Expose MCP default port (optional, MCP uses stdio by default)
EXPOSE 8000

# Set environment variables
ENV PYTHONUNBUFFERED=1
ENV CACHE_DIR=/app/.cache

# Health check using our health_check tool
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
    CMD python -c "import asyncio; import sys; sys.path.insert(0, '/app/src'); from flutter_mcp.server import health_check; print(asyncio.run(health_check()))"

# Run the MCP server
CMD ["python", "-m", "flutter_mcp.server"]
```

--------------------------------------------------------------------------------
/npm-wrapper/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "flutter-mcp",
  "version": "0.1.1",
  "description": "NPM wrapper for Flutter MCP Server - Real-time Flutter/Dart documentation for AI assistants",
  "main": "index.js",
  "bin": {
    "flutter-mcp": "bin/flutter-mcp.js"
  },
  "scripts": {
    "test": "echo \"No tests for wrapper\"",
    "postinstall": "node scripts/install.js",
    "prepublishOnly": "node -e \"console.log('Preparing to publish Flutter MCP npm wrapper...')\""
  },
  "keywords": [
    "flutter",
    "dart",
    "mcp",
    "ai",
    "claude",
    "documentation",
    "pub.dev"
  ],
  "author": "Flutter MCP Team",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/flutter-mcp/flutter-mcp.git"
  },
  "bugs": {
    "url": "https://github.com/flutter-mcp/flutter-mcp/issues"
  },
  "homepage": "https://github.com/flutter-mcp/flutter-mcp#readme",
  "preferGlobal": true,
  "engines": {
    "node": ">=16.0.0"
  },
  "dependencies": {
    "execa": "^8.0.1",
    "ora": "^8.0.1",
    "which": "^4.0.0"
  }
}

```

--------------------------------------------------------------------------------
/scripts/publish-pypi.sh:
--------------------------------------------------------------------------------

```bash
#!/bin/bash
# Script to publish Flutter MCP Server to PyPI

set -e  # Exit on error

echo "🚀 Publishing Flutter MCP Server to PyPI..."

# Check Python version
PYTHON_VERSION=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
echo "Python version: $PYTHON_VERSION"

# Clean previous builds
echo "🧹 Cleaning previous builds..."
rm -rf dist/ build/ *.egg-info src/*.egg-info

# Install build tools
echo "📦 Installing build tools..."
pip install --upgrade pip setuptools wheel twine build

# Build the package
echo "🔨 Building package..."
python -m build

# Check the package
echo "✅ Checking package with twine..."
twine check dist/*

# Show what will be uploaded
echo ""
echo "📦 Package contents:"
ls -la dist/

echo ""
echo "⚠️  Ready to upload to PyPI!"
echo "To upload to TestPyPI first (recommended):"
echo "  twine upload --repository testpypi dist/*"
echo ""
echo "To upload to PyPI:"
echo "  twine upload dist/*"
echo ""
echo "Note: You'll need PyPI credentials configured in ~/.pypirc or use:"
echo "  export TWINE_USERNAME=__token__"
echo "  export TWINE_PASSWORD=<your-pypi-token>"
```

--------------------------------------------------------------------------------
/scripts/test-server.sh:
--------------------------------------------------------------------------------

```bash
#!/bin/bash
# Test script for Flutter MCP Server

echo "🚀 Flutter MCP Server Test Script"
echo "================================"

# Check if Redis is running
if command -v redis-cli &> /dev/null; then
    if redis-cli ping &> /dev/null; then
        echo "✅ Redis is running"
    else
        echo "❌ Redis is not running. Starting Redis..."
        if command -v redis-server &> /dev/null; then
            redis-server --daemonize yes
            echo "✅ Redis started"
        else
            echo "❌ Redis is not installed. Please install Redis first:"
            echo "   macOS: brew install redis"
            echo "   Ubuntu: sudo apt-get install redis-server"
            echo ""
            echo "The server will run without caching (slower responses)"
        fi
    fi
else
    echo "⚠️  Redis CLI not found. The server will run without caching."
fi

# Check if uv is available
if ! command -v uv &> /dev/null; then
    # Source uv if installed locally
    if [ -f "$HOME/.local/bin/env" ]; then
        source "$HOME/.local/bin/env"
    fi
fi

echo ""
echo "Starting MCP Inspector..."
echo "========================="

# Run with MCP Inspector
if command -v uv &> /dev/null; then
    uv run mcp dev src/flutter_mcp/server.py
else
    echo "❌ uv not found. Please install uv first:"
    echo "   curl -LsSf https://astral.sh/uv/install.sh | sh"
    echo ""
    echo "Or run directly with Python:"
    echo "   python -m src.flutter_mcp.server"
fi
```

--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------

```toml
[project]
name = "flutter-mcp-server"
version = "0.1.1"
description = "MCP server providing real-time Flutter/Dart documentation to AI assistants"
readme = "docs/README.md"
license = {text = "MIT"}
authors = [{name = "Flutter MCP Contributors"}]
keywords = ["flutter", "dart", "mcp", "ai", "documentation", "pubdev"]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "License :: OSI Approved :: MIT License",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Topic :: Software Development :: Documentation",
    "Topic :: Software Development :: Libraries :: Python Modules",
]
requires-python = ">=3.10"
dependencies = [
    "aiofiles>=24.1.0",
    "beautifulsoup4>=4.13.4",
    "httpx>=0.28.1",
    "humanize>=4.11.0",
    "mcp @ git+https://github.com/modelcontextprotocol/python-sdk.git@main",
    "platformdirs>=4.0.0",
    "rich>=13.10.0",
    "structlog>=25.4.0",
]

[project.urls]
"Homepage" = "https://github.com/flutter-mcp/flutter-mcp"
"Bug Reports" = "https://github.com/flutter-mcp/flutter-mcp/issues"
"Source" = "https://github.com/flutter-mcp/flutter-mcp"

[project.scripts]
flutter-mcp = "flutter_mcp.cli:main"

[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"

[tool.setuptools]
package-dir = {"" = "src"}
packages = ["flutter_mcp"]

```

--------------------------------------------------------------------------------
/docs/planning/task-summary.md:
--------------------------------------------------------------------------------

```markdown
# Task Summary: Who Does What

## Tasks Claude Can Do (41 tasks)
All code implementation, documentation writing, and technical content creation:
- ✅ All Python code development (server, tools, parsers)
- ✅ Writing README, API docs, blog posts
- ✅ Creating comparison tables and demos
- ✅ Designing badges and templates
- ✅ Writing marketing copy and Reddit posts
- ✅ Creating Docker/PyPI/npm packages

## Tasks You Need to Do Manually (13 tasks)
Personal actions and real-world engagement:
- 🤝 Reaching out to influencers (T027, T045, T049)
- 📹 Recording demo videos/GIFs (T014, T057)
- 💬 Joining Discord and being active (T018, T044)
- 📊 Creating Google Form for testimonials (T041)
- 🚀 Posting to Reddit/Twitter/YouTube (T028, T060)
- 🎥 Hosting live coding sessions (T056)
- 🧪 Running load tests (T029)
- 🔍 Testing with MCP Inspector (T011)

## Tasks We Do Together (6 tasks)
Collaborative efforts:
- 🤝 Testing with popular packages (T010)
- 🤝 Setting up GitHub repository (T017)
- 🤝 Creating feedback system (T033)
- 🤝 Planning launch week (T051)
- 🤝 Writing weekly Flutter AI tips (T054)
- 🤝 Creating press kit (T059 - I write, you add logo/screenshots)

## Quick Stats
- **Claude does**: 68% of tasks (mostly technical)
- **You do**: 22% of tasks (mostly community/marketing)
- **Together**: 10% of tasks (planning and ongoing work)

This division lets Claude handle all the heavy technical lifting while you focus on human connections and visual content creation!
```

--------------------------------------------------------------------------------
/scripts/build-executables.sh:
--------------------------------------------------------------------------------

```bash
#!/bin/bash
# Build standalone executables for Flutter MCP Server

set -e

echo "🔨 Building Flutter MCP Server executables..."

# Ensure we're in the project root
cd "$(dirname "$0")/.."

# Install PyInstaller if not already installed
pip install pyinstaller

# Clean previous builds
echo "🧹 Cleaning previous builds..."
rm -rf build dist

# Build the executable
echo "🏗️ Building executable..."
pyinstaller build.spec

# Create release directory
mkdir -p releases

# Get the platform
PLATFORM=$(python -c "import platform; print(platform.system().lower())")
ARCH=$(python -c "import platform; print(platform.machine())")

# Move and rename based on platform
if [ "$PLATFORM" = "darwin" ]; then
    if [ "$ARCH" = "arm64" ]; then
        BINARY_NAME="flutter-mcp-macos-arm64"
    else
        BINARY_NAME="flutter-mcp-macos-x64"
    fi
elif [ "$PLATFORM" = "linux" ]; then
    BINARY_NAME="flutter-mcp-linux-x64"
elif [ "$PLATFORM" = "windows" ]; then
    BINARY_NAME="flutter-mcp-windows-x64.exe"
else
    BINARY_NAME="flutter-mcp-$PLATFORM-$ARCH"
fi

# Move the binary
mv "dist/flutter-mcp" "releases/$BINARY_NAME" 2>/dev/null || \
mv "dist/flutter-mcp.exe" "releases/$BINARY_NAME" 2>/dev/null

echo "✅ Build complete! Binary available at: releases/$BINARY_NAME"

# Test the binary
echo "🧪 Testing the binary..."
"./releases/$BINARY_NAME" --version

echo "
📦 Binary details:"
ls -lh "releases/$BINARY_NAME"
file "releases/$BINARY_NAME"

echo "
🚀 To distribute, upload releases/$BINARY_NAME to GitHub Releases"
```

--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------

```python
#!/usr/bin/env python3
"""Setup script for Flutter MCP Server - for backward compatibility only.
Please use pip install with pyproject.toml for modern installations."""

from setuptools import setup, find_packages

# Read long description from README
with open("docs/README.md", "r", encoding="utf-8") as fh:
    long_description = fh.read()

setup(
    name="flutter-mcp-server",
    version="0.1.0",
    author="Flutter MCP Contributors",
    description="MCP server providing real-time Flutter/Dart documentation to AI assistants",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/flutter-mcp/flutter-mcp",
    packages=find_packages(where="src"),
    package_dir={"": "src"},
    classifiers=[
        "Development Status :: 4 - Beta",
        "Intended Audience :: Developers",
        "License :: OSI Approved :: MIT License",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.10",
        "Programming Language :: Python :: 3.11",
        "Programming Language :: Python :: 3.12",
        "Topic :: Software Development :: Documentation",
    ],
    python_requires=">=3.10",
    install_requires=[
        "aiofiles>=24.1.0",
        "beautifulsoup4>=4.13.4",
        "httpx>=0.28.1",
        "mcp @ git+https://github.com/modelcontextprotocol/python-sdk.git@main",
        "platformdirs>=4.0.0",
        "structlog>=25.4.0",
    ],
    entry_points={
        "console_scripts": [
            "flutter-mcp=flutter_mcp.cli:main",
        ],
    },
)
```

--------------------------------------------------------------------------------
/npm-wrapper/index.js:
--------------------------------------------------------------------------------

```javascript
/**
 * Flutter MCP Server Node.js wrapper
 * Main entry point for programmatic usage
 */

const { execa } = require('execa');
const which = require('which');

class FlutterMCPServer {
  constructor(options = {}) {
    this.pythonCmd = null;
    this.options = {
      stdio: options.stdio || false,
      debug: options.debug || false,
      ...options
    };
  }

  async findPython() {
    if (this.pythonCmd) return this.pythonCmd;
    
    const pythonCommands = ['python3', 'python'];
    
    for (const cmd of pythonCommands) {
      try {
        await which(cmd);
        const { stdout } = await execa(cmd, ['--version']);
        const match = stdout.match(/Python (\d+)\.(\d+)/);
        if (match) {
          const major = parseInt(match[1]);
          const minor = parseInt(match[2]);
          if (major >= 3 && minor >= 8) {
            this.pythonCmd = cmd;
            return cmd;
          }
        }
      } catch (e) {
        // Continue to next command
      }
    }
    throw new Error('Python 3.8+ is required but not found');
  }

  async ensureInstalled() {
    const pythonCmd = await this.findPython();
    
    try {
      await execa(pythonCmd, ['-m', 'flutter_mcp', '--version']);
      return true;
    } catch (e) {
      // Try to install
      await execa(pythonCmd, ['-m', 'pip', 'install', 'flutter-mcp-server']);
      return true;
    }
  }

  async start() {
    await this.ensureInstalled();
    const pythonCmd = await this.findPython();
    
    const args = ['-m', 'flutter_mcp'];
    if (this.options.stdio) {
      args.push('--stdio');
    }
    
    const subprocess = execa(pythonCmd, args, {
      stdio: this.options.stdio ? 'inherit' : 'pipe'
    });
    
    return subprocess;
  }

  async stop() {
    // Implement stop functionality if needed
  }
}

module.exports = FlutterMCPServer;
```

--------------------------------------------------------------------------------
/docs/planning/README-highlights.md:
--------------------------------------------------------------------------------

```markdown
# README Highlights & Marketing Psychology

## Key Psychological Triggers We've Implemented

### 1. **Problem Agitation → Solution**
- Opens with relatable pain: "Stop fighting with hallucinated widgets"
- Visual before/after table validates frustration
- Immediate solution: "Real-time Flutter superpowers"

### 2. **Trust Signals**
- "100% Private - your code never leaves your machine"
- Built on "battle-tested Python MCP SDK (14k+ stars)"
- Error handling transparency
- Performance metrics with concrete numbers

### 3. **Social Proof**
- Success stories section
- Pre-written tweet for easy sharing
- Community testimonials
- "Made with ❤️ by the Flutter community"

### 4. **Low Friction Onboarding**
- "Get Started in 2 Minutes" (realistic)
- Platform-specific install commands
- Claude Desktop auto-start (huge win!)
- Natural language usage (no special syntax required)

### 5. **FOMO & Urgency**
- "Give your AI Flutter superpowers"
- "50,000+ packages on pub.dev"
- Coming soon features create anticipation
- Badge for projects creates viral loop

## Technical Clarity Achieved

1. **Redis Dependency** - Upfront with easy install options
2. **MCP Pattern** - Both natural and explicit usage shown
3. **Performance** - Clear expectations (1-2s first, <50ms cached)
4. **Architecture** - "Local RAG server" positioning
5. **Error Handling** - What happens when things fail

## Marketing Positioning

- **Hero Message**: "Give Your AI Real-Time Flutter Superpowers"
- **Value Prop**: Ensure Flutter code actually works
- **Differentiator**: Real-time docs for ANY pub.dev package
- **Target Audience**: Flutter devs using AI assistants

## Viral Elements

1. Click-to-tweet with pre-written message
2. "Powered by Flutter MCP" badge for projects
3. Coming soon features create discussion
4. Easy contribution paths build community

## Next Steps for Launch

1. Create demo GIF/video showing the magic
2. Write technical blog post for launch
3. Prepare GitHub repository with issues/discussions
4. Contact Flutter influencers for early access
5. Plan Reddit launch post for "Show-off Saturday"
```

--------------------------------------------------------------------------------
/tests/test_tools.py:
--------------------------------------------------------------------------------

```python
#!/usr/bin/env python3
"""Test script for Flutter MCP tools"""

import asyncio
import json
import sys
from pathlib import Path

# Add the src directory to the Python path
sys.path.insert(0, str(Path(__file__).parent.parent / 'src'))

from flutter_mcp.server import get_flutter_docs, search_flutter_docs, get_pub_package_info, process_flutter_mentions

async def test_tools():
    print("🧪 Testing Flutter MCP Tools")
    print("=" * 50)
    
    # Test 1: Get Flutter docs
    print("\n1. Testing get_flutter_docs for Container widget:")
    result = await get_flutter_docs("Container", "widgets")
    print(f"   Source: {result.get('source', 'unknown')}")
    print(f"   Content length: {len(result.get('content', ''))} chars")
    print(f"   Has error: {'error' in result}")
    
    # Test 2: Search Flutter docs
    print("\n2. Testing search_flutter_docs for material.AppBar:")
    result = await search_flutter_docs("material.AppBar")
    print(f"   Total results: {result.get('total', 0)}")
    if result.get('results'):
        print(f"   First result source: {result['results'][0].get('source', 'unknown')}")
    
    # Test 3: Get pub package info with README
    print("\n3. Testing get_pub_package_info for provider package:")
    result = await get_pub_package_info("provider")
    print(f"   Source: {result.get('source', 'unknown')}")
    print(f"   Version: {result.get('version', 'unknown')}")
    print(f"   Has README: {'readme' in result}")
    if 'readme' in result:
        print(f"   README length: {len(result['readme'])} chars")
    
    # Test 4: Process Flutter mentions
    print("\n4. Testing process_flutter_mentions:")
    test_text = """
    I want to use @flutter_mcp provider for state management.
    Also need docs for @flutter_mcp material.Scaffold widget.
    """
    result = await process_flutter_mentions(test_text)
    print(f"   Found mentions: {result.get('mentions_found', 0)}")
    for mention in result.get('results', []):
        print(f"   - {mention.get('mention', '')} -> {mention.get('type', 'unknown')}")
    
    print("\n✅ All tests completed!")

if __name__ == "__main__":
    asyncio.run(test_tools())
```

--------------------------------------------------------------------------------
/docs/DEVELOPMENT.md:
--------------------------------------------------------------------------------

```markdown
# Flutter MCP Server Development Guide

## Quick Start

1. **Install Redis** (required for caching):
   ```bash
   # macOS
   brew install redis && brew services start redis
   
   # Ubuntu/Debian
   sudo apt-get install redis-server
   
   # Docker (alternative)
   docker run -d -p 6379:6379 --name flutter-mcp-redis redis:alpine
   ```

2. **Run the test script**:
   ```bash
   ./test-server.sh
   ```

   This will:
   - Check if Redis is running
   - Start the MCP Inspector
   - Open a web interface at http://localhost:5173

3. **Test the tools** in MCP Inspector:
   
   **Get Flutter documentation:**
   ```json
   {
     "class_name": "Container",
     "library": "widgets"
   }
   ```
   
   **Search Flutter docs:**
   ```json
   {
     "query": "material.AppBar"
   }
   ```
   
   **Get pub.dev package info:**
   ```json
   {
     "package_name": "provider"
   }
   ```

## Development Commands

```bash
# Install dependencies
uv sync

# Run server directly
uv run server.py

# Run with MCP Inspector (recommended)
uv run mcp dev server.py

# Run without uv
python server.py
```

## Testing with Claude Desktop

1. Add to Claude Desktop config:
   ```json
   {
     "mcpServers": {
       "flutter-mcp": {
         "command": "uv",
         "args": ["--directory", "/path/to/flutter-docs-mcp", "run", "server.py"]
       }
     }
   }
   ```

2. Restart Claude Desktop

3. Test with queries like:
   - "How do I use the Container widget in Flutter?"
   - "Show me the documentation for material.Scaffold"
   - "What's the latest version of the provider package?"

## Architecture

- **FastMCP**: Handles MCP protocol and tool registration
- **Redis**: Caches processed documentation (24h for APIs, 12h for packages)
- **Rate Limiter**: Ensures respectful scraping (2 requests/second)
- **HTML Parser**: Converts Flutter docs to clean Markdown
- **Structured Logging**: Track performance and debug issues

## Common Issues

1. **Redis not running**: Server works but responses are slower
2. **Rate limiting**: First requests take 1-2 seconds
3. **404 errors**: Check class name and library spelling

## Next Steps

- [ ] Add pub.dev README parsing
- [ ] Implement @flutter_mcp activation
- [ ] Add Flutter cookbook integration
- [ ] Support version-specific docs
```

--------------------------------------------------------------------------------
/docs/planning/ingestion-strategy.md:
--------------------------------------------------------------------------------

```markdown
# Flutter MCP Ingestion Strategy

## Content Extraction Priorities

When we say we "support" a Flutter/Dart package, we extract and process the following content in priority order:

### 1. Essential Content (MVP)
- **Doc Comments (`///`)**: Primary source of API documentation
- **Class/Method Signatures**: Full signatures with parameter types and return values
- **Constructor Parameters**: Named parameters, required vs optional, default values
- **README.md**: Package overview, getting started, basic examples
- **pubspec.yaml**: Dependencies, Flutter/Dart SDK constraints

### 2. High-Value Content (Week 1)
- **Example Directory**: Complete runnable examples showing real usage
- **CHANGELOG.md**: Recent version changes, breaking changes, migration guides
- **Type Definitions**: Enums, typedefs, extension methods
- **Export Statements**: Understanding the public API surface

### 3. Context-Enhancing Content (Week 2+)
- **Test Files**: Understanding expected behavior and edge cases
- **Issue Templates**: Common problems and their solutions
- **Migration Guides**: Version-specific upgrade instructions
- **Platform-Specific Code**: iOS/Android/Web specific implementations

### What We DON'T Extract
- **Full Method Bodies**: Too much noise, not helpful for LLM context
- **Private Implementation Details**: Focus on public API only
- **Generated Code**: Skip `.g.dart`, `.freezed.dart` files
- **Build Configuration**: Detailed build settings aren't useful for API questions

## Semantic Chunking Strategy

Instead of naive text splitting, we chunk semantically:

```
CHUNK 1: package:provider, version:6.1.1, type:class
# ChangeNotifierProvider<T>
A widget that creates a ChangeNotifier and automatically disposes it.
Constructor: ChangeNotifierProvider({required Create<T> create, bool? lazy, Widget? child})
...

CHUNK 2: package:provider, version:6.1.1, type:method, class:ChangeNotifierProvider
# static T of<T>(BuildContext context, {bool listen = true})
Obtains the nearest Provider<T> up its widget tree and returns its value.
...
```

## Metadata Enrichment

Each chunk includes:
- Package name and version
- Source file path
- Content type (class/method/example/changelog)
- Null safety status
- Platform compatibility
- Last updated timestamp

This approach ensures high-quality, relevant context for LLMs while keeping storage and processing costs manageable.
```

--------------------------------------------------------------------------------
/docs/planning/project-summary.md:
--------------------------------------------------------------------------------

```markdown
# Flutter MCP Project Summary

## Vision
Create the Context7 of Flutter - an MCP server that gives AI assistants real-time access to Flutter/Dart documentation, positioning it as the essential tool for Flutter developers using Claude, Cursor, or Windsurf.

## Key Innovation: On-Demand Package Support
Instead of pre-indexing 35,000+ packages, we use an on-demand model:
- User requests `@flutter_mcp provider`
- System fetches, processes, and caches package docs in ~30 seconds
- Future requests are served instantly from cache

## Technical Architecture
- **Core**: Python FastMCP with Redis caching
- **Fetching**: On-demand from api.flutter.dev, pub.dev API
- **Processing**: HTML → Clean Markdown with semantic chunking
- **Activation**: `@flutter_mcp package_name` in prompts

## Marketing Strategy

### Positioning
"The first AI companion that supports ANY pub.dev package on-demand"

### Key Messages
1. **End the State Management Wars** - Impartial expert on all approaches
2. **Beyond the README** - Full source analysis, not just documentation
3. **Always Current** - Real-time fetching, never outdated

### Launch Plan
- **Platform**: r/FlutterDev "Show-off Saturday"
- **Demo**: LLM failing → add @flutter_mcp → perfect answer
- **Engagement**: Live package request fulfillment during launch
- **Influencers**: Reach out to top Flutter YouTubers

### Viral Tactics
- Developer testimonials with specific problems solved
- "Powered by @flutter_mcp" badges
- Community-generated before/after demos
- Flutter package maintainer partnerships

## Success Metrics
- 1,000+ GitHub stars in first month
- 100+ packages indexed in first week
- 50%+ cache hit rate after first month
- 10+ developer testimonials
- Coverage in Flutter Weekly

## Timeline
- **MVP (4 hours)**: Basic server with Flutter API docs
- **Week 1**: Add pub.dev support, search, polish
- **Week 2**: Launch preparation and marketing push
- **Launch Week**: Coordinated multi-platform release

## Files Created
1. `project-tasks.csv` - 60 detailed tasks with priorities
2. `ingestion-strategy.md` - What content to extract from packages
3. `context7-marketing-analysis.md` - Marketing tactics analysis

The project is designed to solve a real problem (outdated AI knowledge of Flutter) with a simple solution (@flutter_mcp activation) that can be built quickly and marketed effectively to the Flutter community.
```

--------------------------------------------------------------------------------
/RELEASE_GUIDE.md:
--------------------------------------------------------------------------------

```markdown
# Release Guide for Flutter MCP Server

## ✅ Package Status

The package has been successfully built and is ready for publication:
- **PyPI Package**: `flutter_mcp_server-0.1.0` 
- **npm Package**: `@flutter-mcp/[email protected]`

## 🚀 Publishing to PyPI

### 1. Create PyPI Account
- Main PyPI: https://pypi.org/account/register/
- Test PyPI: https://test.pypi.org/account/register/

### 2. Get API Token
- Go to https://pypi.org/manage/account/token/
- Create a new API token with scope "Entire account"
- Save the token securely (starts with `pypi-`)

### 3. Publish to TestPyPI (Recommended First)
```bash
# Set your TestPyPI token
export TWINE_USERNAME=__token__
export TWINE_PASSWORD=<your-test-pypi-token>

# Upload to TestPyPI
twine upload --repository testpypi dist/*

# Test installation
pip install -i https://test.pypi.org/simple/ flutter-mcp-server
```

### 4. Publish to PyPI
```bash
# Set your PyPI token
export TWINE_USERNAME=__token__
export TWINE_PASSWORD=<your-pypi-token>

# Upload to PyPI
twine upload dist/*
```

### 5. Verify Installation
```bash
pip install flutter-mcp-server
flutter-mcp --version
```

## 📦 Publishing npm Package

### 1. Login to npm
```bash
npm login
```

### 2. Publish the Package
```bash
cd npm-wrapper
./publish.sh
```

### 3. Verify Installation
```bash
npx @flutter-mcp/server --version
```

## 🎉 What's New in This Release

### Transport Support (v0.1.0)
- **STDIO Transport** (default) - For Claude Desktop and most MCP clients
- **HTTP Transport** - For MCP SuperAssistant and HTTP-based clients  
- **SSE Transport** - For Server-Sent Events based clients

### Usage Examples

#### HTTP Transport (for MCP SuperAssistant)
```bash
flutter-mcp start --transport http --port 8000
```

#### SSE Transport
```bash
flutter-mcp start --transport sse --port 8080
```

#### Custom Host Binding
```bash
flutter-mcp start --transport http --host 0.0.0.0 --port 3000
```

## 📝 Post-Release Checklist

- [ ] Upload to TestPyPI and test
- [ ] Upload to PyPI
- [ ] Publish npm package
- [ ] Create GitHub release with tag `v0.1.0`
- [ ] Update the main README if needed
- [ ] Announce in relevant communities

## 🔧 Troubleshooting

### "Package already exists"
The package name might be taken. Check:
- PyPI: https://pypi.org/project/flutter-mcp-server/
- npm: https://www.npmjs.com/package/@flutter-mcp/server

### Build Issues
```bash
# Clean and rebuild
rm -rf dist/ build/ *.egg-info src/*.egg-info
python -m build
```

### npm Login Issues
```bash
npm whoami  # Check if logged in
npm login   # Login again if needed
```
```

--------------------------------------------------------------------------------
/docs/PUBLISHING.md:
--------------------------------------------------------------------------------

```markdown
# Publishing Flutter MCP Server

This document explains how to publish Flutter MCP Server to PyPI and npm.

## PyPI Publication

### Prerequisites

1. PyPI account: https://pypi.org/account/register/
2. PyPI API token: https://pypi.org/manage/account/token/
3. TestPyPI account (optional but recommended): https://test.pypi.org/account/register/

### Setup

1. Configure PyPI credentials:
   ```bash
   cp .pypirc.template ~/.pypirc
   # Edit ~/.pypirc with your API tokens
   ```

   Or use environment variables:
   ```bash
   export TWINE_USERNAME=__token__
   export TWINE_PASSWORD=pypi-your-token-here
   ```

2. Install build tools:
   ```bash
   pip install --upgrade pip setuptools wheel twine build
   ```

### Publishing Process

1. Update version in:
   - `pyproject.toml`
   - `setup.py`
   - `src/flutter_mcp/cli.py` (__version__)

2. Run the publish script:
   ```bash
   ./scripts/publish-pypi.sh
   ```

3. Test on TestPyPI first (recommended):
   ```bash
   twine upload --repository testpypi dist/*
   
   # Test installation
   pip install -i https://test.pypi.org/simple/ flutter-mcp-server
   ```

4. Publish to PyPI:
   ```bash
   twine upload dist/*
   ```

5. Verify installation:
   ```bash
   pip install flutter-mcp-server
   flutter-mcp --version
   ```

## NPM Publication

### Prerequisites

1. npm account: https://www.npmjs.com/signup
2. Login to npm: `npm login`

### Publishing Process

1. Update version in `npm-wrapper/package.json`

2. Navigate to npm wrapper directory:
   ```bash
   cd npm-wrapper
   ```

3. Run the publish script:
   ```bash
   ./publish.sh
   ```

4. Verify installation:
   ```bash
   npx @flutter-mcp/server --version
   ```

## Version Synchronization

Keep versions synchronized across:
- `pyproject.toml`
- `setup.py`
- `src/flutter_mcp/cli.py`
- `npm-wrapper/package.json`

## Release Checklist

- [ ] Update version numbers
- [ ] Update CHANGELOG
- [ ] Run tests: `pytest`
- [ ] Test locally: `flutter-mcp start`
- [ ] Build and check package: `./scripts/publish-pypi.sh`
- [ ] Publish to TestPyPI
- [ ] Test installation from TestPyPI
- [ ] Publish to PyPI
- [ ] Publish npm wrapper
- [ ] Create GitHub release
- [ ] Update documentation

## Troubleshooting

### "Invalid distribution file"
- Ensure README.md exists in docs/
- Check MANIFEST.in includes all necessary files

### "Version already exists"
- Increment version number
- Delete old builds: `rm -rf dist/ build/`

### npm publish fails
- Ensure you're logged in: `npm whoami`
- Check package name availability
- Verify package.json is valid: `npm pack --dry-run`
```

--------------------------------------------------------------------------------
/context7-installation-analysis.md:
--------------------------------------------------------------------------------

```markdown
# Flutter MCP vs Context7: Installation Simplicity Achieved! 🎉

## Installation Comparison

### Context7
```bash
npx -y @upstash/context7-mcp
```

### Flutter MCP (After Improvements)
```bash
pip install flutter-mcp-server
flutter-mcp start
```

Or even simpler with executables:
```bash
# Download and run - no Python needed!
curl -L https://github.com/flutter-mcp/releases/latest/flutter-mcp-macos -o flutter-mcp
chmod +x flutter-mcp
./flutter-mcp
```

## What We Changed

### Phase 1: Removed External Dependencies ✅
- **Before**: Required Python + Redis server
- **After**: Just Python (SQLite built-in)
- **Impact**: 50% reduction in setup complexity

### Phase 2: Single Executable Distribution ✅
- **Before**: pip install + dependencies
- **After**: Download one file and run
- **Impact**: Zero dependencies for end users

## Key Improvements Made

1. **Replaced Redis with SQLite**
   - No external services to install/manage
   - Automatic cache directory creation
   - Platform-aware storage locations
   - Same performance for single-user tool

2. **Added PyInstaller Packaging**
   - Creates standalone executables
   - Bundles Python runtime
   - Works on Windows, macOS, Linux
   - ~30MB download vs multi-step install

3. **Simplified Configuration**
   - Removed all Redis configuration options
   - Works with zero config out of the box
   - Optional cache directory override only

4. **Multiple Distribution Options**
   - PyPI: `pip install flutter-mcp-server`
   - Docker: `docker run ghcr.io/flutter-mcp/flutter-mcp`
   - Executable: Download and run
   - Source: Clone and develop

## Performance Impact

- **First query**: Same (1-2 seconds to fetch)
- **Cached queries**: <50ms (SQLite nearly as fast as Redis)
- **Startup time**: PyInstaller adds ~1 second (acceptable)
- **Memory usage**: Slightly lower without Redis

## User Experience Wins

1. **Zero Configuration Required**
   - No Redis URLs
   - No service management
   - No port conflicts

2. **Works Everywhere**
   - macOS, Windows, Linux
   - No admin rights needed
   - Portable executables

3. **Graceful Degradation**
   - Cache automatically created
   - Works offline with cache
   - Clear error messages

## Conclusion

Flutter MCP now matches Context7's installation simplicity while maintaining all functionality. Users can choose their preferred installation method:

- **Developers**: `pip install` for easy updates
- **Non-technical users**: Download executable
- **Teams**: Docker for consistency
- **Contributors**: Clone and develop

The key insight from Context7: **Hide complexity, not functionality**. By replacing Redis with SQLite and adding executable distribution, we achieved the same "it just works" experience! 🚀
```

--------------------------------------------------------------------------------
/.github/workflows/build-executables.yml:
--------------------------------------------------------------------------------

```yaml
name: Build Executables

on:
  push:
    tags:
      - 'v*'
  workflow_dispatch:

jobs:
  build:
    strategy:
      matrix:
        include:
          - os: ubuntu-latest
            platform: linux
            arch: x64
          - os: macos-latest
            platform: macos
            arch: x64
          - os: macos-14  # M1 runner
            platform: macos
            arch: arm64
          - os: windows-latest
            platform: windows
            arch: x64

    runs-on: ${{ matrix.os }}
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.11'
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install pyinstaller
        pip install -e .
    
    - name: Build executable
      run: |
        pyinstaller build.spec
    
    - name: Rename executable
      shell: bash
      run: |
        mkdir -p releases
        if [ "${{ matrix.platform }}" = "windows" ]; then
          mv dist/flutter-mcp.exe releases/flutter-mcp-${{ matrix.platform }}-${{ matrix.arch }}.exe
        else
          mv dist/flutter-mcp releases/flutter-mcp-${{ matrix.platform }}-${{ matrix.arch }}
        fi
    
    - name: Test executable
      shell: bash
      run: |
        if [ "${{ matrix.platform }}" = "windows" ]; then
          ./releases/flutter-mcp-${{ matrix.platform }}-${{ matrix.arch }}.exe --version
        else
          ./releases/flutter-mcp-${{ matrix.platform }}-${{ matrix.arch }} --version
        fi
    
    - name: Upload artifact
      uses: actions/upload-artifact@v4
      with:
        name: flutter-mcp-${{ matrix.platform }}-${{ matrix.arch }}
        path: releases/*

  release:
    needs: build
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/v')
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Download all artifacts
      uses: actions/download-artifact@v4
      with:
        path: releases
        pattern: flutter-mcp-*
        merge-multiple: true
    
    - name: Create Release
      uses: softprops/action-gh-release@v1
      with:
        files: releases/*
        body: |
          # Flutter MCP Server ${{ github.ref_name }}
          
          ## Installation
          
          ### Option 1: Download Executable (Easiest!)
          Download the appropriate executable for your platform below. No Python required!
          
          ### Option 2: Install from PyPI
          ```bash
          pip install flutter-mcp-server
          ```
          
          ### Option 3: Docker
          ```bash
          docker run -p 8000:8000 ghcr.io/flutter-mcp/flutter-mcp:${{ github.ref_name }}
          ```
          
          ## What's New
          See [CHANGELOG.md](https://github.com/flutter-mcp/flutter-mcp/blob/main/CHANGELOG.md) for details.
        draft: false
        prerelease: false
```

--------------------------------------------------------------------------------
/docs/planning/context7-marketing-analysis.md:
--------------------------------------------------------------------------------

```markdown
# Context7 Marketing & Community Engagement Analysis

## Key Success Factors

### 1. Strong Value Proposition
- **Clear Problem Statement**: "LLMs are trained on old data" - immediately resonates with developers
- **Simple Solution**: "Get up-to-date, version-specific documentation"
- **Instant Benefit**: "Stop getting broken, outdated code"

### 2. GitHub-First Strategy
- **13.7k stars** in a short time
- Open source with MIT license
- Active issue tracking (45 open issues)
- Community contributions encouraged through PRs

### 3. Free Pricing Model
- "Free for personal use" - removes barriers to adoption
- Built on Upstash infrastructure
- No hidden costs or limitations mentioned

### 4. Developer-Centric Messaging
- Technical but accessible language
- Real examples (Next.js `after()` function, React Query)
- Focus on time-saving and frustration reduction

### 5. Multiple Integration Paths
- One-click Cursor installation
- Support for 14+ languages
- Multiple package managers (npm, deno, etc.)
- Works with any LLM-powered editor

### 6. Community Building Tactics
- **Easy Contribution**: "Add your project" with simple form or PR
- **Direct Feedback Channels**: Email and GitHub
- **Documentation Integration**: Libraries can add Context7 links
- **Phased Launch**: Started simple, added features based on feedback

### 7. Content Marketing
- Technical blog posts on Upstash blog
- Clear before/after examples
- Step-by-step installation guides
- Focus on specific use cases

### 8. Positioning Strategy
- Backed by established company (Upstash)
- "Community-maintained" messaging
- Focus on solving universal developer pain point
- No direct competitor comparisons

## Tactics to Adapt for Flutter Documentation MCP

### 1. Clear Problem Framing
- "Flutter's rapid evolution means AI assistants give outdated widget examples"
- "Stop debugging AI-generated Flutter code that uses deprecated APIs"

### 2. Flutter-Specific Examples
- Show common Flutter pain points (e.g., null safety migration, new widgets)
- Use real Flutter code examples in marketing materials
- Highlight version-specific challenges (Flutter 2.x vs 3.x)

### 3. Community Integration
- Launch on r/FlutterDev, Flutter Discord
- Partner with Flutter YouTube channels
- Get featured in Flutter Weekly newsletter

### 4. Free Tier Strategy
- Start completely free for individual developers
- Build trust and adoption first
- Consider team/enterprise tiers later

### 5. Easy Onboarding
- One-click installation for popular Flutter IDEs
- Video tutorials showing immediate value
- "Add to your Flutter project in 30 seconds"

### 6. Developer Advocacy
- Encourage Flutter package authors to add support
- Create badges for "Context7-enabled" packages
- Build relationships with popular package maintainers

### 7. Content Strategy
- Weekly blog posts solving real Flutter problems
- Before/after code comparisons
- Guest posts from Flutter influencers

### 8. Growth Metrics to Track
- GitHub stars and forks
- Daily active users
- Number of Flutter packages indexed
- Community contributions
- Support queries (indicator of engagement)

## Launch Checklist

1. **Pre-Launch**
   - Build MVP with core Flutter packages
   - Create compelling demos
   - Prepare documentation
   - Set up GitHub repository

2. **Soft Launch**
   - Share with Flutter friends/colleagues
   - Get initial feedback
   - Fix critical issues

3. **Public Launch**
   - Post on r/FlutterDev with problem/solution focus
   - Share in Flutter Discord channels
   - Submit to Flutter Weekly
   - Launch on Product Hunt (Flutter/Dev Tools category)

4. **Post-Launch**
   - Respond to all feedback quickly
   - Regular updates showing progress
   - Build in public on Twitter/X
   - Create video content for YouTube

## Key Takeaway
Context7's success comes from solving a real, universal developer problem with a free, easy-to-use solution backed by strong technical execution and community engagement. The same approach can work for Flutter developers who face similar challenges with AI-generated code.
```

--------------------------------------------------------------------------------
/docs/CLIENT-CONFIGURATIONS.md:
--------------------------------------------------------------------------------

```markdown
# MCP Client Configurations

This document provides configuration examples for various MCP clients to connect to Flutter MCP Server.

## Transport Modes Overview

Flutter MCP Server supports three transport modes:
- **STDIO** (default): Standard input/output communication
- **HTTP**: REST-like HTTP transport
- **SSE**: Server-Sent Events for streaming

## Claude Desktop

**Transport**: STDIO

Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "flutter-mcp": {
      "command": "flutter-mcp",
      "args": ["start"],
      "env": {}
    }
  }
}
```

Or using npx:
```json
{
  "mcpServers": {
    "flutter-mcp": {
      "command": "npx",
      "args": ["@flutter-mcp/server", "start"],
      "env": {}
    }
  }
}
```

## MCP SuperAssistant

**Transport**: HTTP

1. Start the server:
   ```bash
   flutter-mcp start --transport http --port 8000
   ```

2. In MCP SuperAssistant:
   - Click "Add Server"
   - Name: `Flutter MCP`
   - URL: `http://localhost:8000`
   - Type: `HTTP MCP Server`

## Claude Code (claude.ai/code)

**Transport**: STDIO

### Global Configuration

Install globally and Claude Code will auto-detect:
```bash
pip install flutter-mcp-server
```

### Per-Project Configuration

Create `.mcp.json` in your project root:
```json
{
  "mcpServers": {
    "flutter-mcp": {
      "command": "/path/to/flutter-mcp/venv/bin/flutter-mcp",
      "args": ["start"]
    }
  }
}
```

## VS Code + Continue

**Transport**: STDIO

In `.continuerc.json`:
```json
{
  "models": [
    {
      "provider": "claude",
      "mcp_servers": {
        "flutter-mcp": {
          "command": "flutter-mcp",
          "args": ["start"]
        }
      }
    }
  ]
}
```

## Custom HTTP Client

**Transport**: HTTP

```python
import httpx

# Start server: flutter-mcp start --transport http --port 8000

client = httpx.Client(base_url="http://localhost:8000")

# Make MCP requests
response = client.post("/mcp/v1/tools/list")
tools = response.json()

# Call a tool
response = client.post("/mcp/v1/tools/call", json={
    "name": "get_flutter_docs",
    "arguments": {
        "query": "StatefulWidget"
    }
})
```

## Custom SSE Client

**Transport**: SSE

```javascript
// Start server: flutter-mcp start --transport sse --port 8080

const eventSource = new EventSource('http://localhost:8080/sse');

eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Received:', data);
};

// Send requests via POST to the same server
fetch('http://localhost:8080/mcp/v1/tools/list', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' }
})
.then(res => res.json())
.then(console.log);
```

## Docker Configurations

### Claude Desktop with Docker

```json
{
  "mcpServers": {
    "flutter-mcp": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "ghcr.io/flutter-mcp/flutter-mcp:latest"
      ]
    }
  }
}
```

### HTTP Server with Docker

```bash
# Run with HTTP transport exposed
docker run -p 8000:8000 ghcr.io/flutter-mcp/flutter-mcp:latest \
  flutter-mcp start --transport http --host 0.0.0.0 --port 8000
```

## Environment Variables

All transport modes support these environment variables:

```bash
# Cache directory
export CACHE_DIR=/path/to/cache

# Debug logging
export DEBUG=1

# Transport settings (when not using CLI args)
export MCP_TRANSPORT=http
export MCP_PORT=8000
export MCP_HOST=0.0.0.0
```

## Troubleshooting Connection Issues

### STDIO Transport
- Ensure the command path is correct
- Check Python is installed: `python3 --version`
- Verify installation: `flutter-mcp --version`

### HTTP/SSE Transport
- Check port availability: `lsof -i :8000`
- Try different port: `--port 8080`
- Bind to all interfaces: `--host 0.0.0.0`
- Check firewall settings

### Common Issues

1. **"Connection refused"**
   - Server not running
   - Wrong port
   - Firewall blocking connection

2. **"Command not found"**
   - Package not installed
   - Wrong path in configuration
   - Virtual environment not activated

3. **"Transport mismatch"**
   - Client expects different transport
   - Check client documentation
   - Use correct transport flag

## Testing Connection

### Test STDIO
```bash
echo '{"method": "mcp/v1/tools/list"}' | flutter-mcp start
```

### Test HTTP
```bash
# Start server
flutter-mcp start --transport http --port 8000

# Test with curl
curl -X POST http://localhost:8000/mcp/v1/tools/list
```

### Test SSE
```bash
# Start server
flutter-mcp start --transport sse --port 8080

# Test with curl
curl http://localhost:8080/sse
```
```

--------------------------------------------------------------------------------
/docs/planning/IMPLEMENTATION_SUMMARY.md:
--------------------------------------------------------------------------------

```markdown
# Flutter MCP Server - Implementation Summary

## 🎯 Project Overview

We've successfully built a complete Flutter MCP (Model Context Protocol) server that provides real-time Flutter/Dart documentation to AI assistants. The server supports ALL 50,000+ packages on pub.dev through on-demand fetching.

## ✅ Completed Features

### Core Functionality
- ✅ **FastMCP Server**: Built with Python using the FastMCP framework
- ✅ **5 MCP Tools**: 
  - `get_flutter_docs` - Fetches Flutter/Dart API documentation
  - `get_pub_package_info` - Gets package info with full README from pub.dev
  - `search_flutter_docs` - Intelligent search across documentation
  - `process_flutter_mentions` - Parses @flutter_mcp mentions in text
  - `health_check` - Monitors scraper and service health
- ✅ **Redis Caching**: 24h for APIs, 12h for packages with graceful fallback
- ✅ **Rate Limiting**: 2 requests/second to respect server resources
- ✅ **HTML to Markdown Converter**: Clean documentation for AI consumption
- ✅ **Smart URL Resolution**: Pattern matching for Flutter/Dart libraries

### Developer Experience
- ✅ **CLI Interface**: `flutter-mcp start/dev/help/version` commands
- ✅ **Multiple Installation Options**:
  - PyPI: `pip install flutter-mcp-server`
  - Docker: `docker run ghcr.io/flutter-mcp/flutter-mcp`
  - Docker Compose with Redis included
- ✅ **Works Without Redis**: Graceful degradation with warnings
- ✅ **Structured Logging**: Using structlog for debugging

### Testing & Quality
- ✅ **Integration Tests**: 80% pass rate (4/5 tests)
- ✅ **Tested with Popular Packages**: provider, bloc, dio, get, riverpod
- ✅ **Health Check System**: Real-time monitoring of scraper status
- ✅ **Error Handling**: Graceful failures with helpful messages

### Documentation & Distribution
- ✅ **Comprehensive README**: Quick start, features, tool reference
- ✅ **CONTRIBUTING.md**: Community guidelines and development setup
- ✅ **DEVELOPMENT.md**: Local development guide
- ✅ **MIT License**: Open source friendly
- ✅ **PyPI Ready**: pyproject.toml with git dependency for MCP
- ✅ **Docker Support**: Dockerfile and docker-compose.yml

## 📊 Technical Architecture

```
Client (AI) → MCP Protocol → FastMCP Server
                                  ↓
                            Rate Limiter (2/sec)
                                  ↓
                            Cache Check (Redis)
                                  ↓ (miss)
                            Web Scraper
                                  ↓
                            HTML Parser → Markdown
                                  ↓
                            Cache Store → Response
```

## 🚀 Launch Readiness

### What's Ready
- ✅ Server is fully functional
- ✅ All critical tools implemented
- ✅ PyPI package structure complete
- ✅ Docker images configured
- ✅ Installation instructions clear
- ✅ Health monitoring in place

### What's Needed for Launch
1. **PyPI Publication**: Run `python -m build` and `twine upload`
2. **Docker Hub Push**: Build and push Docker image
3. **Demo GIF/Video**: Show the 20-second experience
4. **GitHub Repository**: Push to public repo
5. **Reddit Post**: Launch on r/FlutterDev

## 📈 Key Metrics to Track

- GitHub stars (target: 100+ in first month)
- PyPI downloads
- Docker pulls
- Active packages being queried
- Cache hit rate
- Community contributions

## 🎨 Marketing Message

**Hero**: "Give Your AI Real-Time Flutter Superpowers"
**Value Prop**: "Supports ALL 50,000+ pub.dev packages on-demand"
**Differentiator**: "Never outdated, always current documentation"

## 🔧 Technical Decisions Made

1. **Python over TypeScript**: Easier for Claude to maintain
2. **On-demand over Pre-indexing**: "Supports ALL packages" message
3. **FastMCP over Raw MCP**: Simpler, cleaner code
4. **Git dependency for MCP**: Until official PyPI release
5. **Health check as tool**: Can be monitored programmatically

## 🎁 Bonus Features Implemented

- CLI with multiple commands
- Docker Compose for easy dev setup
- Integration test suite
- Structured logging throughout
- @flutter_mcp mention processing

## 📝 Lessons Learned

1. **Scraper fragility is real**: Health checks are essential
2. **README location varies**: Had to try multiple selectors
3. **Rate limiting matters**: 2/sec keeps servers happy
4. **Cache is optional but valuable**: 10x+ speed improvement
5. **Clear messaging wins**: "ALL packages" is powerful

## 🙏 Acknowledgments

Special thanks to Gemini Pro for strategic advice on launch readiness and the importance of the "First Five Minutes" experience.

---

**Total Implementation Time**: ~6 hours
**Lines of Code**: ~880 (server.py)
**Test Coverage**: Core functionality tested
**Ready for Launch**: ✅ YES!
```

--------------------------------------------------------------------------------
/src/flutter_mcp/cli.py:
--------------------------------------------------------------------------------

```python
#!/usr/bin/env python3
"""CLI entry point for Flutter MCP Server"""

import sys
import argparse
import os
from typing import Optional
import asyncio

# Add version info
__version__ = "0.1.1"


def main():
    """Main CLI entry point"""
    parser = argparse.ArgumentParser(
        prog='flutter-mcp',
        description='Flutter MCP Server - Real-time Flutter/Dart documentation for AI assistants',
        epilog='For more information, visit: https://github.com/flutter-mcp/flutter-mcp'
    )
    
    parser.add_argument(
        'command',
        choices=['start', 'serve', 'dev', 'version', 'help'],
        nargs='?',
        default='start',
        help='Command to run (default: start)'
    )
    
    parser.add_argument(
        '--cache-dir',
        default=None,
        help='Custom cache directory (default: platform-specific)'
    )
    
    parser.add_argument(
        '--debug',
        action='store_true',
        help='Enable debug logging'
    )
    
    parser.add_argument(
        '--version',
        action='version',
        version=f'%(prog)s {__version__}'
    )
    
    parser.add_argument(
        '--transport',
        choices=['stdio', 'sse', 'http'],
        default='stdio',
        help='Transport protocol to use (default: stdio)'
    )
    
    parser.add_argument(
        '--port',
        type=int,
        default=8000,
        help='Port to listen on for HTTP/SSE transport (default: 8000)'
    )
    
    parser.add_argument(
        '--host',
        default='127.0.0.1',
        help='Host to bind to for HTTP/SSE transport (default: 127.0.0.1)'
    )
    
    args = parser.parse_args()
    
    # Handle commands
    if args.command == 'version':
        print(f"Flutter MCP Server v{__version__}", file=sys.stderr)
        sys.exit(0)
    
    elif args.command == 'help':
        parser.print_help(sys.stderr)
        sys.exit(0)
    
    elif args.command == 'dev':
        # Run with MCP Inspector
        print("🚀 Starting Flutter MCP Server with MCP Inspector...", file=sys.stderr)
        print("📝 Opening browser at http://localhost:5173", file=sys.stderr)
        print("⚡ Use Ctrl+C to stop the server\n", file=sys.stderr)
        
        import subprocess
        try:
            # Set environment variables
            env = os.environ.copy()
            if args.cache_dir:
                env['CACHE_DIR'] = args.cache_dir
            if args.debug:
                env['DEBUG'] = '1'
            
            subprocess.run(['mcp', 'dev', 'src/flutter_mcp/server.py'], env=env)
        except KeyboardInterrupt:
            print("\n\n✅ Server stopped", file=sys.stderr)
        except FileNotFoundError:
            print("❌ Error: MCP CLI not found. Please install with: pip install 'mcp[cli]'", file=sys.stderr)
            sys.exit(1)
    
    else:  # start or serve
        # Run the server directly
        # Print cool header using rich
        from flutter_mcp.logging_utils import print_server_header
        print_server_header()
        
        from rich.console import Console
        console = Console(stderr=True)
        
        console.print(f"\n[bold green]🚀 Starting Flutter MCP Server v{__version__}[/bold green]")
        console.print("[cyan]📦 Using built-in SQLite cache[/cyan]")
        if args.cache_dir:
            console.print(f"[dim]💾 Cache directory: {args.cache_dir}[/dim]")
        
        # Show transport-specific information
        if args.transport == 'stdio':
            console.print("[yellow]⚡ Server running via STDIO - connect your AI assistant[/yellow]")
        elif args.transport in ['sse', 'http']:
            console.print(f"[yellow]🌐 Server running on {args.transport.upper()} transport[/yellow]")
            console.print(f"[yellow]📡 Listening on http://{args.host}:{args.port}[/yellow]")
            if args.transport == 'sse':
                console.print(f"[dim]   SSE endpoint: http://{args.host}:{args.port}/sse[/dim]")
            
        console.print("[yellow]⚡ Use Ctrl+C to stop the server[/yellow]\n")
        
        # Set environment variables
        if args.cache_dir:
            os.environ['CACHE_DIR'] = args.cache_dir
        if args.debug:
            os.environ['DEBUG'] = '1'
        
        # Set transport configuration
        os.environ['MCP_TRANSPORT'] = args.transport
        os.environ['MCP_PORT'] = str(args.port)
        os.environ['MCP_HOST'] = args.host
        
        # Set flag to indicate we're running from CLI
        sys._flutter_mcp_cli = True
        
        try:
            # Import and run the server
            from . import main as server_main
            server_main()
        except KeyboardInterrupt:
            print("\n\n✅ Server stopped", file=sys.stderr)
        except ImportError as e:
            print(f"❌ Error: Failed to import server: {e}", file=sys.stderr)
            print("Make sure you're in the correct directory and dependencies are installed", file=sys.stderr)
            sys.exit(1)


if __name__ == "__main__":
    main()
```

--------------------------------------------------------------------------------
/npm-wrapper/bin/flutter-mcp.js:
--------------------------------------------------------------------------------

```javascript
#!/usr/bin/env node
/**
 * Flutter MCP Server wrapper for Node.js
 * This script ensures Python is available and runs the Flutter MCP server
 */

const { execa } = require('execa');
const which = require('which');
const ora = require('ora');
const path = require('path');
const fs = require('fs');

async function findPython() {
  const pythonCommands = ['python3', 'python'];
  
  for (const cmd of pythonCommands) {
    try {
      await which(cmd);
      // Verify it's Python 3.8+
      const { stdout } = await execa(cmd, ['--version']);
      const match = stdout.match(/Python (\d+)\.(\d+)/);
      if (match) {
        const major = parseInt(match[1]);
        const minor = parseInt(match[2]);
        if (major >= 3 && minor >= 8) {
          return cmd;
        }
      }
    } catch (e) {
      // Continue to next command
    }
  }
  return null;
}

async function installFlutterMCP(pythonCmd, forceInstall = false) {
  const spinner = ora('Checking Flutter MCP Server installation...').start();
  
  try {
    // Check if already installed
    if (!forceInstall) {
      try {
        await execa(pythonCmd, ['-m', 'flutter_mcp', '--version']);
        spinner.succeed('Flutter MCP Server is ready');
        return true;
      } catch (e) {
        // Not installed, continue with installation
      }
    }
    
    // Install using pip
    spinner.text = 'Installing Flutter MCP Server from PyPI...';
    
    // For npx usage, install to user directory to avoid permission issues
    const isNpx = process.env.npm_execpath && process.env.npm_execpath.includes('npx');
    const pipArgs = ['-m', 'pip', 'install', '--user', 'flutter-mcp'];
    
    if (!isNpx) {
      // For global install, try without --user first
      pipArgs.splice(pipArgs.indexOf('--user'), 1);
    }
    
    await execa(pythonCmd, pipArgs, {
      stdio: 'inherit'
    });
    
    spinner.succeed('Flutter MCP Server installed successfully');
    return true;
  } catch (error) {
    spinner.fail('Failed to install Flutter MCP Server');
    console.error(error.message);
    return false;
  }
}

async function runFlutterMCP(pythonCmd, args) {
  try {
    // Run the server
    await execa(pythonCmd, ['-m', 'flutter_mcp', ...args], {
      stdio: 'inherit'
    });
  } catch (error) {
    if (error.exitCode !== 0) {
      console.error('Flutter MCP Server exited with error');
      process.exit(error.exitCode);
    }
  }
}

async function main() {
  const args = process.argv.slice(2);
  
  // Check for help flag
  if (args.includes('--help') || args.includes('-h')) {
    console.log(`
Flutter MCP Server - Real-time Flutter/Dart documentation for AI assistants

Usage: 
  npx flutter-mcp [options]              # One-time usage
  npm install -g flutter-mcp             # Global installation
  flutter-mcp [options]                  # After global install

Options:
  --help, -h        Show this help message
  --version, -v     Show version information
  --install         Install/update the Python package
  --stdio           Run in stdio mode (default for MCP clients)
  --http            Run in HTTP mode
  --sse             Run in Server-Sent Events mode
  --port <port>     Port for HTTP/SSE mode (default: 3000)
  
Examples:
  # Quick start with npx (no installation)
  npx flutter-mcp
  
  # Install globally then use
  npm install -g flutter-mcp
  flutter-mcp
  
  # Use with Claude Desktop (stdio mode)
  npx flutter-mcp --stdio

Claude Desktop Configuration:
  {
    "mcpServers": {
      "flutter-docs": {
        "command": "npx",
        "args": ["flutter-mcp", "--stdio"]
      }
    }
  }

For more information, visit: https://github.com/flutter-mcp/flutter-mcp
`);
    process.exit(0);
  }
  
  // Find Python
  const spinner = ora('Checking Python installation...').start();
  const pythonCmd = await findPython();
  
  if (!pythonCmd) {
    spinner.fail('Python 3.8+ is required but not found');
    console.error(`
Please install Python 3.8 or later:
- macOS: brew install python3
- Ubuntu/Debian: sudo apt install python3 python3-pip
- Windows: https://www.python.org/downloads/
`);
    process.exit(1);
  }
  
  spinner.succeed(`Found Python: ${pythonCmd}`);
  
  // Install Flutter MCP if needed
  const forceInstall = args.includes('--install');
  const installed = await installFlutterMCP(pythonCmd, forceInstall);
  if (!installed) {
    process.exit(1);
  }
  
  // If --install flag was provided, exit here
  if (args.includes('--install') && !args.includes('--stdio')) {
    console.log('\nFlutter MCP Server is ready to use!');
    process.exit(0);
  }
  
  // Default to stdio mode if no transport specified
  if (!args.includes('--http') && !args.includes('--sse') && !args.includes('--stdio')) {
    args.push('--stdio');
  }
  
  // Run the server
  if (!args.includes('--stdio')) {
    console.log('\nStarting Flutter MCP Server...\n');
  }
  await runFlutterMCP(pythonCmd, args);
}

// Handle errors
process.on('unhandledRejection', (error) => {
  console.error('Unhandled error:', error);
  process.exit(1);
});

// Run main function
main().catch((error) => {
  console.error('Fatal error:', error);
  process.exit(1);
});
```

--------------------------------------------------------------------------------
/docs/token-management-implementation.md:
--------------------------------------------------------------------------------

```markdown
# Token Management Implementation Plan

## Overview

This document outlines the implementation of token management for Flutter MCP, inspired by Context7's simple approach but adapted for our client-side architecture.

## Goals

1. **Simple API**: Add optional `tokens` parameter to all documentation tools
2. **Smart Truncation**: Preserve most important content when limits are reached
3. **Performance**: Fast token counting without impacting response times
4. **Transparency**: Clear indication when content is truncated
5. **Context7-like UX**: Sensible defaults, no required parameters

## Implementation Phases

### Phase 1: Basic Token Management (Status: In Progress)
- [ ] Add `tokens` parameter to all documentation tools
- [ ] Implement basic token counting (word-based approximation)
- [ ] Simple truncation at section boundaries
- [ ] Update response format with token metadata

### Phase 2: Smart Truncation (Status: Pending)
- [ ] Create priority-based content classification
- [ ] Implement Flutter-aware section detection
- [ ] Add intelligent truncation algorithm
- [ ] Preserve markdown formatting during truncation

### Phase 3: Cache Integration (Status: Pending)
- [ ] Update cache schema to store token counts
- [ ] Modify cache read/write operations
- [ ] Ensure backward compatibility with existing cache

### Phase 4: Testing & Documentation (Status: Pending)
- [ ] Unit tests for token counting
- [ ] Integration tests for truncation
- [ ] Update API documentation
- [ ] Add usage examples

## Technical Design

### Token Counting Strategy

**Approximation Method** (Default):
```python
def approximate_tokens(text: str) -> int:
    """Fast token approximation: ~1.3 tokens per word"""
    return int(len(text.split()) * 1.3)
```

**Accurate Counting** (Optional):
- Use tiktoken for GPT models
- Lazy-loaded to avoid startup overhead
- Configurable via environment variable

### Default Token Limits

| Tool | Default | Minimum | Rationale |
|------|---------|---------|-----------|
| get_flutter_docs | 8,000 | 1,000 | Single class documentation |
| search_flutter_docs | 5,000 | 1,000 | Multiple search results |
| get_pub_package_info | 6,000 | 1,000 | Package info + README |
| process_flutter_mentions | 4,000 | 500 | Per mention |

### Truncation Priority

1. **CRITICAL**: Class description, constructor signatures
2. **HIGH**: Common methods (build, setState), essential properties
3. **MEDIUM**: Secondary methods, code examples
4. **LOW**: Inherited members, see also sections
5. **MINIMAL**: Related classes, external links

### Response Format

```json
{
  "content": "# Widget Name\n...",
  "source": "live|cache",
  "truncated": true,
  "token_count": 2000,
  "original_tokens": 5234,
  "sections_included": ["description", "constructors"],
  "sections_truncated": ["methods", "examples"],
  "truncation_note": "Documentation limited to 2000 tokens."
}
```

## Implementation Progress

### ✅ Completed
- Created implementation plan document
- Added `tokens` parameter to all documentation tools
- Implemented `TokenManager` class with approximation and accurate counting
- Created `DocumentTruncator` class with section detection
- Updated tool signatures with validation
- Integrated token management into server processing pipeline
- Updated cache to store and retrieve token counts
- Added schema migration for existing cache databases
- Updated response format to include token metadata
- Created comprehensive test suite
- Added usage examples and demo script

### 🎉 All phases complete!

## Implementation Summary

### What Was Built

1. **TokenManager** (`src/flutter_mcp/token_manager.py`)
   - Fast word-based approximation (default)
   - Optional accurate counting with tiktoken
   - Environment variable configuration
   - ~1.3 tokens per word ratio

2. **DocumentTruncator** (`src/flutter_mcp/truncation.py`)
   - Smart section detection for Flutter docs
   - Priority-based content preservation
   - Maintains markdown formatting
   - Graceful degradation for edge cases

3. **Server Integration**
   - All tools now accept optional `tokens` parameter
   - Automatic truncation when limits exceeded
   - Token metadata in all responses
   - Transparent to existing users (backward compatible)

4. **Cache Enhancement**
   - Stores token counts with content
   - Avoids re-counting for cached docs
   - Schema migration for existing databases
   - Statistics tracking for cached tokens

5. **Testing & Documentation**
   - Comprehensive test suite
   - Interactive demo script
   - Usage examples

### Key Features

- **Simple like Context7**: Optional parameter, sensible defaults
- **Fast**: Approximation takes <1ms for typical docs
- **Smart**: Preserves most important content when truncating
- **Transparent**: Users see token counts and truncation status
- **Cached**: Token counts stored to avoid recalculation

### Usage

```python
# Default usage - no change needed
docs = await get_flutter_docs("Container")

# With token limit
docs = await get_flutter_docs("Container", tokens=2000)

# Response includes token info
{
  "content": "...",
  "token_count": 1998,
  "truncated": true,
  "truncation_note": "Documentation limited to 2000 tokens."
}
```

## Notes

- Using word-based approximation for performance (1.3 tokens/word)
- Optional tiktoken integration for accuracy
- Cache stores both content and token count
- Backward compatible with existing cache entries
```

--------------------------------------------------------------------------------
/docs/planning/flutter-mcp-project-summary.md:
--------------------------------------------------------------------------------

```markdown
# Flutter MCP Server Project - Complete Summary

## Background: MCP Server Configuration Journey

### Initial Setup - Three Main MCP Servers

1. **Firebase MCP** (Account-wide access)
   - Official Firebase CLI MCP server
   - Access to all Firebase projects
   - No `--dir` flag for unscoped access
   - Authentication via `firebase login`

2. **Supabase MCP** (Account-wide access)
   - Uses Personal Access Token (NOT project API keys)
   - Token from Account Settings → Access Tokens
   - `--read-only` flag recommended for safety
   - Access to all Supabase projects without `--project-ref`

3. **ZEN MCP Server**
   - Docker-based multi-AI orchestration
   - Connects Claude with Gemini, O3, GPT-4o
   - Enables AI-to-AI conversations
   - Already running as Docker container

### Configuration Files

**Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json`):
```json
{
  "mcpServers": {
    "firebase-all": {
      "command": "npx",
      "args": ["-y", "firebase-tools@latest", "experimental:mcp"]
    },
    "supabase-all": {
      "command": "npx",
      "args": [
        "-y",
        "@supabase/mcp-server-supabase@latest",
        "--read-only"
      ],
      "env": {
        "SUPABASE_ACCESS_TOKEN": "sbp_YOUR_TOKEN_HERE"
      }
    },
    "zen": {
      "command": "docker",
      "args": [
        "exec",
        "-i",
        "zen-mcp-server",
        "python",
        "server.py"
      ]
    }
  }
}
```

**Claude Code** (stored in `~/.claude.json`):
```bash
# Add globally with user scope
claude mcp add firebase-global -s user -- npx -y firebase-tools@latest experimental:mcp
claude mcp add supabase-global -s user -e SUPABASE_ACCESS_TOKEN=your_token -- npx -y @supabase/mcp-server-supabase@latest --read-only
claude mcp add zen -s user -- docker exec -i zen-mcp-server python server.py
```

## Context7 and Deepwiki Research

### Context7 (by Upstash)
- **Purpose**: Real-time library documentation
- **Problem Solved**: Outdated API information in LLMs
- **Coverage**: 50+ JavaScript/Python libraries
- **Key Feature**: Dynamic documentation fetching
- **Cost**: Completely FREE, no API keys needed
- **Usage**: Add "use context7" to prompts
- **Architecture**: Local Node.js execution

### Deepwiki (by Cognition Labs)
- **Purpose**: GitHub repository understanding
- **Problem Solved**: Quick codebase comprehension
- **Coverage**: 50,000+ indexed repositories
- **Key Feature**: AI-analyzed repository documentation
- **Cost**: Free for public repos
- **Architecture**: Remote SSE server

### Why They Don't Work for Flutter
- Context7: Only supports JavaScript/Python libraries
- Deepwiki: Works for Flutter repos but doesn't understand Dart/Flutter APIs specifically

## Flutter MCP Server Project Plan

### Vision
Create a Context7-like MCP server specifically for Flutter/Dart ecosystem that provides:
- Real-time Flutter/Dart API documentation
- Pub.dev package documentation on-demand
- Flutter cookbook and samples
- Stack Overflow Flutter solutions

### Technical Decisions

1. **Inspiration**: Context7's approach (real-time docs > static knowledge)
2. **Language**: Python (easier for Claude Code to write)
3. **Architecture**: On-demand fetching (better for marketing "supports ALL pub.dev packages")
4. **Distribution**: Public GitHub/npm package

### Data Sources to Integrate
- **Official APIs**: api.flutter.dev, api.dart.dev
- **Package Registry**: pub.dev (on-demand fetching)
- **Examples**: Flutter cookbook, official samples
- **Community**: Stack Overflow Flutter tags

### MVP Scope
- Start with official Flutter/Dart API documentation only
- Estimated time: 2-4 hours with Claude Code
- Focus on working prototype first

### Marketing Strategy
- **Reddit Pitch**: "MCP server that gives Claude access to ALL pub.dev packages"
- **Key Differentiator**: Always up-to-date Flutter/Dart documentation
- **Target Audience**: Flutter developers using Claude/Cursor/VS Code

### Technical Requirements
1. MCP protocol implementation in Python
2. Web scraping/API integration for documentation sources
3. Caching mechanism for performance
4. Simple installation via npx/pip

### Development Approach
1. Use Claude Code to build the server
2. Start with minimal viable version
3. Test with personal projects
4. Expand to more sources
5. Release to community

## Next Steps

1. **Get MCP Documentation**: Need current MCP server development guide
2. **Create Project Structure**: Basic Python MCP server template
3. **MVP Features**:
   - Connect to api.flutter.dev
   - Parse and return documentation
   - Handle basic queries
4. **Test & Iterate**: Use with Claude Desktop/Code
5. **Expand**: Add pub.dev, cookbook, etc.
6. **Release**: GitHub + announcement on r/FlutterDev

## Resources Needed

- Current MCP server development documentation
- Python MCP SDK examples
- Flutter/Dart API endpoints
- Pub.dev API documentation
- Testing environment setup guide

## Potential Challenges

1. **API Rate Limits**: Need caching strategy
2. **Documentation Parsing**: Flutter docs structure complexity
3. **Performance**: Fast response times for good UX
4. **Maintenance**: Keeping up with Flutter updates

## Success Metrics

- Working MVP in 4 hours
- <1 second response time
- Covers 100% of official Flutter/Dart APIs
- Positive reception on Reddit/Twitter
- 100+ GitHub stars in first month

---

*This document summarizes the entire conversation about MCP servers configuration and the Flutter MCP server project idea from [Date: 2025-06-20]*
```

--------------------------------------------------------------------------------
/docs/VERSION_SPECIFICATION.md:
--------------------------------------------------------------------------------

```markdown
# Version Specification System

The Flutter MCP server now supports advanced version specifications for pub.dev packages, allowing AI assistants to fetch documentation for specific package versions based on various constraint formats.

## Overview

When referencing packages with `@flutter_mcp`, you can now specify version constraints similar to how they work in `pubspec.yaml` files. This ensures AI assistants get documentation that matches the exact version requirements of a project.

## Supported Formats

### 1. Exact Versions

Specify an exact version to fetch documentation for that specific release:

```
@flutter_mcp riverpod:2.5.1
@flutter_mcp provider:6.0.5
@flutter_mcp dio:5.3.2
```

### 2. Caret Syntax (^)

The caret syntax allows compatible updates according to semantic versioning:

```
@flutter_mcp provider:^6.0.0    # Allows >=6.0.0 <7.0.0
@flutter_mcp bloc:^8.1.0        # Allows >=8.1.0 <9.0.0
@flutter_mcp get:^4.6.5         # Allows >=4.6.5 <5.0.0
```

For packages with 0.x.x versions, the caret is more restrictive:
- `^0.2.3` allows `>=0.2.3 <0.3.0`
- `^0.0.3` allows `>=0.0.3 <0.0.4`

### 3. Version Ranges

Specify explicit version ranges using comparison operators:

```
@flutter_mcp dio:>=5.0.0 <6.0.0    # Any 5.x version
@flutter_mcp http:>0.13.0 <=1.0.0  # Greater than 0.13.0, up to and including 1.0.0
@flutter_mcp provider:>=6.0.0       # 6.0.0 or higher
@flutter_mcp bloc:<9.0.0            # Any version below 9.0.0
```

### 4. Special Keywords

Use keywords to fetch specific version types:

```
@flutter_mcp provider:latest   # Absolute latest version (including pre-releases)
@flutter_mcp riverpod:stable   # Latest stable version (no pre-releases)
@flutter_mcp bloc:dev          # Latest dev version
@flutter_mcp get:beta          # Latest beta version
@flutter_mcp dio:alpha         # Latest alpha version
```

### 5. No Version (Current Behavior)

When no version is specified, the system fetches the latest stable version:

```
@flutter_mcp provider          # Latest stable version
@flutter_mcp riverpod          # Latest stable version
```

## Examples in Context

### Example 1: Upgrading Dependencies

```
I'm upgrading from @flutter_mcp provider:^5.0.0 to @flutter_mcp provider:^6.0.0.
What are the breaking changes I need to be aware of?
```

### Example 2: Testing Pre-release Features

```
I want to try the new features in @flutter_mcp riverpod:beta.
Can you show me what's new compared to @flutter_mcp riverpod:stable?
```

### Example 3: Version Compatibility

```
My project uses @flutter_mcp dio:>=5.0.0 <6.0.0 for networking.
Is this compatible with @flutter_mcp retrofit:^4.0.0?
```

### Example 4: Legacy Code

```
I'm maintaining legacy code that uses @flutter_mcp provider:5.0.0.
Can you help me understand the API from that specific version?
```

## How It Works

### Version Resolution

1. **Parsing**: The system parses the version specification to understand the constraint type
2. **Resolution**: For constraints (not exact versions), the system queries pub.dev to find all available versions
3. **Selection**: The highest version that satisfies the constraint is selected
4. **Fetching**: Documentation for the selected version is retrieved and cached

### Caching

Version-specific documentation is cached separately:
- Cache key includes the package name and resolved version
- Different version constraints that resolve to the same version share the cache
- Cache duration: 12 hours for package documentation

### Error Handling

The system provides helpful error messages:
- If a version doesn't exist: Lists available versions
- If constraint can't be resolved: Explains why
- If package doesn't exist: Standard package not found error

## Implementation Details

### Version Parser

The `VersionParser` class handles parsing of version specifications:
- Regex patterns for different constraint formats
- Semantic version comparison logic
- Support for pre-release versions

### Version Resolver

The `VersionResolver` class interfaces with pub.dev API:
- Fetches available versions from pub.dev
- Applies constraint logic to find best match
- Handles special keywords (latest, stable, etc.)

### Integration

The version system is fully integrated with:
- `process_flutter_mentions`: Parses mentions with version specs
- `get_pub_package_info`: Fetches version-specific documentation
- Cache system: Version-aware cache keys

## Best Practices

1. **Use Caret for Flexibility**: `^` allows compatible updates
   ```
   @flutter_mcp provider:^6.0.0
   ```

2. **Exact Versions for Reproducibility**: When you need specific behavior
   ```
   @flutter_mcp riverpod:2.5.1
   ```

3. **Ranges for Compatibility**: When working with multiple packages
   ```
   @flutter_mcp dio:>=5.0.0 <6.0.0
   ```

4. **Keywords for Exploration**: Testing new features
   ```
   @flutter_mcp bloc:beta
   ```

## Limitations

1. **Flutter/Dart Classes**: Version specifications only work with pub.dev packages, not Flutter framework classes
   - ✅ `@flutter_mcp provider:^6.0.0`
   - ❌ `@flutter_mcp material.AppBar:^3.0.0`

2. **Version Availability**: Only versions published on pub.dev are accessible

3. **Rate Limiting**: Version resolution requires additional API calls, subject to rate limits

## Future Enhancements

Potential future improvements:
1. Flutter SDK version-specific documentation
2. Git commit/branch references for packages
3. Local path references for development
4. Version comparison tools
5. Migration guide generation between versions
```

--------------------------------------------------------------------------------
/ERROR_HANDLING.md:
--------------------------------------------------------------------------------

```markdown
# Flutter MCP Server - Error Handling & Resilience

This document describes the comprehensive error handling and resilience features implemented in the Flutter MCP Server.

## Overview

The Flutter MCP Server is designed to be highly resilient and provide a good user experience even when external services are unavailable or experiencing issues. The server implements multiple layers of error handling, retry logic, and graceful degradation.

## Error Handling Features

### 1. Retry Logic with Exponential Backoff

All HTTP requests implement automatic retry with exponential backoff:

- **Max retries**: 3 attempts
- **Base delay**: 1 second
- **Max delay**: 16 seconds
- **Jitter**: Random 0-1 second added to prevent thundering herd
- **Smart retries**: Only retries on network errors and 5xx server errors, not 4xx client errors

```python
@with_retry(max_retries=3)
async def fetch_data():
    # Automatic retry on network failures
    pass
```

### 2. Comprehensive Error Types

The server categorizes errors for better handling:

- `NetworkError`: Connection failures, timeouts
- `DocumentationNotFoundError`: Resource not found (404)
- `RateLimitError`: Rate limit exceeded (429)
- `CacheError`: Cache operation failures

### 3. User-Friendly Error Responses

All errors return structured responses with:

```json
{
  "error": true,
  "error_type": "not_found",
  "message": "Documentation not found for widgets.NonExistentWidget",
  "suggestions": [
    "Check if 'NonExistentWidget' is spelled correctly",
    "Verify that 'NonExistentWidget' exists in the 'widgets' library",
    "Common libraries: widgets, material, cupertino, painting, rendering",
    "Try searching with: search_flutter_docs('NonExistentWidget')"
  ],
  "context": {
    "class": "NonExistentWidget",
    "library": "widgets",
    "status_code": 404
  },
  "timestamp": "2024-01-20T10:30:00Z"
}
```

### 4. Circuit Breaker Pattern

Prevents cascading failures when external services are down:

- **Failure threshold**: 5 consecutive failures
- **Recovery timeout**: 60 seconds
- **States**: CLOSED (normal), OPEN (failing), HALF-OPEN (testing)

```python
flutter_docs_circuit = CircuitBreaker(
    failure_threshold=5,
    recovery_timeout=60.0
)
```

### 5. Graceful Degradation

The server continues operating even when some components fail:

- **Cache failures**: Continue without caching
- **README fetch failures**: Return package info without README
- **Enrichment failures**: Return search results without full documentation

### 6. Health Monitoring

Comprehensive health check system:

```python
# Health check with timeout protection
async def health_check():
    # Tests Flutter docs API
    # Tests pub.dev API  
    # Tests cache functionality
    # Returns detailed status for each component
```

### 7. Timeout Protection

All operations have configurable timeouts:

- **Default timeout**: 30 seconds
- **Connection timeout**: 10 seconds
- **Health check timeout**: 10 seconds

### 8. Rate Limiting

Respectful rate limiting for external APIs:

- **Default rate**: 2 requests/second
- **Adjustable during high load**
- **Per-service rate limiters**

## Error Scenarios Handled

### Network Errors

- Connection timeouts
- DNS resolution failures
- Connection refused
- Network unreachable

**User Experience**: Clear message about network issues with retry suggestions

### API Errors

- 404 Not Found: Helpful suggestions for correct names/formats
- 429 Rate Limited: Advises waiting and provides retry timing
- 500-599 Server Errors: Indicates external service issues
- Invalid responses: Handles malformed JSON/HTML

### Input Validation

- Invalid class names
- Invalid package names (must be lowercase with underscores)
- Malformed queries
- Empty inputs

### Cache Errors

- Cache initialization failures: Falls back to no-cache mode
- Cache read/write errors: Logged but don't fail requests
- Corrupted cache entries: Automatic cleanup

## Testing Error Handling

Run the error handling test suite:

```bash
python test_error_handling.py
```

This tests:
1. Invalid Flutter class names
2. Invalid library names
3. Non-existent packages
4. Invalid package name formats
5. Search with no results
6. Mention processing with errors
7. Health check functionality
8. Graceful degradation

## Logging

Structured logging with contextual information:

```python
logger.error(
    "http_error",
    status_code=404,
    url="https://api.flutter.dev/...",
    class_name="NonExistentWidget",
    library="widgets"
)
```

## Recovery Mechanisms

### Automatic Recovery

1. **Cache clearing**: After 3 consecutive failures
2. **Connection pool reset**: After 5 consecutive failures  
3. **Rate limit reduction**: After 7 consecutive failures

### Manual Recovery

- Restart server to reset all circuit breakers
- Clear cache directory to remove corrupted data
- Check logs for specific error patterns

## Best Practices

1. **Always check for errors** in responses:
   ```python
   result = await get_flutter_docs("Widget", "widgets")
   if result.get("error"):
       # Handle error
   ```

2. **Use suggestions** provided in error responses
3. **Implement backoff** when seeing rate limit errors
4. **Monitor health endpoint** for service status

## Configuration

Error handling can be configured via environment variables:

```bash
# Retry configuration
MAX_RETRIES=3
BASE_RETRY_DELAY=1.0
MAX_RETRY_DELAY=16.0

# Timeout configuration  
DEFAULT_TIMEOUT=30.0
CONNECTION_TIMEOUT=10.0

# Circuit breaker
FAILURE_THRESHOLD=5
RECOVERY_TIMEOUT=60.0

# Rate limiting
REQUESTS_PER_SECOND=2.0
```

## Monitoring

Monitor these metrics for service health:

- Error rates by type
- Circuit breaker state changes
- Cache hit/miss rates
- Response times
- Retry counts

## Future Improvements

- [ ] Implement request queuing during rate limits
- [ ] Add fallback to cached documentation during outages
- [ ] Implement progressive retry delays based on error type
- [ ] Add webhook notifications for circuit breaker state changes
- [ ] Implement request deduplication
```

--------------------------------------------------------------------------------
/src/flutter_mcp/token_manager.py:
--------------------------------------------------------------------------------

```python
"""Token counting module for Flutter MCP server.

Provides both approximate and accurate token counting methods with
configurable behavior via environment variables.
"""

import os
import re
from typing import Optional, Union
import structlog

logger = structlog.get_logger(__name__)


class TokenManager:
    """Manages token counting with both approximation and accurate methods."""
    
    # Average tokens per word based on empirical observations
    TOKENS_PER_WORD = 1.3
    
    # Word splitting pattern
    WORD_PATTERN = re.compile(r'\b\w+\b')
    
    def __init__(self):
        """Initialize the TokenManager."""
        self._tiktoken = None
        self._encoder = None
        self._accurate_mode = self._get_accurate_mode()
        
        logger.info(
            "TokenManager initialized",
            accurate_mode=self._accurate_mode
        )
    
    def _get_accurate_mode(self) -> bool:
        """Check if accurate token counting is enabled via environment variable."""
        env_value = os.environ.get('FLUTTER_MCP_ACCURATE_TOKENS', 'false').lower()
        return env_value in ('true', '1', 'yes', 'on')
    
    def _ensure_tiktoken(self) -> bool:
        """Lazy load tiktoken if needed and available.
        
        Returns:
            bool: True if tiktoken is available, False otherwise.
        """
        if self._tiktoken is None:
            try:
                import tiktoken
                self._tiktoken = tiktoken
                # Use cl100k_base encoding (used by GPT-3.5/GPT-4)
                self._encoder = tiktoken.get_encoding("cl100k_base")
                logger.info("Tiktoken loaded successfully")
                return True
            except ImportError:
                logger.warning(
                    "Tiktoken not available, falling back to approximation",
                    hint="Install with: pip install tiktoken"
                )
                return False
        return True
    
    def approximate_tokens(self, text: str) -> int:
        """Approximate token count using word-based estimation.
        
        This method is fast and doesn't require external dependencies.
        Uses a simple heuristic of 1.3 tokens per word.
        
        Args:
            text: The text to count tokens for.
            
        Returns:
            int: Approximate number of tokens.
        """
        if not text:
            return 0
        
        # Count words using regex pattern
        words = self.WORD_PATTERN.findall(text)
        word_count = len(words)
        
        # Apply multiplier for approximation
        token_count = int(word_count * self.TOKENS_PER_WORD)
        
        logger.debug(
            "Approximate token count",
            word_count=word_count,
            token_count=token_count,
            text_length=len(text)
        )
        
        return token_count
    
    def accurate_tokens(self, text: str) -> Optional[int]:
        """Count tokens accurately using tiktoken.
        
        This method requires the tiktoken library to be installed.
        It provides exact token counts but is slower than approximation.
        
        Args:
            text: The text to count tokens for.
            
        Returns:
            Optional[int]: Exact number of tokens, or None if tiktoken unavailable.
        """
        if not text:
            return 0
        
        if not self._ensure_tiktoken():
            return None
        
        try:
            tokens = self._encoder.encode(text)
            token_count = len(tokens)
            
            logger.debug(
                "Accurate token count",
                token_count=token_count,
                text_length=len(text)
            )
            
            return token_count
        except Exception as e:
            logger.error(
                "Error counting tokens with tiktoken",
                error=str(e),
                text_length=len(text)
            )
            return None
    
    def count_tokens(self, text: str, force_accurate: bool = False) -> int:
        """Count tokens using the configured method.
        
        By default, uses the method configured via FLUTTER_MCP_ACCURATE_TOKENS
        environment variable. Can be overridden with force_accurate parameter.
        
        Args:
            text: The text to count tokens for.
            force_accurate: Force accurate counting regardless of configuration.
            
        Returns:
            int: Number of tokens (approximate or accurate based on configuration).
        """
        if not text:
            return 0
        
        # Determine which method to use
        use_accurate = force_accurate or self._accurate_mode
        
        if use_accurate:
            # Try accurate counting first
            accurate_count = self.accurate_tokens(text)
            if accurate_count is not None:
                return accurate_count
            
            # Fall back to approximation if accurate counting fails
            logger.info(
                "Falling back to approximation",
                reason="Accurate counting failed or unavailable"
            )
        
        # Use approximation
        return self.approximate_tokens(text)
    
    def set_accurate_mode(self, enabled: bool) -> None:
        """Dynamically enable or disable accurate token counting.
        
        Args:
            enabled: Whether to use accurate token counting.
        """
        self._accurate_mode = enabled
        logger.info(
            "Token counting mode changed",
            accurate_mode=enabled
        )
    
    def get_mode(self) -> str:
        """Get the current token counting mode.
        
        Returns:
            str: 'accurate' if using tiktoken, 'approximate' otherwise.
        """
        return 'accurate' if self._accurate_mode else 'approximate'
    
    def estimate_cost(
        self, 
        token_count: int, 
        cost_per_1k_tokens: float = 0.002
    ) -> float:
        """Estimate cost based on token count.
        
        Args:
            token_count: Number of tokens.
            cost_per_1k_tokens: Cost per 1000 tokens (default: $0.002).
            
        Returns:
            float: Estimated cost in dollars.
        """
        return (token_count / 1000) * cost_per_1k_tokens


# Module-level instance for convenience
_token_manager = TokenManager()

# Expose main methods at module level
approximate_tokens = _token_manager.approximate_tokens
accurate_tokens = _token_manager.accurate_tokens
count_tokens = _token_manager.count_tokens
set_accurate_mode = _token_manager.set_accurate_mode
get_mode = _token_manager.get_mode
estimate_cost = _token_manager.estimate_cost


def get_token_manager() -> TokenManager:
    """Get the singleton TokenManager instance.
    
    Returns:
        TokenManager: The module-level token manager instance.
    """
    return _token_manager
```

--------------------------------------------------------------------------------
/src/flutter_mcp/recovery.py:
--------------------------------------------------------------------------------

```python
"""
Recovery mechanisms for Flutter MCP Server.

This module provides automatic recovery and self-healing capabilities
for the Flutter documentation server.
"""

import asyncio
import time
from typing import Dict, Any, Optional, Callable
from datetime import datetime, timedelta
import structlog

logger = structlog.get_logger()


class HealthMonitor:
    """
    Monitors service health and triggers recovery actions.
    """
    
    def __init__(self, check_interval: float = 300.0):  # 5 minutes
        self.check_interval = check_interval
        self.last_check = None
        self.consecutive_failures = 0
        self.recovery_actions = []
        self.is_monitoring = False
        
    def add_recovery_action(self, action: Callable, threshold: int = 3):
        """Add a recovery action to trigger after threshold failures."""
        self.recovery_actions.append({
            "action": action,
            "threshold": threshold,
            "triggered": False
        })
    
    async def start_monitoring(self, health_check_func: Callable):
        """Start continuous health monitoring."""
        self.is_monitoring = True
        logger.info("health_monitoring_started", interval=self.check_interval)
        
        while self.is_monitoring:
            try:
                # Perform health check
                result = await health_check_func()
                status = result.get("status", "unknown")
                
                if status in ["failed", "degraded"]:
                    self.consecutive_failures += 1
                    logger.warning(
                        "health_check_failed",
                        status=status,
                        consecutive_failures=self.consecutive_failures
                    )
                    
                    # Trigger recovery actions if needed
                    await self._trigger_recovery_actions()
                else:
                    if self.consecutive_failures > 0:
                        logger.info("health_recovered", previous_failures=self.consecutive_failures)
                    self.consecutive_failures = 0
                    self._reset_recovery_actions()
                
                self.last_check = datetime.utcnow()
                
            except Exception as e:
                logger.error(
                    "health_monitor_error",
                    error=str(e),
                    error_type=type(e).__name__
                )
                self.consecutive_failures += 1
            
            # Wait for next check
            await asyncio.sleep(self.check_interval)
    
    async def _trigger_recovery_actions(self):
        """Trigger appropriate recovery actions based on failure count."""
        for action_config in self.recovery_actions:
            if (self.consecutive_failures >= action_config["threshold"] and 
                not action_config["triggered"]):
                try:
                    logger.info(
                        "triggering_recovery_action",
                        threshold=action_config["threshold"],
                        failures=self.consecutive_failures
                    )
                    await action_config["action"]()
                    action_config["triggered"] = True
                except Exception as e:
                    logger.error(
                        "recovery_action_failed",
                        error=str(e),
                        error_type=type(e).__name__
                    )
    
    def _reset_recovery_actions(self):
        """Reset triggered flags on recovery actions."""
        for action_config in self.recovery_actions:
            action_config["triggered"] = False
    
    def stop_monitoring(self):
        """Stop health monitoring."""
        self.is_monitoring = False
        logger.info("health_monitoring_stopped")


class CacheRecovery:
    """
    Handles cache-related recovery operations.
    """
    
    @staticmethod
    async def clear_corrupted_entries(cache_manager):
        """Clear potentially corrupted cache entries."""
        try:
            logger.info("clearing_corrupted_cache_entries")
            # Implementation depends on cache manager interface
            # This is a placeholder for the actual implementation
            stats = cache_manager.get_stats()
            logger.info("cache_recovery_completed", stats=stats)
        except Exception as e:
            logger.error("cache_recovery_failed", error=str(e))


class ConnectionPoolRecovery:
    """
    Manages HTTP connection pool recovery.
    """
    
    @staticmethod
    async def reset_connection_pools():
        """Reset all HTTP connection pools."""
        logger.info("resetting_connection_pools")
        # Force garbage collection of old connections
        import gc
        gc.collect()
        logger.info("connection_pools_reset")


class RateLimiterRecovery:
    """
    Handles rate limiter recovery and adjustment.
    """
    
    @staticmethod
    async def adjust_rate_limits(rate_limiter, factor: float = 0.5):
        """Temporarily reduce rate limits during recovery."""
        original_rate = 1.0 / rate_limiter.min_interval
        new_rate = original_rate * factor
        rate_limiter.min_interval = 1.0 / new_rate
        
        logger.info(
            "rate_limits_adjusted",
            original_rate=original_rate,
            new_rate=new_rate,
            factor=factor
        )
        
        # Reset after 5 minutes
        await asyncio.sleep(300)
        rate_limiter.min_interval = 1.0 / original_rate
        logger.info("rate_limits_restored", rate=original_rate)


async def create_recovery_system(cache_manager, rate_limiter, health_check_func):
    """
    Create and configure the recovery system.
    
    Returns:
        HealthMonitor: Configured health monitor instance
    """
    monitor = HealthMonitor(check_interval=300.0)  # 5 minutes
    
    # Add recovery actions with increasing severity
    
    # Level 1: Clear cache (after 3 failures)
    async def clear_cache():
        await CacheRecovery.clear_corrupted_entries(cache_manager)
    
    monitor.add_recovery_action(clear_cache, threshold=3)
    
    # Level 2: Reset connections (after 5 failures)
    async def reset_connections():
        await ConnectionPoolRecovery.reset_connection_pools()
    
    monitor.add_recovery_action(reset_connections, threshold=5)
    
    # Level 3: Reduce rate limits (after 7 failures)
    async def reduce_rates():
        await RateLimiterRecovery.adjust_rate_limits(rate_limiter, factor=0.5)
    
    monitor.add_recovery_action(reduce_rates, threshold=7)
    
    # Start monitoring in background
    asyncio.create_task(monitor.start_monitoring(health_check_func))
    
    return monitor


class GracefulShutdown:
    """
    Handles graceful shutdown of the server.
    """
    
    def __init__(self):
        self.shutdown_handlers = []
        self.is_shutting_down = False
    
    def add_handler(self, handler: Callable):
        """Add a shutdown handler."""
        self.shutdown_handlers.append(handler)
    
    async def shutdown(self):
        """Perform graceful shutdown."""
        if self.is_shutting_down:
            return
        
        self.is_shutting_down = True
        logger.info("graceful_shutdown_started")
        
        # Execute all shutdown handlers
        for handler in self.shutdown_handlers:
            try:
                await handler()
            except Exception as e:
                logger.error(
                    "shutdown_handler_error",
                    error=str(e),
                    error_type=type(e).__name__
                )
        
        logger.info("graceful_shutdown_completed")
```

--------------------------------------------------------------------------------
/docs/truncation-algorithm.md:
--------------------------------------------------------------------------------

```markdown
# Smart Truncation Algorithm for Flutter/Dart Documentation

## Overview

The smart truncation algorithm is designed to intelligently reduce Flutter and Dart documentation to fit within token limits while preserving the most critical information for developers. This algorithm uses a priority-based system to ensure that essential information is retained even under severe token constraints.

## Key Features

### 1. Priority-Based Content Classification

The algorithm classifies documentation content into five priority levels:

- **CRITICAL (1)**: Must always be retained
  - Class descriptions
  - Constructor signatures
  
- **HIGH (2)**: Retained whenever possible
  - Primary method signatures (build, createState, initState, dispose)
  - Common properties (child, children, padding, margin, etc.)
  - Constructor descriptions

- **MEDIUM (3)**: Retained if space allows
  - Secondary methods
  - Less common properties
  - First 2 code examples
  
- **LOW (4)**: First to be removed
  - Private methods
  - Verbose method descriptions
  - Additional code examples (3+)
  
- **MINIMAL (5)**: Removed first
  - Inherited members
  - See also sections
  - Related classes

### 2. Intelligent Section Parsing

The algorithm parses Flutter documentation into semantic sections:

```python
sections = [
    "description",      # Class overview
    "constructors",     # Constructor signatures and docs
    "properties",       # Widget properties
    "methods",          # Class methods
    "examples"          # Code examples
]
```

Each section is further broken down into sub-components with individual priorities.

### 3. Flutter-Aware Prioritization

The algorithm has built-in knowledge of Flutter's widget hierarchy and common patterns:

#### High-Priority Widgets
```python
HIGH_PRIORITY_WIDGETS = {
    "Container", "Row", "Column", "Text", "Image", "Scaffold",
    "AppBar", "ListView", "GridView", "Stack", "Positioned",
    "Center", "Padding", "SizedBox", "Expanded", "Flexible",
    # ... and more
}
```

#### High-Priority Methods
```python
HIGH_PRIORITY_METHODS = {
    "build", "createState", "initState", "dispose", "setState",
    "didChangeDependencies", "didUpdateWidget", "deactivate"
}
```

#### High-Priority Properties
```python
HIGH_PRIORITY_PROPERTIES = {
    "child", "children", "width", "height", "color", "padding",
    "margin", "alignment", "decoration", "style", "onPressed",
    "onTap", "controller", "value", "enabled", "visible"
}
```

### 4. Truncation Strategies

The algorithm supports multiple truncation strategies:

#### Balanced (Default)
Maintains a good mix of all documentation types:
- Keeps description, main constructors, key properties, and primary methods
- Includes 1-2 code examples if space allows
- Best for general-purpose documentation

#### Signatures
Prioritizes method and constructor signatures:
- Maximizes retention of code signatures
- Reduces or removes descriptions
- Ideal when the user needs API reference information

#### Examples
Prioritizes code examples:
- Keeps more code examples than other strategies
- Useful for learning and implementation guidance

#### Minimal
Keeps only the most essential information:
- Class description
- Primary constructor
- build() method for widgets
- child/children properties

### 5. Smart Code Truncation

When truncating code blocks, the algorithm:
- Preserves syntactic validity when possible
- Balances braces and brackets
- Truncates at line boundaries
- Adds ellipsis comments to indicate truncation

Example:
```dart
Container(
  width: 200,
  height: 200,
  child: Column(
    children: [
      Text('Line 1'),
      // ...
    ],
  ),
)
```

### 6. Progressive Truncation

The algorithm applies truncation progressively:

1. Calculate total token count
2. If under limit, return unchanged
3. Remove MINIMAL priority content
4. Remove LOW priority content
5. Reduce MEDIUM priority content
6. Trim HIGH priority content (descriptions only)
7. CRITICAL content is never removed

## Usage Examples

### Basic Usage

```python
from flutter_mcp.truncation import truncate_flutter_docs

# Truncate to 4000 tokens with balanced strategy
truncated_doc = truncate_flutter_docs(
    content=original_documentation,
    class_name="Container",
    max_tokens=4000,
    strategy="balanced"
)
```

### Advanced Usage with Metadata

```python
from flutter_mcp.truncation import AdaptiveTruncator

truncator = AdaptiveTruncator(max_tokens=2000)
truncated_doc, metadata = truncator.truncate_with_strategy(
    doc_content=original_documentation,
    class_name="ListView",
    library="widgets",
    strategy="signatures"
)

print(f"Compression ratio: {metadata['compression_ratio']:.1%}")
print(f"Was truncated: {metadata['was_truncated']}")
```

### Integration with MCP Server

```python
# In the MCP tool
@mcp.tool()
async def get_flutter_docs(
    class_name: str, 
    library: str = "widgets",
    max_tokens: int = None  # Optional truncation
) -> Dict[str, Any]:
    # Fetch documentation...
    
    # Apply smart truncation if requested
    if max_tokens:
        content = truncate_flutter_docs(
            content,
            class_name,
            max_tokens=max_tokens,
            strategy="balanced"
        )
```

## Token Limits and Recommendations

| Use Case | Recommended Token Limit | Strategy |
|----------|------------------------|----------|
| Quick reference | 500-1000 | minimal |
| API overview | 2000-4000 | signatures |
| Learning/Tutorial | 4000-8000 | examples |
| Full documentation | 8000+ | balanced |

## Implementation Details

### Token Estimation

The algorithm uses a simple but effective token estimation:
- English text: ~4 characters per token
- Code: ~3 characters per token

This provides a good approximation for planning truncation without requiring actual tokenization.

### Section Preservation

When a section must be truncated:
1. Code sections are truncated at line boundaries
2. Text sections are truncated at sentence boundaries
3. Lists are truncated at item boundaries
4. A truncation notice is always added

### Example Output

Original documentation: 15,000 characters (~3,750 tokens)
Truncated to 1,000 tokens:

```markdown
# Container (Truncated Documentation)

## Description
A convenience widget that combines common painting, positioning, and sizing widgets.

## Constructors
### Container({Key? key, AlignmentGeometry? alignment, ...})
```dart
Container({
  Key? key,
  this.alignment,
  this.padding,
  this.color,
  this.decoration,
  double? width,
  double? height,
  this.child,
})
```

## Properties
- **child**: The child contained by the container
- **padding**: Empty space to inscribe inside the decoration
- **color**: The color to paint behind the child
- **width**: Container width constraint
- **height**: Container height constraint

## Methods
### build(BuildContext context)
```dart
@override
Widget build(BuildContext context) {
  // ... (truncated)
}
```

---
*Note: This documentation has been intelligently truncated to fit within token limits. Some sections may have been removed or shortened.*
```

## Performance Considerations

The truncation algorithm is designed to be efficient:
- O(n) parsing of documentation
- O(n log n) sorting of sections by priority
- O(n) reconstruction of truncated documentation

Typical truncation takes <50ms for large documents.

## Future Enhancements

Potential improvements to the algorithm:

1. **ML-based importance scoring**: Use machine learning to determine section importance based on usage patterns
2. **Context-aware truncation**: Adjust priorities based on the user's query context
3. **Cross-reference preservation**: Maintain links between related classes when truncating
4. **Incremental loading**: Support progressive disclosure of truncated content
5. **Custom priority profiles**: Allow users to define their own priority preferences

## Conclusion

The smart truncation algorithm ensures that Flutter/Dart documentation remains useful even under severe token constraints. By understanding the structure and importance of different documentation sections, it preserves the most critical information while gracefully degrading less essential content.
```

--------------------------------------------------------------------------------
/src/flutter_mcp/cache.py:
--------------------------------------------------------------------------------

```python
"""SQLite-based cache implementation for Flutter MCP Server."""

import json
import sqlite3
import time
from pathlib import Path
from typing import Optional, Dict, Any
import logging

try:
    from platformdirs import user_cache_dir
except ImportError:
    # Fallback to simple home directory approach
    def user_cache_dir(app_name: str, app_author: str) -> str:
        """Simple fallback for cache directory."""
        home = Path.home()
        if hasattr(home, 'absolute'):
            return str(home / '.cache' / app_name)
        return str(Path('.') / '.cache' / app_name)

logger = logging.getLogger(__name__)


class CacheManager:
    """SQLite-based cache manager for Flutter documentation."""
    
    def __init__(self, app_name: str = "FlutterMCP", ttl_hours: int = 24):
        """Initialize cache manager.
        
        Args:
            app_name: Application name for cache directory
            ttl_hours: Time-to-live for cache entries in hours
        """
        self.app_name = app_name
        self.ttl_seconds = ttl_hours * 3600
        self.db_path = self._get_db_path()
        self._init_db()
    
    def _get_db_path(self) -> Path:
        """Get platform-specific cache database path."""
        cache_dir = user_cache_dir(self.app_name, self.app_name)
        cache_path = Path(cache_dir)
        cache_path.mkdir(parents=True, exist_ok=True)
        return cache_path / "cache.db"
    
    def _init_db(self) -> None:
        """Initialize the cache database."""
        with sqlite3.connect(str(self.db_path)) as conn:
            # Check if we need to migrate the schema
            cursor = conn.execute("""
                SELECT sql FROM sqlite_master 
                WHERE type='table' AND name='doc_cache'
            """)
            existing_schema = cursor.fetchone()
            
            if existing_schema and 'token_count' not in existing_schema[0]:
                # Migrate existing table to add token_count column
                logger.info("Migrating cache schema to add token_count")
                conn.execute("""
                    ALTER TABLE doc_cache 
                    ADD COLUMN token_count INTEGER DEFAULT NULL
                """)
            else:
                # Create new table with token_count
                conn.execute("""
                    CREATE TABLE IF NOT EXISTS doc_cache (
                        key TEXT PRIMARY KEY NOT NULL,
                        value TEXT NOT NULL,
                        created_at INTEGER NOT NULL,
                        expires_at INTEGER NOT NULL,
                        token_count INTEGER DEFAULT NULL
                    )
                """)
            
            # Create index for expiration queries
            conn.execute("""
                CREATE INDEX IF NOT EXISTS idx_expires_at 
                ON doc_cache(expires_at)
            """)
            conn.commit()
    
    def get(self, key: str) -> Optional[Dict[str, Any]]:
        """Get value from cache with lazy expiration.
        
        Args:
            key: Cache key
            
        Returns:
            Cached value as dict or None if not found/expired
        """
        current_time = int(time.time())
        
        with sqlite3.connect(str(self.db_path)) as conn:
            cursor = conn.execute(
                "SELECT value, expires_at, token_count FROM doc_cache WHERE key = ?",
                (key,)
            )
            row = cursor.fetchone()
            
            if not row:
                return None
            
            value, expires_at, token_count = row
            
            # Check if expired
            if expires_at < current_time:
                # Lazy deletion
                conn.execute("DELETE FROM doc_cache WHERE key = ?", (key,))
                conn.commit()
                logger.debug(f"Cache expired for key: {key}")
                return None
            
            try:
                result = json.loads(value)
                # Add token_count to the result if it exists
                if token_count is not None:
                    result['_cached_token_count'] = token_count
                return result
            except json.JSONDecodeError:
                logger.error(f"Failed to decode cache value for key: {key}")
                return None
    
    def set(self, key: str, value: Dict[str, Any], ttl_override: Optional[int] = None, token_count: Optional[int] = None) -> None:
        """Set value in cache.
        
        Args:
            key: Cache key
            value: Value to cache (must be JSON-serializable)
            ttl_override: Optional TTL override in seconds
            token_count: Optional token count to store with the cached data
        """
        current_time = int(time.time())
        ttl = ttl_override or self.ttl_seconds
        expires_at = current_time + ttl
        
        # Extract token count from value if present and not provided explicitly
        if token_count is None and '_cached_token_count' in value:
            token_count = value.pop('_cached_token_count', None)
        
        try:
            value_json = json.dumps(value)
        except (TypeError, ValueError) as e:
            logger.error(f"Failed to serialize value for key {key}: {e}")
            return
        
        with sqlite3.connect(str(self.db_path)) as conn:
            conn.execute(
                """INSERT OR REPLACE INTO doc_cache 
                   (key, value, created_at, expires_at, token_count) 
                   VALUES (?, ?, ?, ?, ?)""",
                (key, value_json, current_time, expires_at, token_count)
            )
            conn.commit()
            logger.debug(f"Cached key: {key} (expires in {ttl}s, tokens: {token_count})")
    
    def delete(self, key: str) -> None:
        """Delete a key from cache.
        
        Args:
            key: Cache key to delete
        """
        with sqlite3.connect(str(self.db_path)) as conn:
            conn.execute("DELETE FROM doc_cache WHERE key = ?", (key,))
            conn.commit()
    
    def clear_expired(self) -> int:
        """Clear all expired entries from cache.
        
        Returns:
            Number of entries cleared
        """
        current_time = int(time.time())
        
        with sqlite3.connect(str(self.db_path)) as conn:
            cursor = conn.execute(
                "DELETE FROM doc_cache WHERE expires_at < ?",
                (current_time,)
            )
            conn.commit()
            return cursor.rowcount
    
    def clear_all(self) -> None:
        """Clear all entries from cache."""
        with sqlite3.connect(str(self.db_path)) as conn:
            conn.execute("DELETE FROM doc_cache")
            conn.commit()
    
    def get_stats(self) -> Dict[str, Any]:
        """Get cache statistics.
        
        Returns:
            Dictionary with cache statistics
        """
        current_time = int(time.time())
        
        with sqlite3.connect(str(self.db_path)) as conn:
            # Total entries
            total = conn.execute("SELECT COUNT(*) FROM doc_cache").fetchone()[0]
            
            # Expired entries
            expired = conn.execute(
                "SELECT COUNT(*) FROM doc_cache WHERE expires_at < ?",
                (current_time,)
            ).fetchone()[0]
            
            # Entries with token counts
            with_tokens = conn.execute(
                "SELECT COUNT(*) FROM doc_cache WHERE token_count IS NOT NULL"
            ).fetchone()[0]
            
            # Total tokens cached
            total_tokens = conn.execute(
                "SELECT SUM(token_count) FROM doc_cache WHERE token_count IS NOT NULL AND expires_at >= ?",
                (current_time,)
            ).fetchone()[0] or 0
            
            # Database size
            db_size = self.db_path.stat().st_size if self.db_path.exists() else 0
            
            return {
                "total_entries": total,
                "expired_entries": expired,
                "active_entries": total - expired,
                "entries_with_token_counts": with_tokens,
                "total_cached_tokens": total_tokens,
                "database_size_bytes": db_size,
                "database_path": str(self.db_path)
            }


# Global cache instance
_cache_instance: Optional[CacheManager] = None


def get_cache() -> CacheManager:
    """Get or create the global cache instance."""
    global _cache_instance
    if _cache_instance is None:
        _cache_instance = CacheManager()
    return _cache_instance
```

--------------------------------------------------------------------------------
/docs/planning/project-tasks.csv:
--------------------------------------------------------------------------------

```
Task ID,Category,Task Description,Priority,Status,Who Does This,Implementation Notes,Dependencies,Estimated Time
T001,Core Development,Set up FastMCP Python project structure,Critical,DONE,Claude,Use uv package manager with mcp[cli] httpx redis beautifulsoup4 structlog,,1 hour
T002,Core Development,Implement Redis connection and caching layer,Critical,DONE,Claude,Configure TTLs: 24h for API docs / 12h for packages / 7d for cookbook examples,T001,2 hours
T003,Core Development,Create rate limiter class (2 req/sec),Critical,DONE,Claude,Use asyncio Semaphore pattern from initial-vision.md,T001,1 hour
T004,Documentation Processing,Build HTML to Markdown converter,Critical,DONE,Claude,Extract: description / constructors / properties / methods / code examples,T001,4 hours
T005,Documentation Processing,Implement smart URL resolver,Critical,DONE,Claude,Pattern matching for widgets/material/cupertino/dart:core libraries,T004,2 hours
T006,API & Integration,Create get_flutter_docs tool,Critical,DONE,Claude,On-demand fetching with cache check first,T002/T003/T004,3 hours
T007,API & Integration,Create get_pub_package_docs tool,Critical,DONE,Claude,Use official pub.dev API - format package info nicely,T002/T003,2 hours
T008,API & Integration,Implement @flutter_mcp activation parser,Critical,DONE,Claude,Parse mentions from prompts to trigger package-specific context,T006/T007,2 hours
T009,Core Development,Add structured logging with structlog,High,DONE,Claude,Log: cache hits/misses / fetch times / errors / query patterns,T001,1 hour
T010,Testing & QA,Test with popular packages,Critical,DONE,You + Claude,Test: provider / bloc / get_it / dio / http / freezed,T006/T007,2 hours
T011,Testing & QA,Test with MCP Inspector,Critical,DONE,You,Verify tools work correctly in MCP Inspector before Claude Desktop,T006/T007,1 hour
T012,Documentation,Write comprehensive README,Critical,DONE,Claude,Installation / features / examples / troubleshooting / contribution guide,,2 hours
T013,Documentation,Create installation one-liners,Critical,DONE,Claude,npx command / pip install / docker run examples,T012,1 hour
T014,Marketing & Launch,Create demo video/GIF,Critical,TODO,You,Show: LLM failing -> add @flutter_mcp -> success with latest API info,,3 hours
T015,Marketing & Launch,Write launch blog post,High,TODO,Claude,Technical deep-dive on architecture and problem solved,T014,2 hours
T016,Marketing & Launch,Prepare Reddit launch post,Critical,TODO,Claude,Title: 'Built a free tool that gives Claude/ChatGPT current knowledge of any pub.dev package',T014,1 hour
T017,Community Engagement,Set up GitHub repository,Critical,DONE,You + Claude,Clear README / CONTRIBUTING.md / issue templates / MIT license,,1 hour
T018,Community Engagement,Create Discord/Slack presence,Medium,TODO,You,Join Flutter Discord / be active before launch,,Ongoing
T019,Distribution,Package for PyPI,High,DONE,Claude,Create pyproject.toml with proper metadata and dependencies,T010,1 hour
T020,Distribution,Create Docker image,Medium,DONE,Claude,Include Redis or document external Redis requirement,T010,2 hours
T021,Distribution,npm wrapper package,Low,DONE,Claude,For easier npx installation (wraps Python server),T019,2 hours
T022,Advanced Features,Add search_flutter_docs tool,Medium,DONE,Claude,Search across multiple sources when direct URL fails,T005,3 hours
T023,Advanced Features,Flutter cookbook integration,Medium,TODO,Claude,Scrape and process Flutter cookbook examples,T004,4 hours
T024,Advanced Features,Stack Overflow integration,Low,TODO,Claude,Search Flutter-tagged questions for common issues,T022,4 hours
T025,Advanced Features,Version-specific documentation,Low,TODO,Claude,Allow @flutter_mcp provider:5.0.0 syntax,T006,6 hours
T026,Marketing & Launch,Create comparison table,Medium,TODO,Claude,Flutter MCP vs vanilla LLM vs other tools,,1 hour
T027,Marketing & Launch,Reach out to Flutter influencers,Medium,TODO,You,Contact Flutter YouTubers / bloggers for early access,,2 hours
T028,Community Engagement,Implement live request fulfillment,High,TODO,You,Monitor launch thread and add requested packages in real-time,T007,4 hours
T029,Testing & QA,Load testing with concurrent requests,Medium,TODO,You,Ensure Redis and rate limiting work under load,T010,2 hours
T030,Documentation,Create API documentation,Medium,DONE,Claude,Document all MCP tools and their parameters,T012,1 hour
T031,Core Development,Error handling and fallbacks,High,DONE,Claude,Graceful handling when docs not found / network issues,T006/T007,2 hours
T032,Marketing & Launch,SEO optimize GitHub repository,Low,TODO,Claude,Keywords: Flutter MCP / Claude Flutter / Cursor Flutter / AI Flutter docs,,30 min
T033,Community Engagement,Create feedback collection system,Medium,TODO,You + Claude,GitHub discussions / feedback form / analytics,T017,1 hour
T034,Advanced Features,Null safety awareness,Medium,TODO,Claude,Tag content with null-safety status where applicable,T004,3 hours
T035,Marketing & Launch,Create 'use @flutter_mcp' badge,Low,TODO,Claude,Markdown badge for package maintainers to add to READMEs,,1 hour
T036,Core Development,Implement on-demand ingestion,Critical,TODO,Claude,Queue system for processing new packages when first requested,T007,6 hours
T037,Documentation Processing,Build Dart code parser,High,TODO,Claude,Extract doc comments / class signatures / method signatures from source,T036,8 hours
T038,Advanced Features,Public status page,Medium,TODO,Claude,Show which packages are indexed / being processed / can be requested,T036,3 hours
T039,Marketing & Launch,Define success metrics,High,TODO,Claude,GitHub stars / daily active users / packages indexed / cache hit rate,,1 hour
T040,Testing & QA,Create integration tests,Medium,DONE,Claude,Test full flow: request -> fetch -> process -> cache -> retrieve,T010,3 hours
T041,Marketing & Launch,Create developer testimonial system,High,TODO,You,Google Form for collecting specific problem-solving stories,T014,1 hour
T042,Marketing & Launch,Build showcase page,High,TODO,Claude,Curated examples of complex queries the tool handles perfectly,T014,2 hours
T043,Marketing & Launch,Design 'Powered by @flutter_mcp' badge,Medium,TODO,Claude,SVG badge for users to add to their projects/READMEs,,1 hour
T044,Community Engagement,Create Discord channel,High,TODO,You,Dedicated space for Q&A / feature requests / bug reports,T017,1 hour
T045,Marketing & Launch,Flutter package maintainer outreach,Critical,TODO,You,Contact top 20 package maintainers for early access and feedback,T010,3 hours
T046,Content Creation,Write technical deep-dive posts,Medium,TODO,Claude,3-part series: Architecture / Parsing Strategy / RAG Optimization,T015,6 hours
T047,Community Engagement,Define contribution guidelines,High,TODO,Claude,Good first issues / PR template / code of conduct,T017,2 hours
T048,Marketing & Launch,Create meme templates,Low,TODO,Claude,Generic LLM vs @flutter_mcp format - let community fill in,T014,1 hour
T049,Marketing & Launch,YouTube influencer outreach,High,TODO,You,Contact: FilledStacks / Reso Coder / Flutter Explained / Code With Andrea,T014,3 hours
T050,Advanced Features,Package maintainer dashboard,Low,TODO,Claude,Let maintainers see usage stats for their packages,T038,4 hours
T051,Marketing & Launch,Launch week planning,Critical,TODO,You + Claude,Day 1: Reddit / Day 2: Twitter / Day 3: Newsletter / Day 4-5: YouTube,T016,2 hours
T052,Community Engagement,Implement feature voting system,Medium,TODO,Claude,Let community vote on which packages to prioritize,T033,2 hours
T053,Marketing & Launch,Create comparison demos,Critical,TODO,Claude,Side-by-side: ChatGPT vs ChatGPT+@flutter_mcp on same query,T014,3 hours
T054,Content Creation,Weekly 'Flutter AI Tips' series,Low,TODO,You + Claude,Short posts showing cool things possible with @flutter_mcp,,Ongoing
T055,Marketing & Launch,SEO content creation,Medium,TODO,Claude,Blog posts targeting 'Flutter AI' / 'Claude Flutter' / 'Cursor Flutter' keywords,T015,4 hours
T056,Community Engagement,Host live coding session,Medium,TODO,You,Twitch/YouTube stream solving Flutter problems with the tool,T014,2 hours
T057,Marketing & Launch,Create viral launch video,Critical,TODO,You,30-second video: problem → solution → wow moment,T014,4 hours
T058,Advanced Features,VS Code extension exploration,Low,TODO,Claude,Research deeper IDE integration possibilities beyond MCP,T010,6 hours
T059,Marketing & Launch,Press kit creation,Medium,TODO,Claude + You,Logo / screenshots / one-pager / key messages for easy sharing,T014,2 hours
T060,Community Engagement,Flutter Weekly submission,High,TODO,You,Submit to Flutter Weekly newsletter after launch,T016,30 min
```

--------------------------------------------------------------------------------
/tests/test_integration.py:
--------------------------------------------------------------------------------

```python
#!/usr/bin/env python3
"""Integration tests for Flutter MCP Server"""

import asyncio
import sys
from typing import List, Tuple
from pathlib import Path

# Add the src directory to the Python path
sys.path.insert(0, str(Path(__file__).parent.parent / 'src'))

from flutter_mcp.server import get_flutter_docs, search_flutter_docs, get_pub_package_info, process_flutter_mentions, health_check


class TestResult:
    def __init__(self, name: str, passed: bool, message: str = ""):
        self.name = name
        self.passed = passed
        self.message = message


async def test_flutter_docs_core_widgets() -> TestResult:
    """Test fetching documentation for core Flutter widgets"""
    test_cases = [
        ("Container", "widgets"),
        ("Scaffold", "material"),
        ("Text", "widgets"),
        ("Column", "widgets"),
        ("Row", "widgets"),
    ]
    
    for class_name, library in test_cases:
        try:
            result = await get_flutter_docs(class_name, library)
            if "error" in result:
                return TestResult(
                    "Flutter Docs - Core Widgets",
                    False,
                    f"Failed to fetch {library}.{class_name}: {result['error']}"
                )
            
            # Verify content
            content = result.get("content", "")
            if len(content) < 100:
                return TestResult(
                    "Flutter Docs - Core Widgets",
                    False,
                    f"Content too short for {library}.{class_name}: {len(content)} chars"
                )
        except Exception as e:
            return TestResult(
                "Flutter Docs - Core Widgets",
                False,
                f"Exception fetching {library}.{class_name}: {str(e)}"
            )
    
    return TestResult("Flutter Docs - Core Widgets", True, f"Tested {len(test_cases)} core widgets")


async def test_pub_packages_popular() -> TestResult:
    """Test fetching information for popular pub.dev packages"""
    test_packages = [
        "provider",
        "bloc",
        "dio",
        "get",
        "riverpod",
    ]
    
    for package in test_packages:
        try:
            result = await get_pub_package_info(package)
            if "error" in result:
                return TestResult(
                    "Pub.dev Packages - Popular",
                    False,
                    f"Failed to fetch {package}: {result['error']}"
                )
            
            # Verify required fields
            if not result.get("version"):
                return TestResult(
                    "Pub.dev Packages - Popular",
                    False,
                    f"No version for {package}"
                )
            
            if "readme" not in result or len(result["readme"]) < 100:
                return TestResult(
                    "Pub.dev Packages - Popular",
                    False,
                    f"README missing or too short for {package}"
                )
        except Exception as e:
            return TestResult(
                "Pub.dev Packages - Popular",
                False,
                f"Exception fetching {package}: {str(e)}"
            )
    
    return TestResult("Pub.dev Packages - Popular", True, f"Tested {len(test_packages)} popular packages")


async def test_search_functionality() -> TestResult:
    """Test search functionality with various patterns"""
    test_queries = [
        "Container",
        "material.AppBar",
        "cupertino.CupertinoButton",
        "dart:core.List",
    ]
    
    for query in test_queries:
        try:
            result = await search_flutter_docs(query)
            if result.get("total", 0) == 0:
                return TestResult(
                    "Search Functionality",
                    False,
                    f"No results for query: {query}"
                )
        except Exception as e:
            return TestResult(
                "Search Functionality",
                False,
                f"Exception searching for {query}: {str(e)}"
            )
    
    return TestResult("Search Functionality", True, f"Tested {len(test_queries)} search patterns")


async def test_flutter_mentions() -> TestResult:
    """Test @flutter_mcp mention processing"""
    test_text = """
    I need help with @flutter_mcp provider for state management.
    Also, how do I use @flutter_mcp material.Scaffold properly?
    What about @flutter_mcp dart:async.Future?
    """
    
    try:
        result = await process_flutter_mentions(test_text)
        
        if result.get("mentions_found", 0) != 3:
            return TestResult(
                "Flutter Mentions",
                False,
                f"Expected 3 mentions, found {result.get('mentions_found', 0)}"
            )
        
        # Check each mention was processed
        results = result.get("results", [])
        if len(results) != 3:
            return TestResult(
                "Flutter Mentions",
                False,
                f"Expected 3 results, got {len(results)}"
            )
        
        # Verify mention types
        expected_types = ["pub_package", "flutter_class", "dart_api"]
        actual_types = [r.get("type") for r in results]
        
        for expected in expected_types:
            if expected not in actual_types:
                return TestResult(
                    "Flutter Mentions",
                    False,
                    f"Missing expected type: {expected}. Got: {actual_types}"
                )
        
    except Exception as e:
        return TestResult(
            "Flutter Mentions",
            False,
            f"Exception processing mentions: {str(e)}"
        )
    
    return TestResult("Flutter Mentions", True, "All mention types processed correctly")


async def test_health_check_functionality() -> TestResult:
    """Test health check returns expected format"""
    try:
        result = await health_check()
        
        # Verify structure
        required_fields = ["status", "timestamp", "checks", "message"]
        for field in required_fields:
            if field not in result:
                return TestResult(
                    "Health Check",
                    False,
                    f"Missing required field: {field}"
                )
        
        # Verify checks
        required_checks = ["flutter_docs", "pub_dev", "redis"]
        for check in required_checks:
            if check not in result["checks"]:
                return TestResult(
                    "Health Check",
                    False,
                    f"Missing required check: {check}"
                )
        
        # Verify status is valid
        valid_statuses = ["ok", "degraded", "failed"]
        if result["status"] not in valid_statuses:
            return TestResult(
                "Health Check",
                False,
                f"Invalid status: {result['status']}"
            )
        
    except Exception as e:
        return TestResult(
            "Health Check",
            False,
            f"Exception running health check: {str(e)}"
        )
    
    return TestResult("Health Check", True, "Health check structure valid")


async def run_all_tests():
    """Run all integration tests"""
    print("🧪 Flutter MCP Server Integration Tests")
    print("=" * 50)
    
    tests = [
        test_flutter_docs_core_widgets(),
        test_pub_packages_popular(),
        test_search_functionality(),
        test_flutter_mentions(),
        test_health_check_functionality(),
    ]
    
    # Run tests with progress indicator
    results = []
    for i, test in enumerate(tests, 1):
        print(f"\n[{i}/{len(tests)}] Running {test.__name__}...", end="", flush=True)
        result = await test
        results.append(result)
        
        if result.passed:
            print(f" ✅ PASSED")
        else:
            print(f" ❌ FAILED")
            print(f"     {result.message}")
    
    # Summary
    print("\n" + "=" * 50)
    print("Test Summary:")
    print("=" * 50)
    
    passed = sum(1 for r in results if r.passed)
    total = len(results)
    
    for result in results:
        status = "✅ PASS" if result.passed else "❌ FAIL"
        print(f"{status} | {result.name}")
        if result.message and result.passed:
            print(f"      {result.message}")
    
    print(f"\nTotal: {passed}/{total} passed ({passed/total*100:.0f}%)")
    
    # Return exit code
    return 0 if passed == total else 1


if __name__ == "__main__":
    import warnings
    warnings.filterwarnings("ignore", category=DeprecationWarning)
    
    # Set up event loop
    exit_code = asyncio.run(run_all_tests())
    sys.exit(exit_code)
```

--------------------------------------------------------------------------------
/docs/token-counting-analysis.md:
--------------------------------------------------------------------------------

```markdown
# Token Counting Analysis for Flutter MCP

## Executive Summary

For the Flutter MCP documentation server, implementing accurate and performant token counting is crucial to ensure responses fit within LLM context windows. This analysis recommends using model-specific tokenizers with intelligent caching for optimal accuracy and performance.

## Recommended Approach

### Primary Strategy: Model-Specific Tokenizers with Caching

Use official tokenizers for each supported model family:
- **OpenAI Models**: `tiktoken` library
- **Claude Models**: `anthropic` library's `count_tokens()` API
- **Gemini Models**: `google-genai` library's `count_tokens()` method

### Implementation Architecture

```python
# utils/token_counter.py
import tiktoken
import anthropic
from google import genai
from google.genai.types import HttpOptions
from typing import Union, Dict, Any
import structlog

logger = structlog.get_logger()

class TokenCounter:
    """Unified token counter with model-specific tokenizer support."""
    
    def __init__(self):
        self._tokenizer_cache: Dict[str, Any] = {}
        self._anthropic_client = None
        self._genai_client = None
        
    def _get_openai_tokenizer(self, model: str):
        """Get or create OpenAI tokenizer."""
        if model not in self._tokenizer_cache:
            try:
                # Try model-specific encoding
                self._tokenizer_cache[model] = tiktoken.encoding_for_model(model)
            except KeyError:
                # Fallback to cl100k_base for newer models
                self._tokenizer_cache[model] = tiktoken.get_encoding("cl100k_base")
        return self._tokenizer_cache[model]
    
    def _get_anthropic_client(self):
        """Get or create Anthropic client."""
        if self._anthropic_client is None:
            self._anthropic_client = anthropic.Anthropic()
        return self._anthropic_client
    
    def _get_genai_client(self):
        """Get or create Google GenAI client."""
        if self._genai_client is None:
            self._genai_client = genai.Client(
                http_options=HttpOptions(api_version="v1")
            )
        return self._genai_client
    
    def count_tokens(self, text: str, model: str = "gpt-4") -> int:
        """
        Count tokens for the given text and model.
        
        Args:
            text: The text to count tokens for
            model: The model name (e.g., "gpt-4", "claude-3-opus", "gemini-1.5-pro")
            
        Returns:
            Number of tokens
        """
        try:
            # OpenAI models
            if model.startswith(("gpt-", "text-embedding-")):
                tokenizer = self._get_openai_tokenizer(model)
                return len(tokenizer.encode(text))
            
            # Claude models
            elif model.startswith("claude-"):
                client = self._get_anthropic_client()
                response = client.beta.messages.count_tokens(
                    model=model,
                    messages=[{"role": "user", "content": text}]
                )
                return response.input_tokens
            
            # Gemini models
            elif model.startswith("gemini-"):
                client = self._get_genai_client()
                response = client.models.count_tokens(
                    model=model,
                    contents=text
                )
                return response.total_tokens
            
            # Unknown model - use cl100k_base as fallback
            else:
                logger.warning(f"Unknown model {model}, using cl100k_base tokenizer")
                tokenizer = self._get_openai_tokenizer("cl100k_base")
                return len(tokenizer.encode(text))
                
        except Exception as e:
            logger.error(f"Error counting tokens for {model}: {e}")
            # Fallback to character-based approximation with safety margin
            return int(len(text) / 3.5)  # Conservative estimate

# Global instance for reuse
token_counter = TokenCounter()
```

## Performance Optimization Strategies

### 1. Tokenizer Caching
- **Critical**: Cache tokenizer instances to avoid initialization overhead
- OpenAI's `tiktoken` has minimal overhead, but still benefits from caching
- Anthropic and Google clients should be singleton instances

### 2. Batch Processing
When processing multiple documents:
```python
# For tiktoken (OpenAI)
encoding = tiktoken.get_encoding("cl100k_base")
token_counts = [len(tokens) for tokens in encoding.encode_batch(texts)]

# For other providers, implement parallel processing
from concurrent.futures import ThreadPoolExecutor

def batch_count_tokens(texts: List[str], model: str) -> List[int]:
    with ThreadPoolExecutor(max_workers=5) as executor:
        futures = [executor.submit(token_counter.count_tokens, text, model) 
                   for text in texts]
        return [future.result() for future in futures]
```

### 3. Redis Integration for Token Count Caching
```python
async def get_documentation_with_token_count(
    self, 
    query: str, 
    model: str = "gpt-4"
) -> Tuple[str, int]:
    """Get documentation with pre-calculated token count."""
    
    # Check Redis for cached result with token count
    cache_key = f"flutter_doc:{query}:{model}"
    cached = await self.redis.get(cache_key)
    
    if cached:
        data = json.loads(cached)
        return data["content"], data["token_count"]
    
    # Fetch and process documentation
    content = await self.fetch_documentation(query)
    
    # Count tokens on final formatted content
    token_count = token_counter.count_tokens(content, model)
    
    # Cache with token count
    await self.redis.set(
        cache_key,
        json.dumps({
            "content": content,
            "token_count": token_count
        }),
        ex=86400  # 24 hour TTL
    )
    
    return content, token_count
```

## Markdown Formatting Considerations

### Count Tokens on Final Output
Always count tokens on the exact string sent to the LLM:

```python
def prepare_response(raw_content: str, max_tokens: int, model: str) -> str:
    """Prepare and truncate response to fit token limit."""
    
    # Apply all formatting transformations
    formatted_content = format_markdown(raw_content)
    
    # Count tokens on formatted content
    token_count = token_counter.count_tokens(formatted_content, model)
    
    # Truncate if necessary
    if token_count > max_tokens:
        # Intelligent truncation - keep complete sections
        formatted_content = truncate_intelligently(
            formatted_content, 
            max_tokens, 
            model
        )
    
    return formatted_content
```

### Token Impact of Markdown Elements
- **Code blocks**: Very token-intensive (backticks + language + indentation)
- **Links**: Full markdown syntax counts `[text](url)`
- **Headers**: All `#` characters count as tokens
- **Lists**: Bullets and indentation consume tokens

## Approximation Methods (Fallback Only)

When model-specific tokenizers are unavailable:

```python
def approximate_tokens(text: str, model_family: str = "general") -> int:
    """
    Approximate token count with model-specific adjustments.
    Use only as fallback when proper tokenizers unavailable.
    """
    # Base approximations
    char_ratio = {
        "gpt": 4.0,      # GPT models: ~4 chars/token
        "claude": 3.8,   # Claude: slightly more tokens
        "gemini": 4.2,   # Gemini: slightly fewer tokens
        "general": 3.5   # Conservative default
    }
    
    ratio = char_ratio.get(model_family, 3.5)
    base_count = len(text) / ratio
    
    # Adjust for code content (more tokens)
    code_blocks = text.count("```")
    if code_blocks > 0:
        base_count *= 1.15
    
    # Safety margin
    return int(base_count * 1.2)
```

## Implementation Timeline

### Phase 1: Core Implementation (2 hours)
1. Implement `TokenCounter` class with OpenAI support
2. Add fallback approximation method
3. Integrate with existing response pipeline

### Phase 2: Multi-Model Support (2 hours)
1. Add Anthropic client support
2. Add Google GenAI client support
3. Implement model detection logic

### Phase 3: Optimization (1 hour)
1. Add Redis caching for token counts
2. Implement batch processing
3. Add performance monitoring

## Testing Strategy

```python
# tests/test_token_counter.py
import pytest
from utils.token_counter import token_counter

class TestTokenCounter:
    
    @pytest.mark.parametrize("model,text,expected_range", [
        ("gpt-4", "Hello, world!", (3, 5)),
        ("claude-3-opus-20240229", "Hello, world!", (3, 5)),
        ("gemini-1.5-pro", "Hello, world!", (3, 5)),
    ])
    def test_basic_counting(self, model, text, expected_range):
        count = token_counter.count_tokens(text, model)
        assert expected_range[0] <= count <= expected_range[1]
    
    def test_markdown_formatting(self):
        markdown = "# Header\n```python\nprint('hello')\n```"
        count = token_counter.count_tokens(markdown, "gpt-4")
        # Markdown should produce more tokens than plain text
        plain_count = token_counter.count_tokens("Header print hello", "gpt-4")
        assert count > plain_count
    
    def test_fallback_approximation(self):
        # Test with unknown model
        count = token_counter.count_tokens("Test text", "unknown-model")
        assert count > 0
```

## Recommendations

1. **Use Model-Specific Tokenizers**: Accuracy is worth the minimal performance cost
2. **Cache Everything**: Both tokenizer instances and token counts
3. **Count Final Output**: Always count tokens on the exact formatted string
4. **Plan for Growth**: Design the system to easily add new model support
5. **Monitor Performance**: Track token counting time in your metrics

## Conclusion

For the Flutter MCP project, implementing proper token counting with model-specific tokenizers will ensure accurate context window management while maintaining the fast response times required by the Context7-style architecture. The recommended approach balances accuracy, performance, and maintainability while providing graceful fallbacks for edge cases.
```

--------------------------------------------------------------------------------
/src/flutter_mcp/truncation.py:
--------------------------------------------------------------------------------

```python
"""
Smart truncation module for Flutter documentation.

Implements priority-based truncation that preserves the most important content
while respecting token limits and maintaining markdown formatting.
"""

import re
from typing import List, Tuple, Optional
from dataclasses import dataclass


@dataclass
class Section:
    """Represents a documentation section with content and priority."""
    name: str
    content: str
    priority: int  # Lower number = higher priority
    start_pos: int
    end_pos: int


class DocumentTruncator:
    """Smart truncation for Flutter/Dart documentation."""
    
    # Section priorities (lower = more important)
    SECTION_PRIORITIES = {
        'description': 1,
        'summary': 1,
        'constructors': 2,
        'properties': 3,
        'methods': 4,
        'parameters': 5,
        'returns': 5,
        'examples': 6,
        'example': 6,
        'see also': 7,
        'implementation': 8,
        'source': 9,
    }
    
    # Approximate tokens per character (rough estimate)
    TOKENS_PER_CHAR = 0.25
    
    def __init__(self):
        """Initialize the document truncator."""
        pass
    
    def truncate_to_limit(self, content: str, token_limit: int) -> str:
        """
        Truncate content to fit within token limit while preserving structure.
        
        Args:
            content: The markdown content to truncate
            token_limit: Maximum number of tokens allowed
            
        Returns:
            Truncated content with truncation notice if needed
        """
        # Quick check - if content is already small enough, return as-is
        estimated_tokens = self._estimate_tokens(content)
        if estimated_tokens <= token_limit:
            return content
        
        # Detect sections in the content
        sections = self._detect_sections(content)
        
        # If no sections detected, fall back to simple truncation
        if not sections:
            return self._simple_truncate(content, token_limit)
        
        # Build truncated content based on priorities
        truncated = self._priority_truncate(content, sections, token_limit)
        
        # Add truncation notice
        return self._add_truncation_notice(truncated)
    
    def _estimate_tokens(self, text: str) -> int:
        """Estimate token count from text length."""
        return int(len(text) * self.TOKENS_PER_CHAR)
    
    def _detect_sections(self, content: str) -> List[Section]:
        """Detect markdown sections in the content."""
        sections = []
        
        # Pattern for markdown headers (##, ###, ####)
        header_pattern = r'^(#{2,4})\s+(.+)$'
        
        lines = content.split('\n')
        current_section = None
        current_content = []
        current_start = 0
        
        for i, line in enumerate(lines):
            match = re.match(header_pattern, line, re.MULTILINE)
            
            if match:
                # Save previous section if exists
                if current_section:
                    section_content = '\n'.join(current_content)
                    sections.append(Section(
                        name=current_section,
                        content=section_content,
                        priority=self._get_section_priority(current_section),
                        start_pos=current_start,
                        end_pos=i
                    ))
                
                # Start new section
                current_section = match.group(2).lower().strip()
                current_content = [line]
                current_start = i
            elif current_section:
                current_content.append(line)
        
        # Don't forget the last section
        if current_section and current_content:
            section_content = '\n'.join(current_content)
            sections.append(Section(
                name=current_section,
                content=section_content,
                priority=self._get_section_priority(current_section),
                start_pos=current_start,
                end_pos=len(lines)
            ))
        
        # Sort sections by priority
        sections.sort(key=lambda s: s.priority)
        
        return sections
    
    def _get_section_priority(self, section_name: str) -> int:
        """Get priority for a section name."""
        section_lower = section_name.lower()
        
        # Check for exact matches first
        if section_lower in self.SECTION_PRIORITIES:
            return self.SECTION_PRIORITIES[section_lower]
        
        # Check for partial matches
        for key, priority in self.SECTION_PRIORITIES.items():
            if key in section_lower or section_lower in key:
                return priority
        
        # Default priority for unknown sections
        return 10
    
    def _simple_truncate(self, content: str, token_limit: int) -> str:
        """Simple truncation when no sections are detected."""
        char_limit = int(token_limit / self.TOKENS_PER_CHAR)
        
        if len(content) <= char_limit:
            return content
        
        # Try to truncate at a paragraph boundary
        truncated = content[:char_limit]
        last_para = truncated.rfind('\n\n')
        
        if last_para > char_limit * 0.8:  # If we found a paragraph break in the last 20%
            return truncated[:last_para]
        
        # Otherwise truncate at last complete sentence
        last_period = truncated.rfind('. ')
        if last_period > char_limit * 0.8:
            return truncated[:last_period + 1]
        
        # Last resort: truncate at word boundary
        last_space = truncated.rfind(' ')
        if last_space > 0:
            return truncated[:last_space]
        
        return truncated
    
    def _priority_truncate(self, content: str, sections: List[Section], token_limit: int) -> str:
        """Truncate based on section priorities."""
        result_parts = []
        current_tokens = 0
        
        # First, try to get the content before any sections (usually the main description)
        lines = content.split('\n')
        pre_section_content = []
        
        for line in lines:
            if re.match(r'^#{2,4}\s+', line):
                break
            pre_section_content.append(line)
        
        if pre_section_content:
            pre_content = '\n'.join(pre_section_content).strip()
            if pre_content:
                pre_tokens = self._estimate_tokens(pre_content)
                if current_tokens + pre_tokens <= token_limit:
                    result_parts.append(pre_content)
                    current_tokens += pre_tokens
        
        # Add sections by priority
        for section in sections:
            section_tokens = self._estimate_tokens(section.content)
            
            if current_tokens + section_tokens <= token_limit:
                result_parts.append(section.content)
                current_tokens += section_tokens
            else:
                # Try to add at least part of this section
                remaining_tokens = token_limit - current_tokens
                if remaining_tokens > 100:  # Only add if we have reasonable space
                    partial = self._simple_truncate(section.content, remaining_tokens)
                    if partial.strip():
                        result_parts.append(partial)
                break
        
        return '\n\n'.join(result_parts)
    
    def _add_truncation_notice(self, content: str) -> str:
        """Add a notice that content was truncated."""
        if not content.endswith('\n'):
            content += '\n'
        
        notice = "\n---\n*Note: This documentation has been truncated to fit within token limits. " \
                 "Some sections may have been omitted or shortened.*"
        
        return content + notice


# Module-level instance for convenience
_truncator = DocumentTruncator()


def truncate_flutter_docs(
    content: str, 
    class_name: str, 
    max_tokens: int,
    strategy: str = "balanced"
) -> str:
    """
    Truncate Flutter documentation to fit within token limit.
    
    Args:
        content: The documentation content to truncate
        class_name: Name of the class (for context, not currently used)
        max_tokens: Maximum number of tokens allowed
        strategy: Truncation strategy (currently only "balanced" is supported)
        
    Returns:
        Truncated documentation content
    """
    return _truncator.truncate_to_limit(content, max_tokens)


def create_truncator() -> DocumentTruncator:
    """
    Create a new DocumentTruncator instance.
    
    Returns:
        A new DocumentTruncator instance
    """
    return DocumentTruncator()


# Example usage and testing
if __name__ == "__main__":
    truncator = DocumentTruncator()
    
    # Test with sample Flutter documentation
    sample_content = """
# Widget class

A widget is an immutable description of part of a user interface.

## Description

Widgets are the central class hierarchy in the Flutter framework. A widget is an 
immutable description of part of a user interface. Widgets can be inflated into 
elements, which manage the underlying render tree.

## Constructors

### Widget({Key? key})

Initializes key for subclasses.

## Properties

### hashCode → int
The hash code for this object.

### key → Key?
Controls how one widget replaces another widget in the tree.

### runtimeType → Type
A representation of the runtime type of the object.

## Methods

### createElement() → Element
Inflates this configuration to a concrete instance.

### debugDescribeChildren() → List<DiagnosticsNode>
Returns a list of DiagnosticsNode objects describing this node's children.

### debugFillProperties(DiagnosticPropertiesBuilder properties) → void
Add additional properties associated with the node.

## Examples

```dart
class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text('Hello World'),
    );
  }
}
```

## See Also

- StatelessWidget
- StatefulWidget
- InheritedWidget
"""
    
    # Test truncation
    truncated = truncator.truncate_to_limit(sample_content, 500)
    print("Original length:", len(sample_content))
    print("Truncated length:", len(truncated))
    print("\nTruncated content:")
    print(truncated)
```

--------------------------------------------------------------------------------
/tests/test_token_management.py:
--------------------------------------------------------------------------------

```python
"""Tests for token management functionality."""

import pytest
from unittest.mock import Mock, patch, MagicMock
from flutter_mcp.token_manager import TokenManager
from flutter_mcp.truncation import DocumentTruncator
from flutter_mcp.server import process_documentation
import json


class TestTokenManager:
    """Test TokenManager functionality."""
    
    def test_approximate_tokens(self):
        """Test word-based token approximation."""
        manager = TokenManager()
        
        # Test various text samples
        assert manager.approximate_tokens("Hello world") == 2  # 2 words * 1.3 = 2.6 -> 2
        assert manager.approximate_tokens("The quick brown fox") == 5  # 4 * 1.3 = 5.2 -> 5
        assert manager.approximate_tokens("") == 0
        assert manager.approximate_tokens("   ") == 0
        
        # Test with punctuation and special characters
        text = "Hello, world! How are you?"
        expected = int(5 * 1.3)  # 5 words
        assert manager.approximate_tokens(text) == expected
    
    def test_count_tokens_approximation(self):
        """Test count_tokens in approximation mode."""
        manager = TokenManager()
        manager.set_accurate_mode(False)
        
        text = "This is a test sentence with several words"
        tokens = manager.count_tokens(text)
        expected = int(8 * 1.3)  # 8 words
        assert tokens == expected
    
    @patch('flutter_mcp.token_manager.tiktoken')
    def test_accurate_tokens(self, mock_tiktoken):
        """Test accurate token counting with tiktoken."""
        # Mock tiktoken encoder
        mock_encoder = Mock()
        mock_encoder.encode.return_value = [1, 2, 3, 4, 5]  # 5 tokens
        mock_tiktoken.get_encoding.return_value = mock_encoder
        
        manager = TokenManager()
        tokens = manager.accurate_tokens("Test text")
        
        assert tokens == 5
        mock_tiktoken.get_encoding.assert_called_once_with("cl100k_base")
        mock_encoder.encode.assert_called_once_with("Test text")
    
    def test_mode_switching(self):
        """Test switching between accurate and approximation modes."""
        manager = TokenManager()
        
        # Default should be approximation
        assert manager.get_mode() == "approximation"
        
        # Switch to accurate
        manager.set_accurate_mode(True)
        assert manager.get_mode() == "accurate"
        
        # Switch back
        manager.set_accurate_mode(False)
        assert manager.get_mode() == "approximation"


class TestDocumentTruncator:
    """Test DocumentTruncator functionality."""
    
    def test_detect_sections(self):
        """Test markdown section detection."""
        truncator = DocumentTruncator()
        
        content = """# Widget

## Description
This is a description.

## Constructors
Here are constructors.

## Properties
Some properties.

## Methods
Various methods.

## Examples
Code examples here.
"""
        sections = truncator._detect_sections(content)
        
        assert len(sections) == 6  # Including pre-section content
        assert "Description" in sections
        assert "Constructors" in sections
        assert "Properties" in sections
        assert "Methods" in sections
        assert "Examples" in sections
    
    def test_truncate_no_truncation_needed(self):
        """Test that content within limit is not truncated."""
        truncator = DocumentTruncator()
        
        content = "Short content"
        result = truncator.truncate_to_limit(content, 10000)
        
        assert result == content  # Should be unchanged
    
    def test_simple_truncation(self):
        """Test simple truncation when no sections detected."""
        truncator = DocumentTruncator()
        
        # Create content that will exceed token limit
        content = "word " * 1000  # 5000 characters, ~1250 tokens
        result = truncator.truncate_to_limit(content, 100)  # Very low limit
        
        assert len(result) < len(content)
        assert result.endswith("...")
        assert "\n\n---\n*Note: Documentation has been truncated" not in result  # Simple truncation
    
    def test_section_based_truncation(self):
        """Test priority-based section truncation."""
        truncator = DocumentTruncator()
        
        content = """# Widget

## Description
This is a very important description that should be kept.

## Constructors
Constructor information here.

## Properties
Property details.

## Methods
Method information.

## Examples
""" + "Example code " * 100 + """

## See Also
References and links.
"""
        
        # Truncate to a limit that should keep only high-priority sections
        result = truncator.truncate_to_limit(content, 200)  # ~800 characters
        
        assert "Description" in result
        assert "very important description" in result
        assert "See Also" not in result  # Low priority
        assert "*Note: Documentation has been truncated" in result


class TestServerIntegration:
    """Test token management integration with server."""
    
    @patch('flutter_mcp.server.token_manager')
    @patch('flutter_mcp.server.truncator')
    def test_process_documentation_with_tokens(self, mock_truncator, mock_token_manager):
        """Test process_documentation with token limit."""
        # Mock token counting
        mock_token_manager.count_tokens.side_effect = [5000, 2000]  # Before and after truncation
        
        # Mock truncation
        mock_truncator.truncate_to_limit.return_value = "Truncated content"
        
        # Mock BeautifulSoup
        with patch('flutter_mcp.server.BeautifulSoup') as mock_bs:
            mock_soup = Mock()
            mock_soup.find.return_value = None
            mock_soup.find_all.return_value = []
            mock_bs.return_value = mock_soup
            
            result = process_documentation("<html></html>", "TestClass", tokens=2000)
        
        assert isinstance(result, dict)
        assert result["content"] == "Truncated content"
        assert result["token_count"] == 2000
        assert result["original_tokens"] == 5000
        assert result["truncated"] == True
        assert "truncation_note" in result
        
        # Verify truncation was called with correct parameters
        mock_truncator.truncate_to_limit.assert_called_once()
        args = mock_truncator.truncate_to_limit.call_args[0]
        assert args[1] == 2000  # Token limit
    
    @patch('flutter_mcp.server.token_manager')
    def test_process_documentation_without_truncation(self, mock_token_manager):
        """Test process_documentation when no truncation needed."""
        # Mock token counting - content fits within limit
        mock_token_manager.count_tokens.return_value = 1000
        
        # Mock BeautifulSoup
        with patch('flutter_mcp.server.BeautifulSoup') as mock_bs:
            mock_soup = Mock()
            mock_soup.find.return_value = None
            mock_soup.find_all.return_value = []
            mock_bs.return_value = mock_soup
            
            result = process_documentation("<html></html>", "TestClass", tokens=5000)
        
        assert isinstance(result, dict)
        assert result["token_count"] == 1000
        assert result["original_tokens"] == 1000
        assert result["truncated"] == False
        assert result["truncation_note"] == ""


class TestCacheIntegration:
    """Test token count storage in cache."""
    
    def test_cache_with_token_count(self):
        """Test that cache stores and retrieves token counts."""
        from flutter_mcp.cache import SQLiteCache
        import tempfile
        import os
        
        # Create temporary cache
        with tempfile.TemporaryDirectory() as temp_dir:
            cache_path = os.path.join(temp_dir, "test_cache.db")
            cache = SQLiteCache(cache_path)
            
            # Test data with token count
            test_data = {
                "content": "Test content",
                "_cached_token_count": 42
            }
            
            # Store in cache
            cache.set("test_key", test_data, ttl=3600, token_count=42)
            
            # Retrieve from cache
            result = cache.get("test_key")
            
            assert result is not None
            assert result["content"] == "Test content"
            assert result["_cached_token_count"] == 42
            
            # Test statistics
            stats = cache.get_stats()
            assert stats["entries_with_token_counts"] == 1
            assert stats["total_cached_tokens"] == 42
    
    def test_cache_backward_compatibility(self):
        """Test that old cache entries without token counts still work."""
        from flutter_mcp.cache import SQLiteCache
        import tempfile
        import os
        import sqlite3
        
        # Create temporary cache
        with tempfile.TemporaryDirectory() as temp_dir:
            cache_path = os.path.join(temp_dir, "test_cache.db")
            
            # Manually create old-style cache entry
            conn = sqlite3.connect(cache_path)
            conn.execute("""
                CREATE TABLE IF NOT EXISTS doc_cache (
                    key TEXT PRIMARY KEY NOT NULL,
                    value TEXT NOT NULL,
                    created_at INTEGER NOT NULL,
                    expires_at INTEGER NOT NULL
                )
            """)
            
            import time
            import json
            now = int(time.time())
            conn.execute(
                "INSERT INTO doc_cache (key, value, created_at, expires_at) VALUES (?, ?, ?, ?)",
                ("old_key", json.dumps({"content": "Old content"}), now, now + 3600)
            )
            conn.commit()
            conn.close()
            
            # Now use the cache (should migrate schema)
            cache = SQLiteCache(cache_path)
            
            # Should be able to retrieve old entry
            result = cache.get("old_key")
            assert result is not None
            assert result["content"] == "Old content"
            assert "_cached_token_count" not in result  # No token count for old entry
            
            # Should be able to add new entry with token count
            cache.set("new_key", {"content": "New content"}, ttl=3600, token_count=100)
            
            # Verify both entries exist
            stats = cache.get_stats()
            assert stats["total_entries"] == 2
            assert stats["entries_with_token_counts"] == 1
            assert stats["total_cached_tokens"] == 100


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
```
Page 1/2FirstPrevNextLast