From 93915c3c70e3b2c0f8373c316fefda14888f067e Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2026 17:15:49 +0000 Subject: [PATCH 1/4] feat(mcp-core): Add submit_feedback tool for agent friction reports Agents can report missing, broken, or confusing tools. Reports are sent as Sentry User Feedback to the MCP server's own Sentry project. Co-Authored-By: Scott Cooper --- packages/mcp-core/src/skillDefinitions.json | 35 +++++- packages/mcp-core/src/toolDefinitions.json | 51 +++++++++ packages/mcp-core/src/tools/catalog/index.ts | 2 + .../src/tools/catalog/submit-feedback.test.ts | 69 ++++++++++++ .../src/tools/catalog/submit-feedback.ts | 102 ++++++++++++++++++ 5 files changed, 254 insertions(+), 5 deletions(-) create mode 100644 packages/mcp-core/src/tools/catalog/submit-feedback.test.ts create mode 100644 packages/mcp-core/src/tools/catalog/submit-feedback.ts diff --git a/packages/mcp-core/src/skillDefinitions.json b/packages/mcp-core/src/skillDefinitions.json index 1f3a1d245..c0495010e 100644 --- a/packages/mcp-core/src/skillDefinitions.json +++ b/packages/mcp-core/src/skillDefinitions.json @@ -5,7 +5,7 @@ "description": "Read-only access to core Sentry data: issues, events, traces, replays, releases, cron monitors, uptime monitors, metric monitors, profiles, documentation, and project metadata", "defaultEnabled": true, "order": 1, - "toolCount": 47, + "toolCount": 48, "tools": [ { "name": "find_alert_rules", @@ -237,6 +237,11 @@ "description": "Search Sentry spans and traces: requests, API/HTTP calls, endpoints, DB queries, AI/LLM calls, and other operations. Use for latency, throughput, slowness, and performance questions.\n\n`query` is natural language (preferred) or Sentry search syntax; a configured agent translates it into query, fields, and sort.\n\nAlso use for spans whose trace contains a matching log, metric, or other span, e.g. 'slow checkout requests that also logged an error'.\n\nSupports aggregations ('p95 duration by span.op'), individual spans ('slowest API calls today'), and time series ('requests per minute last hour').\n\nNOT for exceptions/crashes (use search_errors), standalone log lines (use search_logs), or a single trace's span tree (use get_sentry_resource with the trace).\n\n\nsearch_traces(organizationSlug='my-org', query='slowest API calls in the last 24 hours')\nsearch_traces(organizationSlug='my-org', query='p95 duration of db spans grouped by span.op over 7 days')\nsearch_traces(organizationSlug='my-org', query='checkout requests that also have an error log')\n\n\n\n- name/otherName notation means /; parse it directly, don't call find_organizations/find_projects.\n- Natural language is usually enough. Only pass fields/sort when you need exact columns or ordering.\n", "requiredScopes": ["event:read"] }, + { + "name": "submit_feedback", + "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", + "requiredScopes": [] + }, { "name": "whoami", "description": "Identify the authenticated user in Sentry.\n\nUse this tool when you need to:\n- Get the user's name and email address.", @@ -250,7 +255,7 @@ "description": "Sentry's AI debugger that helps you analyze, root cause, and fix issues", "defaultEnabled": true, "order": 2, - "toolCount": 17, + "toolCount": 18, "tools": [ { "name": "analyze_issue_with_seer", @@ -332,6 +337,11 @@ "description": "Search Sentry spans and traces: requests, API/HTTP calls, endpoints, DB queries, AI/LLM calls, and other operations. Use for latency, throughput, slowness, and performance questions.\n\n`query` is natural language (preferred) or Sentry search syntax; a configured agent translates it into query, fields, and sort.\n\nAlso use for spans whose trace contains a matching log, metric, or other span, e.g. 'slow checkout requests that also logged an error'.\n\nSupports aggregations ('p95 duration by span.op'), individual spans ('slowest API calls today'), and time series ('requests per minute last hour').\n\nNOT for exceptions/crashes (use search_errors), standalone log lines (use search_logs), or a single trace's span tree (use get_sentry_resource with the trace).\n\n\nsearch_traces(organizationSlug='my-org', query='slowest API calls in the last 24 hours')\nsearch_traces(organizationSlug='my-org', query='p95 duration of db spans grouped by span.op over 7 days')\nsearch_traces(organizationSlug='my-org', query='checkout requests that also have an error log')\n\n\n\n- name/otherName notation means /; parse it directly, don't call find_organizations/find_projects.\n- Natural language is usually enough. Only pass fields/sort when you need exact columns or ordering.\n", "requiredScopes": ["event:read"] }, + { + "name": "submit_feedback", + "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", + "requiredScopes": [] + }, { "name": "whoami", "description": "Identify the authenticated user in Sentry.\n\nUse this tool when you need to:\n- Get the user's name and email address.", @@ -346,7 +356,7 @@ "defaultEnabled": false, "deprecated": true, "order": 3, - "toolCount": 6, + "toolCount": 7, "tools": [ { "name": "find_organizations", @@ -373,6 +383,11 @@ "description": "Search Sentry documentation for SDK setup, instrumentation, and configuration guidance.\n\nUse this tool when you need to:\n- Set up Sentry SDK or framework integrations (Django, Flask, Express, Next.js, etc.)\n- Configure features like performance monitoring, error sampling, or release tracking\n- Implement custom instrumentation (spans, transactions, breadcrumbs)\n- Configure data scrubbing, filtering, or sampling rules\n\nReturns snippets only. Use the Sentry tool `get_doc` to fetch full documentation content.\n\n\n```\nsearch_docs(query='Django setup configuration SENTRY_DSN', guide='python/django')\nsearch_docs(query='source maps webpack upload', guide='javascript/nextjs')\n```\n\n\n\n- Use guide parameter to filter to specific technologies (e.g., 'javascript/nextjs')\n- Include specific feature names like 'beforeSend', 'tracesSampleRate', 'SENTRY_DSN'\n", "requiredScopes": [] }, + { + "name": "submit_feedback", + "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", + "requiredScopes": [] + }, { "name": "whoami", "description": "Identify the authenticated user in Sentry.\n\nUse this tool when you need to:\n- Get the user's name and email address.", @@ -386,7 +401,7 @@ "description": "Resolve, assign, and update issues", "defaultEnabled": false, "order": 4, - "toolCount": 25, + "toolCount": 26, "tools": [ { "name": "add_issue_note", @@ -498,6 +513,11 @@ "description": "Search Sentry spans and traces: requests, API/HTTP calls, endpoints, DB queries, AI/LLM calls, and other operations. Use for latency, throughput, slowness, and performance questions.\n\n`query` is natural language (preferred) or Sentry search syntax; a configured agent translates it into query, fields, and sort.\n\nAlso use for spans whose trace contains a matching log, metric, or other span, e.g. 'slow checkout requests that also logged an error'.\n\nSupports aggregations ('p95 duration by span.op'), individual spans ('slowest API calls today'), and time series ('requests per minute last hour').\n\nNOT for exceptions/crashes (use search_errors), standalone log lines (use search_logs), or a single trace's span tree (use get_sentry_resource with the trace).\n\n\nsearch_traces(organizationSlug='my-org', query='slowest API calls in the last 24 hours')\nsearch_traces(organizationSlug='my-org', query='p95 duration of db spans grouped by span.op over 7 days')\nsearch_traces(organizationSlug='my-org', query='checkout requests that also have an error log')\n\n\n\n- name/otherName notation means /; parse it directly, don't call find_organizations/find_projects.\n- Natural language is usually enough. Only pass fields/sort when you need exact columns or ordering.\n", "requiredScopes": ["event:read"] }, + { + "name": "submit_feedback", + "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", + "requiredScopes": [] + }, { "name": "unlink_issue", "description": "Remove an external ticket or GitHub pull request reference from a Sentry issue by URL.\nRemoves only the Sentry association. It does not delete the external ticket or the Sentry issue, or change resolution status.\nSupports native integrations and installed Sentry Apps. Repeating the request is safe: not_linked means the association is absent, whether removed by this call or already absent.\n\nunlink_issue(organizationSlug='my-org', issueId='PROJECT-123', externalIssueUrl='https://github.com/example/repo/issues/42')\n", @@ -521,7 +541,7 @@ "description": "Create and modify projects, teams, DSNs, cron monitor environments, uptime monitors, metric monitors, and alert rules", "defaultEnabled": false, "order": 5, - "toolCount": 23, + "toolCount": 24, "tools": [ { "name": "add_team_to_project", @@ -608,6 +628,11 @@ "description": "Revoke a team's access to an existing Sentry project.\n\nUse this tool when you need to:\n- Remove a team from a project\n- Revoke team access without changing project metadata\n- Check project team assignments before removing access\n\nBe careful when using this tool because it revokes project access.\n\n\nremove_team_from_project(organizationSlug='my-organization', projectSlug='my-project', teamSlug='my-team')\n\n\n\n- The team must already be assigned to the project.\n- This tool will not remove the last team assigned to a project.\n", "requiredScopes": ["project:write", "team:read", "org:read"] }, + { + "name": "submit_feedback", + "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", + "requiredScopes": [] + }, { "name": "update_alert_rule", "description": "Update a Sentry Alert (workflow), including notification actions and connections.\nUse get_alert_rule with kind='issue' first to inspect the complete triggers and actionFilters configuration.\nUse get_alert_options to discover notification actions, integrations, conditions, and available sources.\nOmit fields to leave them unchanged. Pass null to clear owner or environment.\ntriggers replaces the trigger conditions. actionFilters replaces ALL action groups: copy the complete configuration, retain existing IDs, and change only the intended values. Omitted groups, conditions, and actions are removed.\nFor Slack or Microsoft Teams, change config.targetDisplay to the channel name and use integrationId for the workspace or team. Sentry resolves the channel ID. Slack also accepts an explicit new targetIdentifier; a copied old ID is cleared when the name or workspace changes.\nOther actions use their provider's config and data. For Discord, PagerDuty, Opsgenie, and email, update targetIdentifier to the channel, service, team, or recipient ID; changing only its display name does not change the destination.\nUse addProjectSlugs/removeProjectSlugs to connect/disconnect a project's issue stream. Other monitors in that project remain connected. Use addDetectorIds/removeDetectorIds for individual monitors. Unmentioned connections are preserved.\nMetric Monitor detection queries and thresholds are separate operations.\nAll-project connections require Sentry's all-project feature and an API token with org:write in addition to alerts:write.\nA project-constrained session can only edit alerts affecting that project exclusively.\nRequires alerts:write; reconnect OAuth if the existing token lacks it.\n\nupdate_alert_rule(organizationSlug='my-org', ruleIdOrName='12345', status='disabled')\nupdate_alert_rule(organizationSlug='my-org', projectSlug='backend', ruleIdOrName='Notify backend team', frequencyMinutes=30)\n", diff --git a/packages/mcp-core/src/toolDefinitions.json b/packages/mcp-core/src/toolDefinitions.json index 3165f01c0..83b39140e 100644 --- a/packages/mcp-core/src/toolDefinitions.json +++ b/packages/mcp-core/src/toolDefinitions.json @@ -7567,6 +7567,57 @@ "skills": ["inspect", "triage", "seer"], "surface": "direct" }, + { + "name": "submit_feedback", + "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", + "inputSchema": { + "type": "object", + "properties": { + "task": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "A short phrase naming what the user asked you to do." + }, + "kind": { + "type": "string", + "enum": ["missing", "broken", "confusing", "idea"], + "description": "missing: no tool could do it; broken: a tool failed or returned something wrong; confusing: a tool or its docs were unclear; idea: a suggestion." + }, + "impact": { + "type": "string", + "enum": ["blocked", "worked_around", "friction"], + "description": "blocked: you could not finish; worked_around: you finished another way; friction: you finished, but it was harder than it should be." + }, + "description": { + "type": "string", + "minLength": 1, + "maxLength": 4096, + "description": "What you tried, including tool calls and any error, and what went wrong." + }, + "toolName": { + "description": "The Sentry MCP tool the feedback is about, if any.", + "type": "string", + "maxLength": 100 + } + }, + "required": ["task", "kind", "impact", "description"] + }, + "outputSchema": { + "type": "object", + "properties": { + "submitted": { + "type": "boolean", + "description": "Whether the feedback was sent to the Sentry MCP maintainers." + } + }, + "required": ["submitted"], + "additionalProperties": false + }, + "requiredScopes": [], + "skills": ["inspect", "seer", "docs", "triage", "project-management"], + "surface": "catalog" + }, { "name": "unlink_issue", "description": "Remove an external ticket or GitHub pull request reference from a Sentry issue by URL.\nRemoves only the Sentry association. It does not delete the external ticket or the Sentry issue, or change resolution status.\nSupports native integrations and installed Sentry Apps. Repeating the request is safe: not_linked means the association is absent, whether removed by this call or already absent.\n\nunlink_issue(organizationSlug='my-org', issueId='PROJECT-123', externalIssueUrl='https://github.com/example/repo/issues/42')\n", diff --git a/packages/mcp-core/src/tools/catalog/index.ts b/packages/mcp-core/src/tools/catalog/index.ts index a156b888e..75ef2de99 100644 --- a/packages/mcp-core/src/tools/catalog/index.ts +++ b/packages/mcp-core/src/tools/catalog/index.ts @@ -71,6 +71,7 @@ import searchAgentConversations from "./search-agent-conversations"; import addIssueNote from "./add-issue-note"; import onboardingStatusUpdate from "./onboarding-status-update"; import searchAttributes from "./search-attributes"; +import submitFeedback from "./submit-feedback"; import type { ToolConfig } from "../types"; const legacyGetAIConversationDetails = { @@ -180,6 +181,7 @@ const catalogTools = { search_ai_conversations: legacySearchAIConversations, add_issue_note: addIssueNote, onboarding_status_update: onboardingStatusUpdate, + submit_feedback: submitFeedback, } as const satisfies Record>; export default catalogTools; diff --git a/packages/mcp-core/src/tools/catalog/submit-feedback.test.ts b/packages/mcp-core/src/tools/catalog/submit-feedback.test.ts new file mode 100644 index 000000000..5de203c61 --- /dev/null +++ b/packages/mcp-core/src/tools/catalog/submit-feedback.test.ts @@ -0,0 +1,69 @@ +import { captureFeedback, getClient } from "@sentry/core"; +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { createTestContext } from "../../test-utils/context.js"; +import { + assertStructuredOnlyResult, + getStructuredContent, +} from "../../test-utils/structured-content.js"; +import submitFeedback from "./submit-feedback.js"; + +vi.mock("@sentry/core", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + captureFeedback: vi.fn(() => "event-id"), + getClient: vi.fn(), + }; +}); + +const params = { + task: "find slow endpoints", + kind: "missing" as const, + impact: "blocked" as const, + description: "No tool returns p95 latency. Contact jane@example.com.", + toolName: "search_traces", +}; + +describe("submit_feedback", () => { + beforeEach(() => { + vi.mocked(captureFeedback).mockClear(); + vi.mocked(getClient).mockReturnValue({ + getDsn: () => ({ host: "o1.ingest.sentry.io" }), + } as unknown as ReturnType); + }); + + it("sends scrubbed feedback to Sentry", async () => { + const result = await submitFeedback.handler(params, createTestContext()); + + assertStructuredOnlyResult(result); + expect(getStructuredContent(result)).toMatchInlineSnapshot(` + { + "submitted": true, + } + `); + expect(vi.mocked(captureFeedback).mock.calls[0]?.[0]) + .toMatchInlineSnapshot(` + { + "message": "Task: find slow endpoints + Tool: search_traces + + No tool returns p95 latency. Contact [REDACTED_EMAIL].", + "source": "mcp_agent", + "tags": { + "feedback.impact": "blocked", + "feedback.kind": "missing", + "feedback.tool": "search_traces", + }, + } + `); + }); + + it("does not send feedback when Sentry is not configured", async () => { + vi.mocked(getClient).mockReturnValue(undefined); + + const result = await submitFeedback.handler(params, createTestContext()); + + expect(getStructuredContent(result)).toEqual({ submitted: false }); + expect(captureFeedback).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/mcp-core/src/tools/catalog/submit-feedback.ts b/packages/mcp-core/src/tools/catalog/submit-feedback.ts new file mode 100644 index 000000000..d18ec938d --- /dev/null +++ b/packages/mcp-core/src/tools/catalog/submit-feedback.ts @@ -0,0 +1,102 @@ +import { captureFeedback, getClient } from "@sentry/core"; +import { z } from "zod"; +import { defineTool } from "../../internal/tool-helpers/define"; +import { structuredResult } from "../../internal/tool-helpers/results"; +import { ALL_SKILLS } from "../../skills"; +import { scrubSensitiveText } from "../../telem/sentry"; + +export const submitFeedbackOutputSchema = z.object({ + submitted: z + .boolean() + .describe("Whether the feedback was sent to the Sentry MCP maintainers."), +}); + +export default defineTool({ + name: "submit_feedback", + description: [ + "Report friction with the Sentry MCP server to its maintainers.", + "", + "Use this tool when you need to:", + "- Report that no Sentry MCP tool could do what the user asked", + "- Report a tool that failed, returned wrong data, or was confusing", + "- Suggest an improvement to the Sentry MCP tools", + "", + "", + "submit_feedback(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')", + "", + "", + "", + "- Call at most once per task, after you finish or give up.", + "- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.", + "- Do not include secrets, credentials, or personal data.", + "", + ].join("\n"), + inputSchema: { + task: z + .string() + .trim() + .min(1) + .max(200) + .describe("A short phrase naming what the user asked you to do."), + kind: z + .enum(["missing", "broken", "confusing", "idea"]) + .describe( + "missing: no tool could do it; broken: a tool failed or returned something wrong; confusing: a tool or its docs were unclear; idea: a suggestion.", + ), + impact: z + .enum(["blocked", "worked_around", "friction"]) + .describe( + "blocked: you could not finish; worked_around: you finished another way; friction: you finished, but it was harder than it should be.", + ), + description: z + .string() + .trim() + .min(1) + .max(4096) + .describe( + "What you tried, including tool calls and any error, and what went wrong.", + ), + toolName: z + .string() + .trim() + .max(100) + .optional() + .describe("The Sentry MCP tool the feedback is about, if any."), + }, + outputSchema: submitFeedbackOutputSchema, + skills: ALL_SKILLS, + requiredScopes: [], + annotations: { + readOnlyHint: false, + destructiveHint: false, + openWorldHint: true, + }, + async handler(params) { + // Without a configured DSN (e.g. stdio without SENTRY_DSN) there is + // nowhere to send feedback, so report that instead of pretending. + if (!getClient()?.getDsn()) { + return structuredResult({ submitted: false }); + } + + captureFeedback({ + source: "mcp_agent", + message: scrubSensitiveText( + [ + `Task: ${params.task}`, + params.toolName ? `Tool: ${params.toolName}` : null, + "", + params.description, + ] + .filter((line): line is string => line !== null) + .join("\n"), + ), + tags: { + "feedback.kind": params.kind, + "feedback.impact": params.impact, + ...(params.toolName ? { "feedback.tool": params.toolName } : {}), + }, + }); + + return structuredResult({ submitted: true }); + }, +}); From cffd83e1d9fc6f6396216a23b23a6efc7d260453 Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2026 17:32:13 +0000 Subject: [PATCH 2/4] fix(mcp-core): Hide submit_feedback when Sentry has no DSN Without a DSN the tool cannot deliver feedback, so drop it from the available tools instead of returning submitted: false. Co-Authored-By: David Cramer Co-Authored-By: Scott Cooper --- packages/mcp-core/src/server.test.ts | 1 + packages/mcp-core/src/toolDefinitions.json | 8 ++-- .../catalog-runtime/availability.test.ts | 22 ++++++++- .../src/tools/catalog-runtime/availability.ts | 11 +++++ .../src/tools/catalog/submit-feedback.test.ts | 47 ++++++------------- .../src/tools/catalog/submit-feedback.ts | 18 +++---- 6 files changed, 57 insertions(+), 50 deletions(-) diff --git a/packages/mcp-core/src/server.test.ts b/packages/mcp-core/src/server.test.ts index d0a99a772..f6051172b 100644 --- a/packages/mcp-core/src/server.test.ts +++ b/packages/mcp-core/src/server.test.ts @@ -42,6 +42,7 @@ vi.mock("@sentry/core", () => ({ ), captureException: vi.fn(), captureMessage: vi.fn(), + getClient: vi.fn(), })); vi.mock("@sentry/core/server", () => ({ diff --git a/packages/mcp-core/src/toolDefinitions.json b/packages/mcp-core/src/toolDefinitions.json index 83b39140e..d632e3cde 100644 --- a/packages/mcp-core/src/toolDefinitions.json +++ b/packages/mcp-core/src/toolDefinitions.json @@ -7606,12 +7606,12 @@ "outputSchema": { "type": "object", "properties": { - "submitted": { - "type": "boolean", - "description": "Whether the feedback was sent to the Sentry MCP maintainers." + "feedbackId": { + "type": "string", + "description": "ID of the feedback sent to the Sentry MCP maintainers." } }, - "required": ["submitted"], + "required": ["feedbackId"], "additionalProperties": false }, "requiredScopes": [], diff --git a/packages/mcp-core/src/tools/catalog-runtime/availability.test.ts b/packages/mcp-core/src/tools/catalog-runtime/availability.test.ts index b627354c8..eee80d490 100644 --- a/packages/mcp-core/src/tools/catalog-runtime/availability.test.ts +++ b/packages/mcp-core/src/tools/catalog-runtime/availability.test.ts @@ -1,4 +1,5 @@ -import { describe, expect, it } from "vitest"; +import { getClient } from "@sentry/core"; +import { describe, expect, it, vi } from "vitest"; import type { Skill } from "../../skills"; import { getServerContext } from "../../test-setup"; import type { ServerContext } from "../../types"; @@ -14,6 +15,11 @@ import { prepareToolParams, } from "./availability"; +vi.mock("@sentry/core", async (importOriginal) => { + const actual = await importOriginal(); + return { ...actual, getClient: vi.fn(actual.getClient) }; +}); + function getProjectManagementContext( constraints: Partial = {}, ): ServerContext { @@ -74,6 +80,20 @@ describe("catalog availability", () => { ); }); + it("shows submit_feedback only when Sentry telemetry has a DSN", () => { + const context = getServerContext({ + grantedSkills: new Set(["inspect"]), + }); + + vi.mocked(getClient).mockReturnValueOnce(undefined); + expect(getSearchableToolNames(context)).not.toContain("submit_feedback"); + + vi.mocked(getClient).mockReturnValueOnce({ + getDsn: () => ({ host: "o1.ingest.sentry.io" }), + } as unknown as ReturnType); + expect(getSearchableToolNames(context)).toContain("submit_feedback"); + }); + it("hides create_project from project-scoped project-management sessions", () => { const context = getProjectManagementContext({ organizationSlug: "my-org", diff --git a/packages/mcp-core/src/tools/catalog-runtime/availability.ts b/packages/mcp-core/src/tools/catalog-runtime/availability.ts index dc9c0237c..11a87acb8 100644 --- a/packages/mcp-core/src/tools/catalog-runtime/availability.ts +++ b/packages/mcp-core/src/tools/catalog-runtime/availability.ts @@ -1,4 +1,5 @@ import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js"; +import { getClient } from "@sentry/core"; import type { ServerNotification, ServerRequest, @@ -117,6 +118,12 @@ function isHiddenByConstraints({ ); } +// submit_feedback can only deliver reports when Sentry telemetry has a DSN +// (e.g. stdio without SENTRY_DSN has none), so hide it otherwise. +function isMissingFeedbackDsn(key: string): boolean { + return key === "submit_feedback" && !getClient()?.getDsn(); +} + export function getFilteredInputSchema( tool: ToolConfig, context: ServerContext, @@ -180,6 +187,10 @@ export function getAvailableTools({ continue; } + if (isMissingFeedbackDsn(key)) { + continue; + } + availableTools.push({ key, tool, ...placement }); } diff --git a/packages/mcp-core/src/tools/catalog/submit-feedback.test.ts b/packages/mcp-core/src/tools/catalog/submit-feedback.test.ts index 5de203c61..315a7ec98 100644 --- a/packages/mcp-core/src/tools/catalog/submit-feedback.test.ts +++ b/packages/mcp-core/src/tools/catalog/submit-feedback.test.ts @@ -1,5 +1,5 @@ -import { captureFeedback, getClient } from "@sentry/core"; -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { captureFeedback } from "@sentry/core"; +import { describe, expect, it, vi } from "vitest"; import { createTestContext } from "../../test-utils/context.js"; import { assertStructuredOnlyResult, @@ -9,36 +9,26 @@ import submitFeedback from "./submit-feedback.js"; vi.mock("@sentry/core", async (importOriginal) => { const actual = await importOriginal(); - return { - ...actual, - captureFeedback: vi.fn(() => "event-id"), - getClient: vi.fn(), - }; + return { ...actual, captureFeedback: vi.fn(() => "event-id") }; }); -const params = { - task: "find slow endpoints", - kind: "missing" as const, - impact: "blocked" as const, - description: "No tool returns p95 latency. Contact jane@example.com.", - toolName: "search_traces", -}; - describe("submit_feedback", () => { - beforeEach(() => { - vi.mocked(captureFeedback).mockClear(); - vi.mocked(getClient).mockReturnValue({ - getDsn: () => ({ host: "o1.ingest.sentry.io" }), - } as unknown as ReturnType); - }); - it("sends scrubbed feedback to Sentry", async () => { - const result = await submitFeedback.handler(params, createTestContext()); + const result = await submitFeedback.handler( + { + task: "find slow endpoints", + kind: "missing", + impact: "blocked", + description: "No tool returns p95 latency. Contact jane@example.com.", + toolName: "search_traces", + }, + createTestContext(), + ); assertStructuredOnlyResult(result); expect(getStructuredContent(result)).toMatchInlineSnapshot(` { - "submitted": true, + "feedbackId": "event-id", } `); expect(vi.mocked(captureFeedback).mock.calls[0]?.[0]) @@ -57,13 +47,4 @@ describe("submit_feedback", () => { } `); }); - - it("does not send feedback when Sentry is not configured", async () => { - vi.mocked(getClient).mockReturnValue(undefined); - - const result = await submitFeedback.handler(params, createTestContext()); - - expect(getStructuredContent(result)).toEqual({ submitted: false }); - expect(captureFeedback).not.toHaveBeenCalled(); - }); }); diff --git a/packages/mcp-core/src/tools/catalog/submit-feedback.ts b/packages/mcp-core/src/tools/catalog/submit-feedback.ts index d18ec938d..29cc23db4 100644 --- a/packages/mcp-core/src/tools/catalog/submit-feedback.ts +++ b/packages/mcp-core/src/tools/catalog/submit-feedback.ts @@ -1,4 +1,4 @@ -import { captureFeedback, getClient } from "@sentry/core"; +import { captureFeedback } from "@sentry/core"; import { z } from "zod"; import { defineTool } from "../../internal/tool-helpers/define"; import { structuredResult } from "../../internal/tool-helpers/results"; @@ -6,9 +6,9 @@ import { ALL_SKILLS } from "../../skills"; import { scrubSensitiveText } from "../../telem/sentry"; export const submitFeedbackOutputSchema = z.object({ - submitted: z - .boolean() - .describe("Whether the feedback was sent to the Sentry MCP maintainers."), + feedbackId: z + .string() + .describe("ID of the feedback sent to the Sentry MCP maintainers."), }); export default defineTool({ @@ -72,13 +72,7 @@ export default defineTool({ openWorldHint: true, }, async handler(params) { - // Without a configured DSN (e.g. stdio without SENTRY_DSN) there is - // nowhere to send feedback, so report that instead of pretending. - if (!getClient()?.getDsn()) { - return structuredResult({ submitted: false }); - } - - captureFeedback({ + const feedbackId = captureFeedback({ source: "mcp_agent", message: scrubSensitiveText( [ @@ -97,6 +91,6 @@ export default defineTool({ }, }); - return structuredResult({ submitted: true }); + return structuredResult({ feedbackId }); }, }); From 8aaa68e3765e8bf7c8494b13dde1eb692539bb04 Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2026 17:35:30 +0000 Subject: [PATCH 3/4] fix(mcp-core): Cap submit_feedback message at Sentry's 4096 limit Co-Authored-By: Scott Cooper Co-Authored-By: David Cramer --- .../src/tools/catalog/submit-feedback.test.ts | 17 ++++++++++++ .../src/tools/catalog/submit-feedback.ts | 26 ++++++++++++------- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/packages/mcp-core/src/tools/catalog/submit-feedback.test.ts b/packages/mcp-core/src/tools/catalog/submit-feedback.test.ts index 315a7ec98..40693666a 100644 --- a/packages/mcp-core/src/tools/catalog/submit-feedback.test.ts +++ b/packages/mcp-core/src/tools/catalog/submit-feedback.test.ts @@ -47,4 +47,21 @@ describe("submit_feedback", () => { } `); }); + + it("truncates messages to Sentry's feedback length limit", async () => { + await submitFeedback.handler( + { + task: "find slow endpoints", + kind: "broken", + impact: "friction", + description: "x".repeat(4096), + toolName: "search_traces", + }, + createTestContext(), + ); + + const message = vi.mocked(captureFeedback).mock.calls.at(-1)?.[0].message; + expect(message?.startsWith("Task: find slow endpoints\n")).toBe(true); + expect(message).toHaveLength(4096); + }); }); diff --git a/packages/mcp-core/src/tools/catalog/submit-feedback.ts b/packages/mcp-core/src/tools/catalog/submit-feedback.ts index 29cc23db4..fdae09dd8 100644 --- a/packages/mcp-core/src/tools/catalog/submit-feedback.ts +++ b/packages/mcp-core/src/tools/catalog/submit-feedback.ts @@ -5,6 +5,10 @@ import { structuredResult } from "../../internal/tool-helpers/results"; import { ALL_SKILLS } from "../../skills"; import { scrubSensitiveText } from "../../telem/sentry"; +// Sentry rejects User Feedback messages longer than 4096 code points. Slicing +// UTF-16 units keeps us at or under that. +const MAX_FEEDBACK_MESSAGE_LENGTH = 4096; + export const submitFeedbackOutputSchema = z.object({ feedbackId: z .string() @@ -72,18 +76,20 @@ export default defineTool({ openWorldHint: true, }, async handler(params) { + const message = scrubSensitiveText( + [ + `Task: ${params.task}`, + params.toolName ? `Tool: ${params.toolName}` : null, + "", + params.description, + ] + .filter((line): line is string => line !== null) + .join("\n"), + ); + const feedbackId = captureFeedback({ source: "mcp_agent", - message: scrubSensitiveText( - [ - `Task: ${params.task}`, - params.toolName ? `Tool: ${params.toolName}` : null, - "", - params.description, - ] - .filter((line): line is string => line !== null) - .join("\n"), - ), + message: message.slice(0, MAX_FEEDBACK_MESSAGE_LENGTH), tags: { "feedback.kind": params.kind, "feedback.impact": params.impact, From 62b4d60bea942bf796d2968b8abf4b6e247af227 Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2026 17:38:21 +0000 Subject: [PATCH 4/4] ref(mcp-core): Rename submit_feedback to submit_feedback_to_sentry_team Makes the destination explicit so agents don't confuse it with the user's own Sentry org. Co-Authored-By: Scott Cooper Co-Authored-By: David Cramer --- packages/mcp-core/src/skillDefinitions.json | 20 +++++++++---------- packages/mcp-core/src/toolDefinitions.json | 4 ++-- .../catalog-runtime/availability.test.ts | 10 +++++++--- .../src/tools/catalog-runtime/availability.ts | 4 ++-- packages/mcp-core/src/tools/catalog/index.ts | 4 ++-- ...=> submit-feedback-to-sentry-team.test.ts} | 8 ++++---- ...k.ts => submit-feedback-to-sentry-team.ts} | 8 ++++---- 7 files changed, 31 insertions(+), 27 deletions(-) rename packages/mcp-core/src/tools/catalog/{submit-feedback.test.ts => submit-feedback-to-sentry-team.test.ts} (88%) rename packages/mcp-core/src/tools/catalog/{submit-feedback.ts => submit-feedback-to-sentry-team.ts} (90%) diff --git a/packages/mcp-core/src/skillDefinitions.json b/packages/mcp-core/src/skillDefinitions.json index c0495010e..41beeedd0 100644 --- a/packages/mcp-core/src/skillDefinitions.json +++ b/packages/mcp-core/src/skillDefinitions.json @@ -238,8 +238,8 @@ "requiredScopes": ["event:read"] }, { - "name": "submit_feedback", - "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", + "name": "submit_feedback_to_sentry_team", + "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback_to_sentry_team(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", "requiredScopes": [] }, { @@ -338,8 +338,8 @@ "requiredScopes": ["event:read"] }, { - "name": "submit_feedback", - "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", + "name": "submit_feedback_to_sentry_team", + "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback_to_sentry_team(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", "requiredScopes": [] }, { @@ -384,8 +384,8 @@ "requiredScopes": [] }, { - "name": "submit_feedback", - "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", + "name": "submit_feedback_to_sentry_team", + "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback_to_sentry_team(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", "requiredScopes": [] }, { @@ -514,8 +514,8 @@ "requiredScopes": ["event:read"] }, { - "name": "submit_feedback", - "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", + "name": "submit_feedback_to_sentry_team", + "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback_to_sentry_team(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", "requiredScopes": [] }, { @@ -629,8 +629,8 @@ "requiredScopes": ["project:write", "team:read", "org:read"] }, { - "name": "submit_feedback", - "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", + "name": "submit_feedback_to_sentry_team", + "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback_to_sentry_team(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", "requiredScopes": [] }, { diff --git a/packages/mcp-core/src/toolDefinitions.json b/packages/mcp-core/src/toolDefinitions.json index d632e3cde..827186518 100644 --- a/packages/mcp-core/src/toolDefinitions.json +++ b/packages/mcp-core/src/toolDefinitions.json @@ -7568,8 +7568,8 @@ "surface": "direct" }, { - "name": "submit_feedback", - "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", + "name": "submit_feedback_to_sentry_team", + "description": "Report friction with the Sentry MCP server to its maintainers.\n\nUse this tool when you need to:\n- Report that no Sentry MCP tool could do what the user asked\n- Report a tool that failed, returned wrong data, or was confusing\n- Suggest an improvement to the Sentry MCP tools\n\n\nsubmit_feedback_to_sentry_team(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')\n\n\n\n- Call at most once per task, after you finish or give up.\n- Feedback goes to the Sentry MCP maintainers, not the user's Sentry organization.\n- Do not include secrets, credentials, or personal data.\n", "inputSchema": { "type": "object", "properties": { diff --git a/packages/mcp-core/src/tools/catalog-runtime/availability.test.ts b/packages/mcp-core/src/tools/catalog-runtime/availability.test.ts index eee80d490..be2fc1cc5 100644 --- a/packages/mcp-core/src/tools/catalog-runtime/availability.test.ts +++ b/packages/mcp-core/src/tools/catalog-runtime/availability.test.ts @@ -80,18 +80,22 @@ describe("catalog availability", () => { ); }); - it("shows submit_feedback only when Sentry telemetry has a DSN", () => { + it("shows submit_feedback_to_sentry_team only when Sentry telemetry has a DSN", () => { const context = getServerContext({ grantedSkills: new Set(["inspect"]), }); vi.mocked(getClient).mockReturnValueOnce(undefined); - expect(getSearchableToolNames(context)).not.toContain("submit_feedback"); + expect(getSearchableToolNames(context)).not.toContain( + "submit_feedback_to_sentry_team", + ); vi.mocked(getClient).mockReturnValueOnce({ getDsn: () => ({ host: "o1.ingest.sentry.io" }), } as unknown as ReturnType); - expect(getSearchableToolNames(context)).toContain("submit_feedback"); + expect(getSearchableToolNames(context)).toContain( + "submit_feedback_to_sentry_team", + ); }); it("hides create_project from project-scoped project-management sessions", () => { diff --git a/packages/mcp-core/src/tools/catalog-runtime/availability.ts b/packages/mcp-core/src/tools/catalog-runtime/availability.ts index 11a87acb8..7d3feff6c 100644 --- a/packages/mcp-core/src/tools/catalog-runtime/availability.ts +++ b/packages/mcp-core/src/tools/catalog-runtime/availability.ts @@ -118,10 +118,10 @@ function isHiddenByConstraints({ ); } -// submit_feedback can only deliver reports when Sentry telemetry has a DSN +// submit_feedback_to_sentry_team can only deliver reports when Sentry telemetry has a DSN // (e.g. stdio without SENTRY_DSN has none), so hide it otherwise. function isMissingFeedbackDsn(key: string): boolean { - return key === "submit_feedback" && !getClient()?.getDsn(); + return key === "submit_feedback_to_sentry_team" && !getClient()?.getDsn(); } export function getFilteredInputSchema( diff --git a/packages/mcp-core/src/tools/catalog/index.ts b/packages/mcp-core/src/tools/catalog/index.ts index 75ef2de99..0b47f82f1 100644 --- a/packages/mcp-core/src/tools/catalog/index.ts +++ b/packages/mcp-core/src/tools/catalog/index.ts @@ -71,7 +71,7 @@ import searchAgentConversations from "./search-agent-conversations"; import addIssueNote from "./add-issue-note"; import onboardingStatusUpdate from "./onboarding-status-update"; import searchAttributes from "./search-attributes"; -import submitFeedback from "./submit-feedback"; +import submitFeedbackToSentryTeam from "./submit-feedback-to-sentry-team"; import type { ToolConfig } from "../types"; const legacyGetAIConversationDetails = { @@ -181,7 +181,7 @@ const catalogTools = { search_ai_conversations: legacySearchAIConversations, add_issue_note: addIssueNote, onboarding_status_update: onboardingStatusUpdate, - submit_feedback: submitFeedback, + submit_feedback_to_sentry_team: submitFeedbackToSentryTeam, } as const satisfies Record>; export default catalogTools; diff --git a/packages/mcp-core/src/tools/catalog/submit-feedback.test.ts b/packages/mcp-core/src/tools/catalog/submit-feedback-to-sentry-team.test.ts similarity index 88% rename from packages/mcp-core/src/tools/catalog/submit-feedback.test.ts rename to packages/mcp-core/src/tools/catalog/submit-feedback-to-sentry-team.test.ts index 40693666a..398af683b 100644 --- a/packages/mcp-core/src/tools/catalog/submit-feedback.test.ts +++ b/packages/mcp-core/src/tools/catalog/submit-feedback-to-sentry-team.test.ts @@ -5,16 +5,16 @@ import { assertStructuredOnlyResult, getStructuredContent, } from "../../test-utils/structured-content.js"; -import submitFeedback from "./submit-feedback.js"; +import submitFeedbackToSentryTeam from "./submit-feedback-to-sentry-team.js"; vi.mock("@sentry/core", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, captureFeedback: vi.fn(() => "event-id") }; }); -describe("submit_feedback", () => { +describe("submit_feedback_to_sentry_team", () => { it("sends scrubbed feedback to Sentry", async () => { - const result = await submitFeedback.handler( + const result = await submitFeedbackToSentryTeam.handler( { task: "find slow endpoints", kind: "missing", @@ -49,7 +49,7 @@ describe("submit_feedback", () => { }); it("truncates messages to Sentry's feedback length limit", async () => { - await submitFeedback.handler( + await submitFeedbackToSentryTeam.handler( { task: "find slow endpoints", kind: "broken", diff --git a/packages/mcp-core/src/tools/catalog/submit-feedback.ts b/packages/mcp-core/src/tools/catalog/submit-feedback-to-sentry-team.ts similarity index 90% rename from packages/mcp-core/src/tools/catalog/submit-feedback.ts rename to packages/mcp-core/src/tools/catalog/submit-feedback-to-sentry-team.ts index fdae09dd8..a9d9021da 100644 --- a/packages/mcp-core/src/tools/catalog/submit-feedback.ts +++ b/packages/mcp-core/src/tools/catalog/submit-feedback-to-sentry-team.ts @@ -9,14 +9,14 @@ import { scrubSensitiveText } from "../../telem/sentry"; // UTF-16 units keeps us at or under that. const MAX_FEEDBACK_MESSAGE_LENGTH = 4096; -export const submitFeedbackOutputSchema = z.object({ +export const submitFeedbackToSentryTeamOutputSchema = z.object({ feedbackId: z .string() .describe("ID of the feedback sent to the Sentry MCP maintainers."), }); export default defineTool({ - name: "submit_feedback", + name: "submit_feedback_to_sentry_team", description: [ "Report friction with the Sentry MCP server to its maintainers.", "", @@ -26,7 +26,7 @@ export default defineTool({ "- Suggest an improvement to the Sentry MCP tools", "", "", - "submit_feedback(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')", + "submit_feedback_to_sentry_team(task='find slow endpoints', kind='missing', impact='blocked', description='No tool returns p95 latency per endpoint.')", "", "", "", @@ -67,7 +67,7 @@ export default defineTool({ .optional() .describe("The Sentry MCP tool the feedback is about, if any."), }, - outputSchema: submitFeedbackOutputSchema, + outputSchema: submitFeedbackToSentryTeamOutputSchema, skills: ALL_SKILLS, requiredScopes: [], annotations: {