Skip to content

Commit 3ce0cd8

Browse files
committed
functioning app with mcp
0 parents  commit 3ce0cd8

23 files changed

Lines changed: 1747 additions & 0 deletions

.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.12

README.md

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# Python Todo List App with MCP Integration
2+
3+
A Flask-based todo list application that exposes operations as MCP (Model Context Protocol) tools over HTTP and can be deployed to Azure App Service.
4+
5+
## Features
6+
7+
-**CRUD Operations**: Create, read, update, delete todos
8+
- 🎯 **Priority Management**: Set priority levels (low, medium, high)
9+
-**Mark Complete/Incomplete**: Toggle completion status
10+
- 🌐 **Web Interface**: Clean, responsive Bootstrap UI
11+
- 💬 **Chat Interface**: Placeholder for future LLM integration
12+
- 🔧 **MCP Tools**: HTTP-accessible tools for external integrations
13+
- ☁️ **Azure Ready**: Optimized for Azure App Service deployment
14+
15+
## MCP Tools Available
16+
17+
The application exposes the following MCP tools over HTTP:
18+
19+
- `create_todo(title, description, priority)` - Create a new todo item
20+
- `list_todos(filter_completed)` - Get all todos with optional filtering
21+
- `update_todo(id, title, description, priority, completed)` - Update existing todo
22+
- `delete_todo(id)` - Delete a todo item
23+
- `mark_todo_complete(id, completed)` - Mark todo as complete/incomplete
24+
25+
## Local Development
26+
27+
### Prerequisites
28+
29+
- Python 3.12+
30+
- Virtual environment (venv)
31+
32+
### Setup
33+
34+
1. **Clone and setup environment**:
35+
```bash
36+
git clone <repository-url>
37+
cd python-todo-mcp-agent
38+
python -m venv .venv
39+
.venv\Scripts\activate # Windows
40+
# or
41+
source .venv/bin/activate # Linux/Mac
42+
```
43+
44+
2. **Install dependencies**:
45+
```bash
46+
pip install -r requirements.txt
47+
```
48+
49+
3. **Set environment variables** (optional):
50+
```bash
51+
set SECRET_KEY=your-secret-key-here
52+
set DATABASE_URL=sqlite:///todos.db
53+
```
54+
55+
4. **Run the application**:
56+
```bash
57+
python main.py
58+
```
59+
60+
5. **Access the application**:
61+
- Web Interface: http://localhost:8000
62+
- Chat Interface: http://localhost:8000/chat
63+
- Health Check: http://localhost:8000/health
64+
- MCP Endpoint: http://localhost:8000/mcp
65+
- MCP Tools: http://localhost:8000/mcp/tools/*
66+
67+
## Azure Deployment
68+
69+
### Prerequisites
70+
71+
- Azure CLI installed and logged in
72+
- Azure Developer CLI (azd) installed
73+
74+
### Deploy with AZD
75+
76+
1. **Initialize AZD**:
77+
```bash
78+
azd init
79+
```
80+
81+
2. **Set environment variables**:
82+
```bash
83+
azd env set SECRET_KEY "your-production-secret-key"
84+
azd env set DATABASE_URL "sqlite:///todos.db"
85+
```
86+
87+
3. **Deploy to Azure**:
88+
```bash
89+
azd up
90+
```
91+
92+
### Infrastructure
93+
94+
The deployment creates:
95+
96+
- **App Service Plan**: P0V3 (Premium V3, Linux)
97+
- **App Service**: Python 3.12 runtime
98+
- **Managed Identity**: Secure Azure resource access
99+
100+
## Architecture
101+
102+
```
103+
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
104+
│ Web Browser │────│ Flask App │────│ SQLite DB │
105+
│ (Todo UI) │ │ (CRUD API) │ │ (Data Store) │
106+
└─────────────────┘ └──────────────────┘ └─────────────────┘
107+
108+
┌──────────────────┐
109+
│ MCP Server │
110+
│ (HTTP Tools) │
111+
└──────────────────┘
112+
113+
┌──────────────────┐
114+
│ External Tools │
115+
│ & Integrations │
116+
└──────────────────┘
117+
```
118+
119+
## API Endpoints
120+
121+
### REST API
122+
- `GET /api/todos` - List all todos
123+
- `POST /api/todos` - Create new todo
124+
- `GET /api/todos/{id}` - Get specific todo
125+
- `PUT /api/todos/{id}` - Update todo
126+
- `DELETE /api/todos/{id}` - Delete todo
127+
- `PATCH /api/todos/{id}/complete` - Toggle completion
128+
129+
### MCP Integration
130+
- `GET /mcp` - MCP server info and available tools
131+
- `POST /mcp` - MCP protocol endpoint (JSON-RPC 2.0)
132+
- `GET/POST /mcp/tools/create_todo` - Direct tool access
133+
- `GET/POST /mcp/tools/list_todos` - Direct tool access
134+
- `POST /mcp/tools/update_todo` - Direct tool access
135+
- `POST /mcp/tools/delete_todo` - Direct tool access
136+
- `POST /mcp/tools/mark_todo_complete` - Direct tool access
137+
138+
## Environment Variables
139+
140+
| Variable | Description | Default |
141+
|----------|-------------|---------|
142+
| `SECRET_KEY` | Flask secret key for sessions | `dev-secret-key` |
143+
| `DATABASE_URL` | Database connection string | `sqlite:///todos.db` |
144+
145+
## Development Notes
146+
147+
- **Database**: Uses SQLite for simplicity (can be upgraded to Azure SQL)
148+
- **Styling**: Bootstrap 5 with Font Awesome icons
149+
- **Frontend**: Vanilla JavaScript with fetch API
150+
- **Backend**: Flask with SQLAlchemy ORM
151+
- **MCP**: Native JSON-RPC 2.0 implementation in Flask
152+
- **Security**: HTTPS only, managed identity, CORS enabled
153+
154+
## Future Enhancements
155+
156+
- 🤖 **LLM Integration**: Connect chat interface to language models
157+
- 🗄️ **Database Upgrade**: Migrate to Azure SQL Database
158+
- 🔐 **Authentication**: Add user accounts and auth
159+
- 📱 **Mobile App**: React Native or Flutter companion
160+
- 🔍 **Search**: Full-text search capabilities
161+
- 📊 **Analytics**: Usage metrics and insights
162+
163+
## Contributing
164+
165+
1. Fork the repository
166+
2. Create a feature branch
167+
3. Make your changes
168+
4. Add tests if applicable
169+
5. Submit a pull request
170+
171+
## License
172+
173+
This project is licensed under the MIT License.

azure.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
name: python-todo-mcp-agent
2+
metadata:
3+
template: python-webapp@0.0.1-beta
4+
infra:
5+
provider: bicep
6+
path: infra
7+
services:
8+
todo-app:
9+
project: src
10+
host: appservice
11+
language: python

infra/main.bicep

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
targetScope = 'resourceGroup'
2+
3+
@description('Name of the environment')
4+
param environmentName string
5+
6+
@description('Primary location for all resources')
7+
param location string = resourceGroup().location
8+
9+
@description('Secret key for Flask application')
10+
@secure()
11+
param secretKey string = ''
12+
13+
@description('Database URL for the application')
14+
param databaseUrl string = ''
15+
16+
// Generate unique resource token
17+
var resourceToken = uniqueString(subscription().id, resourceGroup().id, location, environmentName)
18+
19+
// Define resource prefix
20+
var resourcePrefix = 'tda'
21+
22+
// App Service Plan name
23+
var appServicePlanName = 'az-${resourcePrefix}-plan-${resourceToken}'
24+
25+
// App Service name
26+
var appServiceName = 'az-${resourcePrefix}-app-${resourceToken}'
27+
28+
// User-assigned managed identity name
29+
var managedIdentityName = 'az-${resourcePrefix}-mi-${resourceToken}'
30+
31+
// Create User-assigned Managed Identity
32+
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
33+
name: managedIdentityName
34+
location: location
35+
tags: {
36+
'azd-env-name': environmentName
37+
'azd-service-name': 'todo-app'
38+
}
39+
}
40+
41+
// Create App Service Plan (P0V3 Linux)
42+
resource appServicePlan 'Microsoft.Web/serverfarms@2024-04-01' = {
43+
name: appServicePlanName
44+
location: location
45+
tags: {
46+
'azd-env-name': environmentName
47+
'azd-service-name': 'todo-app'
48+
}
49+
sku: {
50+
name: 'P0v3'
51+
tier: 'Premium0V3'
52+
size: 'P0v3'
53+
family: 'Pv3'
54+
capacity: 1
55+
}
56+
properties: {
57+
reserved: true // Linux App Service Plan
58+
}
59+
kind: 'linux'
60+
}
61+
62+
// Create App Service
63+
resource appService 'Microsoft.Web/sites@2024-04-01' = {
64+
name: appServiceName
65+
location: location
66+
tags: {
67+
'azd-env-name': environmentName
68+
'azd-service-name': 'todo-app'
69+
}
70+
identity: {
71+
type: 'UserAssigned'
72+
userAssignedIdentities: {
73+
'${managedIdentity.id}': {}
74+
}
75+
}
76+
properties: {
77+
serverFarmId: appServicePlan.id
78+
reserved: true
79+
httpsOnly: true
80+
siteConfig: {
81+
linuxFxVersion: 'PYTHON|3.12'
82+
appSettings: [
83+
{
84+
name: 'SECRET_KEY'
85+
value: secretKey
86+
}
87+
{
88+
name: 'DATABASE_URL'
89+
value: databaseUrl
90+
}
91+
{
92+
name: 'SCM_DO_BUILD_DURING_DEPLOYMENT'
93+
value: 'true'
94+
}
95+
{
96+
name: 'ENABLE_ORYX_BUILD'
97+
value: 'true'
98+
}
99+
]
100+
cors: {
101+
allowedOrigins: ['*']
102+
supportCredentials: false
103+
}
104+
alwaysOn: false
105+
healthCheckPath: '/health'
106+
}
107+
}
108+
}
109+
110+
// Outputs
111+
output RESOURCE_GROUP_ID string = resourceGroup().id
112+
output AZURE_LOCATION string = location
113+
output SERVICE_TODO_APP_IDENTITY_PRINCIPAL_ID string = managedIdentity.properties.principalId
114+
output SERVICE_TODO_APP_NAME string = appService.name
115+
output SERVICE_TODO_APP_URI string = 'https://${appService.properties.defaultHostName}'

infra/main.parameters.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
3+
"contentVersion": "1.0.0.0",
4+
"parameters": {
5+
"environmentName": {
6+
"value": "${AZURE_ENV_NAME}"
7+
},
8+
"location": {
9+
"value": "${AZURE_LOCATION}"
10+
},
11+
"secretKey": {
12+
"value": "${SECRET_KEY}"
13+
},
14+
"databaseUrl": {
15+
"value": "${DATABASE_URL}"
16+
}
17+
}
18+
}

instance/todos.db

8 KB
Binary file not shown.

main.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""
2+
Application entry point for Azure deployment.
3+
"""
4+
import os
5+
import sys
6+
7+
# Add the current directory to Python path
8+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
9+
10+
# Import after path setup to avoid linting issues
11+
from src.app import create_app # noqa: E402
12+
13+
app = create_app()
14+
15+
if __name__ == '__main__':
16+
app.run(debug=False, host='0.0.0.0', port=8000)

requirements.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Flask==3.0.0
2+
Flask-CORS==4.0.0
3+
Flask-SQLAlchemy==3.1.1
4+
SQLAlchemy==2.0.23
5+
gunicorn==21.2.0
6+
python-dotenv==1.0.0
7+
azure-identity==1.15.0
8+
azure-keyvault-secrets==4.8.0
9+
azure-monitor-opentelemetry==1.2.0
10+
requests==2.31.0

run_mcp_server.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""
2+
Standalone MCP server runner.
3+
This runs the FastMCP server on its own port.
4+
"""
5+
import asyncio
6+
import sys
7+
import os
8+
9+
# Add the current directory to Python path
10+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
11+
12+
# Import after path setup to avoid linting issues
13+
from src.app import create_app # noqa: E402
14+
from src.mcp_server import create_mcp_server # noqa: E402
15+
16+
17+
async def main():
18+
"""Run the MCP server."""
19+
# Create Flask app for context
20+
flask_app = create_app()
21+
22+
# Create MCP server
23+
mcp_server = create_mcp_server(flask_app)
24+
25+
# Run the FastMCP server
26+
print("Starting MCP server on port 3001...")
27+
print("Connect with MCP Inspector using HTTP transport at:")
28+
print("http://localhost:3001")
29+
30+
# Start the server
31+
await mcp_server.server.run(transport="http", port=3001)
32+
33+
34+
if __name__ == '__main__':
35+
asyncio.run(main())

src/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# This file makes src a Python package

0 commit comments

Comments
 (0)