Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 36 additions & 34 deletions internal/mcp_impl/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,45 +95,47 @@ func addEvalTool(s *server.MCPServer) {
`),
),
)
s.AddTool(tool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
script, err := request.RequireString("script")
if err != nil {
return mcp.NewToolResultError(err.Error()), nil
}
s.AddTool(tool, handleEvalTool)
}

parsed := parser.Parse(script)
if len(parsed.Errors) != 0 {
out := make([]string, len(parsed.Errors))
for index, err := range parsed.Errors {
out[index] = err.Msg
}
mcp.NewToolResultError(strings.Join(out, ", "))
}
func handleEvalTool(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
script, err := request.RequireString("script")
if err != nil {
return mcp.NewToolResultError(err.Error()), nil
}

balances, mcpErr := parseBalancesJson(request.GetArguments()["balances"])
if mcpErr != nil {
return mcpErr, nil
parsed := parser.Parse(script)
if len(parsed.Errors) != 0 {
out := make([]string, len(parsed.Errors))
for index, err := range parsed.Errors {
out[index] = err.Msg
}
return mcp.NewToolResultError(strings.Join(out, ", ")), nil
}

vars, mcpErr := parseVarsJson(request.GetArguments()["vars"])
if mcpErr != nil {
return mcpErr, nil
}
balances, mcpErr := parseBalancesJson(request.GetArguments()["balances"])
if mcpErr != nil {
return mcpErr, nil
}

out, iErr := interpreter.RunProgram(
ctx,
parsed.Value,
vars,
interpreter.StaticStore{
Balances: balances,
},
map[string]struct{}{},
)
if iErr != nil {
return mcp.NewToolResultError(iErr.Error()), nil
}
return mcp.NewToolResultJSON(*out)
})
vars, mcpErr := parseVarsJson(request.GetArguments()["vars"])
if mcpErr != nil {
return mcpErr, nil
}

out, iErr := interpreter.RunProgram(
ctx,
parsed.Value,
vars,
interpreter.StaticStore{
Balances: balances,
},
map[string]struct{}{},
)
if iErr != nil {
return mcp.NewToolResultError(iErr.Error()), nil
}
return mcp.NewToolResultJSON(*out)
}

func addCheckTool(s *server.MCPServer) {
Expand Down
28 changes: 28 additions & 0 deletions internal/mcp_impl/handlers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package mcp_impl

import (
"context"
"testing"

"github.com/mark3labs/mcp-go/mcp"
"github.com/stretchr/testify/require"
)

func TestHandleEvalToolRejectsParseErrors(t *testing.T) {
result, err := handleEvalTool(context.Background(), mcp.CallToolRequest{
Params: mcp.CallToolParams{
Arguments: map[string]any{
"script": "send [COIN 100] (",
"balances": map[string]any{},
"vars": map[string]any{},
},
},
})

require.NoError(t, err)
require.True(t, result.IsError)
require.NotEmpty(t, result.Content)
text, ok := result.Content[0].(mcp.TextContent)
require.True(t, ok)
require.Contains(t, text.Text, "mismatched input")
}
4 changes: 4 additions & 0 deletions numscript.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ func (p ParseResult) RunWithFeatureFlags(
store Store,
featureFlags map[string]struct{},
) (ExecutionResult, InterpreterError) {
if len(p.parseResult.Errors) != 0 {
return ExecutionResult{}, p.parseResult.Errors[0]
}

if featureFlags == nil {
featureFlags = make(map[string]struct{})
}
Expand Down
9 changes: 9 additions & 0 deletions numscript_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ func TestGetVarsNovars(t *testing.T) {
)
}

func TestRunRejectsParseErrors(t *testing.T) {
parseResult := numscript.Parse(`send [COIN 100] (`)
require.NotEmpty(t, parseResult.GetParsingErrors())

_, err := parseResult.Run(context.Background(), nil, interpreter.StaticStore{})
require.Error(t, err)
require.Equal(t, parseResult.GetParsingErrors()[0].Error(), err.Error())
}

func TestDoNotGetWorldBalance(t *testing.T) {
parseResult := numscript.Parse(`send [COIN 100] (
source = @world
Expand Down