Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-mcp

Model Context Protocol server for Pudu language documentation and compiler tools

0.1.1Apache-2.01

InstallClose

Registry.pudu

Pudu91 lines3.8 KB

GitHub ↗
1/** @App.Tools.Registry.Router — lists tools and routes tool calls */2module PuduLangMcp.App.Tools.Registry34import Std.Json as Json5import Std.Map as Map6import PuduLangMcp.App.Context as Context7import PuduLangMcp.App.Tools.Compiler as Compiler8import PuduLangMcp.App.Tools.Docs as Docs9import PuduLangMcp.App.Tools.Language as Language10import PuduLangMcp.App.Tools.Reference as Reference11import PuduLangMcp.App.Tools.Status as Status12import PuduLangMcp.Constants.Protocol as Protocol13import PuduLangMcp.Constants.Server as Server14import PuduLangMcp.Domain.Catalog.Arguments as Arguments15import PuduLangMcp.Domain.Catalog.ToolSpec as ToolSpec16import PuduLangMcp.Domain.Catalog.Tools as Tools17import PuduLangMcp.Domain.Protocol.Pagination as Pagination18import PuduLangMcp.Domain.Rpc.Reply as Reply19import PuduLangMcp.Errors.RpcError as RpcError20import PuduLangMcp.Errors.ToolError as ToolError21import PuduLangMcp.Utils.JsonAccess as Access2223/// Every tool's handler, by tool name.24export fn handlers() -> Map[Str, fn(&Context.Context, &Arguments.Args) -> Result[Str, ToolError.ToolFailure]] {25  mapOf([26      ("pudu_docs_search", Docs.search),27      ("pudu_docs_read", Docs.read),28      ("pudu_reference_search", Reference.search),29      ("pudu_module_reference", Reference.moduleTool),30      ("pudu_check", Compiler.check),31      ("pudu_format", Compiler.format),32      ("pudu_lint", Compiler.lint),33      ("pudu_run", Compiler.run),34      ("pudu_test", Compiler.test),35      ("pudu_hover", Language.hover),36      ("pudu_definition", Language.definition),37      ("pudu_references", Language.references),38      ("pudu_completion", Language.completion),39      ("pudu_signature_help", Language.signatureHelp),40      ("pudu_code_actions", Language.codeActions),41      ("pudu_rename_preview", Language.renamePreview),42      ("pudu_document_symbols", Language.documentSymbols),43      ("pudu_workspace_symbols", Language.workspaceSymbols),44      ("pudu_toolchain", Status.toolchain)45    ])46}4748/// Answers one page of the tool catalogue.49export fn list(context: &Context.Context, params: &Json.Json) -> Result[Json.Json, RpcError.ProtocolError] {50  let cursor = Pagination.cursorOf(params) ?51  let paged = Pagination.page(&Tools.all(), &cursor, Server.PAGE_SIZE) ?52  var fields = [("tools", Json.list(&paged[0].map(|spec: ToolSpec.ToolSpec| ToolSpec.toJson(&spec))))]53  if let Some(next) = paged[1] { fields = fields.push(("nextCursor", Json.Text(next))) }54  Ok(Reply.complete(&fields, &Reply.Cached(Server.LIST_TTL_MS, Protocol.CACHE_PUBLIC)))55}5657/// Answers one tool call: its result text, or a tool error the model can act on.58export fn call(context: &Context.Context, params: &Json.Json) -> Result[Json.Json, RpcError.ProtocolError] {59  let name = match Access.member(params, "name") {60    case Some(Json.Text(given)) => given61    case _ => { return Err(RpcError.InvalidParams("name must be a string")) }62  }63  let spec = match Tools.find(name) {64    case Some(found) => found65    case None => { return Err(RpcError.InvalidParams("Unknown tool: " + name)) }66  }67  let handler = match Map.get(&handlers(), name) {68    case Some(found) => found69    case None => { return Err(RpcError.Internal("tool " + name + " has no handler")) }70  }71  let arguments = match Access.member(params, "arguments") {72    case Some(given) => given73    case None => Json.Null74  }75  match Arguments.validate(&spec, &arguments) {76    case Err(failure) => Ok(toolResult(ToolError.explain(&failure), true))77    case Ok(args) => match handler(context, &args) {78      case Ok(text) => Ok(toolResult(text, false))79      case Err(failure) => Ok(toolResult(ToolError.explain(&failure), true))80    }81  }82}8384/// A complete tool result carrying one text block.85export fn toolResult(text: Str, isError: Bool) -> Json.Json {86  Reply.complete(&[87      ("content", Json.list(&[Json.object(&[("type", Json.Text("text")), ("text", Json.Text(text))])])),88      ("isError", Json.Boolean(isError))89    ], &Reply.NoCache)90}91