Skip to content

Commit 7bffb4e

Browse files
authored
fix for modified metatdata (#968)
* fix for modified metatdata Signed-off-by: Shoumi <[email protected]> * lint & flake8 fixes Signed-off-by: Shoumi <[email protected]> * test fixes Signed-off-by: Shoumi <[email protected]> --------- Signed-off-by: Shoumi <[email protected]>
1 parent cc61b9e commit 7bffb4e

File tree

9 files changed

+459
-69
lines changed

9 files changed

+459
-69
lines changed

mcpgateway/admin.py

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -858,8 +858,20 @@ async def admin_add_server(request: Request, db: Session = Depends(get_db), user
858858
team_service = TeamManagementService(db)
859859
team_id = await team_service.verify_team_for_user(user_email, team_id)
860860

861+
# Extract metadata for server creation
862+
creation_metadata = MetadataCapture.extract_creation_metadata(request, user)
863+
861864
# Ensure default visibility is private and assign to personal team when available
862-
await server_service.register_server(db, server, created_by=user_email, team_id=team_id, visibility=visibility)
865+
await server_service.register_server(
866+
db,
867+
server,
868+
created_by=user_email, # Use the consistent user_email
869+
created_from_ip=creation_metadata["created_from_ip"],
870+
created_via=creation_metadata["created_via"],
871+
created_user_agent=creation_metadata["created_user_agent"],
872+
team_id=team_id,
873+
visibility=visibility,
874+
)
863875
return JSONResponse(
864876
content={"message": "Server created successfully!", "success": True},
865877
status_code=200,
@@ -1011,6 +1023,8 @@ async def admin_edit_server(
10111023
team_service = TeamManagementService(db)
10121024
team_id = await team_service.verify_team_for_user(user_email, team_id)
10131025

1026+
mod_metadata = MetadataCapture.extract_modification_metadata(request, user, 0)
1027+
10141028
server = ServerUpdate(
10151029
id=form.get("id"),
10161030
name=form.get("name"),
@@ -1025,7 +1039,15 @@ async def admin_edit_server(
10251039
owner_email=user_email,
10261040
)
10271041

1028-
await server_service.update_server(db, server_id, server)
1042+
await server_service.update_server(
1043+
db,
1044+
server_id,
1045+
server,
1046+
modified_by=mod_metadata["modified_by"],
1047+
modified_from_ip=mod_metadata["modified_from_ip"],
1048+
modified_via=mod_metadata["modified_via"],
1049+
modified_user_agent=mod_metadata["modified_user_agent"],
1050+
)
10291051

10301052
return JSONResponse(
10311053
content={"message": "Server updated successfully!", "success": True},
@@ -5805,7 +5827,17 @@ async def admin_edit_gateway(
58055827
owner_email=user_email,
58065828
team_id=team_id,
58075829
)
5808-
await gateway_service.update_gateway(db, gateway_id, gateway)
5830+
5831+
mod_metadata = MetadataCapture.extract_modification_metadata(request, user, 0)
5832+
await gateway_service.update_gateway(
5833+
db,
5834+
gateway_id,
5835+
gateway,
5836+
modified_by=mod_metadata["modified_by"],
5837+
modified_from_ip=mod_metadata["modified_from_ip"],
5838+
modified_via=mod_metadata["modified_via"],
5839+
modified_user_agent=mod_metadata["modified_user_agent"],
5840+
)
58095841
return JSONResponse(
58105842
content={"message": "Gateway updated successfully!", "success": True},
58115843
status_code=200,
@@ -6204,6 +6236,7 @@ async def admin_edit_resource(
62046236
tags: List[str] = [tag.strip() for tag in tags_str.split(",") if tag.strip()] if tags_str else []
62056237

62066238
try:
6239+
mod_metadata = MetadataCapture.extract_modification_metadata(request, user, 0)
62076240
resource = ResourceUpdate(
62086241
name=str(form["name"]),
62096242
description=str(form.get("description")),
@@ -6212,7 +6245,15 @@ async def admin_edit_resource(
62126245
template=str(form.get("template")),
62136246
tags=tags,
62146247
)
6215-
await resource_service.update_resource(db, uri, resource)
6248+
await resource_service.update_resource(
6249+
db,
6250+
uri,
6251+
resource,
6252+
modified_by=mod_metadata["modified_by"],
6253+
modified_from_ip=mod_metadata["modified_from_ip"],
6254+
modified_via=mod_metadata["modified_via"],
6255+
modified_user_agent=mod_metadata["modified_user_agent"],
6256+
)
62166257
return JSONResponse(
62176258
content={"message": "Resource updated successfully!", "success": True},
62186259
status_code=200,
@@ -6684,14 +6725,23 @@ async def admin_edit_prompt(
66846725
tags_str = str(form.get("tags", ""))
66856726
tags: List[str] = [tag.strip() for tag in tags_str.split(",") if tag.strip()] if tags_str else []
66866727
try:
6728+
mod_metadata = MetadataCapture.extract_modification_metadata(request, user, 0)
66876729
prompt = PromptUpdate(
66886730
name=str(form["name"]),
66896731
description=str(form.get("description")),
66906732
template=str(form["template"]),
66916733
arguments=arguments,
66926734
tags=tags,
66936735
)
6694-
await prompt_service.update_prompt(db, name, prompt)
6736+
await prompt_service.update_prompt(
6737+
db,
6738+
name,
6739+
prompt,
6740+
modified_by=mod_metadata["modified_by"],
6741+
modified_from_ip=mod_metadata["modified_from_ip"],
6742+
modified_via=mod_metadata["modified_via"],
6743+
modified_user_agent=mod_metadata["modified_user_agent"],
6744+
)
66956745

66966746
root_path = request.scope.get("root_path", "")
66976747
is_inactive_checked: str = str(form.get("is_inactive_checked", "false"))

mcpgateway/main.py

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,7 @@ async def get_server(server_id: str, db: Session = Depends(get_db), user=Depends
11291129
@require_permission("servers.create")
11301130
async def create_server(
11311131
server: ServerCreate,
1132+
request: Request,
11321133
team_id: Optional[str] = Body(None, description="Team ID to assign server to"),
11331134
visibility: str = Body("private", description="Server visibility: private, team, public"),
11341135
db: Session = Depends(get_db),
@@ -1139,6 +1140,7 @@ async def create_server(
11391140
11401141
Args:
11411142
server (ServerCreate): The data for the new server.
1143+
request (Request): The incoming request object for extracting metadata.
11421144
team_id (Optional[str]): Team ID to assign the server to.
11431145
visibility (str): Server visibility level (private, team, public).
11441146
db (Session): The database session used to interact with the data store.
@@ -1151,6 +1153,9 @@ async def create_server(
11511153
HTTPException: If there is a conflict with the server name or other errors.
11521154
"""
11531155
try:
1156+
# Extract metadata from request
1157+
metadata = MetadataCapture.extract_creation_metadata(request, user)
1158+
11541159
# Get user email and handle team assignment
11551160
user_email = get_user_email(user)
11561161

@@ -1165,7 +1170,17 @@ async def create_server(
11651170
team_id = personal_team.id if personal_team else None
11661171

11671172
logger.debug(f"User {user_email} is creating a new server for team {team_id}")
1168-
return await server_service.register_server(db, server, created_by=user_email, team_id=team_id, owner_email=user_email, visibility=visibility)
1173+
return await server_service.register_server(
1174+
db,
1175+
server,
1176+
created_by=metadata["created_by"],
1177+
created_from_ip=metadata["created_from_ip"],
1178+
created_via=metadata["created_via"],
1179+
created_user_agent=metadata["created_user_agent"],
1180+
team_id=team_id,
1181+
owner_email=user_email,
1182+
visibility=visibility,
1183+
)
11691184
except ServerNameConflictError as e:
11701185
raise HTTPException(status_code=409, detail=str(e))
11711186
except ServerError as e:
@@ -1183,6 +1198,7 @@ async def create_server(
11831198
async def update_server(
11841199
server_id: str,
11851200
server: ServerUpdate,
1201+
request: Request,
11861202
db: Session = Depends(get_db),
11871203
user=Depends(get_current_user_with_permissions),
11881204
) -> ServerRead:
@@ -1192,6 +1208,7 @@ async def update_server(
11921208
Args:
11931209
server_id (str): The ID of the server to update.
11941210
server (ServerUpdate): The updated server data.
1211+
request (Request): The incoming request object containing metadata.
11951212
db (Session): The database session used to interact with the data store.
11961213
user (str): The authenticated user making the request.
11971214
@@ -1203,7 +1220,18 @@ async def update_server(
12031220
"""
12041221
try:
12051222
logger.debug(f"User {user} is updating server with ID {server_id}")
1206-
return await server_service.update_server(db, server_id, server)
1223+
# Extract modification metadata
1224+
mod_metadata = MetadataCapture.extract_modification_metadata(request, user, 0) # Version will be incremented in service
1225+
1226+
return await server_service.update_server(
1227+
db,
1228+
server_id,
1229+
server,
1230+
modified_by=mod_metadata["modified_by"],
1231+
modified_from_ip=mod_metadata["modified_from_ip"],
1232+
modified_via=mod_metadata["modified_via"],
1233+
modified_user_agent=mod_metadata["modified_user_agent"],
1234+
)
12071235
except ServerNotFoundError as e:
12081236
raise HTTPException(status_code=404, detail=str(e))
12091237
except ServerNameConflictError as e:
@@ -2281,6 +2309,7 @@ async def read_resource(uri: str, request: Request, db: Session = Depends(get_db
22812309
async def update_resource(
22822310
uri: str,
22832311
resource: ResourceUpdate,
2312+
request: Request,
22842313
db: Session = Depends(get_db),
22852314
user=Depends(get_current_user_with_permissions),
22862315
) -> ResourceRead:
@@ -2290,6 +2319,7 @@ async def update_resource(
22902319
Args:
22912320
uri (str): URI of the resource.
22922321
resource (ResourceUpdate): New resource data.
2322+
request (Request): The FastAPI request object for metadata extraction.
22932323
db (Session): Database session.
22942324
user (str): Authenticated user.
22952325
@@ -2301,7 +2331,18 @@ async def update_resource(
23012331
"""
23022332
try:
23032333
logger.debug(f"User {user} is updating resource with URI {uri}")
2304-
result = await resource_service.update_resource(db, uri, resource)
2334+
# Extract modification metadata
2335+
mod_metadata = MetadataCapture.extract_modification_metadata(request, user, 0) # Version will be incremented in service
2336+
2337+
result = await resource_service.update_resource(
2338+
db,
2339+
uri,
2340+
resource,
2341+
modified_by=mod_metadata["modified_by"],
2342+
modified_from_ip=mod_metadata["modified_from_ip"],
2343+
modified_via=mod_metadata["modified_via"],
2344+
modified_user_agent=mod_metadata["modified_user_agent"],
2345+
)
23052346
except ResourceNotFoundError as e:
23062347
raise HTTPException(status_code=404, detail=str(e))
23072348
except ValidationError as e:
@@ -2654,6 +2695,7 @@ async def get_prompt_no_args(
26542695
async def update_prompt(
26552696
name: str,
26562697
prompt: PromptUpdate,
2698+
request: Request,
26572699
db: Session = Depends(get_db),
26582700
user=Depends(get_current_user_with_permissions),
26592701
) -> PromptRead:
@@ -2663,6 +2705,7 @@ async def update_prompt(
26632705
Args:
26642706
name (str): Identifier of the prompt to update.
26652707
prompt (PromptUpdate): New prompt content and metadata.
2708+
request (Request): The FastAPI request object for metadata extraction.
26662709
db (Session): Active SQLAlchemy session.
26672710
user (str): Authenticated username.
26682711
@@ -2676,7 +2719,18 @@ async def update_prompt(
26762719
logger.info(f"User: {user} requested to update prompt: {name} with data={prompt}")
26772720
logger.debug(f"User: {user} requested to update prompt: {name} with data={prompt}")
26782721
try:
2679-
return await prompt_service.update_prompt(db, name, prompt)
2722+
# Extract modification metadata
2723+
mod_metadata = MetadataCapture.extract_modification_metadata(request, user, 0) # Version will be incremented in service
2724+
2725+
return await prompt_service.update_prompt(
2726+
db,
2727+
name,
2728+
prompt,
2729+
modified_by=mod_metadata["modified_by"],
2730+
modified_from_ip=mod_metadata["modified_from_ip"],
2731+
modified_via=mod_metadata["modified_via"],
2732+
modified_user_agent=mod_metadata["modified_user_agent"],
2733+
)
26802734
except Exception as e:
26812735
if isinstance(e, PromptNotFoundError):
26822736
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
@@ -2890,6 +2944,7 @@ async def get_gateway(gateway_id: str, db: Session = Depends(get_db), user=Depen
28902944
async def update_gateway(
28912945
gateway_id: str,
28922946
gateway: GatewayUpdate,
2947+
request: Request,
28932948
db: Session = Depends(get_db),
28942949
user=Depends(get_current_user_with_permissions),
28952950
) -> GatewayRead:
@@ -2899,6 +2954,7 @@ async def update_gateway(
28992954
Args:
29002955
gateway_id: Gateway ID.
29012956
gateway: Gateway update data.
2957+
request (Request): The FastAPI request object for metadata extraction.
29022958
db: Database session.
29032959
user: Authenticated user.
29042960
@@ -2907,7 +2963,18 @@ async def update_gateway(
29072963
"""
29082964
logger.debug(f"User '{user}' requested update on gateway {gateway_id} with data={gateway}")
29092965
try:
2910-
return await gateway_service.update_gateway(db, gateway_id, gateway)
2966+
# Extract modification metadata
2967+
mod_metadata = MetadataCapture.extract_modification_metadata(request, user, 0) # Version will be incremented in service
2968+
2969+
return await gateway_service.update_gateway(
2970+
db,
2971+
gateway_id,
2972+
gateway,
2973+
modified_by=mod_metadata["modified_by"],
2974+
modified_from_ip=mod_metadata["modified_from_ip"],
2975+
modified_via=mod_metadata["modified_via"],
2976+
modified_user_agent=mod_metadata["modified_user_agent"],
2977+
)
29112978
except Exception as ex:
29122979
if isinstance(ex, GatewayNotFoundError):
29132980
return JSONResponse(content={"message": "Gateway not found"}, status_code=status.HTTP_404_NOT_FOUND)

mcpgateway/services/gateway_service.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -843,13 +843,27 @@ async def list_gateways_for_user(
843843
gateways = db.execute(query).scalars().all()
844844
return [GatewayRead.model_validate(g).masked() for g in gateways]
845845

846-
async def update_gateway(self, db: Session, gateway_id: str, gateway_update: GatewayUpdate, include_inactive: bool = True) -> GatewayRead:
846+
async def update_gateway(
847+
self,
848+
db: Session,
849+
gateway_id: str,
850+
gateway_update: GatewayUpdate,
851+
modified_by: Optional[str] = None,
852+
modified_from_ip: Optional[str] = None,
853+
modified_via: Optional[str] = None,
854+
modified_user_agent: Optional[str] = None,
855+
include_inactive: bool = True,
856+
) -> GatewayRead:
847857
"""Update a gateway.
848858
849859
Args:
850860
db: Database session
851861
gateway_id: Gateway ID to update
852862
gateway_update: Updated gateway data
863+
modified_by: Username of the person modifying the gateway
864+
modified_from_ip: IP address where the modification request originated
865+
modified_via: Source of modification (ui/api/import)
866+
modified_user_agent: User agent string from the modification request
853867
include_inactive: Whether to include inactive gateways
854868
855869
Returns:
@@ -1036,7 +1050,21 @@ async def update_gateway(self, db: Session, gateway_id: str, gateway_update: Gat
10361050
if gateway_update.tags is not None:
10371051
gateway.tags = gateway_update.tags
10381052

1053+
# Update metadata fields
10391054
gateway.updated_at = datetime.now(timezone.utc)
1055+
if modified_by:
1056+
gateway.modified_by = modified_by
1057+
if modified_from_ip:
1058+
gateway.modified_from_ip = modified_from_ip
1059+
if modified_via:
1060+
gateway.modified_via = modified_via
1061+
if modified_user_agent:
1062+
gateway.modified_user_agent = modified_user_agent
1063+
if hasattr(gateway, "version") and gateway.version is not None:
1064+
gateway.version = gateway.version + 1
1065+
else:
1066+
gateway.version = 1
1067+
10401068
db.commit()
10411069
db.refresh(gateway)
10421070

0 commit comments

Comments
 (0)