CKT commited on
Commit
4c571f8
·
1 Parent(s): d21e0d2

MCP server working

Browse files
.gitignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ venv/
2
+ _context/
3
+ .DS_Store
4
+ .env
5
+ .gradio/
app.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import random
3
+ import json
4
+ import uuid
5
+ import os # Added for path joining
6
+ from datetime import datetime # Added for timestamps
7
+
8
+ # --- Start of JSON I/O Helper Functions ---
9
+
10
+ DATA_DIR = "data" # This will be relative to app.py, so matchmaker/data
11
+ PROFILES_FILE = os.path.join(DATA_DIR, "profiles.json")
12
+ QUESTIONNAIRE_FILE = os.path.join(DATA_DIR, "questionnaire.json")
13
+ MESSAGES_FILE = os.path.join(DATA_DIR, "messages.json") # Though not used in this step
14
+
15
+ def load_json_data(filepath, default_data=None):
16
+ """Loads JSON data from a file. Returns default_data if file not found or error."""
17
+ # Construct path relative to this script's directory if not absolute
18
+ base_dir = os.path.dirname(os.path.abspath(__file__))
19
+ absolute_filepath = os.path.join(base_dir, filepath) if not os.path.isabs(filepath) else filepath
20
+
21
+ try:
22
+ # Ensure directory exists before trying to open file
23
+ file_dir = os.path.dirname(absolute_filepath)
24
+ if not os.path.exists(file_dir):
25
+ os.makedirs(file_dir, exist_ok=True)
26
+
27
+ if not os.path.exists(absolute_filepath):
28
+ with open(absolute_filepath, 'w') as f:
29
+ effective_default = default_data
30
+ if effective_default is None:
31
+ if absolute_filepath.endswith("profiles.json"):
32
+ effective_default = {}
33
+ elif absolute_filepath.endswith("messages.json"):
34
+ effective_default = []
35
+ else: # questionnaire.json or other
36
+ effective_default = {} # Should be pre-populated, but as a fallback
37
+ json.dump(effective_default, f, indent=2)
38
+ return effective_default
39
+
40
+ with open(absolute_filepath, 'r') as f:
41
+ return json.load(f)
42
+ except (IOError, json.JSONDecodeError) as e:
43
+ print(f"Error loading {absolute_filepath}: {e}")
44
+ if default_data is not None: return default_data
45
+ if absolute_filepath.endswith("profiles.json"): return {}
46
+ if absolute_filepath.endswith("messages.json"): return []
47
+ return {}
48
+
49
+ def save_json_data(filepath, data):
50
+ """Saves Python data to a JSON file."""
51
+ base_dir = os.path.dirname(os.path.abspath(__file__))
52
+ absolute_filepath = os.path.join(base_dir, filepath) if not os.path.isabs(filepath) else filepath
53
+ try:
54
+ os.makedirs(os.path.dirname(absolute_filepath), exist_ok=True)
55
+ with open(absolute_filepath, 'w') as f:
56
+ json.dump(data, f, indent=2)
57
+ return True
58
+ except IOError as e:
59
+ print(f"Error saving {absolute_filepath}: {e}")
60
+ return False
61
+
62
+ # --- End of JSON I/O Helper Functions ---
63
+
64
+ # --- Start of MCP Matchmaker Tools ---
65
+
66
+ def profile_questionnaire_func(request: gr.Request):
67
+ """
68
+ Generates and returns a profile questionnaire, a new public profile_id,
69
+ and a new private auth_id. Also creates an initial profile stub.
70
+ """
71
+ # 1. Generate profile_id and auth_id
72
+ profile_id = f"user_{''.join(random.choices('abcdefghijklmnopqrstuvwxyz0123456789', k=8))}"
73
+ auth_id = str(uuid.uuid4())
74
+
75
+ # 2. Read questionnaire.json
76
+ questionnaire_data = load_json_data(QUESTIONNAIRE_FILE, default_data={"title": "Error Loading Questionnaire", "questions": []})
77
+ if not questionnaire_data.get("questions") or questionnaire_data.get("title") == "Error Loading Questionnaire":
78
+ print(f"Critical Error: Could not load or parse questionnaire from {QUESTIONNAIRE_FILE}. Please ensure it exists and is valid JSON.")
79
+ questionnaire_data = {"title": "Questionnaire Unavailable", "questions": []} # Fallback
80
+
81
+ # 3. Create new profile entry in profiles.json
82
+ profiles = load_json_data(PROFILES_FILE, default_data={})
83
+ timestamp = datetime.utcnow().isoformat() + "Z" # ISO 8601 format
84
+
85
+ profiles[profile_id] = {
86
+ "profile_id": profile_id,
87
+ "auth_id": auth_id,
88
+ "created_at": timestamp,
89
+ "updated_at": timestamp,
90
+ "name": "",
91
+ "profile_image_filename": None,
92
+ "profile_summary": "",
93
+ "answers": {}
94
+ }
95
+ if not save_json_data(PROFILES_FILE, profiles):
96
+ print(f"Critical Error: Failed to save profile for {profile_id} to {PROFILES_FILE}")
97
+ # Decide how to handle this error - maybe return an error to the client?
98
+
99
+ # 4. Return IDs, questionnaire data, and instructions
100
+ instructions_for_agent = "You have received a `profile_id` (public identifier for this user\'s profile) and an `auth_id` (private key for authentication for this user). Store both securely. The `auth_id` must be sent as an `X-Auth-ID` header in subsequent requests that require authentication for this user (e.g., `update_profile_answers`, `get_matches`, `get_messages`, `get_profile` for own profile, `send_message`). The `profile_id` is used to publicly identify this user to others (e.g., in matches, or when sending/receiving messages)."
101
+ instructions_for_user = "Your profile creation process has started! You\'ve been assigned a unique Profile ID and a secret Auth ID. Your AI agent will use these to manage your profile and interactions."
102
+
103
+ return {
104
+ "profile_id": profile_id,
105
+ "auth_id": auth_id,
106
+ "questionnaire": questionnaire_data,
107
+ "instructions_for_agent": instructions_for_agent,
108
+ "instructions_for_user": instructions_for_user
109
+ }
110
+
111
+ # --- End of MCP Matchmaker Tools ---
112
+
113
+ # Original example functions from the user's app.py for context
114
+ def print_headers(text, request: gr.Request):
115
+ """
116
+ Print the headers of the request for debugging purposes.
117
+
118
+ Args:
119
+ text (str): The text to print
120
+ request (gr.Request): The request object
121
+
122
+ Returns:
123
+ str: The text to print
124
+ """
125
+ print(f"Headers for print_headers request: {request.headers}")
126
+ print(f"Text for print_headers: {text}")
127
+ return text
128
+
129
+ # Gradio interface for printing headers
130
+ headers_demo = gr.Interface(
131
+ fn=print_headers,
132
+ inputs=gr.Textbox(label="Input Text"),
133
+ outputs=gr.Textbox(label="Output Text (same as input)"),
134
+ title="Headers Debug",
135
+ description="Prints request headers to the console. Check your terminal."
136
+ )
137
+
138
+ # --- Start of New Profile Questionnaire Interface ---
139
+ profile_questionnaire_demo = gr.Interface(
140
+ fn=profile_questionnaire_func,
141
+ inputs=None, # No direct input from user for this one, it's triggered by the agent
142
+ outputs=gr.JSON(label="Questionnaire, IDs, and Instructions"),
143
+ title="MCP - Profile Questionnaire",
144
+ description="Generates a new user profile questionnaire, Profile ID, and Auth ID. (Agent-triggered MCP tool)"
145
+ )
146
+ # --- End of New Profile Questionnaire Interface ---
147
+
148
+ # Adjusted TabbedInterface to include the new tool
149
+ demo = gr.TabbedInterface(
150
+ [profile_questionnaire_demo, headers_demo],
151
+ ["MCP - Profile Questionnaire", "Headers Debug"]
152
+ )
153
+
154
+ if __name__ == "__main__":
155
+ demo.launch(mcp_server=True)
data/messages.json ADDED
@@ -0,0 +1 @@
 
 
1
+ []
data/profiles.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "user_6ngnjagx": {
3
+ "profile_id": "user_6ngnjagx",
4
+ "auth_id": "1edfeebd-e9f8-416e-afc4-4c1698932ac0",
5
+ "created_at": "2025-06-05T16:26:32.384174Z",
6
+ "updated_at": "2025-06-05T16:26:32.384174Z",
7
+ "name": "",
8
+ "profile_image_filename": null,
9
+ "profile_summary": "",
10
+ "answers": {}
11
+ }
12
+ }
data/questionnaire.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "title": "MCP Matchmaker Profile Questionnaire",
3
+ "questions": [
4
+ { "id": "q_name", "text": "What is your name?", "type": "text", "purpose": "metadata", "maps_to_field": "name" },
5
+ { "id": "q_profile_image_filename", "text": "Enter the filename for your profile picture (e.g., my_image.jpg):", "type": "text", "purpose": "metadata", "maps_to_field": "profile_image_filename" },
6
+ { "id": "q_profile_summary", "text": "Write a brief introduction for your profile (1-2 sentences):", "type": "text", "purpose": "metadata", "maps_to_field": "profile_summary" },
7
+ { "id": "q_hobby", "text": "What are your main hobbies or interests?", "type": "text", "purpose": "matchmaking" },
8
+ { "id": "q_looking_for", "text": "What are you looking for in a match?", "type": "long_text", "purpose": "matchmaking" },
9
+ { "id": "q_vibe", "text": "Describe your general vibe (e.g., adventurous, homebody, intellectual)?", "type": "text", "purpose": "matchmaking" }
10
+ ]
11
+ }
requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ gradio[mcp]
utils/__init__.py ADDED
File without changes
utils/storage.py ADDED
File without changes