module Unison.MCP.Tools (tools) where

import Control.Monad.Except (ExceptT)
import Control.Monad.Reader
import Control.Monad.Trans.Except (runExceptT)
import Data.Aeson qualified as Aeson
import Data.ByteString.Lazy qualified as BL
import Data.Data (Proxy (..))
import Data.List.NonEmpty qualified as NEL
import Data.Text (Text)
import Data.Text qualified as Text
import Data.Text.Encoding qualified as Text
import Text.RawString.QQ (r)
import Unison.Cli.MonadUtils qualified as Cli
import Unison.Codebase qualified as Codebase
import Unison.Codebase.Branch qualified as Branch
import Unison.Codebase.Editor.HandleInput.InstallLib (handleInstallLib)
import Unison.Codebase.Editor.Input (Event (..), FindScope (..), Input (..))
import Unison.Codebase.Editor.Input qualified as Input
import Unison.Codebase.Path qualified as Path
import Unison.Codebase.ProjectPath
import Unison.Core.Project (ProjectBranchName (..), ProjectName (..))
import Unison.HashQualified qualified as HQ
import Unison.MCP.Cli (cliToMCP, handleInputMCP)
import Unison.MCP.Share.API (ReadmeResponse (..))
import Unison.MCP.Share.API qualified as Share
import Unison.MCP.Types
import Unison.MCP.Wrapper
import Unison.MCP.Wrapper qualified as MCPWrapper
import Unison.NameSegment qualified as NameSegment
import Unison.Prelude (readUtf8)
import Unison.Project (ProjectBranchNameOrLatestRelease (..))
import Unison.Syntax.NameSegment qualified as NameSegment
import Unison.Util.Relation qualified as R
import UnliftIO qualified

-- MCP errors are just returned to the agent as text.
type MCPError = Text

type EMCP = ExceptT MCPError MCP

tools :: [MCPWrapper.Tool MCP]
tools :: [Tool MCP]
tools =
  [ Tool MCP
installLibTool,
    Tool MCP
shareProjectSearchTool,
    Tool MCP
typecheckCodeTool,
    Tool MCP
docsTool,
    Tool MCP
shareProjectReadmeTool,
    Tool MCP
listProjectDefinitionsTool,
    Tool MCP
listProjectLibrariesTool,
    Tool MCP
listLibraryDefinitionsTool,
    Tool MCP
viewDefinitionsTool,
    Tool MCP
listLocalProjectsTool,
    Tool MCP
listProjectBranchesTool,
    Tool MCP
getCurrentProjectContextTool,
    Tool MCP
searchDefinitionsTool,
    Tool MCP
searchByTypeTool,
    Tool MCP
dependenciesTool,
    Tool MCP
dependentsTool
  ]

currentProjectContext :: (MonadIO m, MonadReader Env m) => m ProjectContext
currentProjectContext :: forall (m :: * -> *).
(MonadIO m, MonadReader Env m) =>
m ProjectContext
currentProjectContext = do
  Env {Codebase IO Symbol Ann
codebase :: Codebase IO Symbol Ann
$sel:codebase:Env :: Env -> Codebase IO Symbol Ann
codebase} <- m Env
forall r (m :: * -> *). MonadReader r m => m r
ask
  ProjectPath
pp <- IO ProjectPath -> m ProjectPath
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ProjectPath -> m ProjectPath)
-> IO ProjectPath -> m ProjectPath
forall a b. (a -> b) -> a -> b
$ Codebase IO Symbol Ann -> Transaction ProjectPath -> IO ProjectPath
forall (m :: * -> *) v a b.
MonadIO m =>
Codebase m v a -> Transaction b -> m b
Codebase.runTransaction Codebase IO Symbol Ann
codebase (Transaction ProjectPath -> IO ProjectPath)
-> Transaction ProjectPath -> IO ProjectPath
forall a b. (a -> b) -> a -> b
$ Transaction ProjectPath
HasCallStack => Transaction ProjectPath
Codebase.expectCurrentProjectPath
  ProjectContext -> m ProjectContext
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ProjectContext -> m ProjectContext)
-> ProjectContext -> m ProjectContext
forall a b. (a -> b) -> a -> b
$
    ProjectContext
      { $sel:projectName:ProjectContext :: ProjectName
projectName = ProjectPath
pp.project.name,
        $sel:branchName:ProjectContext :: ProjectBranchName
branchName = ProjectPath
pp.branch.name
      }

installLibTool :: Tool MCP
installLibTool :: Tool MCP
installLibTool =
  Tool
    { $sel:toolName:Tool :: Text
toolName = ToolKind -> Text
toToolName ToolKind
LibInstallTool,
      $sel:toolDescription:Tool :: Text
toolDescription = Text
"Install a library from Unison Share into the specified project.",
      $sel:toolAnnotations:Tool :: ToolAnnotations
toolAnnotations =
        ToolAnnotations
          { $sel:title:ToolAnnotations :: Maybe Text
title = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"Install Library",
            $sel:readOnlyHint:ToolAnnotations :: Maybe Bool
readOnlyHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False,
            $sel:destructiveHint:ToolAnnotations :: Maybe Bool
destructiveHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:idempotentHint:ToolAnnotations :: Maybe Bool
idempotentHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False,
            $sel:openWorldHint:ToolAnnotations :: Maybe Bool
openWorldHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True
          },
      $sel:toolArgType:Tool :: Proxy LibInstallToolArguments
toolArgType = Proxy LibInstallToolArguments
forall {k} (t :: k). Proxy t
Proxy,
      $sel:toolHandler:Tool :: LibInstallToolArguments -> MCP CallToolResult
toolHandler = \(LibInstallToolArguments {ProjectContext
projectContext :: ProjectContext
$sel:projectContext:LibInstallToolArguments :: LibInstallToolArguments -> ProjectContext
projectContext, Text
libProjectName :: Text
$sel:libProjectName:LibInstallToolArguments :: LibInstallToolArguments -> Text
libProjectName, Maybe Text
libBranchName :: Maybe Text
$sel:libBranchName:LibInstallToolArguments :: LibInstallToolArguments -> Maybe Text
libBranchName}) -> EMCP CallToolResult -> MCP CallToolResult
handleToolError (EMCP CallToolResult -> MCP CallToolResult)
-> EMCP CallToolResult -> MCP CallToolResult
forall a b. (a -> b) -> a -> b
$ do
        (Maybe ()
_r, CliOutput
output) <- ProjectContext -> Cli () -> ExceptT Text MCP (Maybe (), CliOutput)
forall a.
ProjectContext -> Cli a -> ExceptT Text MCP (Maybe a, CliOutput)
cliToMCP ProjectContext
projectContext (Cli () -> ExceptT Text MCP (Maybe (), CliOutput))
-> Cli () -> ExceptT Text MCP (Maybe (), CliOutput)
forall a b. (a -> b) -> a -> b
$ do
          Bool
-> ProjectAndBranch
     ProjectName (Maybe ProjectBranchNameOrLatestRelease)
-> Cli ()
handleInstallLib Bool
False (ProjectName
-> Maybe ProjectBranchNameOrLatestRelease
-> ProjectAndBranch
     ProjectName (Maybe ProjectBranchNameOrLatestRelease)
forall a b. a -> b -> ProjectAndBranch a b
ProjectAndBranch (Text -> ProjectName
UnsafeProjectName Text
libProjectName) (ProjectBranchName -> ProjectBranchNameOrLatestRelease
ProjectBranchNameOrLatestRelease'Name (ProjectBranchName -> ProjectBranchNameOrLatestRelease)
-> (Text -> ProjectBranchName)
-> Text
-> ProjectBranchNameOrLatestRelease
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ProjectBranchName
UnsafeProjectBranchName (Text -> ProjectBranchNameOrLatestRelease)
-> Maybe Text -> Maybe ProjectBranchNameOrLatestRelease
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Text
libBranchName))
        let outputJSON :: Text
outputJSON = ByteString -> Text
Text.decodeUtf8 (ByteString -> Text)
-> (ByteString -> ByteString) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.toStrict (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ CliOutput -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encode CliOutput
output
        CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
textToolResult Text
outputJSON
    }

shareProjectSearchTool :: Tool MCP
shareProjectSearchTool :: Tool MCP
shareProjectSearchTool =
  Tool
    { $sel:toolName:Tool :: Text
toolName = ToolKind -> Text
toToolName ToolKind
ShareProjectSearchTool,
      $sel:toolDescription:Tool :: Text
toolDescription = Text
"Search Unison Share for projects and libraries.",
      $sel:toolAnnotations:Tool :: ToolAnnotations
toolAnnotations =
        ToolAnnotations
          { $sel:title:ToolAnnotations :: Maybe Text
title = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"Share Project Search",
            $sel:readOnlyHint:ToolAnnotations :: Maybe Bool
readOnlyHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:destructiveHint:ToolAnnotations :: Maybe Bool
destructiveHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False,
            $sel:idempotentHint:ToolAnnotations :: Maybe Bool
idempotentHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:openWorldHint:ToolAnnotations :: Maybe Bool
openWorldHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True
          },
      $sel:toolArgType:Tool :: Proxy ShareProjectSearchToolArguments
toolArgType = Proxy ShareProjectSearchToolArguments
forall {k} (t :: k). Proxy t
Proxy,
      $sel:toolHandler:Tool :: ShareProjectSearchToolArguments -> MCP CallToolResult
toolHandler = \(ShareProjectSearchToolArguments {Text
query :: Text
$sel:query:ShareProjectSearchToolArguments :: ShareProjectSearchToolArguments -> Text
query}) -> do
        Env {AuthenticatedHttpClient
authenticatedHTTPClient :: AuthenticatedHttpClient
$sel:authenticatedHTTPClient:Env :: Env -> AuthenticatedHttpClient
authenticatedHTTPClient} <- MCP Env
forall r (m :: * -> *). MonadReader r m => m r
ask
        Either ClientError Value
result <- IO (Either ClientError Value) -> MCP (Either ClientError Value)
forall a. IO a -> MCP a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
UnliftIO.liftIO (IO (Either ClientError Value) -> MCP (Either ClientError Value))
-> IO (Either ClientError Value) -> MCP (Either ClientError Value)
forall a b. (a -> b) -> a -> b
$ AuthenticatedHttpClient -> Text -> IO (Either ClientError Value)
Share.shareSearch AuthenticatedHttpClient
authenticatedHTTPClient Text
query
        case Either ClientError Value
result of
          Right Value
searchResult -> do
            let outputJSON :: Text
outputJSON = ByteString -> Text
Text.decodeUtf8 (ByteString -> Text)
-> (ByteString -> ByteString) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.toStrict (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ Value -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encode Value
searchResult
            CallToolResult -> MCP CallToolResult
forall a. a -> MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> MCP CallToolResult)
-> CallToolResult -> MCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
textToolResult Text
outputJSON
          Left ClientError
err -> do
            let errorMsg :: Text
errorMsg = Text
"Error searching Unison Share: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
Text.pack (ClientError -> String
forall a. Show a => a -> String
show ClientError
err)
            CallToolResult -> MCP CallToolResult
forall a. a -> MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> MCP CallToolResult)
-> CallToolResult -> MCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
errorToolResult Text
errorMsg
    }

typecheckCodeTool :: Tool MCP
typecheckCodeTool :: Tool MCP
typecheckCodeTool =
  Tool
    { $sel:toolName:Tool :: Text
toolName = ToolKind -> Text
toToolName ToolKind
TypecheckCodeTool,
      $sel:toolDescription:Tool :: Text
toolDescription =
        Text
[r| Typecheck a code snippet within the context of a project. Only definitions which which are part of libraries or which have been previously added or updated will be available to reference within code.

          The result will indicate any errors and suggested fixes, or will indicate that the code typechecks and is ready to add or update.

          If you would like to test the behaviour of any pure functions, you may prefix a code snippet with an angle bracket.

          e.g.

          ```
          > 1 + 2
          ```

          Or

          ```
          > let
              isGreaterThan3 x = x > 3
              isGreaterThan3 4
          ```

          If you wish to write unit tests, you may do so like this:

          ```
          test> Nat.tests.additionIsCommutative = test.verify do
            Each.repeat 100
            n = Random.natIn 0 1000
            m = Random.natIn 0 1000
            ensureEqual (n + m) (m + n)
          ```
        |],
      $sel:toolAnnotations:Tool :: ToolAnnotations
toolAnnotations =
        ToolAnnotations
          { $sel:title:ToolAnnotations :: Maybe Text
title = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"Typecheck Code",
            $sel:readOnlyHint:ToolAnnotations :: Maybe Bool
readOnlyHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:destructiveHint:ToolAnnotations :: Maybe Bool
destructiveHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False,
            $sel:idempotentHint:ToolAnnotations :: Maybe Bool
idempotentHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:openWorldHint:ToolAnnotations :: Maybe Bool
openWorldHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
          },
      $sel:toolArgType:Tool :: Proxy TypecheckCodeToolArguments
toolArgType = Proxy TypecheckCodeToolArguments
forall {k} (t :: k). Proxy t
Proxy,
      $sel:toolHandler:Tool :: TypecheckCodeToolArguments -> MCP CallToolResult
toolHandler = \(TypecheckCodeToolArguments {Either String Text
code :: Either String Text
$sel:code:TypecheckCodeToolArguments :: TypecheckCodeToolArguments -> Either String Text
code, ProjectContext
projectContext :: ProjectContext
$sel:projectContext:TypecheckCodeToolArguments :: TypecheckCodeToolArguments -> ProjectContext
projectContext}) -> EMCP CallToolResult -> MCP CallToolResult
handleToolError do
        Text
source <- case Either String Text
code of
          Left String
filePath -> IO Text -> ExceptT Text MCP Text
forall a. IO a -> ExceptT Text MCP a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Text -> ExceptT Text MCP Text)
-> IO Text -> ExceptT Text MCP Text
forall a b. (a -> b) -> a -> b
$ String -> IO Text
readUtf8 String
filePath
          Right Text
codeSnippet -> Text -> ExceptT Text MCP Text
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Text
codeSnippet
        CliOutput
output <- ProjectContext
-> [Either Event Input] -> ExceptT Text MCP CliOutput
handleInputMCP ProjectContext
projectContext [Event -> Either Event Input
forall a b. a -> Either a b
Left (Event -> Either Event Input) -> Event -> Either Event Input
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Event
UnisonFileChanged Text
"scratch.u" Text
source]
        let outputJSON :: Text
outputJSON = ByteString -> Text
Text.decodeUtf8 (ByteString -> Text)
-> (ByteString -> ByteString) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.toStrict (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ CliOutput -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encode CliOutput
output
        CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
textToolResult Text
outputJSON
    }

docsTool :: Tool MCP
docsTool :: Tool MCP
docsTool =
  Tool
    { $sel:toolName:Tool :: Text
toolName = ToolKind -> Text
toToolName ToolKind
DocsTool,
      $sel:toolDescription:Tool :: Text
toolDescription = Text
"Fetch documentation for a definition in a local project.",
      $sel:toolAnnotations:Tool :: ToolAnnotations
toolAnnotations =
        ToolAnnotations
          { $sel:title:ToolAnnotations :: Maybe Text
title = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"Documentation",
            $sel:readOnlyHint:ToolAnnotations :: Maybe Bool
readOnlyHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:destructiveHint:ToolAnnotations :: Maybe Bool
destructiveHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False,
            $sel:idempotentHint:ToolAnnotations :: Maybe Bool
idempotentHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:openWorldHint:ToolAnnotations :: Maybe Bool
openWorldHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
          },
      $sel:toolArgType:Tool :: Proxy DocsToolArguments
toolArgType = Proxy DocsToolArguments
forall {k} (t :: k). Proxy t
Proxy,
      $sel:toolHandler:Tool :: DocsToolArguments -> MCP CallToolResult
toolHandler = \(DocsToolArguments {Name
name :: Name
$sel:name:DocsToolArguments :: DocsToolArguments -> Name
name, ProjectContext
projectContext :: ProjectContext
$sel:projectContext:DocsToolArguments :: DocsToolArguments -> ProjectContext
projectContext}) -> EMCP CallToolResult -> MCP CallToolResult
handleToolError (EMCP CallToolResult -> MCP CallToolResult)
-> EMCP CallToolResult -> MCP CallToolResult
forall a b. (a -> b) -> a -> b
$ do
        CliOutput
output <- ProjectContext
-> [Either Event Input] -> ExceptT Text MCP CliOutput
handleInputMCP ProjectContext
projectContext [Input -> Either Event Input
forall a b. b -> Either a b
Right (Input -> Either Event Input) -> Input -> Either Event Input
forall a b. (a -> b) -> a -> b
$ Name -> Input
DocToMarkdownI Name
name]
        let outputJSON :: Text
outputJSON = ByteString -> Text
Text.decodeUtf8 (ByteString -> Text)
-> (ByteString -> ByteString) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.toStrict (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ CliOutput -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encode CliOutput
output
        CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
textToolResult Text
outputJSON
    }

shareProjectReadmeTool :: Tool MCP
shareProjectReadmeTool :: Tool MCP
shareProjectReadmeTool =
  Tool
    { $sel:toolName:Tool :: Text
toolName = ToolKind -> Text
toToolName ToolKind
ShareProjectReadmeTool,
      $sel:toolDescription:Tool :: Text
toolDescription = Text
"Fetch the README for a project from Unison Share. Read the markdownReadMe value in the response.",
      $sel:toolAnnotations:Tool :: ToolAnnotations
toolAnnotations =
        ToolAnnotations
          { $sel:title:ToolAnnotations :: Maybe Text
title = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"Project README",
            $sel:readOnlyHint:ToolAnnotations :: Maybe Bool
readOnlyHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:destructiveHint:ToolAnnotations :: Maybe Bool
destructiveHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False,
            $sel:idempotentHint:ToolAnnotations :: Maybe Bool
idempotentHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:openWorldHint:ToolAnnotations :: Maybe Bool
openWorldHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True
          },
      $sel:toolArgType:Tool :: Proxy ShareProjectReadmeToolArguments
toolArgType = Proxy ShareProjectReadmeToolArguments
forall {k} (t :: k). Proxy t
Proxy,
      $sel:toolHandler:Tool :: ShareProjectReadmeToolArguments -> MCP CallToolResult
toolHandler = \(ShareProjectReadmeToolArguments {Text
projectName :: Text
$sel:projectName:ShareProjectReadmeToolArguments :: ShareProjectReadmeToolArguments -> Text
projectName, Text
projectOwnerHandle :: Text
$sel:projectOwnerHandle:ShareProjectReadmeToolArguments :: ShareProjectReadmeToolArguments -> Text
projectOwnerHandle}) -> EMCP CallToolResult -> MCP CallToolResult
handleToolError (EMCP CallToolResult -> MCP CallToolResult)
-> EMCP CallToolResult -> MCP CallToolResult
forall a b. (a -> b) -> a -> b
$ do
        Env {AuthenticatedHttpClient
$sel:authenticatedHTTPClient:Env :: Env -> AuthenticatedHttpClient
authenticatedHTTPClient :: AuthenticatedHttpClient
authenticatedHTTPClient} <- ExceptT Text MCP Env
forall r (m :: * -> *). MonadReader r m => m r
ask
        Either ClientError ReadmeResponse
result <- IO (Either ClientError ReadmeResponse)
-> ExceptT Text MCP (Either ClientError ReadmeResponse)
forall a. IO a -> ExceptT Text MCP a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
UnliftIO.liftIO (IO (Either ClientError ReadmeResponse)
 -> ExceptT Text MCP (Either ClientError ReadmeResponse))
-> IO (Either ClientError ReadmeResponse)
-> ExceptT Text MCP (Either ClientError ReadmeResponse)
forall a b. (a -> b) -> a -> b
$ AuthenticatedHttpClient
-> Text -> Text -> IO (Either ClientError ReadmeResponse)
Share.shareProjectReadme AuthenticatedHttpClient
authenticatedHTTPClient Text
projectOwnerHandle Text
projectName
        case Either ClientError ReadmeResponse
result of
          Right ReadmeResponse {Text
markdownReadMe :: Text
$sel:markdownReadMe:ReadmeResponse :: ReadmeResponse -> Text
markdownReadMe} -> do
            CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
textToolResult Text
markdownReadMe
          Left ClientError
err -> do
            let errorMsg :: Text
errorMsg = Text
"Error getting readme from Unison Share: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
Text.pack (ClientError -> String
forall a. Show a => a -> String
show ClientError
err)
            CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
errorToolResult Text
errorMsg
    }

listProjectDefinitionsTool :: Tool MCP
listProjectDefinitionsTool :: Tool MCP
listProjectDefinitionsTool =
  Tool
    { $sel:toolName:Tool :: Text
toolName = ToolKind -> Text
toToolName ToolKind
ListProjectDefinitionsTool,
      $sel:toolDescription:Tool :: Text
toolDescription = Text
"List all definitions in the provided project.",
      $sel:toolAnnotations:Tool :: ToolAnnotations
toolAnnotations =
        ToolAnnotations
          { $sel:title:ToolAnnotations :: Maybe Text
title = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"List Project Definitions",
            $sel:readOnlyHint:ToolAnnotations :: Maybe Bool
readOnlyHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:destructiveHint:ToolAnnotations :: Maybe Bool
destructiveHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False,
            $sel:idempotentHint:ToolAnnotations :: Maybe Bool
idempotentHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:openWorldHint:ToolAnnotations :: Maybe Bool
openWorldHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
          },
      $sel:toolArgType:Tool :: Proxy ProjectContextArgument
toolArgType = Proxy ProjectContextArgument
forall {k} (t :: k). Proxy t
Proxy,
      $sel:toolHandler:Tool :: ProjectContextArgument -> MCP CallToolResult
toolHandler = \(ProjectContextArgument ProjectContext
projectContext) -> EMCP CallToolResult -> MCP CallToolResult
handleToolError (EMCP CallToolResult -> MCP CallToolResult)
-> EMCP CallToolResult -> MCP CallToolResult
forall a b. (a -> b) -> a -> b
$ do
        CallToolResult
output <-
          ProjectContext
-> Cli (Branch0 IO)
-> ExceptT Text MCP (Maybe (Branch0 IO), CliOutput)
forall a.
ProjectContext -> Cli a -> ExceptT Text MCP (Maybe a, CliOutput)
cliToMCP ProjectContext
projectContext Cli (Branch0 IO)
Cli.getCurrentBranch0 ExceptT Text MCP (Maybe (Branch0 IO), CliOutput)
-> ((Maybe (Branch0 IO), CliOutput) -> EMCP CallToolResult)
-> EMCP CallToolResult
forall a b.
ExceptT Text MCP a
-> (a -> ExceptT Text MCP b) -> ExceptT Text MCP b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
            (Just Branch0 IO
b, CliOutput
_output) -> do
              let noLibBranch :: Branch0 IO
noLibBranch = Branch0 IO -> Branch0 IO
forall (m :: * -> *). Branch0 m -> Branch0 m
Branch.deleteLibdeps Branch0 IO
b
              if (Relation Referent Name -> Bool
forall a b. Relation a b -> Bool
R.null (Relation Referent Name -> Bool) -> Relation Referent Name -> Bool
forall a b. (a -> b) -> a -> b
$ Branch0 IO -> Relation Referent Name
forall (m :: * -> *). Branch0 m -> Relation Referent Name
Branch.deepTerms Branch0 IO
noLibBranch) Bool -> Bool -> Bool
&& (Relation TypeReference Name -> Bool
forall a b. Relation a b -> Bool
R.null (Relation TypeReference Name -> Bool)
-> Relation TypeReference Name -> Bool
forall a b. (a -> b) -> a -> b
$ Branch0 IO -> Relation TypeReference Name
forall (m :: * -> *). Branch0 m -> Relation TypeReference Name
Branch.deepTypes Branch0 IO
noLibBranch)
                then CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
textToolResult Text
"No definitions found in the project. There may be definitions within the project's installed libraries."
                else CliOutput -> CallToolResult
forall a. ToJSON a => a -> CallToolResult
jsonToolResult (CliOutput -> CallToolResult)
-> ExceptT Text MCP CliOutput -> EMCP CallToolResult
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ProjectContext
-> [Either Event Input] -> ExceptT Text MCP CliOutput
handleInputMCP ProjectContext
projectContext [Input -> Either Event Input
forall a b. b -> Either a b
Right (Input -> Either Event Input) -> Input -> Either Event Input
forall a b. (a -> b) -> a -> b
$ Bool -> FindScope -> [String] -> Input
Input.FindI Bool
False (Path' -> FindScope
FindLocal Path'
Path.Root') []]
            (Maybe (Branch0 IO), CliOutput)
_ -> CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> (Text -> CallToolResult) -> Text -> EMCP CallToolResult
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> CallToolResult
errorToolResult (Text -> EMCP CallToolResult) -> Text -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text
"No current branch found"
        let outputJSON :: Text
outputJSON = ByteString -> Text
Text.decodeUtf8 (ByteString -> Text)
-> (ByteString -> ByteString) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.toStrict (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ CallToolResult -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encode CallToolResult
output
        CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
textToolResult Text
outputJSON
    }

listProjectLibrariesTool :: Tool MCP
listProjectLibrariesTool :: Tool MCP
listProjectLibrariesTool =
  Tool
    { $sel:toolName:Tool :: Text
toolName = ToolKind -> Text
toToolName ToolKind
ListProjectLibrariesTool,
      $sel:toolDescription:Tool :: Text
toolDescription = Text
"List the all libraries in the provided project's lib namespace.",
      $sel:toolAnnotations:Tool :: ToolAnnotations
toolAnnotations =
        ToolAnnotations
          { $sel:title:ToolAnnotations :: Maybe Text
title = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"List Project Libraries",
            $sel:readOnlyHint:ToolAnnotations :: Maybe Bool
readOnlyHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:destructiveHint:ToolAnnotations :: Maybe Bool
destructiveHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False,
            $sel:idempotentHint:ToolAnnotations :: Maybe Bool
idempotentHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:openWorldHint:ToolAnnotations :: Maybe Bool
openWorldHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
          },
      $sel:toolArgType:Tool :: Proxy ProjectContextArgument
toolArgType = Proxy ProjectContextArgument
forall {k} (t :: k). Proxy t
Proxy,
      $sel:toolHandler:Tool :: ProjectContextArgument -> MCP CallToolResult
toolHandler = \(ProjectContextArgument ProjectContext
projectContext) -> EMCP CallToolResult -> MCP CallToolResult
handleToolError (EMCP CallToolResult -> MCP CallToolResult)
-> EMCP CallToolResult -> MCP CallToolResult
forall a b. (a -> b) -> a -> b
$ do
        let libPath :: Path'
libPath = Absolute -> Path'
Path.AbsolutePath' (Absolute -> Path') -> Absolute -> Path'
forall a b. (a -> b) -> a -> b
$ Path -> Absolute
Path.Absolute ([NameSegment] -> Path
Path.fromList [NameSegment
NameSegment.libSegment])
        CliOutput
output <- ProjectContext
-> [Either Event Input] -> ExceptT Text MCP CliOutput
handleInputMCP ProjectContext
projectContext [Input -> Either Event Input
forall a b. b -> Either a b
Right (Input -> Either Event Input) -> Input -> Either Event Input
forall a b. (a -> b) -> a -> b
$ Path' -> Input
Input.FindShallowI Path'
libPath]
        let outputJSON :: Text
outputJSON = ByteString -> Text
Text.decodeUtf8 (ByteString -> Text)
-> (ByteString -> ByteString) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.toStrict (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ CliOutput -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encode CliOutput
output
        CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
textToolResult Text
outputJSON
    }

listLibraryDefinitionsTool :: Tool MCP
listLibraryDefinitionsTool :: Tool MCP
listLibraryDefinitionsTool =
  Tool
    { $sel:toolName:Tool :: Text
toolName = ToolKind -> Text
toToolName ToolKind
ListLibraryDefinitionsTool,
      $sel:toolDescription:Tool :: Text
toolDescription = Text
"List all definitions in the specified library.",
      $sel:toolAnnotations:Tool :: ToolAnnotations
toolAnnotations =
        ToolAnnotations
          { $sel:title:ToolAnnotations :: Maybe Text
title = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"List Library Definitions",
            $sel:readOnlyHint:ToolAnnotations :: Maybe Bool
readOnlyHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:destructiveHint:ToolAnnotations :: Maybe Bool
destructiveHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False,
            $sel:idempotentHint:ToolAnnotations :: Maybe Bool
idempotentHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:openWorldHint:ToolAnnotations :: Maybe Bool
openWorldHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
          },
      $sel:toolArgType:Tool :: Proxy ListLibraryDefinitionsToolArguments
toolArgType = Proxy ListLibraryDefinitionsToolArguments
forall {k} (t :: k). Proxy t
Proxy,
      $sel:toolHandler:Tool :: ListLibraryDefinitionsToolArguments -> MCP CallToolResult
toolHandler = \(ListLibraryDefinitionsToolArguments {Text
libName :: Text
$sel:libName:ListLibraryDefinitionsToolArguments :: ListLibraryDefinitionsToolArguments -> Text
libName, ProjectContext
projectContext :: ProjectContext
$sel:projectContext:ListLibraryDefinitionsToolArguments :: ListLibraryDefinitionsToolArguments -> ProjectContext
projectContext}) -> EMCP CallToolResult -> MCP CallToolResult
handleToolError (EMCP CallToolResult -> MCP CallToolResult)
-> EMCP CallToolResult -> MCP CallToolResult
forall a b. (a -> b) -> a -> b
$ do
        let libPath :: Path'
libPath = Absolute -> Path'
Path.AbsolutePath' (Absolute -> Path') -> Absolute -> Path'
forall a b. (a -> b) -> a -> b
$ Path -> Absolute
Path.Absolute ([NameSegment] -> Path
Path.fromList [NameSegment
NameSegment.libSegment, Text -> NameSegment
NameSegment.unsafeParseText Text
libName])
        CliOutput
definitions <- ProjectContext
-> [Either Event Input] -> ExceptT Text MCP CliOutput
handleInputMCP ProjectContext
projectContext [Input -> Either Event Input
forall a b. b -> Either a b
Right (Input -> Either Event Input) -> Input -> Either Event Input
forall a b. (a -> b) -> a -> b
$ Bool -> FindScope -> [String] -> Input
Input.FindI Bool
False (Path' -> FindScope
FindLocal Path'
libPath) []]
        let outputJSON :: Text
outputJSON = ByteString -> Text
Text.decodeUtf8 (ByteString -> Text)
-> (ByteString -> ByteString) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.toStrict (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ CliOutput -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encode CliOutput
definitions
        CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
textToolResult Text
outputJSON
    }

viewDefinitionsTool :: Tool MCP
viewDefinitionsTool :: Tool MCP
viewDefinitionsTool =
  Tool
    { $sel:toolName:Tool :: Text
toolName = ToolKind -> Text
toToolName ToolKind
ViewDefinitionsTool,
      $sel:toolDescription:Tool :: Text
toolDescription = Text
"View the source code of the specified definitions. Definitions inside a library must be prefixed by their full library prefix, e.g. `lib.unison_base_1_0_0.data.List`",
      $sel:toolAnnotations:Tool :: ToolAnnotations
toolAnnotations =
        ToolAnnotations
          { $sel:title:ToolAnnotations :: Maybe Text
title = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"View Definitions",
            $sel:readOnlyHint:ToolAnnotations :: Maybe Bool
readOnlyHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:destructiveHint:ToolAnnotations :: Maybe Bool
destructiveHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False,
            $sel:idempotentHint:ToolAnnotations :: Maybe Bool
idempotentHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:openWorldHint:ToolAnnotations :: Maybe Bool
openWorldHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
          },
      $sel:toolArgType:Tool :: Proxy ViewDefinitionsToolArguments
toolArgType = Proxy ViewDefinitionsToolArguments
forall {k} (t :: k). Proxy t
Proxy,
      $sel:toolHandler:Tool :: ViewDefinitionsToolArguments -> MCP CallToolResult
toolHandler = \(ViewDefinitionsToolArguments {ProjectContext
projectContext :: ProjectContext
$sel:projectContext:ViewDefinitionsToolArguments :: ViewDefinitionsToolArguments -> ProjectContext
projectContext, [Name]
names :: [Name]
$sel:names:ViewDefinitionsToolArguments :: ViewDefinitionsToolArguments -> [Name]
names}) -> EMCP CallToolResult -> MCP CallToolResult
handleToolError (EMCP CallToolResult -> MCP CallToolResult)
-> EMCP CallToolResult -> MCP CallToolResult
forall a b. (a -> b) -> a -> b
$ do
        case [Name] -> Maybe (NonEmpty Name)
forall a. [a] -> Maybe (NonEmpty a)
NEL.nonEmpty [Name]
names of
          Maybe (NonEmpty Name)
Nothing ->
            CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
errorToolResult Text
"No names provided to view definitions"
          Just NonEmpty Name
nonEmptyNames -> do
            let names' :: NonEmpty (HashQualified Name)
names' = Name -> HashQualified Name
forall n. n -> HashQualified n
HQ.NameOnly (Name -> HashQualified Name)
-> NonEmpty Name -> NonEmpty (HashQualified Name)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty Name
nonEmptyNames
            CliOutput
definitions <- ProjectContext
-> [Either Event Input] -> ExceptT Text MCP CliOutput
handleInputMCP ProjectContext
projectContext [Input -> Either Event Input
forall a b. b -> Either a b
Right (Input -> Either Event Input) -> Input -> Either Event Input
forall a b. (a -> b) -> a -> b
$ OutputLocation
-> ShowDefinitionScope -> NonEmpty (HashQualified Name) -> Input
Input.ShowDefinitionI OutputLocation
Input.ConsoleLocation ShowDefinitionScope
Input.ShowDefinitionLocal NonEmpty (HashQualified Name)
names']
            let outputJSON :: Text
outputJSON = ByteString -> Text
Text.decodeUtf8 (ByteString -> Text)
-> (ByteString -> ByteString) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.toStrict (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ CliOutput -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encode CliOutput
definitions
            CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
textToolResult Text
outputJSON
    }

listLocalProjectsTool :: Tool MCP
listLocalProjectsTool :: Tool MCP
listLocalProjectsTool =
  Tool
    { $sel:toolName:Tool :: Text
toolName = ToolKind -> Text
toToolName ToolKind
ListLocalProjectsTool,
      $sel:toolDescription:Tool :: Text
toolDescription = Text
"List all local projects.",
      $sel:toolAnnotations:Tool :: ToolAnnotations
toolAnnotations =
        ToolAnnotations
          { $sel:title:ToolAnnotations :: Maybe Text
title = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"List Local Projects",
            $sel:readOnlyHint:ToolAnnotations :: Maybe Bool
readOnlyHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:destructiveHint:ToolAnnotations :: Maybe Bool
destructiveHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False,
            $sel:idempotentHint:ToolAnnotations :: Maybe Bool
idempotentHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:openWorldHint:ToolAnnotations :: Maybe Bool
openWorldHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
          },
      $sel:toolArgType:Tool :: Proxy ()
toolArgType = Proxy ()
forall {k} (t :: k). Proxy t
Proxy,
      $sel:toolHandler:Tool :: () -> MCP CallToolResult
toolHandler = \(()) -> EMCP CallToolResult -> MCP CallToolResult
handleToolError (EMCP CallToolResult -> MCP CallToolResult)
-> EMCP CallToolResult -> MCP CallToolResult
forall a b. (a -> b) -> a -> b
$ do
        ProjectContext
pc <- ExceptT Text MCP ProjectContext
forall (m :: * -> *).
(MonadIO m, MonadReader Env m) =>
m ProjectContext
currentProjectContext
        CliOutput
projects <- ProjectContext
-> [Either Event Input] -> ExceptT Text MCP CliOutput
handleInputMCP ProjectContext
pc [Input -> Either Event Input
forall a b. b -> Either a b
Right Input
Input.ProjectsI]
        let outputJSON :: Text
outputJSON = ByteString -> Text
Text.decodeUtf8 (ByteString -> Text)
-> (ByteString -> ByteString) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.toStrict (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ CliOutput -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encode CliOutput
projects
        CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
textToolResult Text
outputJSON
    }

listProjectBranchesTool :: Tool MCP
listProjectBranchesTool :: Tool MCP
listProjectBranchesTool =
  Tool
    { $sel:toolName:Tool :: Text
toolName = ToolKind -> Text
toToolName ToolKind
ListProjectBranchesTool,
      $sel:toolDescription:Tool :: Text
toolDescription = Text
"List all branches of a project.",
      $sel:toolAnnotations:Tool :: ToolAnnotations
toolAnnotations =
        ToolAnnotations
          { $sel:title:ToolAnnotations :: Maybe Text
title = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"List Project Branches",
            $sel:readOnlyHint:ToolAnnotations :: Maybe Bool
readOnlyHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:destructiveHint:ToolAnnotations :: Maybe Bool
destructiveHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False,
            $sel:idempotentHint:ToolAnnotations :: Maybe Bool
idempotentHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:openWorldHint:ToolAnnotations :: Maybe Bool
openWorldHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
          },
      $sel:toolArgType:Tool :: Proxy ProjectNameArgument
toolArgType = Proxy ProjectNameArgument
forall {k} (t :: k). Proxy t
Proxy,
      $sel:toolHandler:Tool :: ProjectNameArgument -> MCP CallToolResult
toolHandler = \(ProjectNameArgument {ProjectName
projectName :: ProjectName
$sel:projectName:ProjectNameArgument :: ProjectNameArgument -> ProjectName
projectName}) -> EMCP CallToolResult -> MCP CallToolResult
handleToolError (EMCP CallToolResult -> MCP CallToolResult)
-> EMCP CallToolResult -> MCP CallToolResult
forall a b. (a -> b) -> a -> b
$ do
        ProjectContext
projectContext <- ExceptT Text MCP ProjectContext
forall (m :: * -> *).
(MonadIO m, MonadReader Env m) =>
m ProjectContext
currentProjectContext
        CliOutput
branches <- ProjectContext
-> [Either Event Input] -> ExceptT Text MCP CliOutput
handleInputMCP ProjectContext
projectContext [Input -> Either Event Input
forall a b. b -> Either a b
Right (Input -> Either Event Input) -> Input -> Either Event Input
forall a b. (a -> b) -> a -> b
$ Maybe ProjectName -> Input
Input.BranchesI (ProjectName -> Maybe ProjectName
forall a. a -> Maybe a
Just ProjectName
projectName)]
        let outputJSON :: Text
outputJSON = ByteString -> Text
Text.decodeUtf8 (ByteString -> Text)
-> (ByteString -> ByteString) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.toStrict (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ CliOutput -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encode CliOutput
branches
        CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
textToolResult Text
outputJSON
    }

getCurrentProjectContextTool :: Tool MCP
getCurrentProjectContextTool :: Tool MCP
getCurrentProjectContextTool =
  Tool
    { $sel:toolName:Tool :: Text
toolName = ToolKind -> Text
toToolName ToolKind
GetCurrentProjectContextTool,
      $sel:toolDescription:Tool :: Text
toolDescription = Text
"Get the current project context.",
      $sel:toolAnnotations:Tool :: ToolAnnotations
toolAnnotations =
        ToolAnnotations
          { $sel:title:ToolAnnotations :: Maybe Text
title = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"Get Current Project Context",
            $sel:readOnlyHint:ToolAnnotations :: Maybe Bool
readOnlyHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:destructiveHint:ToolAnnotations :: Maybe Bool
destructiveHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False,
            $sel:idempotentHint:ToolAnnotations :: Maybe Bool
idempotentHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:openWorldHint:ToolAnnotations :: Maybe Bool
openWorldHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
          },
      $sel:toolArgType:Tool :: Proxy ()
toolArgType = Proxy ()
forall {k} (t :: k). Proxy t
Proxy,
      $sel:toolHandler:Tool :: () -> MCP CallToolResult
toolHandler = \() -> EMCP CallToolResult -> MCP CallToolResult
handleToolError (EMCP CallToolResult -> MCP CallToolResult)
-> EMCP CallToolResult -> MCP CallToolResult
forall a b. (a -> b) -> a -> b
$ do
        ProjectContext
projectContext <- ExceptT Text MCP ProjectContext
forall (m :: * -> *).
(MonadIO m, MonadReader Env m) =>
m ProjectContext
currentProjectContext
        let outputJSON :: Text
outputJSON = ByteString -> Text
Text.decodeUtf8 (ByteString -> Text)
-> (ByteString -> ByteString) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.toStrict (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ ProjectContext -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encode ProjectContext
projectContext
        CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
textToolResult Text
outputJSON
    }

searchDefinitionsTool :: Tool MCP
searchDefinitionsTool :: Tool MCP
searchDefinitionsTool =
  Tool
    { $sel:toolName:Tool :: Text
toolName = ToolKind -> Text
toToolName ToolKind
SearchDefinitionsTool,
      $sel:toolDescription:Tool :: Text
toolDescription = Text
"Search for definitions in the current project or its library dependencies by name.",
      $sel:toolAnnotations:Tool :: ToolAnnotations
toolAnnotations =
        ToolAnnotations
          { $sel:title:ToolAnnotations :: Maybe Text
title = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"Search Definitions By Name",
            $sel:readOnlyHint:ToolAnnotations :: Maybe Bool
readOnlyHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:destructiveHint:ToolAnnotations :: Maybe Bool
destructiveHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False,
            $sel:idempotentHint:ToolAnnotations :: Maybe Bool
idempotentHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:openWorldHint:ToolAnnotations :: Maybe Bool
openWorldHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
          },
      $sel:toolArgType:Tool :: Proxy SearchDefinitionsToolArguments
toolArgType = Proxy SearchDefinitionsToolArguments
forall {k} (t :: k). Proxy t
Proxy,
      $sel:toolHandler:Tool :: SearchDefinitionsToolArguments -> MCP CallToolResult
toolHandler = \(SearchDefinitionsToolArguments {ProjectContext
projectContext :: ProjectContext
$sel:projectContext:SearchDefinitionsToolArguments :: SearchDefinitionsToolArguments -> ProjectContext
projectContext, Text
query :: Text
$sel:query:SearchDefinitionsToolArguments :: SearchDefinitionsToolArguments -> Text
query}) -> EMCP CallToolResult -> MCP CallToolResult
handleToolError (EMCP CallToolResult -> MCP CallToolResult)
-> EMCP CallToolResult -> MCP CallToolResult
forall a b. (a -> b) -> a -> b
$ do
        CliOutput
definitions <- ProjectContext
-> [Either Event Input] -> ExceptT Text MCP CliOutput
handleInputMCP ProjectContext
projectContext [Input -> Either Event Input
forall a b. b -> Either a b
Right (Input -> Either Event Input) -> Input -> Either Event Input
forall a b. (a -> b) -> a -> b
$ Bool -> FindScope -> [String] -> Input
Input.FindI Bool
False (Path' -> FindScope
FindLocal Path'
Path.Root') [Text -> String
Text.unpack Text
query]]
        let outputJSON :: Text
outputJSON = ByteString -> Text
Text.decodeUtf8 (ByteString -> Text)
-> (ByteString -> ByteString) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.toStrict (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ CliOutput -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encode CliOutput
definitions
        CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
textToolResult Text
outputJSON
    }

searchByTypeTool :: Tool MCP
searchByTypeTool :: Tool MCP
searchByTypeTool =
  Tool
    { $sel:toolName:Tool :: Text
toolName = ToolKind -> Text
toToolName ToolKind
SearchByTypeTool,
      $sel:toolDescription:Tool :: Text
toolDescription = Text
"Search for definitions in the current project or its library dependencies by type.",
      $sel:toolAnnotations:Tool :: ToolAnnotations
toolAnnotations =
        ToolAnnotations
          { $sel:title:ToolAnnotations :: Maybe Text
title = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"Search Definitions By Type",
            $sel:readOnlyHint:ToolAnnotations :: Maybe Bool
readOnlyHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:destructiveHint:ToolAnnotations :: Maybe Bool
destructiveHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False,
            $sel:idempotentHint:ToolAnnotations :: Maybe Bool
idempotentHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:openWorldHint:ToolAnnotations :: Maybe Bool
openWorldHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
          },
      $sel:toolArgType:Tool :: Proxy SearchByTypeToolArguments
toolArgType = Proxy SearchByTypeToolArguments
forall {k} (t :: k). Proxy t
Proxy,
      $sel:toolHandler:Tool :: SearchByTypeToolArguments -> MCP CallToolResult
toolHandler = \(SearchByTypeToolArguments {ProjectContext
projectContext :: ProjectContext
$sel:projectContext:SearchByTypeToolArguments :: SearchByTypeToolArguments -> ProjectContext
projectContext, Text
query :: Text
$sel:query:SearchByTypeToolArguments :: SearchByTypeToolArguments -> Text
query}) -> EMCP CallToolResult -> MCP CallToolResult
handleToolError (EMCP CallToolResult -> MCP CallToolResult)
-> EMCP CallToolResult -> MCP CallToolResult
forall a b. (a -> b) -> a -> b
$ do
        CliOutput
definitions <- ProjectContext
-> [Either Event Input] -> ExceptT Text MCP CliOutput
handleInputMCP ProjectContext
projectContext [Input -> Either Event Input
forall a b. b -> Either a b
Right (Input -> Either Event Input) -> Input -> Either Event Input
forall a b. (a -> b) -> a -> b
$ Bool -> FindScope -> [String] -> Input
Input.FindI Bool
False (Path' -> FindScope
FindLocal Path'
Path.Root') [String
":", Text -> String
Text.unpack Text
query]]
        let outputJSON :: Text
outputJSON = ByteString -> Text
Text.decodeUtf8 (ByteString -> Text)
-> (ByteString -> ByteString) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.toStrict (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ CliOutput -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encode CliOutput
definitions
        CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
textToolResult Text
outputJSON
    }

dependenciesTool :: Tool MCP
dependenciesTool :: Tool MCP
dependenciesTool =
  Tool
    { $sel:toolName:Tool :: Text
toolName = ToolKind -> Text
toToolName ToolKind
DependenciesTool,
      $sel:toolDescription:Tool :: Text
toolDescription = Text
"List the dependencies of a definition.",
      $sel:toolAnnotations:Tool :: ToolAnnotations
toolAnnotations =
        ToolAnnotations
          { $sel:title:ToolAnnotations :: Maybe Text
title = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"List all definitions a given term or type depends on.",
            $sel:readOnlyHint:ToolAnnotations :: Maybe Bool
readOnlyHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:destructiveHint:ToolAnnotations :: Maybe Bool
destructiveHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False,
            $sel:idempotentHint:ToolAnnotations :: Maybe Bool
idempotentHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:openWorldHint:ToolAnnotations :: Maybe Bool
openWorldHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
          },
      $sel:toolArgType:Tool :: Proxy ProjectDefinitionNameArgument
toolArgType = Proxy ProjectDefinitionNameArgument
forall {k} (t :: k). Proxy t
Proxy,
      $sel:toolHandler:Tool :: ProjectDefinitionNameArgument -> MCP CallToolResult
toolHandler = \(ProjectDefinitionNameArgument {ProjectContext
projectContext :: ProjectContext
$sel:projectContext:ProjectDefinitionNameArgument :: ProjectDefinitionNameArgument -> ProjectContext
projectContext, Name
definitionName :: Name
$sel:definitionName:ProjectDefinitionNameArgument :: ProjectDefinitionNameArgument -> Name
definitionName}) -> EMCP CallToolResult -> MCP CallToolResult
handleToolError (EMCP CallToolResult -> MCP CallToolResult)
-> EMCP CallToolResult -> MCP CallToolResult
forall a b. (a -> b) -> a -> b
$ do
        CliOutput
output <- ProjectContext
-> [Either Event Input] -> ExceptT Text MCP CliOutput
handleInputMCP ProjectContext
projectContext [Input -> Either Event Input
forall a b. b -> Either a b
Right (Input -> Either Event Input) -> Input -> Either Event Input
forall a b. (a -> b) -> a -> b
$ HashQualified Name -> Input
Input.ListDependenciesI (Name -> HashQualified Name
forall n. n -> HashQualified n
HQ.NameOnly Name
definitionName)]
        let outputJSON :: Text
outputJSON = ByteString -> Text
Text.decodeUtf8 (ByteString -> Text)
-> (ByteString -> ByteString) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.toStrict (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ CliOutput -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encode CliOutput
output
        CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
textToolResult Text
outputJSON
    }

dependentsTool :: Tool MCP
dependentsTool :: Tool MCP
dependentsTool =
  Tool
    { $sel:toolName:Tool :: Text
toolName = ToolKind -> Text
toToolName ToolKind
DependentsTool,
      $sel:toolDescription:Tool :: Text
toolDescription = Text
"List the dependents of a definition.",
      $sel:toolAnnotations:Tool :: ToolAnnotations
toolAnnotations =
        ToolAnnotations
          { $sel:title:ToolAnnotations :: Maybe Text
title = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"List all definitions that depend on a given term or type.",
            $sel:readOnlyHint:ToolAnnotations :: Maybe Bool
readOnlyHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:destructiveHint:ToolAnnotations :: Maybe Bool
destructiveHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False,
            $sel:idempotentHint:ToolAnnotations :: Maybe Bool
idempotentHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True,
            $sel:openWorldHint:ToolAnnotations :: Maybe Bool
openWorldHint = Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
          },
      $sel:toolArgType:Tool :: Proxy ProjectDefinitionNameArgument
toolArgType = Proxy ProjectDefinitionNameArgument
forall {k} (t :: k). Proxy t
Proxy,
      $sel:toolHandler:Tool :: ProjectDefinitionNameArgument -> MCP CallToolResult
toolHandler = \(ProjectDefinitionNameArgument {ProjectContext
$sel:projectContext:ProjectDefinitionNameArgument :: ProjectDefinitionNameArgument -> ProjectContext
projectContext :: ProjectContext
projectContext, Name
$sel:definitionName:ProjectDefinitionNameArgument :: ProjectDefinitionNameArgument -> Name
definitionName :: Name
definitionName}) -> EMCP CallToolResult -> MCP CallToolResult
handleToolError (EMCP CallToolResult -> MCP CallToolResult)
-> EMCP CallToolResult -> MCP CallToolResult
forall a b. (a -> b) -> a -> b
$ do
        CliOutput
output <- ProjectContext
-> [Either Event Input] -> ExceptT Text MCP CliOutput
handleInputMCP ProjectContext
projectContext [Input -> Either Event Input
forall a b. b -> Either a b
Right (Input -> Either Event Input) -> Input -> Either Event Input
forall a b. (a -> b) -> a -> b
$ HashQualified Name -> Input
Input.ListDependentsI (Name -> HashQualified Name
forall n. n -> HashQualified n
HQ.NameOnly Name
definitionName)]
        let outputJSON :: Text
outputJSON = ByteString -> Text
Text.decodeUtf8 (ByteString -> Text)
-> (ByteString -> ByteString) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.toStrict (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ CliOutput -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encode CliOutput
output
        CallToolResult -> EMCP CallToolResult
forall a. a -> ExceptT Text MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> EMCP CallToolResult)
-> CallToolResult -> EMCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
textToolResult Text
outputJSON
    }

handleToolError :: EMCP CallToolResult -> MCP CallToolResult
handleToolError :: EMCP CallToolResult -> MCP CallToolResult
handleToolError EMCP CallToolResult
action = do
  Either Text CallToolResult
result <- EMCP CallToolResult -> MCP (Either Text CallToolResult)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT EMCP CallToolResult
action
  case Either Text CallToolResult
result of
    Left Text
err -> CallToolResult -> MCP CallToolResult
forall a. a -> MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CallToolResult -> MCP CallToolResult)
-> CallToolResult -> MCP CallToolResult
forall a b. (a -> b) -> a -> b
$ Text -> CallToolResult
errorToolResult Text
err
    Right CallToolResult
res -> CallToolResult -> MCP CallToolResult
forall a. a -> MCP a
forall (f :: * -> *) a. Applicative f => a -> f a
pure CallToolResult
res