Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
e321d8e
html changes assocaited mcp server
rakdutta Nov 12, 2025
09faa45
search gateway
rakdutta Nov 12, 2025
57f6fa8
select all
rakdutta Nov 12, 2025
a0f3a1d
left panel
rakdutta Nov 12, 2025
3e88fb1
two column resources and prompts
rakdutta Nov 12, 2025
3a494ad
docstring
rakdutta Nov 13, 2025
66c1400
endpoint
rakdutta Nov 14, 2025
31404dd
partial html endpoint
rakdutta Nov 14, 2025
1fa784a
gateway_id log in console
rakdutta Nov 14, 2025
7f5d446
filter tools/prompts
rakdutta Nov 14, 2025
4b50080
partial_html endpoint
rakdutta Nov 14, 2025
6b018b9
filter resources
rakdutta Nov 14, 2025
8adac11
remove testing md file
rakdutta Nov 14, 2025
8b81ab3
docstring server
rakdutta Nov 14, 2025
00ffd7f
lint fix admin.js
rakdutta Nov 14, 2025
4e0f636
lint fix
rakdutta Nov 14, 2025
70e40a7
lint fix js and html
rakdutta Nov 14, 2025
fb7640b
flake
rakdutta Nov 14, 2025
9b9c682
remove extra log
rakdutta Nov 14, 2025
1a2db70
update gateway,list team
rakdutta Nov 17, 2025
537088c
public
rakdutta Nov 17, 2025
534b41c
fix ruff
rakdutta Nov 17, 2025
49d731f
user instuction add
rakdutta Nov 17, 2025
2c6d2ba
black
rakdutta Nov 17, 2025
07d18db
bandit
rakdutta Nov 17, 2025
d5ac4df
add REST mcp server
rakdutta Nov 18, 2025
80108bd
select all
rakdutta Nov 18, 2025
c0c313e
select all
rakdutta Nov 18, 2025
7fe7b10
REST-select-all
rakdutta Nov 18, 2025
43eb85e
lint flake8
rakdutta Nov 19, 2025
3f80c22
pagination resource
rakdutta Nov 19, 2025
421a336
lint
rakdutta Nov 19, 2025
b3d745d
lint
rakdutta Nov 19, 2025
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
207 changes: 202 additions & 5 deletions mcpgateway/admin.py

Large diffs are not rendered by default.

172 changes: 88 additions & 84 deletions mcpgateway/services/gateway_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -1246,10 +1246,15 @@ async def list_gateways_for_user(

access_conditions = []
# Filter by specific team

# Team-owned gateways (team-scoped gateways)
access_conditions.append(and_(DbGateway.team_id == team_id, DbGateway.visibility.in_(["team", "public"])))

access_conditions.append(and_(DbGateway.team_id == team_id, DbGateway.owner_email == user_email))

# Also include global public gateways (no team_id) so public gateways are visible regardless of selected team
access_conditions.append(DbGateway.visibility == "public")

query = query.where(or_(*access_conditions))
else:
# Get user's accessible teams
Expand Down Expand Up @@ -1411,7 +1416,8 @@ async def update_gateway(
# FIX for Issue #1025: Determine if URL actually changed before we update it
# We need this early because we update gateway.url below, and need to know
# if it actually changed to decide whether to re-fetch tools
url_changed = gateway_update.url is not None and self.normalize_url(str(gateway_update.url)) != gateway.url
# tools/resoures/prompts are need to be re-fetched not only if URL changed , in case any update like authentication and visibility changed
# url_changed = gateway_update.url is not None and self.normalize_url(str(gateway_update.url)) != gateway.url

# Update fields if provided
if gateway_update.name is not None:
Expand Down Expand Up @@ -1491,96 +1497,96 @@ async def update_gateway(
gateway.auth_value = decoded_auth

# Try to reinitialize connection if URL actually changed
if url_changed:
# Initialize empty lists in case initialization fails
tools_to_add = []
resources_to_add = []
prompts_to_add = []

try:
ca_certificate = getattr(gateway, "ca_certificate", None)
capabilities, tools, resources, prompts = await self._initialize_gateway(
gateway.url, gateway.auth_value, gateway.transport, gateway.auth_type, gateway.oauth_config, ca_certificate
)
new_tool_names = [tool.name for tool in tools]
new_resource_uris = [resource.uri for resource in resources]
new_prompt_names = [prompt.name for prompt in prompts]

if gateway_update.one_time_auth:
# For one-time auth, clear auth_type and auth_value after initialization
gateway.auth_type = "one_time_auth"
gateway.auth_value = None
gateway.oauth_config = None

# Update tools using helper method
tools_to_add = self._update_or_create_tools(db, tools, gateway, "update")

# Update resources using helper method
resources_to_add = self._update_or_create_resources(db, resources, gateway, "update")

# Update prompts using helper method
prompts_to_add = self._update_or_create_prompts(db, prompts, gateway, "update")
# if url_changed:
# Initialize empty lists in case initialization fails
tools_to_add = []
resources_to_add = []
prompts_to_add = []

# Log newly added items
items_added = len(tools_to_add) + len(resources_to_add) + len(prompts_to_add)
if items_added > 0:
if tools_to_add:
logger.info(f"Added {len(tools_to_add)} new tools during gateway update")
if resources_to_add:
logger.info(f"Added {len(resources_to_add)} new resources during gateway update")
if prompts_to_add:
logger.info(f"Added {len(prompts_to_add)} new prompts during gateway update")
logger.info(f"Total {items_added} new items added during gateway update")

# Count items before cleanup for logging

# Delete tools that are no longer available from the gateway
stale_tools = [tool for tool in gateway.tools if tool.original_name not in new_tool_names]
for tool in stale_tools:
db.delete(tool)

# Delete resources that are no longer available from the gateway
stale_resources = [resource for resource in gateway.resources if resource.uri not in new_resource_uris]
for resource in stale_resources:
db.delete(resource)

# Delete prompts that are no longer available from the gateway
stale_prompts = [prompt for prompt in gateway.prompts if prompt.name not in new_prompt_names]
for prompt in stale_prompts:
db.delete(prompt)
try:
ca_certificate = getattr(gateway, "ca_certificate", None)
capabilities, tools, resources, prompts = await self._initialize_gateway(
gateway.url, gateway.auth_value, gateway.transport, gateway.auth_type, gateway.oauth_config, ca_certificate
)
new_tool_names = [tool.name for tool in tools]
new_resource_uris = [resource.uri for resource in resources]
new_prompt_names = [prompt.name for prompt in prompts]

gateway.capabilities = capabilities
gateway.tools = [tool for tool in gateway.tools if tool.original_name in new_tool_names] # keep only still-valid rows
gateway.resources = [resource for resource in gateway.resources if resource.uri in new_resource_uris] # keep only still-valid rows
gateway.prompts = [prompt for prompt in gateway.prompts if prompt.name in new_prompt_names] # keep only still-valid rows
if gateway_update.one_time_auth:
# For one-time auth, clear auth_type and auth_value after initialization
gateway.auth_type = "one_time_auth"
gateway.auth_value = None
gateway.oauth_config = None

# Log cleanup results
tools_removed = len(stale_tools)
resources_removed = len(stale_resources)
prompts_removed = len(stale_prompts)
# Update tools using helper method
tools_to_add = self._update_or_create_tools(db, tools, gateway, "update")

if tools_removed > 0:
logger.info(f"Removed {tools_removed} tools no longer available during gateway update")
if resources_removed > 0:
logger.info(f"Removed {resources_removed} resources no longer available during gateway update")
if prompts_removed > 0:
logger.info(f"Removed {prompts_removed} prompts no longer available during gateway update")
# Update resources using helper method
resources_to_add = self._update_or_create_resources(db, resources, gateway, "update")

gateway.last_seen = datetime.now(timezone.utc)
# Update prompts using helper method
prompts_to_add = self._update_or_create_prompts(db, prompts, gateway, "update")

# Add new items to database session
# Log newly added items
items_added = len(tools_to_add) + len(resources_to_add) + len(prompts_to_add)
if items_added > 0:
if tools_to_add:
db.add_all(tools_to_add)
logger.info(f"Added {len(tools_to_add)} new tools during gateway update")
if resources_to_add:
db.add_all(resources_to_add)
logger.info(f"Added {len(resources_to_add)} new resources during gateway update")
if prompts_to_add:
db.add_all(prompts_to_add)

# Update tracking with new URL
self._active_gateways.discard(gateway.url)
self._active_gateways.add(gateway.url)
except Exception as e:
logger.warning(f"Failed to initialize updated gateway: {e}")
logger.info(f"Added {len(prompts_to_add)} new prompts during gateway update")
logger.info(f"Total {items_added} new items added during gateway update")

# Count items before cleanup for logging

# Delete tools that are no longer available from the gateway
stale_tools = [tool for tool in gateway.tools if tool.original_name not in new_tool_names]
for tool in stale_tools:
db.delete(tool)

# Delete resources that are no longer available from the gateway
stale_resources = [resource for resource in gateway.resources if resource.uri not in new_resource_uris]
for resource in stale_resources:
db.delete(resource)

# Delete prompts that are no longer available from the gateway
stale_prompts = [prompt for prompt in gateway.prompts if prompt.name not in new_prompt_names]
for prompt in stale_prompts:
db.delete(prompt)

gateway.capabilities = capabilities
gateway.tools = [tool for tool in gateway.tools if tool.original_name in new_tool_names] # keep only still-valid rows
gateway.resources = [resource for resource in gateway.resources if resource.uri in new_resource_uris] # keep only still-valid rows
gateway.prompts = [prompt for prompt in gateway.prompts if prompt.name in new_prompt_names] # keep only still-valid rows

# Log cleanup results
tools_removed = len(stale_tools)
resources_removed = len(stale_resources)
prompts_removed = len(stale_prompts)

if tools_removed > 0:
logger.info(f"Removed {tools_removed} tools no longer available during gateway update")
if resources_removed > 0:
logger.info(f"Removed {resources_removed} resources no longer available during gateway update")
if prompts_removed > 0:
logger.info(f"Removed {prompts_removed} prompts no longer available during gateway update")

gateway.last_seen = datetime.now(timezone.utc)

# Add new items to database session
if tools_to_add:
db.add_all(tools_to_add)
if resources_to_add:
db.add_all(resources_to_add)
if prompts_to_add:
db.add_all(prompts_to_add)

# Update tracking with new URL
self._active_gateways.discard(gateway.url)
self._active_gateways.add(gateway.url)
except Exception as e:
logger.warning(f"Failed to initialize updated gateway: {e}")

# Update tags if provided
if gateway_update.tags is not None:
Expand Down Expand Up @@ -2998,7 +3004,6 @@ def _update_or_create_tools(self, db: Session, tools: List[Any], gateway: DbGate
try:
# Check if tool already exists for this gateway
existing_tool = db.execute(select(DbTool).where(DbTool.original_name == tool.name).where(DbTool.gateway_id == gateway.id)).scalar_one_or_none()

if existing_tool:
# Update existing tool if there are changes
fields_to_update = False
Expand All @@ -3016,7 +3021,6 @@ def _update_or_create_tools(self, db: Session, tools: List[Any], gateway: DbGate

if basic_fields_changed or schema_fields_changed or auth_fields_changed:
fields_to_update = True

if fields_to_update:
existing_tool.url = gateway.url
existing_tool.description = tool.description
Expand Down
13 changes: 8 additions & 5 deletions mcpgateway/services/server_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ def _assemble_associated_items(
resources: Optional[List[str]],
prompts: Optional[List[str]],
a2a_agents: Optional[List[str]] = None,
gateways: Optional[List[str]] = None,
) -> Dict[str, Any]:
"""
Assemble the associated items dictionary from the separate fields.
Expand All @@ -273,37 +274,39 @@ def _assemble_associated_items(
resources: List of resource IDs.
prompts: List of prompt IDs.
a2a_agents: List of A2A agent IDs.
gateways: List of gateway IDs.

Returns:
A dictionary with keys "tools", "resources", "prompts", and "a2a_agents".
A dictionary with keys "tools", "resources", "prompts", "a2a_agents", and "gateways".

Examples:
>>> service = ServerService()
>>> # Test with all None values
>>> result = service._assemble_associated_items(None, None, None)
>>> result
{'tools': [], 'resources': [], 'prompts': [], 'a2a_agents': []}
{'tools': [], 'resources': [], 'prompts': [], 'a2a_agents': [], 'gateways': []}

>>> # Test with empty lists
>>> result = service._assemble_associated_items([], [], [])
>>> result
{'tools': [], 'resources': [], 'prompts': [], 'a2a_agents': []}
{'tools': [], 'resources': [], 'prompts': [], 'a2a_agents': [], 'gateways': []}

>>> # Test with actual values
>>> result = service._assemble_associated_items(['tool1', 'tool2'], ['res1'], ['prompt1'])
>>> result
{'tools': ['tool1', 'tool2'], 'resources': ['res1'], 'prompts': ['prompt1'], 'a2a_agents': []}
{'tools': ['tool1', 'tool2'], 'resources': ['res1'], 'prompts': ['prompt1'], 'a2a_agents': [], 'gateways': []}

>>> # Test with mixed None and values
>>> result = service._assemble_associated_items(['tool1'], None, ['prompt1'])
>>> result
{'tools': ['tool1'], 'resources': [], 'prompts': ['prompt1'], 'a2a_agents': []}
{'tools': ['tool1'], 'resources': [], 'prompts': ['prompt1'], 'a2a_agents': [], 'gateways': []}
"""
return {
"tools": tools or [],
"resources": resources or [],
"prompts": prompts or [],
"a2a_agents": a2a_agents or [],
"gateways": gateways or [],
}

def _get_team_name(self, db: Session, team_id: Optional[str]) -> Optional[str]:
Expand Down
Loading
Loading