Skip to content

Commit 561f3bf

Browse files
authored
Merge pull request #1271 from BudEcosystem/fix/tool_name_prefix
Fix/tool name prefix
2 parents 98dfef6 + bc137d3 commit 561f3bf

File tree

4 files changed

+87
-6
lines changed

4 files changed

+87
-6
lines changed

services/budapp/budapp/prompt_ops/schemas.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,9 @@ class MCPToolConfig(BaseModel):
652652
gateway_config: Dict[str, str] = Field(
653653
default_factory=dict, description="Gateway configuration with connector_id as key and gateway_id as value"
654654
)
655+
gateway_slugs: Dict[str, str] = Field(
656+
default_factory=dict, description="Gateway slugs with connector_id as key and gateway_slug as value"
657+
)
655658
server_config: Dict[str, List[str]] = Field(
656659
default_factory=dict, description="Server configuration with connector_id as key and list of tool IDs as value"
657660
)

services/budapp/budapp/prompt_ops/services.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,22 +1406,28 @@ async def register_connector_for_prompt(
14061406
name=gateway_name, url=connector.url, transport=transport, visibility="public", auth_config=auth_config
14071407
)
14081408

1409+
gateway_id = gateway_response.get("id", gateway_response.get("gateway_id"))
1410+
gateway_slug = gateway_response.get("slug")
1411+
14091412
logger.debug(
14101413
f"Successfully created gateway for connector {connector_id} and prompt {budprompt_id}",
1411-
gateway_id=gateway_response.get("id", gateway_response.get("gateway_id")),
1414+
gateway_id=gateway_id,
1415+
gateway_slug=gateway_slug,
14121416
)
14131417

14141418
# Create GatewayResponse object
14151419
gateway = GatewayResponse(
1416-
gateway_id=gateway_response.get("id", gateway_response.get("gateway_id")),
1420+
gateway_id=gateway_id,
14171421
name=gateway_name,
14181422
url=connector.url,
14191423
transport="SSE",
14201424
visibility="public",
14211425
)
14221426

14231427
# Store MCP tool configuration in Redis via budprompt service
1424-
await self._store_mcp_tool_config(budprompt_id, connector_id, gateway.gateway_id, version, permanent)
1428+
await self._store_mcp_tool_config(
1429+
budprompt_id, connector_id, gateway.gateway_id, gateway_slug, version, permanent
1430+
)
14251431

14261432
# Update PromptVersion metadata with gateway_id (if prompt and version exist in DB)
14271433
try:
@@ -1760,6 +1766,10 @@ async def disconnect_connector_from_prompt(
17601766
# Step 5: Update gateway_config - remove connector
17611767
del gateway_config[connector_id]
17621768

1769+
# Step 5b: Update gateway_slugs - remove connector's slug
1770+
gateway_slugs = mcp_tool.get("gateway_slugs", {})
1771+
gateway_slugs.pop(connector_id, None)
1772+
17631773
# Step 6: Update server_config - remove connector's tools
17641774
server_config.pop(connector_id, None)
17651775

@@ -1794,6 +1804,7 @@ async def disconnect_connector_from_prompt(
17941804
else:
17951805
# Update MCP tool config (connectors still remain)
17961806
mcp_tool["gateway_config"] = gateway_config
1807+
mcp_tool["gateway_slugs"] = gateway_slugs
17971808
mcp_tool["server_config"] = server_config
17981809
mcp_tool["allowed_tools"] = updated_allowed_tools
17991810
mcp_tool["allowed_tool_names"] = updated_allowed_tool_names
@@ -1930,6 +1941,7 @@ async def _store_mcp_tool_config(
19301941
budprompt_id: str,
19311942
connector_id: str,
19321943
gateway_id: str,
1944+
gateway_slug: Optional[str] = None,
19331945
version: Optional[int] = None,
19341946
permanent: bool = False,
19351947
) -> None:
@@ -1939,13 +1951,15 @@ async def _store_mcp_tool_config(
19391951
budprompt_id: The bud prompt ID (can be UUID or draft prompt ID)
19401952
connector_id: The connector ID
19411953
gateway_id: The gateway ID from MCP Foundry
1954+
gateway_slug: The gateway slug from MCP Foundry (used for tool name shortening)
19421955
version: Optional version to update. If None, updates default version
19431956
permanent: Store configuration permanently without expiration
19441957
19451958
Raises:
19461959
ClientException: If storing configuration fails
19471960
"""
19481961
# 1. Create MCPToolConfig using Pydantic schema
1962+
gateway_slugs = {connector_id: gateway_slug} if gateway_slug else {}
19491963
mcp_tool = MCPToolConfig(
19501964
type="mcp",
19511965
server_label=None,
@@ -1955,6 +1969,7 @@ async def _store_mcp_tool_config(
19551969
allowed_tools=[],
19561970
connector_id=None, # Set to None as requested
19571971
gateway_config={connector_id: gateway_id},
1972+
gateway_slugs=gateway_slugs,
19581973
)
19591974
mcp_tool_dict = mcp_tool.model_dump(exclude_none=True)
19601975

@@ -2011,6 +2026,12 @@ async def _store_mcp_tool_config(
20112026
gateway_config[connector_id] = gateway_id
20122027
existing_mcp_tool["gateway_config"] = gateway_config
20132028

2029+
# Also merge gateway_slugs for tool name shortening
2030+
gateway_slugs_dict = existing_mcp_tool.get("gateway_slugs", {})
2031+
if gateway_slug:
2032+
gateway_slugs_dict[connector_id] = gateway_slug
2033+
existing_mcp_tool["gateway_slugs"] = gateway_slugs_dict
2034+
20142035
# Also update server_config to maintain consistency
20152036
server_config = existing_mcp_tool.get("server_config", {})
20162037
# Note: server_config is updated separately when tools are added

services/budprompt/budprompt/executors/v4/tool_loaders.py

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,19 @@ def __init__(self):
5454
self.base_url = app_settings.mcp_foundry_base_url
5555
self.api_key = app_settings.mcp_foundry_api_key
5656

57-
async def load_tools(self, tool_config: MCPToolConfig) -> Optional[MCPServerStreamableHTTP]:
58-
"""Load MCP tools from configuration.
57+
async def load_tools(self, tool_config: MCPToolConfig) -> Optional[Any]:
58+
"""Load MCP tools from configuration with optional name shortening.
59+
60+
When gateway_slugs are provided, tool names are shortened by stripping
61+
the gateway prefix. This helps with:
62+
1. OpenAI's 64-character limit on function/tool names
63+
2. Improved accuracy in smaller LLMs with cleaner tool names
5964
6065
Args:
6166
tool_config: MCP tool configuration
6267
6368
Returns:
64-
MCPServerStreamableHTTP instance or None if server_url is missing
69+
MCPServerStreamableHTTP instance (possibly renamed) or None if server_url is missing
6570
"""
6671
# Only create toolset if server_url is present
6772
if not tool_config.server_url:
@@ -80,6 +85,37 @@ async def load_tools(self, tool_config: MCPToolConfig) -> Optional[MCPServerStre
8085
# Create MCPServerStreamableHTTP instance
8186
mcp_server = MCPServerStreamableHTTP(url=mcp_url, headers=headers if headers else None)
8287

88+
# Get all gateway slugs (multiple connectors = multiple slugs)
89+
gateway_slugs = self._get_gateway_slugs(tool_config)
90+
91+
if gateway_slugs:
92+
# Fetch tool list to get original names
93+
tool_list = await self.get_tool_list(mcp_server, tool_config.server_label or "unknown")
94+
if tool_list and tool_list.get("tools"):
95+
original_names = [tool.name for tool in tool_list["tools"]]
96+
97+
# Generate mapping: short_name -> original_name
98+
# Try each slug to find matching prefix
99+
name_map = {}
100+
for original in original_names:
101+
short = original # Default: keep original if no prefix matches
102+
for slug in gateway_slugs:
103+
prefix = f"{slug}-"
104+
if original.startswith(prefix):
105+
short = original[len(prefix) :]
106+
break # Found matching prefix, stop searching
107+
name_map[short] = original
108+
109+
# Update allowed_tool_names with SHORT names
110+
tool_config.allowed_tool_names = list(name_map.keys())
111+
112+
logger.info(
113+
f"Stripped gateway prefixes from {len(name_map)} tools "
114+
f"for server '{tool_config.server_label}' using {len(gateway_slugs)} slug(s)"
115+
)
116+
117+
return mcp_server.renamed(name_map)
118+
83119
logger.debug(
84120
f"Loaded MCP tool '{tool_config.server_label}' from {mcp_url} "
85121
f"with {len(tool_config.allowed_tools)} allowed tools"
@@ -91,6 +127,24 @@ async def load_tools(self, tool_config: MCPToolConfig) -> Optional[MCPServerStre
91127
logger.error(f"Failed to load MCP tool '{tool_config.server_label}': {str(e)}")
92128
return None
93129

130+
def _get_gateway_slugs(self, tool_config: MCPToolConfig) -> List[str]:
131+
"""Extract all gateway slugs from tool config.
132+
133+
When multiple connectors are registered, gateway_slugs contains:
134+
{connector1: slug1, connector2: slug2, ...}
135+
136+
Returns all slugs so we can strip any matching prefix.
137+
138+
Args:
139+
tool_config: MCP tool configuration
140+
141+
Returns:
142+
List of gateway slugs
143+
"""
144+
if tool_config.gateway_slugs:
145+
return list(tool_config.gateway_slugs.values())
146+
return []
147+
94148
async def get_tool_list(self, mcp_server: MCPServerStreamableHTTP, server_label: str) -> Optional[Dict]:
95149
"""Fetch the list of available tools from an MCP server.
96150

services/budprompt/budprompt/prompt/schemas.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ class MCPToolConfig(BaseModel):
129129
gateway_config: Dict[str, str] = Field(
130130
default_factory=dict, description="Gateway configuration with connector_id as key and gateway_id as value"
131131
)
132+
gateway_slugs: Dict[str, str] = Field(
133+
default_factory=dict, description="Gateway slugs with connector_id as key and gateway_slug as value"
134+
)
132135
server_config: Dict[str, List[str]] = Field(
133136
default_factory=dict, description="Server configuration with connector_id as key and list of tool IDs as value"
134137
)

0 commit comments

Comments
 (0)