11module Echidna.MCP (runMCPServer ) where
22
33import Control.Monad.IO.Class (liftIO )
4+ import Data.Aeson (encode )
45import Data.IORef (readIORef )
5- import Data.Text (pack )
6+ import Data.List (find , isInfixOf )
7+ import Data.Maybe (fromMaybe )
8+ import Data.Set (toList )
9+ import Data.Text (pack , unpack )
10+ import Data.Text.Lazy (toStrict )
11+ import Data.Text.Lazy.Encoding (decodeUtf8 )
612import MCP.Server
713import Network.Wai.Handler.Warp (Port )
814
915import Echidna.Types.Config (Env (.. ))
1016import Echidna.Types.Corpus (corpusSize )
17+ import Echidna.Types.Tx (Tx )
18+ import Echidna.Pretty (ppTx )
1119
1220getCorpusSize :: Env -> ToolCallHandler IO
1321getCorpusSize env _ _ = do
1422 corpus <- liftIO $ readIORef env. corpusRef
1523 pure $ Right $ ContentText $ pack $ show $ corpusSize corpus
1624
25+ inspectCorpusTransactions :: Env -> ToolCallHandler IO
26+ inspectCorpusTransactions env _ args = do
27+ corpus <- liftIO $ readIORef env. corpusRef
28+ let
29+ sequence' = read $ unpack $ fromMaybe " 0" $ lookup " sequence" args
30+ page = read $ unpack $ fromMaybe " 0" $ lookup " page" args
31+ txs = fromMaybe [] $ snd <$> find (\ (i, _) -> i == sequence') (toList corpus)
32+ paginatedTxs = take 10 $ drop (page * 10 ) txs
33+ pure $ Right $ ContentText $ pack $ unlines $ map (ppTx mempty ) paginatedTxs
34+
35+ findTransactionInCorpus :: Env -> ToolCallHandler IO
36+ findTransactionInCorpus env _ args = do
37+ corpus <- liftIO $ readIORef env. corpusRef
38+ let
39+ query = unpack $ fromMaybe " " $ lookup " query" args
40+ results =
41+ [ (seq', i `div` 10 )
42+ | (seq', txs) <- toList corpus
43+ , (tx, i) <- zip txs [0 .. ]
44+ , query `isInfixOf` ppTx mempty tx
45+ ]
46+ pure $ Right $ ContentText $ pack $ show results
47+
1748runMCPServer :: Env -> Port -> IO ()
1849runMCPServer env port = do
1950 let
2051 info = McpServerInfo " Echidna" " 2.2.7" " Echidna MCP server"
21- tools =
52+ tools' =
2253 [ ToolDefinition " getCorpusSize" " Get the current corpus size" (InputSchemaDefinitionObject [] [] ) Nothing
54+ , ToolDefinition " inspectCorpusTransactions" " Inspect corpus transactions"
55+ (InputSchemaDefinitionObject
56+ [ (" sequence" , InputSchemaDefinitionProperty " integer" " Sequence number" )
57+ , (" page" , InputSchemaDefinitionProperty " integer" " Page number (10 txs per page)" )
58+ ]
59+ [" sequence" , " page" ])
60+ Nothing
61+ , ToolDefinition " findTransactionInCorpus" " Find transaction in corpus"
62+ (InputSchemaDefinitionObject
63+ [ (" query" , InputSchemaDefinitionProperty " string" " String to search" )
64+ ]
65+ [" query" ])
66+ Nothing
2367 ]
68+ toolHandler :: ToolCallHandler IO
69+ toolHandler " getCorpusSize" args = getCorpusSize env " getCorpusSize" args
70+ toolHandler " inspectCorpusTransactions" args = inspectCorpusTransactions env " inspectCorpusTransactions" args
71+ toolHandler " findTransactionInCorpus" args = findTransactionInCorpus env " findTransactionInCorpus" args
72+ toolHandler _ _ = pure $ Left $ InternalError " Unknown tool"
2473 handlers = McpServerHandlers
2574 { prompts = Nothing
2675 , resources = Nothing
27- , tools = Just (pure tools, getCorpusSize env )
76+ , tools = Just (pure tools', toolHandler )
2877 }
2978 runMcpServerHttpWithConfig (HttpConfig {httpPort = port, httpHost = " 127.0.0.1" , httpEndpoint = " /mcp" , httpVerbose = False }) info handlers
0 commit comments