@@ -57,6 +57,15 @@ async def list_tools() -> list[Tool]:
5757 },
5858 "required" : ["name_query" ]
5959 }
60+ ),
61+ # NEW TOOL ADDED HERE
62+ Tool (
63+ name = "list_organization_skills" ,
64+ description = "Retrieves a full list of all available skills/competences defined in the organization." ,
65+ inputSchema = {
66+ "type" : "object" ,
67+ "properties" : {}, # No arguments needed
68+ }
6069 )
6170 ]
6271
@@ -66,6 +75,11 @@ async def call_tool(name: str, arguments: dict) -> list[TextContent | ImageConte
6675 return [TextContent (type = "text" , text = find_experts_logic (arguments ["skill_name" ]))]
6776 if name == "get_employee_competence_profile" :
6877 return [TextContent (type = "text" , text = profile_logic (arguments ["name_query" ]))]
78+
79+ # NEW LOGIC HANDLER
80+ if name == "list_organization_skills" :
81+ return [TextContent (type = "text" , text = list_skills_logic ())]
82+
6983 raise ValueError (f"Unknown tool: { name } " )
7084
7185# --- Helper Functions ---
@@ -124,42 +138,66 @@ def profile_logic(name_query: str) -> str:
124138
125139 return "\n \n " .join (results ) if results else f"No employee found for '{ name_query } '."
126140
141+ # NEW LOGIC FUNCTION
142+ def list_skills_logic () -> str :
143+ try :
144+ url = f"{ BASE_URL } /v1/skill"
145+ response = requests .get (url , headers = get_headers (), timeout = 15 )
146+ response .raise_for_status ()
147+ skills = response .json ()
148+ except Exception as e :
149+ return f"Error fetching skills: { str (e )} "
150+
151+ if not skills :
152+ return "No skills defined in the library."
153+
154+ # Group skills by category for better readability
155+ categories = {}
156+ for s in skills :
157+ # Default to "Other" if category is missing/null
158+ cat = s .get ('category' ) or "Uncategorized"
159+ if cat not in categories :
160+ categories [cat ] = []
161+ categories [cat ].append (s .get ('name' , 'Unnamed Skill' ))
162+
163+ output = ["**Organization Skill Library**\n " ]
164+
165+ # Sort categories alphabetically
166+ for cat in sorted (categories .keys ()):
167+ skill_names = sorted (categories [cat ])
168+ # Format: "### Category Name \n - Skill 1, Skill 2..."
169+ output .append (f"### { cat } " )
170+ output .append (", " .join (skill_names ))
171+ output .append ("" ) # Empty line for spacing
172+
173+ return "\n " .join (output )
174+
127175# --- 3. Transport Layer (Raw ASGI) ---
128176
129177sse_transport = SseServerTransport ("/mcp" )
130178
131179class MCPHandler :
132- """
133- A Raw ASGI Handler.
134- This class bypasses Starlette's Request/Response lifecycle entirely.
135- It passes the raw 'send' channel to the MCP SDK, allowing the SDK
136- to write the response headers and body directly without conflict.
137- """
138180 async def __call__ (self , scope , receive , send ):
139181 if scope ["type" ] != "http" :
140182 return
141183
142184 if scope ["method" ] == "POST" :
143- # The SDK handles reading the body and sending the '202 Accepted' response.
144185 await sse_transport .handle_post_message (scope , receive , send )
145186
146187 elif scope ["method" ] == "GET" :
147- # The SDK handles the SSE handshake and streaming.
148188 async with sse_transport .connect_sse (scope , receive , send ) as streams :
149189 await server .run (streams [0 ], streams [1 ], server .create_initialization_options ())
150190
151191 else :
152- # Manual 405 Method Not Allowed
153192 response = Response ("Method Not Allowed" , status_code = 405 )
154193 await response (scope , receive , send )
155194
156195mcp_asgi_app = MCPHandler ()
157196
158197routes = [
159- # Starlette detects `mcp_asgi_app` is an ASGI app (has __call__) and treats it as a raw endpoint.
160198 Route ("/mcp" , endpoint = mcp_asgi_app , methods = ["GET" , "POST" ]),
161- Route ("/sse" , endpoint = mcp_asgi_app , methods = ["GET" ]), # Deprecated alias
162- Route ("/messages" , endpoint = mcp_asgi_app , methods = ["POST" ]), # Alias
199+ Route ("/sse" , endpoint = mcp_asgi_app , methods = ["GET" ]),
200+ Route ("/messages" , endpoint = mcp_asgi_app , methods = ["POST" ]),
163201 Route ("/health" , endpoint = lambda r : Response ("OK" ))
164202]
165203
0 commit comments