@debugg-ai/debugg-ai-mcp 3.0.1 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,39 @@ All notable changes to the DebuggAI MCP project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.2.0]
9
+
10
+ ### Added — Structured tool output (`structuredContent`)
11
+
12
+ Every successful tool result now carries [`structuredContent`](https://modelcontextprotocol.io/specification/2025-06-18/server/tools)
13
+ — the parsed JSON payload — so clients can consume structured data directly
14
+ instead of re-parsing the text blob. The text block is kept for back-compat.
15
+
16
+ Promoted centrally in the CallTool path (`withStructuredContent` in
17
+ `utils/structuredContent.ts`) rather than touching every handler. No-op for
18
+ errors, non-object payloads, or multi-text results.
19
+
20
+ `outputSchema` is intentionally not declared: the action tools return
21
+ polymorphic shapes per action, a faithful schema would need top-level `oneOf`
22
+ (which the Anthropic API rejects), and a permissive schema adds no value.
23
+ `structuredContent` without a declared schema is spec-valid and is the win.
24
+
25
+ ## [3.1.0]
26
+
27
+ ### Added — Tool annotations (behavioral hints for clients)
28
+
29
+ Every tool now declares MCP [tool annotations](https://modelcontextprotocol.io/specification/2025-06-18/server/tools)
30
+ so clients can reason about a tool before calling it (e.g. confirm-gate
31
+ destructive ops, fast-path read-only ones):
32
+
33
+ - `environment`, `test_suite`, `test_case` → `destructiveHint: true` (expose a delete action)
34
+ - `executions`, `probe_page` → `readOnlyHint: true`
35
+ - `project`, `check_app_in_browser`, `trigger_crawl` → write but non-destructive
36
+ - all tools → `openWorldHint: true` (they reach the DebuggAI backend / live web)
37
+
38
+ Annotations are advisory; deletes are still enforced server-side via the existing
39
+ confirmation gate. Presets live in `tools/annotations.ts`.
40
+
8
41
  ## [3.0.1]
9
42
 
10
43
  ### Fixed — 5 action tools were invisible in Claude Code (and any Anthropic-API client)
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
21
21
  import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
22
22
  import { config } from "./config/index.js";
23
23
  import { initTools, getTools, getTool } from "./tools/index.js";
24
- import { Logger, validateInput, createErrorResponse, toMCPError, handleConfigurationError, Telemetry, TelemetryEvents, } from "./utils/index.js";
24
+ import { Logger, validateInput, createErrorResponse, toMCPError, handleConfigurationError, Telemetry, TelemetryEvents, withStructuredContent, } from "./utils/index.js";
25
25
  import { MCPErrorCode, MCPError, } from "./types/index.js";
26
26
  // Logger and server are initialized lazily in main() to avoid triggering
27
27
  // config loading at module load time. If config validation fails (bad env vars),
@@ -116,7 +116,8 @@ function registerHandlers() {
116
116
  const toolDuration = Date.now() - toolStart;
117
117
  requestLogger.info(`Tool execution completed: ${name}`);
118
118
  Telemetry.capture(TelemetryEvents.TOOL_EXECUTED, { toolName: name, durationMs: toolDuration, success: true });
119
- return result;
119
+ // Promote the JSON text payload to structuredContent (back-compat: text stays).
120
+ return withStructuredContent(result);
120
121
  }
121
122
  catch (error) {
122
123
  const mcpError = toMCPError(error, 'tool execution');
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Tool annotation presets (epic p7gft).
3
+ *
4
+ * Annotations are *hints* (MCP 2025-03-26+) that let clients reason about a tool
5
+ * before calling it — e.g. confirm-gate destructive tools, fast-path read-only
6
+ * ones. They are advisory; the server still enforces real safety (deletes also
7
+ * require confirmation via confirmDestructive.ts).
8
+ *
9
+ * Every DebuggAI tool talks to the backend and/or the open web, so
10
+ * `openWorldHint` is true everywhere. `readOnlyHint`/`destructiveHint` reflect a
11
+ * tool's MOST powerful action — the action tools mix reads and writes under one
12
+ * name, so the annotation is the conservative worst case:
13
+ * - READ_ONLY : only get/list/probe — never mutates backend state
14
+ * - WRITES : can create/update/run (not read-only) but cannot delete
15
+ * - DESTRUCTIVE : exposes a delete action (irreversible) — clients should confirm
16
+ *
17
+ * Per the spec, `destructiveHint`/`idempotentHint` are only meaningful when
18
+ * `readOnlyHint` is false, so READ_ONLY omits them.
19
+ */
20
+ export const READ_ONLY = {
21
+ readOnlyHint: true,
22
+ openWorldHint: true,
23
+ };
24
+ export const WRITES = {
25
+ readOnlyHint: false,
26
+ destructiveHint: false,
27
+ openWorldHint: true,
28
+ };
29
+ export const DESTRUCTIVE = {
30
+ readOnlyHint: false,
31
+ destructiveHint: true,
32
+ openWorldHint: true,
33
+ };
@@ -1,5 +1,6 @@
1
1
  import { EnvironmentInputSchema } from '../types/index.js';
2
2
  import { environmentHandler } from '../handlers/environmentHandler.js';
3
+ import { DESTRUCTIVE } from './annotations.js';
3
4
  const CRED_ITEM = {
4
5
  type: 'object',
5
6
  properties: {
@@ -18,6 +19,7 @@ export function buildEnvironmentTool() {
18
19
  return {
19
20
  name: 'environment',
20
21
  title: 'Environment',
22
+ annotations: DESTRUCTIVE,
21
23
  description: DESCRIPTION,
22
24
  inputSchema: {
23
25
  type: 'object',
@@ -1,5 +1,6 @@
1
1
  import { ExecutionsInputSchema } from '../types/index.js';
2
2
  import { executionsHandler } from '../handlers/executionsHandler.js';
3
+ import { READ_ONLY } from './annotations.js';
3
4
  const DESCRIPTION = `Look up workflow executions (history of check_app_in_browser, trigger_crawl, and test-suite runs). Pass an "action":
4
5
  - "get" {uuid} → one execution with FULL detail (nodeExecutions, state, errorInfo) + any screenshot/gif artifacts.
5
6
  - "list" {projectUuid?, status?, page?, pageSize?} → paginated execution summaries. status ∈ completed|running|failed|cancelled|pending.
@@ -9,6 +10,7 @@ export function buildExecutionsTool() {
9
10
  return {
10
11
  name: 'executions',
11
12
  title: 'Workflow Executions',
13
+ annotations: READ_ONLY,
12
14
  description: DESCRIPTION,
13
15
  inputSchema: {
14
16
  type: 'object',
@@ -11,6 +11,7 @@
11
11
  */
12
12
  import { ProbePageInputSchema } from '../types/index.js';
13
13
  import { probePageHandler } from '../handlers/probePageHandler.js';
14
+ import { READ_ONLY } from './annotations.js';
14
15
  const DESCRIPTION = `Probe one or more URLs and return their rendered state — screenshot, page metadata (title/finalUrl/statusCode/loadTimeMs), structured console errors, and per-URL network summary (refetch loops collapse into one row by origin+pathname).
15
16
 
16
17
  WHEN TO USE: "did I just break /settings?" / "smoke-test these 5 routes after my refactor" / "what's actually rendering at /dashboard?" — fast (<10s for 1 URL, <25s for 20), no LLM cost, no agent loop.
@@ -45,6 +46,7 @@ export function buildProbePageTool() {
45
46
  return {
46
47
  name: 'probe_page',
47
48
  title: 'Probe Page',
49
+ annotations: READ_ONLY,
48
50
  description: DESCRIPTION,
49
51
  inputSchema: {
50
52
  type: 'object',
@@ -1,5 +1,6 @@
1
1
  import { ProjectInputSchema } from '../types/index.js';
2
2
  import { projectHandler } from '../handlers/projectHandler.js';
3
+ import { WRITES } from './annotations.js';
3
4
  const DESCRIPTION = `Manage DebuggAI projects. Pass an "action":
4
5
  - "get" {uuid} → one project with full detail.
5
6
  - "list" {q?, page?, pageSize?} → paginated project summaries.
@@ -10,6 +11,7 @@ export function buildProjectTool() {
10
11
  return {
11
12
  name: 'project',
12
13
  title: 'Project',
14
+ annotations: WRITES,
13
15
  description: DESCRIPTION,
14
16
  inputSchema: {
15
17
  type: 'object',
@@ -1,5 +1,6 @@
1
1
  import { TestCaseInputSchema } from '../types/index.js';
2
2
  import { testCaseHandler } from '../handlers/testCaseHandler.js';
3
+ import { DESTRUCTIVE } from './annotations.js';
3
4
  const DESCRIPTION = `Manage individual test cases within a suite. Pass an "action":
4
5
  - "create" {name, description, agentTaskDescription, suiteUuid|(suiteName+project), relativeUrl?, maxSteps?} → add a test case (NOT auto-run).
5
6
  - "update" {testUuid, name?, description?, agentTaskDescription?} → patch a test case.
@@ -8,6 +9,7 @@ export function buildTestCaseTool() {
8
9
  return {
9
10
  name: 'test_case',
10
11
  title: 'Test Case',
12
+ annotations: DESTRUCTIVE,
11
13
  description: DESCRIPTION,
12
14
  inputSchema: {
13
15
  type: 'object',
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { TestPageChangesInputSchema } from '../types/index.js';
7
7
  import { testPageChangesHandler } from '../handlers/testPageChangesHandler.js';
8
+ import { WRITES } from './annotations.js';
8
9
  const BASE_DESCRIPTION = `Give an AI agent eyes on a live website or app. The agent browses it, interacts with it, and tells you whether a given task or check passed. Works on localhost or any URL. Use for visual QA, flow validation, regression checks, or anything that needs a real browser to verify.
9
10
 
10
11
  LOCALHOST SUPPORT: Pass any localhost URL (e.g. http://localhost:3000) and it Just Works. A secure tunnel is automatically created so the remote browser can reach your local dev server — no manual ngrok setup, no port forwarding, no config.
@@ -43,6 +44,7 @@ export function buildTestPageChangesTool(ctx) {
43
44
  return {
44
45
  name: "check_app_in_browser",
45
46
  title: "Run E2E Browser Test",
47
+ annotations: WRITES,
46
48
  description: buildToolDescription(ctx),
47
49
  inputSchema: {
48
50
  type: "object",
@@ -1,5 +1,6 @@
1
1
  import { TestSuiteInputSchema } from '../types/index.js';
2
2
  import { testSuiteHandler } from '../handlers/testSuiteHandler.js';
3
+ import { DESTRUCTIVE } from './annotations.js';
3
4
  const DESCRIPTION = `Manage and run test suites. Identify a suite by suiteUuid, or suiteName + a project identifier (projectUuid|projectName). Pass an "action":
4
5
  - "list" {projectUuid|projectName, search?, page?, pageSize?} → paginated suites with status/pass-rate.
5
6
  - "create" {name, description, projectUuid|projectName} → create a suite.
@@ -18,6 +19,7 @@ export function buildTestSuiteTool() {
18
19
  return {
19
20
  name: 'test_suite',
20
21
  title: 'Test Suite',
22
+ annotations: DESTRUCTIVE,
21
23
  description: DESCRIPTION,
22
24
  inputSchema: {
23
25
  type: 'object',
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { TriggerCrawlInputSchema } from '../types/index.js';
7
7
  import { triggerCrawlHandler } from '../handlers/triggerCrawlHandler.js';
8
+ import { WRITES } from './annotations.js';
8
9
  const BASE_DESCRIPTION = `Trigger a browser-agent crawl of a web app to build the project's knowledge graph. The crawl systematically explores pages, UI states, and navigation flows, then populates the backend's knowledge graph so future evaluations and tests have context about the app.
9
10
 
10
11
  LOCALHOST SUPPORT: Pass any localhost URL (e.g. http://localhost:3000) and it Just Works. A secure tunnel is automatically created so the remote browser can reach your local dev server.
@@ -39,6 +40,7 @@ export function buildTriggerCrawlTool(ctx) {
39
40
  return {
40
41
  name: 'trigger_crawl',
41
42
  title: 'Trigger App Crawl',
43
+ annotations: WRITES,
42
44
  description: buildTriggerCrawlDescription(ctx),
43
45
  inputSchema: {
44
46
  type: 'object',
@@ -7,3 +7,4 @@ export * from './errors.js';
7
7
  export * from './projectAnalyzer.js';
8
8
  export * from './imageUtils.js';
9
9
  export * from './telemetry.js';
10
+ export * from './structuredContent.js';
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Structured tool output (epic 3eb5l).
3
+ *
4
+ * MCP 2025-06-18 added `structuredContent` on tool results: a machine-readable
5
+ * JSON object that mirrors the human-readable text block. Clients that support
6
+ * it consume parsed data directly instead of re-parsing the text blob; the text
7
+ * block stays for back-compat.
8
+ *
9
+ * Every leaf handler already returns its payload as `JSON.stringify(payload)` in
10
+ * a single text item, so rather than touch ~20 handlers we promote it in ONE
11
+ * place — the CallTool path in index.ts wraps each result with this helper.
12
+ *
13
+ * We intentionally do NOT declare `outputSchema` on the tools: the action tools
14
+ * return polymorphic shapes per action, a faithful schema would need top-level
15
+ * `oneOf` (which the Anthropic API rejects, same as input schemas), and a
16
+ * permissive `type:object` schema adds no value. `structuredContent` without a
17
+ * declared schema is spec-valid and is the actual win.
18
+ */
19
+ /**
20
+ * Attach `structuredContent` to a successful tool result when its single text
21
+ * block is a JSON object. No-op for errors, multi-text results, non-object
22
+ * payloads, or results that already set structuredContent.
23
+ */
24
+ export function withStructuredContent(result) {
25
+ if (!result || result.isError || result.structuredContent)
26
+ return result;
27
+ const textItems = (result.content || []).filter((c) => c.type === 'text' && typeof c.text === 'string');
28
+ if (textItems.length !== 1)
29
+ return result;
30
+ let parsed;
31
+ try {
32
+ parsed = JSON.parse(textItems[0].text);
33
+ }
34
+ catch {
35
+ return result; // not JSON (shouldn't happen for our handlers) — leave as-is
36
+ }
37
+ // Spec requires structuredContent to be a JSON object (not array/primitive/null).
38
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
39
+ return result;
40
+ }
41
+ return { ...result, structuredContent: parsed };
42
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@debugg-ai/debugg-ai-mcp",
3
- "version": "3.0.1",
3
+ "version": "3.2.0",
4
4
  "description": "Zero-Config, Fully AI-Managed End-to-End Testing for all code gen platforms.",
5
5
  "type": "module",
6
6
  "bin": {