docs(mcp): state plist inspection session prerequisite

This commit is contained in:
morluto
2026-10-24 04:15:21 +08:00
parent 5796220f23
commit aad3d88cc0
4 changed files with 46 additions and 3 deletions
+4
View File
@@ -156,6 +156,10 @@ anatomy components.
The projection does not read plists. Use `inspect_plist` on a bundle's
`info_plist_path` or a launchd plist to read `CFBundleExecutable`, identifiers,
`SMPrivilegedExecutables`, `BundleProgram`, URL schemes, and usage descriptions.
MCP calls require an existing `open_binary` or `open_bundle_resources` session,
including when `inspect_plist.path` is explicit. For a bundle without a resolved
executable, open its resource session first. The CLI `rea inspect-plist <path>`
opens the selected artifact for its one invocation.
Use `inspect_signature` on an executable candidate for code-signing claims.
## Dylib load resolution
+6
View File
@@ -633,6 +633,12 @@ Binary-only operations and binary analysis snapshots do not apply in this
session. `open_binary` can switch back to executable analysis, and
`close_binary` retires either session kind.
`inspect_plist` requires an open binary or bundle-resource session. An explicit
`path` selects a plist in that context and does not create a session;
`binary_session` reports `target_required` while neither session is open.
Use `open_bundle_resources` for a bundle whose executable cannot be resolved.
The CLI `rea inspect-plist <path>` opens its selected artifact for one invocation.
Each provider client receives `binary_session.analysis_run.run_id` before any
provider startup, including clients whose startup fails. `process_lineage` is
`not_observed` until a dynamic provider starts, then becomes `snapshots` with
+7 -3
View File
@@ -17,7 +17,7 @@ import { nativeCommandTimeoutField } from "../../domain/native/nativeDeadlines.j
const examples: Readonly<Record<string, Readonly<Record<string, unknown>>>> = {
inspect_macho: {},
inspect_signature: {},
inspect_plist: { path: "/Applications/Example.app/Contents/Info.plist" },
inspect_plist: {},
list_architectures: {},
observe_native_ui: { pid: 123, window_id: 456 },
capture_native_ui_scenario: {
@@ -115,9 +115,13 @@ export const NATIVE_TOOL_CONTRACTS = [
),
native(
"inspect_plist",
"Parse Info.plist from the active artifact by default, or pass any local plist path. Returns normalized JSON rather than plutil text. native_command_timeout_ms is each file or plutil command's wall clock (omitted means 60000 ms). The 67108864-byte plist input and decode allowances and the 128-level nesting allowance have no runtime override. The 4096-byte markup probe is a probe window, not a document cap, and has no runtime override.",
"Requires an open binary or bundle-resource session; use open_binary or open_bundle_resources first. Parse its Info.plist by default, or select a local plist with path within that session. Supplying path does not open a session. Returns normalized JSON rather than plutil text. native_command_timeout_ms is each file or plutil command's wall clock (omitted means 60000 ms). The 67108864-byte plist input and decode allowances and the 128-level nesting allowance have no runtime override. The 4096-byte markup probe is a probe window, not a document cap, and has no runtime override.",
z.object({
path: localPathStringSchema.optional(),
path: localPathStringSchema
.optional()
.describe(
"Optional plist selection for an already open binary or bundle-resource session; this does not open a session.",
),
native_command_timeout_ms: nativeCommandTimeoutField,
}),
),
+29
View File
@@ -100,6 +100,35 @@ it("routes bundle resource MCP calls with null executable identity and retained
await expectResourceSchemaBranches(client);
const unbound = await client.callTool({
name: "inspect_plist",
arguments: { path: plistPath },
});
expect(unbound.isError).toBe(true);
expect(unbound.structuredContent).toMatchObject({
error: { code: "target_unavailable", category: "unavailable" },
});
const unopened = await client.callTool({
name: "binary_session",
arguments: {},
});
expect(
toolContract("binary_session").outputSchema.parse(
unopened.structuredContent,
),
).toMatchObject({
result: {
open: false,
tool_availability: expect.arrayContaining([
expect.objectContaining({
name: "inspect_plist",
available: false,
reason: "target_required",
}),
]),
},
});
const opened = await client.callTool({
name: "open_bundle_resources",
arguments: { path: bundle },