Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
67a4793
PoC full flow (hello world example)
tommaso-moro Jan 7, 2026
7d2b463
add avatar resource domain
tommaso-moro Jan 7, 2026
7606aec
add postmessage logic and richer UI
tommaso-moro Jan 7, 2026
02ce9bf
add create issue ui
tommaso-moro Jan 15, 2026
d53ff41
update ui for issue creatioon
tommaso-moro Jan 15, 2026
e3d5db7
fix
tommaso-moro Jan 15, 2026
b149642
ignore banner
tommaso-moro Jan 15, 2026
92aabf2
update docs after rebase
mattdholloway Feb 2, 2026
8b55d08
update toolsnap for get_me
mattdholloway Feb 2, 2026
06270c7
new UI changes
mattdholloway Feb 2, 2026
a770719
update docs
mattdholloway Feb 2, 2026
23de0bc
update workflows that need ui build
mattdholloway Feb 2, 2026
e2a8582
add UI diff
mattdholloway Feb 2, 2026
5bb6228
fix build ui step for windows runners to use git bash
mattdholloway Feb 2, 2026
157ba4d
fix UI diff
mattdholloway Feb 2, 2026
c927390
refactor issue creation UI
mattdholloway Feb 3, 2026
6d0eda6
add AvatarWithFallback component and update UserCard to use it; enhan…
mattdholloway Feb 3, 2026
2b0d8cc
fix formatting of button labels
mattdholloway Feb 3, 2026
b8dc0d5
add create pull request functionality with UI support and insiders
mattdholloway Feb 3, 2026
2d186da
update docs
mattdholloway Feb 3, 2026
072f5c4
add test for insiders mode handling in ServerTool schema
mattdholloway Feb 3, 2026
adc1053
remove `show_ui` param for now
mattdholloway Feb 4, 2026
ee0a440
make insiders mode metadata stripping generic
mattdholloway Feb 4, 2026
2b8f062
remove ui diff
mattdholloway Feb 4, 2026
6070471
Merge branch 'main' into mcp-ui-apps-3
mattdholloway Feb 4, 2026
d0f0334
Merge branch 'mcp-ui-apps-3' of https://github.com/github/github-mcp-…
mattdholloway Feb 4, 2026
37da563
fix CI
mattdholloway Feb 4, 2026
8b23e49
remove redundant mention of old app name
mattdholloway Feb 4, 2026
12af958
add node types to fix ide issues for ts code
mattdholloway Feb 4, 2026
e61c2d2
remove unused TriangleDownIcon import
mattdholloway Feb 4, 2026
54ce61d
update @primer/behaviors and electron-to-chromium versions in package…
mattdholloway Feb 4, 2026
03aad7f
add check to ensure base and head are not the same when creating a ne…
mattdholloway Feb 4, 2026
ad09947
remove old show_ui
mattdholloway Feb 4, 2026
d5e263e
fix gitignore for dist so builds dont break
mattdholloway Feb 4, 2026
dca4d52
add tests for insiders mode handling and metadata stripping in Server…
mattdholloway Feb 4, 2026
932750c
remove unused state and components from CreatePRApp
mattdholloway Feb 4, 2026
16469f8
fix ui build
mattdholloway Feb 4, 2026
d0085a7
update docker build to fix npm issue
mattdholloway Feb 4, 2026
7ce5e08
remove reference to show_ui
mattdholloway Feb 4, 2026
3413b71
Merge branch 'main' into mcp-ui-apps-3
mattdholloway Feb 5, 2026
e20cef3
allow insiders to work for non-ui features
mattdholloway Feb 5, 2026
8a0edfb
formalise insiders inventory support
mattdholloway Feb 5, 2026
d564d98
update docs
mattdholloway Feb 5, 2026
f034e19
fix overflow issues and replace pull request dropdown with matching U…
mattdholloway Feb 5, 2026
934e83d
fix createpullrequest test
mattdholloway Feb 5, 2026
a1922b2
consolidate fetching tools under `ui_get` tool to remove toolset deps
mattdholloway Feb 5, 2026
a47064d
fix issue data prefill in issue_write form
mattdholloway Feb 5, 2026
be4c4c7
fix link component when updating issue
mattdholloway Feb 5, 2026
69579b2
fix avatar URL
mattdholloway Feb 5, 2026
b2164a1
fix broken issue update logic
mattdholloway Feb 5, 2026
fcefcaa
remove dbg
mattdholloway Feb 5, 2026
826b518
Merge remote-tracking branch 'origin/main' into mcp-ui-apps-3
mattdholloway Feb 6, 2026
8fa72ad
fix for new GetFlags
mattdholloway Feb 6, 2026
00b9213
revert to original required fields for create_pull_request
mattdholloway Feb 6, 2026
922fa9f
fix for UI form submission
mattdholloway Feb 6, 2026
a2dcb30
Merge branch 'main' into mcp-ui-apps-3
mattdholloway Feb 9, 2026
24174b9
Simplify MCP App UIs for basic branch
mattdholloway Feb 9, 2026
4dc0d47
Fix header spacing in issue-write and pr-write UIs
mattdholloway Feb 9, 2026
4994f84
fix UI spacing
mattdholloway Feb 9, 2026
fce0c3d
Revert "Simplify MCP App UIs for basic branch"
mattdholloway Feb 9, 2026
c8cf1e9
Merge remote-tracking branch 'origin/main' into mcp-ui-apps-advanced
mattdholloway Feb 13, 2026
5cc9623
Undo dependency downgrades in ui/package-lock.json
mattdholloway Feb 13, 2026
a9bcd2b
Update ui/src/apps/pr-write/App.tsx
mattdholloway Feb 13, 2026
8432a54
Update ui/src/apps/issue-write/App.tsx
mattdholloway Feb 13, 2026
c8848f5
Implement pagination for uiGetBranches (#2012)
Copilot Feb 13, 2026
e021022
Merge branch 'main' into mcp-ui-apps-advanced
mattdholloway Feb 17, 2026
5de74d8
Merge branch 'main' into mcp-ui-apps-advanced
mattdholloway Feb 17, 2026
d0e6c0b
Merge branch 'main' into mcp-ui-apps-advanced
mattdholloway Feb 20, 2026
6c529d0
Merge branch 'main' into mcp-ui-apps-advanced
mattdholloway Mar 2, 2026
096ecbb
Merge branch 'main' into mcp-ui-apps-advanced
mattdholloway Apr 1, 2026
3ea342a
Merge branch 'main' into mcp-ui-apps-advanced
mattdholloway Apr 28, 2026
46c7267
update to new insiders feature flag func
mattdholloway Apr 28, 2026
0a0b7da
ensure transient state is reset on successive tool calls
mattdholloway Apr 29, 2026
2a65fd3
Merge remote-tracking branch 'origin/main' into mcp-ui-apps-advanced
Copilot Jun 1, 2026
489e188
Mark ui_get as app-only visibility
mattdholloway Jun 1, 2026
5698568
Update ui_get toolsnap for app-only visibility
mattdholloway Jun 1, 2026
b5b87d5
Assert ui_get declares app-only visibility
mattdholloway Jun 1, 2026
f310291
Add ui_get to insiders feature docs
mattdholloway Jun 1, 2026
d9292e9
Address ui_get review feedback
mattdholloway Jun 1, 2026
13bb1b0
Fix repo reset and stale base-branch in MCP App views
mattdholloway Jun 1, 2026
6f6e826
Potential fix for pull request finding
mattdholloway Jun 1, 2026
19f5c11
Fix issue-write repo owner mapping and clear stale UI state on reset
mattdholloway Jun 1, 2026
3e11e38
Merge remote-tracking branch 'origin/main' into mcp-ui-apps-advanced
Copilot Jun 1, 2026
064c9cc
Merge remote-tracking branch 'origin/main' into mcp-ui-apps-advanced
Copilot Jun 1, 2026
064250e
Merge branch 'main' into mcp-ui-apps-advanced
mattdholloway Jun 2, 2026
3f9e68f
Merge remote-tracking branch 'origin/main' into mcp-ui-apps-advanced
Copilot Jun 3, 2026
0eccc22
feat: add pull request editing functionality with reviewers support
mattdholloway Jun 9, 2026
d9be621
feat: implement interactive form handling for issue and pull request …
mattdholloway Jun 9, 2026
66e23ed
Merge branch 'main' into mcp-ui-apps-advanced
mattdholloway Jun 15, 2026
2462eee
Close response body per page in ui_get pagination loops
mattdholloway Jun 15, 2026
c16401c
Cache pr-edit.html in build-ui action
mattdholloway Jun 15, 2026
1cffb29
Merge remote-tracking branch 'origin/main' into pr/1974/mcp-ui-apps-a…
mattdholloway Jun 16, 2026
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
Prev Previous commit
Next Next commit
feat: implement interactive form handling for issue and pull request …
…creation and updates
  • Loading branch information
mattdholloway committed Jun 9, 2026
commit d9be6218bb865988200a989b5cf0587b95440710
44 changes: 38 additions & 6 deletions pkg/github/issues.go
Original file line number Diff line number Diff line change
Expand Up @@ -1796,6 +1796,36 @@ func issueWriteHasNonFormParams(args map[string]any) bool {
return false
}

// issueWriteAwaitingFormResult builds the "awaiting form submission" stub
// returned when issue_write hands off to the MCP App form. The body is shared
// by IssueWrite and LegacyIssueWrite. The result is marked IsError=true so
// agents that bail on error don't claim success or chain dependent tool calls
// while the user is still interacting with the form; the host renders the UI
// regardless because rendering is keyed off the tool's _meta.ui resourceUri.
func issueWriteAwaitingFormResult(method, owner, repo string, issueNumber int) *mcp.CallToolResult {
var msg string
if method == "update" {
msg = fmt.Sprintf(
"An interactive form has been shown to the user for editing issue #%d in %s/%s. "+
"STOP — do not call any other tools, do not respond as if the issue was updated, "+
"and do not claim the operation succeeded. The issue has NOT been updated yet; "+
"only the form was rendered. Wait silently for the user to review and click Submit. "+
"When they do, the real result will be delivered to your context automatically.",
issueNumber, owner, repo,
)
} else {
msg = fmt.Sprintf(
"An interactive form has been shown to the user for creating a new issue in %s/%s. "+
"STOP — do not call any other tools, do not respond as if the issue was created, "+
"and do not claim the operation succeeded. The issue has NOT been created yet; "+
"only the form was rendered. Wait silently for the user to review and click Submit. "+
"When they do, the real result will be delivered to your context automatically.",
owner, repo,
)
}
return utils.NewToolResultAwaitingFormSubmission(msg)
}

// IssueWrite is the FeatureFlagIssueFields-enabled variant of issue_write
// (with the issue_fields parameter). LegacyIssueWrite is served when the flag
// is off. Both register under the tool name "issue_write"; exactly one is
Expand Down Expand Up @@ -1949,14 +1979,15 @@ Options are:
uiSubmitted, _ := OptionalParam[bool](args, "_ui_submitted")

if deps.IsFeatureEnabled(ctx, MCPAppsFeatureFlag) && clientSupportsUI(ctx, req) && !uiSubmitted && !issueWriteHasNonFormParams(args) {
issueNumber := 0
if method == "update" {
issueNumber, numErr := RequiredInt(args, "issue_number")
n, numErr := RequiredInt(args, "issue_number")
if numErr != nil {
return utils.NewToolResultError("issue_number is required for update method"), nil, nil
}
return utils.NewToolResultText(fmt.Sprintf("Ready to update issue #%d in %s/%s. IMPORTANT: The issue has NOT been updated yet. Do NOT tell the user the issue was updated. The user MUST click Submit in the form to update it.", issueNumber, owner, repo)), nil, nil
issueNumber = n
}
return utils.NewToolResultText(fmt.Sprintf("Ready to create an issue in %s/%s. IMPORTANT: The issue has NOT been created yet. Do NOT tell the user the issue was created. The user MUST click Submit in the form to create it.", owner, repo)), nil, nil
return issueWriteAwaitingFormResult(method, owner, repo, issueNumber), nil, nil
}

title, err := OptionalParam[string](args, "title")
Expand Down Expand Up @@ -2181,14 +2212,15 @@ Options are:
uiSubmitted, _ := OptionalParam[bool](args, "_ui_submitted")

if deps.IsFeatureEnabled(ctx, MCPAppsFeatureFlag) && clientSupportsUI(ctx, req) && !uiSubmitted && !issueWriteHasNonFormParams(args) {
issueNumber := 0
if method == "update" {
issueNumber, numErr := RequiredInt(args, "issue_number")
n, numErr := RequiredInt(args, "issue_number")
if numErr != nil {
return utils.NewToolResultError("issue_number is required for update method"), nil, nil
}
return utils.NewToolResultText(fmt.Sprintf("Ready to update issue #%d in %s/%s. IMPORTANT: The issue has NOT been updated yet. Do NOT tell the user the issue was updated. The user MUST click Submit in the form to update it.", issueNumber, owner, repo)), nil, nil
issueNumber = n
}
return utils.NewToolResultText(fmt.Sprintf("Ready to create an issue in %s/%s. IMPORTANT: The issue has NOT been created yet. Do NOT tell the user the issue was created. The user MUST click Submit in the form to create it.", owner, repo)), nil, nil
return issueWriteAwaitingFormResult(method, owner, repo, issueNumber), nil, nil
}

title, err := OptionalParam[string](args, "title")
Expand Down
14 changes: 9 additions & 5 deletions pkg/github/issues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1561,7 +1561,8 @@ func Test_IssueWrite_MCPAppsFeature_UIGate(t *testing.T) {
require.NoError(t, err)

textContent := getTextResult(t, result)
assert.Contains(t, textContent.Text, "Ready to create an issue")
assert.Contains(t, textContent.Text, "interactive form has been shown to the user for creating a new issue")
assert.True(t, result.IsError, "form-routing stub should be marked IsError so agents don't claim success")
})

t.Run("UI client with _ui_submitted executes directly", func(t *testing.T) {
Expand Down Expand Up @@ -1611,8 +1612,9 @@ func Test_IssueWrite_MCPAppsFeature_UIGate(t *testing.T) {
require.NoError(t, err)

textContent := getTextResult(t, result)
assert.Contains(t, textContent.Text, "Ready to update issue #1",
assert.Contains(t, textContent.Text, "interactive form has been shown to the user for editing issue #1",
"state change should route through UI form")
assert.True(t, result.IsError, "form-routing stub should be marked IsError so agents don't claim success")
})

t.Run("UI client update without state change returns form message", func(t *testing.T) {
Expand All @@ -1627,8 +1629,9 @@ func Test_IssueWrite_MCPAppsFeature_UIGate(t *testing.T) {
require.NoError(t, err)

textContent := getTextResult(t, result)
assert.Contains(t, textContent.Text, "Ready to update issue #1",
assert.Contains(t, textContent.Text, "interactive form has been shown to the user for editing issue #1",
"update without state should show UI form")
assert.True(t, result.IsError, "form-routing stub should be marked IsError so agents don't claim success")
})

t.Run("UI client with issue_fields routes through UI form", func(t *testing.T) {
Expand All @@ -1648,8 +1651,9 @@ func Test_IssueWrite_MCPAppsFeature_UIGate(t *testing.T) {
require.NoError(t, err)

textContent := getTextResult(t, result)
assert.Contains(t, textContent.Text, "Ready to create an issue",
assert.Contains(t, textContent.Text, "interactive form has been shown to the user for creating a new issue",
"issue_fields should route through UI form")
assert.True(t, result.IsError, "form-routing stub should be marked IsError so agents don't claim success")
})

t.Run("UI client with labels skips form and executes directly", func(t *testing.T) {
Expand All @@ -1666,7 +1670,7 @@ func Test_IssueWrite_MCPAppsFeature_UIGate(t *testing.T) {
require.NoError(t, err)

textContent := getTextResult(t, result)
assert.NotContains(t, textContent.Text, "Ready to create an issue",
assert.NotContains(t, textContent.Text, "interactive form has been shown",
"labels should skip UI form")
assert.Contains(t, textContent.Text, "https://github.com/owner/repo/issues/1",
"labels call should execute directly and return issue URL")
Expand Down
18 changes: 16 additions & 2 deletions pkg/github/pullrequests.go
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,14 @@ func CreatePullRequest(t translations.TranslationHelperFunc) inventory.ServerToo
uiSubmitted, _ := OptionalParam[bool](args, "_ui_submitted")

if deps.IsFeatureEnabled(ctx, MCPAppsFeatureFlag) && clientSupportsUI(ctx, req) && !uiSubmitted && !pullRequestWriteHasNonFormParams(args) {
return utils.NewToolResultText(fmt.Sprintf("Ready to create a pull request in %s/%s. IMPORTANT: The PR has NOT been created yet. Do NOT tell the user the PR was created. The user MUST click Submit in the form to create it.", owner, repo)), nil, nil
return utils.NewToolResultAwaitingFormSubmission(fmt.Sprintf(
"An interactive form has been shown to the user for creating a new pull request in %s/%s. "+
"STOP — do not call any other tools, do not respond as if the pull request was created, "+
"and do not claim the operation succeeded. The pull request has NOT been created yet; "+
"only the form was rendered. Wait silently for the user to review and click Submit. "+
"When they do, the real result will be delivered to your context automatically.",
owner, repo,
)), nil, nil
}

// When creating PR, title/head/base are required
Expand Down Expand Up @@ -900,7 +907,14 @@ func UpdatePullRequest(t translations.TranslationHelperFunc) inventory.ServerToo

uiSubmitted, _ := OptionalParam[bool](args, "_ui_submitted")
if deps.IsFeatureEnabled(ctx, MCPAppsFeatureFlag) && clientSupportsUI(ctx, req) && !uiSubmitted && !pullRequestUpdateHasNonFormParams(args) {
return utils.NewToolResultText(fmt.Sprintf("Ready to update PR #%d in %s/%s. IMPORTANT: The PR has NOT been updated yet. Do NOT tell the user the PR was updated. The user MUST click Submit in the form to update it.", pullNumber, owner, repo)), nil, nil
return utils.NewToolResultAwaitingFormSubmission(fmt.Sprintf(
"An interactive form has been shown to the user for editing pull request #%d in %s/%s. "+
"STOP — do not call any other tools, do not respond as if the pull request was updated, "+
"and do not claim the operation succeeded. The pull request has NOT been updated yet; "+
"only the form was rendered. Wait silently for the user to review and click Submit. "+
"When they do, the real result will be delivered to your context automatically.",
pullNumber, owner, repo,
)), nil, nil
}

_, draftProvided := args["draft"]
Expand Down
101 changes: 99 additions & 2 deletions pkg/github/pullrequests_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2450,7 +2450,8 @@ func Test_CreatePullRequest_MCPAppsFeature_UIGate(t *testing.T) {
require.NoError(t, err)

textContent := getTextResult(t, result)
assert.Contains(t, textContent.Text, "Ready to create a pull request")
assert.Contains(t, textContent.Text, "interactive form has been shown to the user for creating a new pull request")
assert.True(t, result.IsError, "form-routing stub should be marked IsError so agents don't claim success")
})

t.Run("UI client with _ui_submitted executes directly", func(t *testing.T) {
Expand Down Expand Up @@ -2501,13 +2502,109 @@ func Test_CreatePullRequest_MCPAppsFeature_UIGate(t *testing.T) {
require.NoError(t, err)

textContent := getTextResult(t, result)
assert.NotContains(t, textContent.Text, "Ready to create a pull request",
assert.NotContains(t, textContent.Text, "interactive form has been shown",
"non-form param should skip UI form")
assert.Contains(t, textContent.Text, "https://github.com/owner/repo/pull/42",
"non-form param call should execute directly and return PR URL")
})
}

// Test_UpdatePullRequest_MCPAppsFeature_UIGate verifies the form-routing
// behavior for update_pull_request: UI clients without _ui_submitted get a
// pending-form stub (marked IsError so agents don't claim success), UI clients
// with _ui_submitted execute directly, non-UI clients execute directly, and
// UI clients carrying non-form params bypass the form.
func Test_UpdatePullRequest_MCPAppsFeature_UIGate(t *testing.T) {
t.Parallel()

mockPR := &github.PullRequest{
Number: github.Ptr(42),
Title: github.Ptr("Updated"),
HTMLURL: github.Ptr("https://github.com/owner/repo/pull/42"),
Head: &github.PullRequestBranch{SHA: github.Ptr("abc"), Ref: github.Ptr("feature")},
Base: &github.PullRequestBranch{SHA: github.Ptr("def"), Ref: github.Ptr("main")},
User: &github.User{Login: github.Ptr("testuser")},
}

serverTool := UpdatePullRequest(translations.NullTranslationHelper)

client := mustNewGHClient(t, MockHTTPClientWithHandlers(map[string]http.HandlerFunc{
PatchReposPullsByOwnerByRepoByPullNumber: mockResponse(t, http.StatusOK, mockPR),
GetReposPullsByOwnerByRepoByPullNumber: mockResponse(t, http.StatusOK, mockPR),
}))

deps := BaseDeps{
Client: client,
GQLClient: githubv4.NewClient(nil),
featureChecker: featureCheckerFor(MCPAppsFeatureFlag),
}
handler := serverTool.Handler(deps)

t.Run("UI client without _ui_submitted returns form message", func(t *testing.T) {
request := createMCPRequestWithSession(t, ClientNameVSCodeInsiders, true, map[string]any{
"owner": "owner",
"repo": "repo",
"pullNumber": float64(42),
"title": "Updated",
})
result, err := handler(ContextWithDeps(context.Background(), deps), &request)
require.NoError(t, err)

textContent := getTextResult(t, result)
assert.Contains(t, textContent.Text, "interactive form has been shown to the user for editing pull request #42")
assert.True(t, result.IsError, "form-routing stub should be marked IsError so agents don't claim success")
})

t.Run("UI client with _ui_submitted executes directly", func(t *testing.T) {
request := createMCPRequestWithSession(t, ClientNameVSCodeInsiders, true, map[string]any{
"owner": "owner",
"repo": "repo",
"pullNumber": float64(42),
"title": "Updated",
"_ui_submitted": true,
})
result, err := handler(ContextWithDeps(context.Background(), deps), &request)
require.NoError(t, err)

textContent := getTextResult(t, result)
assert.False(t, result.IsError, "submitted form should execute successfully: %s", textContent.Text)
assert.Contains(t, textContent.Text, "https://github.com/owner/repo/pull/42",
"submitted form should return the updated PR URL")
})

t.Run("non-UI client executes directly without _ui_submitted", func(t *testing.T) {
request := createMCPRequest(map[string]any{
"owner": "owner",
"repo": "repo",
"pullNumber": float64(42),
"title": "Updated",
})
result, err := handler(ContextWithDeps(context.Background(), deps), &request)
require.NoError(t, err)

textContent := getTextResult(t, result)
assert.False(t, result.IsError, "non-UI client should execute directly: %s", textContent.Text)
assert.Contains(t, textContent.Text, "https://github.com/owner/repo/pull/42",
"non-UI client should return the updated PR URL")
})

t.Run("UI client with non-form param skips form and executes directly", func(t *testing.T) {
request := createMCPRequestWithSession(t, ClientNameVSCodeInsiders, true, map[string]any{
"owner": "owner",
"repo": "repo",
"pullNumber": float64(42),
"title": "Updated",
"unknown_param": "value",
})
result, err := handler(ContextWithDeps(context.Background(), deps), &request)
require.NoError(t, err)

textContent := getTextResult(t, result)
assert.NotContains(t, textContent.Text, "interactive form has been shown",
"non-form param should skip UI form")
})
}

func Test_pullRequestWriteHasNonFormParams(t *testing.T) {
t.Parallel()

Expand Down
24 changes: 24 additions & 0 deletions pkg/utils/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,27 @@ func NewToolResultResourceLink(message string, link *mcp.ResourceLink) *mcp.Call
IsError: false,
}
}

// NewToolResultAwaitingFormSubmission signals to the agent that a tool call
// has been intercepted to show an MCP App form to the user and has NOT
// performed the requested operation. The agent must stop, not chain dependent
// tool calls, and not claim the operation succeeded. The result is marked
// IsError=true so agents that bail on error don't proceed; the host still
// renders the UI because rendering is keyed off the tool's _meta.ui, not the
// result. The MCP App form will submit the operation directly when the user
// clicks submit, after which a ui/update-model-context call delivers the real
// outcome to the agent.
func NewToolResultAwaitingFormSubmission(message string) *mcp.CallToolResult {
return &mcp.CallToolResult{
Content: []mcp.Content{
&mcp.TextContent{
Text: message,
},
},
StructuredContent: map[string]any{
"status": "awaiting_user_submission",
"reason": "An interactive form is being shown to the user. The operation has not been performed.",
},
IsError: true,
}
}
Loading