Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ed23344
chore: rename package to fastmcp-extensions
devin-ai-integration[bot] Jan 17, 2026
7611255
feat: implement fastmcp-extensions library with consolidated utilities
devin-ai-integration[bot] Jan 17, 2026
0cd2508
refactor: remove domain parameter from decorators
devin-ai-integration[bot] Jan 17, 2026
6409226
fix: update tests to use auto-inferred domain pattern
devin-ai-integration[bot] Jan 17, 2026
f50bc6e
refactor: move testing and measurement utilities to utils submodule
devin-ai-integration[bot] Jan 17, 2026
db4b784
refactor: convert testing module to package for -m syntax support
devin-ai-integration[bot] Jan 17, 2026
094784a
ci: add TK-TODO check workflow
devin-ai-integration[bot] Jan 17, 2026
1fa6843
feat: add --http --app support for unified CLI syntax
devin-ai-integration[bot] Jan 17, 2026
7ece65f
fix: ignore uvicorn transitive dependency in deptry
devin-ai-integration[bot] Jan 17, 2026
225e033
refactor: rename testing module to test_tool for cleaner CLI invocation
devin-ai-integration[bot] Jan 17, 2026
be4d794
refactor: simplify test_tool to standalone file and rename measuremen…
devin-ai-integration[bot] Jan 17, 2026
cbd40d6
refactor: move generic HTTP helpers to _http.py
devin-ai-integration[bot] Jan 17, 2026
7deddee
refactor: rename domain to mcp_module, fix stale docstrings, remove -…
devin-ai-integration[bot] Jan 17, 2026
f7f9c5e
fix: update tests to use mcp_module, add CLI support to describe_serv…
devin-ai-integration[bot] Jan 17, 2026
a0e61de
chore: remove stale poe tasks referencing deleted bin scripts
devin-ai-integration[bot] Jan 17, 2026
809ef7c
chore: fix stale awesome-python-template references
devin-ai-integration[bot] Jan 17, 2026
90fc67a
chore: remove redundant NOTE comment from prerelease-command.yml
devin-ai-integration[bot] Jan 17, 2026
9cd1163
chore: remove TestPyPI references, publish to real PyPI
devin-ai-integration[bot] Jan 17, 2026
c09b9bb
Apply suggestion from @aaronsteers
aaronsteers Jan 17, 2026
e1097d8
Merge branch 'devin/1768613848-initial-library-implementation' of htt…
devin-ai-integration[bot] Jan 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions .github/workflows/tk-todo-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: TK-TODO Check # IGNORE:TK - this workflow checks for TK-TODO markers

on:
push:
branches:
- main
pull_request: {}

permissions:
contents: read

jobs:
tk-todo-check: # IGNORE:TK
name: Check for TK-TODO markers # IGNORE:TK
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Check for TK-TODO markers # IGNORE:TK
run: |
# Find all TK-TODO markers (case-insensitive) that don't have IGNORE:TK on the same line # IGNORE:TK
# Exit with error if any are found

echo "Checking for TK-TODO markers..." # IGNORE:TK

# Use git ls-files to only check tracked files (excludes gitignored files like sdks/)
# grep -i for case-insensitive matching
# grep -v for excluding lines with IGNORE:TK
# grep -n for line numbers

FOUND_TODOS=$(git ls-files | xargs grep -i -n "TK-TODO" 2>/dev/null | grep -i -v "IGNORE:TK" || true) # IGNORE:TK

if [ -n "$FOUND_TODOS" ]; then
echo ""
echo "ERROR: Found TK-TODO markers that must be resolved before merge:" # IGNORE:TK
echo ""
echo "$FOUND_TODOS"
echo ""
echo "To suppress a TK-TODO, add 'IGNORE:TK' (case-insensitive) on the same line." # IGNORE:TK
echo ""
exit 1
else
echo "No unresolved TK-TODO markers found." # IGNORE:TK
fi
279 changes: 147 additions & 132 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,177 +1,192 @@
# Awesome Python Template
# FastMCP Extensions

A modern Python project template with best practices and cutting-edge tooling.
Unofficial extension library for FastMCP 2.0 with patterns, practices, and utilities for building MCP servers.

## 🚀 Features
## Features

- **🔄 Automated releases** with Release Drafter and semantic versioning
- **📦 uv** for fast, reliable package management
- **🏗️ Source layout** with `src/{library-name}` structure
- **🧪 pytest** for comprehensive testing
- **🎨 ruff** for lightning-fast linting and formatting
- **🔍 deptry** for dependency analysis and unused dependency detection
- **⚡ PoeThePoet** for task automation
- **🤖 GitHub Actions** with PR welcome messages and slash command support
- **📋 Dedicated config files** instead of cramming everything into pyproject.toml
- MCP Annotation Constants: Standard annotation hints (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`) following the FastMCP 2.2.7+ specification
- Deferred Registration Decorators: `@mcp_tool`, `@mcp_prompt`, `@mcp_resource` decorators for organizing tools by domain with automatic domain detection
- Registration Utilities: Functions to register tools, prompts, and resources with a FastMCP app, filtered by domain
- Tool Testing Utilities: Helpers for testing MCP tools directly with JSON arguments (stdio and HTTP transports)
- Tool List Measurement: Utilities for measuring tool list size to track context truncation issues
- Prompt Helpers: Generic `get_prompt_text` helper for agents that cannot access prompt assets directly

## 🛠️ Quick Start
## Installation

1. **Clone and setup:**
```bash
git clone <your-repo>
cd <your-repo>
uv sync --extra dev
```

2. **Run tasks with poe:**
```bash
# List all available tasks
uv run poe
```bash
pip install fastmcp-extensions
```

# Run tests
uv run poe test
Or with uv:

# Format and lint code
uv run poe format
uv run poe lint
```bash
uv add fastmcp-extensions
```

# Run all checks
uv run poe check
```
## Quick Start

## 📋 Available Tasks
### Using Annotation Constants

### Core Development
- `poe test` - Run all tests
- `poe test-fast` - Run tests with fast exit on first failure
- `poe test-cov` - Run tests with coverage reporting
- `poe lint` - Check code style and quality
- `poe format` - Format code with ruff
- `poe format-check` - Check if code is properly formatted
- `poe deps` - Check for unused and missing dependencies
```python
from fastmcp_extensions import (
READ_ONLY_HINT,
DESTRUCTIVE_HINT,
IDEMPOTENT_HINT,
OPEN_WORLD_HINT,
)

### Convenience Tasks
- `poe check` - Run format check, linting, dependency check, and tests
- `poe fix` - Auto-format and fix linting issues
- `poe pre-commit` - Run pre-commit style checks
# Use in tool annotations
annotations = {
READ_ONLY_HINT: True,
IDEMPOTENT_HINT: True,
}
```

### Build & Install
- `poe install` - Install with development dependencies
- `poe install-prod` - Install production dependencies only
- `poe build` - Build the package
### Using Deferred Registration

### Utilities
- `poe clean` - Clean up build artifacts and cache
- `poe version` - Show package version
- `poe docs` - Generate documentation (placeholder)
- `poe typecheck` - Run type checking (placeholder)
- `poe security` - Run security checks (placeholder)
```python
from fastmcp import FastMCP
from fastmcp_extensions import mcp_tool, mcp_resource, register_mcp_tools, register_mcp_resources

## 🤖 GitHub Integration
# Define tools with the decorator (domain auto-detected from filename)
@mcp_tool(read_only=True, idempotent=True)
def list_items() -> list[str]:
"""List all available items."""
return ["item1", "item2"]

### PR Welcome Messages
When you open a pull request, you'll automatically get a welcome message with helpful commands.
@mcp_resource("myserver://version", "Server version", "application/json")
def get_version() -> dict:
"""Get server version info."""
return {"version": "1.0.0"}

### Slash Commands
Use `/poe <task-name>` in PR comments to run tasks:
# Register with FastMCP app
app = FastMCP("my-server")
register_mcp_tools(app)
register_mcp_resources(app)
```

- `/poe test` - Run tests
- `/poe lint` - Check code quality
- `/poe format` - Format code
- `/poe check` - Run all checks
### Measuring Tool List Size

**Note**: For security reasons, slash commands run against the base repository code, not the PR changes. This ensures that untrusted code cannot be executed in a privileged environment.
```python
import asyncio
from fastmcp_extensions.measurement import measure_tool_list_detailed

## 📁 Project Structure
async def check_tool_size():
measurement = await measure_tool_list_detailed(app, server_name="my-server")
print(measurement)
# Output:
# MCP Server: my-server
# Tool count: 10
# Total characters: 5,432
# Average chars per tool: 543

```
awesome-python-template/
├── src/
│ └── awesome_python_template/ # Main source code
│ ├── __init__.py
│ └── py.typed
├── tests/ # Test files
│ ├── __init__.py
│ └── test_awesome_python_template.py
├── .github/
│ └── workflows/ # GitHub Actions
│ ├── pr-welcome.yml
│ └── slash-command-dispatch.yml
├── pyproject.toml # Project metadata and minimal config
├── ruff.toml # Ruff configuration
├── pytest.ini # Pytest configuration
├── poe_tasks.toml # PoeThePoet task definitions (reference)
├── uv.lock # Dependency lock file
└── README.md # This file
asyncio.run(check_tool_size())
```

## 🔧 Configuration Files
### Testing Tools

This template uses **dedicated configuration files** for each tool:
```python
from fastmcp_extensions.testing import call_mcp_tool, run_tool_test
import asyncio

- **`ruff.toml`** - Ruff linting and formatting configuration
- **`pytest.ini`** - Pytest testing configuration
- **`pyproject.toml`** - Minimal project metadata and poe tasks
- **`poe_tasks.toml`** - Reference copy of task definitions
# Call a tool programmatically
result = asyncio.run(call_mcp_tool(app, "list_items", {}))

## 🧪 Testing
# Or use the CLI helper
run_tool_test(app, "list_items", '{}')
```

Tests are organized with pytest markers:
- `@pytest.mark.unit` - Unit tests
- `@pytest.mark.integration` - Integration tests
### Getting Prompt Text

Run specific test types:
```bash
uv run poe test-unit # Unit tests only
uv run poe test-integration # Integration tests only
```python
from fastmcp_extensions.prompts import get_prompt_text
import asyncio

# Get prompt text for agents that can't access prompts directly
text = asyncio.run(get_prompt_text(app, "my_prompt", {"arg": "value"}))
```

## 📦 Dependencies
## Poe Tasks for MCP Servers

Development dependencies are defined in `pyproject.toml`:
- **pytest** - Testing framework
- **pytest-cov** - Coverage reporting
- **ruff** - Linting and formatting
- **deptry** - Dependency analysis
- **poethepoet** - Task runner
This library provides template scripts for common MCP development tasks. Copy these to your project and customize:

### Dependency Analysis
- `bin/test_mcp_tool.py` - Test tools with JSON arguments via stdio
- `bin/test_mcp_tool_http.py` - Test tools over HTTP transport
- `bin/measure_mcp_tool_list.py` - Measure tool list size

This template includes `deptry` for detecting unused and missing dependencies. To ignore false positives, search for "deptry" in the repository and update the configuration in `pyproject.toml`:
Add to your `poe_tasks.toml`:

```toml
[tool.deptry]
# To ignore specific error codes globally:
ignore = ["DEP004"] # Example: ignore misplaced dev dependencies
[tool.poe.tasks.mcp-tool-test]
help = "Test MCP tools directly with JSON arguments"
cmd = "python bin/test_mcp_tool.py"

[tool.poe.tasks.mcp-tool-test-http]
help = "Test MCP tools over HTTP transport"
cmd = "python bin/test_mcp_tool_http.py"

# To ignore specific packages, use CLI options in poe tasks:
# poe deps --per-rule-ignores DEP002=package-name
[tool.poe.tasks.mcp-measure-tools]
help = "Measure the size of the MCP tool list output"
cmd = "python bin/measure_mcp_tool_list.py"
```

## 🎯 Best Practices
## API Reference

### Annotations

This template follows modern Python best practices:
| Constant | Description | FastMCP Default |
|----------|-------------|-----------------|
| `READ_ONLY_HINT` | Tool only reads data | `False` |
| `DESTRUCTIVE_HINT` | Tool modifies/deletes data | `True` |
| `IDEMPOTENT_HINT` | Repeated calls have same effect | `False` |
| `OPEN_WORLD_HINT` | Tool interacts with external systems | `True` |

1. **Source layout** - Code in `src/` directory
2. **Dependency management** - uv for fast, reliable installs
3. **Code quality** - Ruff for consistent formatting and linting
4. **Testing** - Comprehensive pytest setup with coverage
5. **Task automation** - PoeThePoet for development workflows
6. **CI/CD** - GitHub Actions with PR automation
7. **Configuration** - Dedicated files for each tool
### Decorators

## 🔄 Development Workflow
- `@mcp_tool(domain, read_only, destructive, idempotent, open_world, extra_help_text)` - Tag a tool for deferred registration
- `@mcp_prompt(name, description, domain)` - Tag a prompt for deferred registration
- `@mcp_resource(uri, description, mime_type, domain)` - Tag a resource for deferred registration

1. Make your changes
2. Run `uv run poe fix` to auto-format and fix linting
3. Run `uv run poe test` to ensure tests pass
4. Push your changes
5. Use `/poe <task>` commands in PR comments as needed
### Registration Functions

## 🤝 Contributing
- `register_mcp_tools(app, domain, exclude_args)` - Register tools with FastMCP app
- `register_mcp_prompts(app, domain)` - Register prompts with FastMCP app
- `register_mcp_resources(app, domain)` - Register resources with FastMCP app

Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for setup and development guidelines.
### Testing Utilities

- `call_mcp_tool(app, tool_name, args)` - Call a tool asynchronously
- `list_mcp_tools(app)` - List all available tools
- `run_tool_test(app, tool_name, json_args)` - Run a tool test with JSON args
- `run_http_tool_test(http_server_command, port, tool_name, args, env)` - Test over HTTP

### Measurement Utilities

- `measure_tool_list(app)` - Get (tool_count, total_chars) tuple
- `measure_tool_list_detailed(app, server_name)` - Get detailed measurement
- `get_tool_details(app)` - Get per-tool size breakdown

### Prompt Utilities

- `get_prompt_text(app, prompt_name, arguments)` - Get prompt text content
- `list_prompts(app)` - List all available prompts

## Development

```bash
# Install dependencies
uv sync --extra dev

# Run tests
uv run poe test

# Format and lint
uv run poe fix

# Run all checks
uv run poe check
```

## 📄 License
## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
MIT License - see [LICENSE](LICENSE) for details.
Loading
Loading