feat(mcp): let Crashlytics event tools return more than 20 stack frames - #11061
Ishkirat-Singh wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces an optional 'maxFrames' parameter to the 'crashlytics_list_events' and 'crashlytics_batch_get_events' MCP tools, allowing users to retrieve more than the default 20 stack frames per trace. It also adds corresponding unit tests and updates the changelog. The review feedback suggests improving type safety in the new test file by avoiding 'any' and redundant type assertions (such as 'as unknown as Event'), aligning with the repository's style guide.
| import { expect } from "chai"; | ||
| import * as sinon from "sinon"; | ||
| import { batch_get_events, list_events } from "./events"; | ||
| import * as crashlyticsEvents from "../../../crashlytics/events"; | ||
| import { Event, Frame } from "../../../crashlytics/types"; | ||
|
|
||
| describe("crashlytics events tools", () => { | ||
| const appId = "1:123456789:android:abcdef"; | ||
| const ctx = {} as any; |
There was a problem hiding this comment.
Avoid using any as an escape hatch. Instead, import and use the proper McpContext type to ensure type safety and adhere to the repository style guide.
| import { expect } from "chai"; | |
| import * as sinon from "sinon"; | |
| import { batch_get_events, list_events } from "./events"; | |
| import * as crashlyticsEvents from "../../../crashlytics/events"; | |
| import { Event, Frame } from "../../../crashlytics/types"; | |
| describe("crashlytics events tools", () => { | |
| const appId = "1:123456789:android:abcdef"; | |
| const ctx = {} as any; | |
| import { expect } from "chai"; | |
| import * as sinon from "sinon"; | |
| import { batch_get_events, list_events } from "./events"; | |
| import * as crashlyticsEvents from "../../../crashlytics/events"; | |
| import { Event, Frame } from "../../../crashlytics/types"; | |
| import { McpContext } from "../../types"; | |
| describe("crashlytics events tools", () => { | |
| const appId = "1:123456789:android:abcdef"; | |
| const ctx = {} as McpContext; |
References
- Never use any or unknown as an escape hatch. Define proper interfaces/types or use type guards. (link)
There was a problem hiding this comment.
Done in 78c7e3b: the spec uses McpContext for the context and drops the Frame[] / unknown assertions.
| function eventWithFrames(count: number): Event { | ||
| const frames: Frame[] = Array.from({ length: count }, (_, i) => ({ | ||
| symbol: `frame${i + 1}`, | ||
| file: "Main.kt", | ||
| line: i + 1, | ||
| })) as Frame[]; | ||
| return { | ||
| exceptions: [{ type: "java.lang.RuntimeException", exceptionMessage: "boom", frames }], | ||
| } as unknown as Event; | ||
| } |
There was a problem hiding this comment.
Avoid using unnecessary type assertions like as Frame[] and as unknown as Event. Since all properties of Event and Frame are optional, these assertions are redundant and violate the repository style guide's rule against using unknown as an escape hatch.
| function eventWithFrames(count: number): Event { | |
| const frames: Frame[] = Array.from({ length: count }, (_, i) => ({ | |
| symbol: `frame${i + 1}`, | |
| file: "Main.kt", | |
| line: i + 1, | |
| })) as Frame[]; | |
| return { | |
| exceptions: [{ type: "java.lang.RuntimeException", exceptionMessage: "boom", frames }], | |
| } as unknown as Event; | |
| } | |
| function eventWithFrames(count: number): Event { | |
| const frames: Frame[] = Array.from({ length: count }, (_, i) => ({ | |
| symbol: `frame${i + 1}`, | |
| file: "Main.kt", | |
| line: i + 1, | |
| })); | |
| return { | |
| exceptions: [{ type: "java.lang.RuntimeException", exceptionMessage: "boom", frames }], | |
| }; | |
| } |
References
- Never use any or unknown as an escape hatch. Define proper interfaces/types or use type guards. (link)
78c7e3b to
9751d09
Compare
formatFrames capped every stack trace at 20 frames through a default parameter that no call site could override, and neither crashlytics_list_events nor crashlytics_batch_get_events exposed it, so an agent that needed a deeper frame had no way to ask for it short of calling the API directly. Add an optional maxFrames input to both tools and thread it through to formatFrames. The default stays at 20, so existing output is unchanged. Fixes firebase#11027
9751d09 to
c04aca9
Compare
Description
formatFramescapped every stack trace at 20 frames through a default parameter that no call site could override, and neithercrashlytics_list_eventsnorcrashlytics_batch_get_eventsexposed it in its input schema. An agent that needed frame 25 had no way to ask for it short of leaving the MCP server and calling the API directly.This adds an optional
maxFramesinput (positive integer) to both tools and threads it throughtoTexttoformatFrames. The default stays at 20, so existing output is unchanged. The other truncations mentioned in the issue (per-frame fields, breadcrumbs, logs) are left as they are; happy to follow up on those separately if wanted.Fixes #11027
Scenarios Tested
src/mcp/tools/crashlytics/events.spec.tswithlistEvents/batchGetEventsstubbed: default output stops after 19 frames plus the "frames omitted" marker,maxFrames: 100includes all 25 frames with no marker, andbatch_get_eventshonoursmaxFrames: 5.npx mocha src/mcp/tools/crashlytics/events.spec.ts: 3 passing.Sample Commands
Via MCP:
crashlytics_list_eventswith{ "appId": "...", "filter": { "issueId": "..." }, "maxFrames": 100 }.