An MCP server for Osprey
at main 74 lines 2.2 kB view raw
1from pydantic import BaseModel 2 3 4class UdfArgumentSpec(BaseModel): 5 name: str 6 type: str 7 default: str | None = None 8 doc: str | None = None 9 10 11class Udf(BaseModel): 12 name: str 13 return_type: str 14 argument_specs: list[UdfArgumentSpec] = [] 15 doc: str | None = None 16 category: str | None = None 17 18 def signature(self) -> str: 19 args = ", ".join( 20 f"{arg.name}: {arg.type}" + (f" = {arg.default}" if arg.default else "") 21 for arg in self.argument_specs 22 ) 23 return f"{self.name}({args}) -> {self.return_type}" 24 25 26class UdfCategory(BaseModel): 27 name: str | None = None 28 udfs: list[Udf] = [] 29 30 31class UdfCatalog(BaseModel): 32 udf_categories: list[UdfCategory] = [] 33 34 def all_udfs(self) -> list[Udf]: 35 return [udf for cat in self.udf_categories for udf in cat.udfs] 36 37 def find_udf(self, name: str) -> Udf | None: 38 name_lower = name.lower() 39 for udf in self.all_udfs(): 40 if udf.name.lower() == name_lower: 41 return udf 42 return None 43 44 def udfs_by_category(self, category: str) -> list[Udf]: 45 for cat in self.udf_categories: 46 if cat.name and cat.name.lower() == category.lower(): 47 return cat.udfs 48 return [] 49 50 def format_for_llm(self) -> str: 51 lines = ["# Available UDFs\n"] 52 53 for cat in self.udf_categories: 54 cat_name = cat.name or "Other" 55 lines.append(f"## {cat_name}\n") 56 57 for udf in cat.udfs: 58 lines.append(f"### {udf.name}") 59 lines.append("```") 60 lines.append(udf.signature()) 61 lines.append("```") 62 if udf.doc: 63 lines.append(udf.doc) 64 65 if udf.argument_specs: 66 lines.append("\n**Parameters:**") 67 for arg in udf.argument_specs: 68 arg_doc = arg.doc or arg.type 69 default = f" (default: {arg.default})" if arg.default else "" 70 lines.append(f"- `{arg.name}`: {arg_doc}{default}") 71 72 lines.append("") 73 74 return "\n".join(lines)