-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathapp.py
132 lines (111 loc) · 4.3 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
from flask import Flask, request, jsonify
from functools import wraps
import asyncio
from typing import Dict, Any, Callable
import os
from server import (
list_tools,
confluence_search,
confluence_get_spaces,
confluence_get_page,
confluence_create_page,
confluence_update_page,
confluence_delete_page
)
app = Flask(__name__)
def async_endpoint(f: Callable) -> Callable:
"""Decorator to handle async route handlers."""
@wraps(f)
def wrapper(*args, **kwargs):
return asyncio.run(f(*args, **kwargs))
return wrapper
def validate_auth() -> Dict[str, str]:
"""Validate required authentication headers."""
confluence_url = request.headers.get('X-Confluence-URL')
access_token = request.headers.get('X-Confluence-Token')
if not confluence_url or not access_token:
raise ValueError("Missing required headers: X-Confluence-URL and X-Confluence-Token")
return {
"confluence_url": confluence_url,
"access_token": access_token
}
@app.route('/api/tools', methods=['GET'])
@async_endpoint
async def get_tools():
"""List available Confluence MCP tools."""
try:
result = await list_tools()
return jsonify(result)
except Exception as e:
return jsonify({"error": str(e)}), 500
@app.route('/api/spaces', methods=['GET'])
@async_endpoint
async def get_spaces():
"""Get list of Confluence spaces."""
try:
auth = validate_auth()
result = await confluence_get_spaces(**auth)
return jsonify(result)
except ValueError as e:
return jsonify({"error": str(e)}), 400
except Exception as e:
return jsonify({"error": str(e)}), 500
@app.route('/api/search', methods=['GET'])
@async_endpoint
async def search():
"""Search Confluence content."""
try:
auth = validate_auth()
query = request.args.get('query')
if not query:
return jsonify({"error": "Missing required parameter: query"}), 400
result = await confluence_search(**auth, query=query)
return jsonify(result)
except ValueError as e:
return jsonify({"error": str(e)}), 400
except Exception as e:
return jsonify({"error": str(e)}), 500
@app.route('/api/pages/<space_key>/<page_id>', methods=['GET', 'PUT', 'DELETE'])
@async_endpoint
async def handle_page(space_key: str, page_id: str):
"""Handle page operations (get, update, delete)."""
try:
auth = validate_auth()
if request.method == 'GET':
result = await confluence_get_page(**auth, space_key=space_key, page_id=page_id)
elif request.method == 'PUT':
if not request.is_json:
return jsonify({"error": "Content-Type must be application/json"}), 400
content = request.json.get('content')
if not content:
return jsonify({"error": "Missing required field: content"}), 400
result = await confluence_update_page(**auth, space_key=space_key, page_id=page_id, content=content)
else: # DELETE
result = await confluence_delete_page(**auth, space_key=space_key, page_id=page_id)
return jsonify(result)
except ValueError as e:
return jsonify({"error": str(e)}), 400
except Exception as e:
return jsonify({"error": str(e)}), 500
@app.route('/api/pages/<space_key>', methods=['POST'])
@async_endpoint
async def create_page(space_key: str):
"""Create a new page in a space."""
try:
auth = validate_auth()
if not request.is_json:
return jsonify({"error": "Content-Type must be application/json"}), 400
data = request.json
title = data.get('title')
content = data.get('content')
if not title or not content:
return jsonify({"error": "Missing required fields: title and content"}), 400
result = await confluence_create_page(**auth, space_key=space_key, title=title, content=content)
return jsonify(result)
except ValueError as e:
return jsonify({"error": str(e)}), 400
except Exception as e:
return jsonify({"error": str(e)}), 500
if __name__ == '__main__':
port = int(os.environ.get('PORT', 8080))
app.run(host='0.0.0.0', port=port)