pmx-canvas 0.9.3 → 0.10.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/.github/extensions/pmx-canvas/runtime.json +1 -1
- package/.github/extensions/pmx-canvas/tools.json +9278 -2014
- package/CHANGELOG.md +22 -1
- package/dist/canvas/index.js +1 -1
- package/dist/canvas/mcp-app.html +1 -1
- package/dist/types/mcp/canvas-access.d.ts +1 -12
- package/dist/types/mcp/resource-subscriptions.d.ts +7 -0
- package/dist/types/mcp/server.d.ts +2 -0
- package/dist/types/server/ax-wait.d.ts +1 -0
- package/dist/types/server/canvas-operations.d.ts +1 -0
- package/dist/types/server/index.d.ts +3 -3
- package/dist/types/server/operations/http.d.ts +10 -0
- package/dist/types/server/operations/index.d.ts +2 -2
- package/dist/types/server/operations/invoker.d.ts +4 -3
- package/dist/types/server/operations/mcp-contracts.d.ts +20 -0
- package/dist/types/server/operations/mcp.d.ts +2 -0
- package/dist/types/server/operations/ops/batch.d.ts +1 -0
- package/dist/types/server/operations/registry.d.ts +2 -2
- package/dist/types/server/operations/types.d.ts +12 -2
- package/dist/types/server/server.d.ts +2 -0
- package/dist/types/server/webpage-node.d.ts +1 -0
- package/docs/api-reference.md +2 -2
- package/docs/cli.md +1 -1
- package/docs/http-api.md +31 -0
- package/docs/mcp.md +93 -21
- package/docs/plans/plan-019-post-0.9-roadmap.md +123 -6
- package/docs/sdk.md +5 -2
- package/package.json +1 -1
- package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/runtime.json +1 -1
- package/plugins/pmx-canvas/plugin.json +1 -1
- package/plugins/pmx-canvas/runtime.json +1 -1
- package/plugins/pmx-canvas/tools.json +9278 -2014
- package/skills/pmx-canvas/SKILL.md +9 -4
- package/skills/pmx-canvas/references/full-reference.md +35 -2
- package/skills/pmx-canvas/references/installing-pmx-canvas.md +7 -7
- package/src/client/canvas/ToolRail.tsx +2 -0
- package/src/mcp/canvas-access.ts +6 -47
- package/src/mcp/resource-subscriptions.ts +181 -0
- package/src/mcp/server.ts +185 -219
- package/src/server/ax-wait.ts +21 -6
- package/src/server/canvas-operations.ts +6 -2
- package/src/server/index.ts +12 -4
- package/src/server/operations/http.ts +69 -21
- package/src/server/operations/index.ts +8 -1
- package/src/server/operations/invoker.ts +53 -5
- package/src/server/operations/mcp-contracts.ts +339 -0
- package/src/server/operations/mcp.ts +153 -18
- package/src/server/operations/ops/ax-await.ts +18 -10
- package/src/server/operations/ops/ax-read.ts +2 -0
- package/src/server/operations/ops/ax-timeline.ts +2 -2
- package/src/server/operations/ops/batch.ts +27 -8
- package/src/server/operations/ops/nodes.ts +18 -3
- package/src/server/operations/registry.ts +24 -4
- package/src/server/operations/types.ts +16 -2
- package/src/server/server.ts +10 -0
- package/src/server/webpage-node.ts +9 -4
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import { type CanvasLayout, type CanvasNodeState, type PmxCanvas } from '../server/index.js';
|
|
2
|
-
import type { PmxAxSource } from '../server/ax-state.js';
|
|
3
2
|
import type { ContextReadInput } from '../server/context-reads.js';
|
|
4
3
|
import { type OperationInvoker } from '../server/operations/index.js';
|
|
5
4
|
type AxStateResult = ReturnType<PmxCanvas['getAxState']>;
|
|
6
5
|
type AxContextResult = ReturnType<PmxCanvas['getAxContext']>;
|
|
7
|
-
type SubmitAxInteractionInput = Parameters<PmxCanvas['submitAxInteraction']>[0];
|
|
8
|
-
type SubmitAxInteractionResult = ReturnType<PmxCanvas['submitAxInteraction']>;
|
|
9
6
|
type GetPendingSteeringResult = ReturnType<PmxCanvas['getPendingSteering']>;
|
|
10
7
|
type ListElicitationsResult = ReturnType<PmxCanvas['listElicitations']>;
|
|
11
8
|
type ListModeRequestsResult = ReturnType<PmxCanvas['listModeRequests']>;
|
|
12
|
-
type IngestActivityInput = Parameters<PmxCanvas['ingestActivity']>[0];
|
|
13
|
-
type IngestActivityResult = ReturnType<PmxCanvas['ingestActivity']>;
|
|
14
9
|
type GetPolicyResult = ReturnType<PmxCanvas['getPolicy']>;
|
|
15
10
|
type GetAxTimelineQuery = Parameters<PmxCanvas['getAxTimeline']>[0];
|
|
16
11
|
type GetAxTimelineResult = ReturnType<PmxCanvas['getAxTimeline']>;
|
|
@@ -38,18 +33,12 @@ export interface CanvasAccess {
|
|
|
38
33
|
listWorkItems(): Promise<ListWorkItemsResult>;
|
|
39
34
|
listApprovalGates(): Promise<ListApprovalGatesResult>;
|
|
40
35
|
listReviewAnnotations(): Promise<ListReviewAnnotationsResult>;
|
|
41
|
-
submitAxInteraction(input: SubmitAxInteractionInput, options?: {
|
|
42
|
-
source?: PmxAxSource;
|
|
43
|
-
}): Promise<SubmitAxInteractionResult>;
|
|
44
36
|
getPendingSteering(options?: {
|
|
45
37
|
consumer?: string;
|
|
46
38
|
limit?: number;
|
|
47
39
|
}): Promise<GetPendingSteeringResult>;
|
|
48
40
|
listElicitations(): Promise<ListElicitationsResult>;
|
|
49
41
|
listModeRequests(): Promise<ListModeRequestsResult>;
|
|
50
|
-
ingestActivity(input: IngestActivityInput, options?: {
|
|
51
|
-
source?: PmxAxSource;
|
|
52
|
-
}): Promise<IngestActivityResult>;
|
|
53
42
|
getPolicy(): Promise<GetPolicyResult>;
|
|
54
43
|
getHistory(): Promise<HistoryResult>;
|
|
55
44
|
getPinnedNodeIds(board?: string): Promise<string[]>;
|
|
@@ -62,7 +51,7 @@ export interface CanvasAccess {
|
|
|
62
51
|
runBatch(operations: RunBatchInput): Promise<RunBatchResult>;
|
|
63
52
|
getCodeGraph(): Promise<CodeGraphResult>;
|
|
64
53
|
getAutomationWebViewStatus(): Promise<AutomationWebViewStatus>;
|
|
65
|
-
screenshotAutomationWebView(options?: AutomationScreenshotOptions): Promise<Uint8Array>;
|
|
54
|
+
screenshotAutomationWebView(options?: AutomationScreenshotOptions, signal?: AbortSignal): Promise<Uint8Array>;
|
|
66
55
|
}
|
|
67
56
|
export declare function refreshCanvasAccess(access: CanvasAccess): Promise<CanvasAccess>;
|
|
68
57
|
/**
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { CanvasAccess } from './canvas-access.js';
|
|
3
|
+
/** One subscription set and event source per MCP connection. Notifications are not reads. */
|
|
4
|
+
export declare function registerResourceSubscriptions(server: McpServer, getCanvas: () => Promise<CanvasAccess>): {
|
|
5
|
+
attach: (canvas: CanvasAccess) => void;
|
|
6
|
+
dispose: () => void;
|
|
7
|
+
};
|
|
@@ -168,6 +168,7 @@ export declare function resolveCanvasNode(nodeRef: CanvasNodeLookupInput): {
|
|
|
168
168
|
};
|
|
169
169
|
export declare function refreshCanvasWebpageNode(id: string, options?: {
|
|
170
170
|
url?: string;
|
|
171
|
+
signal?: AbortSignal;
|
|
171
172
|
}): Promise<{
|
|
172
173
|
ok: boolean;
|
|
173
174
|
id: string;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
2
|
import type { Camera, Tour, TourStop } from '../shared/tour.js';
|
|
3
|
-
import { type TourStep, type TourStepResult } from './tour-control.js';
|
|
3
|
+
import { type TourState, type TourStep, type TourStepResult } from './tour-control.js';
|
|
4
4
|
export type { Tour, TourStop } from '../shared/tour.js';
|
|
5
|
-
export type { TourStep, TourStepResult } from './tour-control.js';
|
|
5
|
+
export type { TourState, TourStep, TourStepResult } from './tour-control.js';
|
|
6
6
|
import type { AgentPhase, AgentPresence, AgentPresenceSnapshot } from '../shared/agent-presence.js';
|
|
7
7
|
import { canvasState } from './canvas-state.js';
|
|
8
8
|
import type { CanvasAnnotation, CanvasNodeState, CanvasEdge, CanvasLayout } from './canvas-state.js';
|
|
@@ -163,7 +163,7 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
163
163
|
ungroupNodes(groupId: string, options?: {
|
|
164
164
|
intentId?: string;
|
|
165
165
|
}): boolean;
|
|
166
|
-
getTour():
|
|
166
|
+
getTour(): TourState;
|
|
167
167
|
setTour(tour: Tour | null): void;
|
|
168
168
|
/** Present a tour stop (index, `next` or `previous`) in the workbench. Not recorded in undo history. */
|
|
169
169
|
goToTourStop(step: TourStep, options?: {
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import { type OperationProgress } from './types.js';
|
|
2
|
+
/** Opt-in NDJSON; the terminal frame retains the ordinary HTTP status/body. */
|
|
3
|
+
export type OperationStreamFrame = {
|
|
4
|
+
type: 'progress';
|
|
5
|
+
progress: OperationProgress;
|
|
6
|
+
} | {
|
|
7
|
+
type: 'result';
|
|
8
|
+
status: number;
|
|
9
|
+
body: unknown;
|
|
10
|
+
};
|
|
1
11
|
export declare function matchOperationPath(template: string, pathname: string): Record<string, string> | null;
|
|
2
12
|
/**
|
|
3
13
|
* Shared body reader: preserves the parsed JSON value as-is (object, array,
|
|
@@ -3,6 +3,6 @@ export { dispatchOperationRoute } from './http.js';
|
|
|
3
3
|
export { runCanvasBatchOperation, type BatchEnvelope } from './ops/batch.js';
|
|
4
4
|
export type { OpenMcpAppCoreResult } from './ops/app.js';
|
|
5
5
|
export { LocalOperationInvoker, HttpOperationInvoker, type OperationInvoker } from './invoker.js';
|
|
6
|
-
export { registerOperationTools, registerCompositeTools, type OperationToolHost } from './mcp.js';
|
|
6
|
+
export { registerOperationTools, registerCompositeTools, registerOperationHelpTool, type OperationToolHost, } from './mcp.js';
|
|
7
7
|
export { compositeToolDefinitions, type CompositeToolDefinition } from './composites.js';
|
|
8
|
-
export { OperationError, defineOperation, type Operation, type OperationContext, type OperationDefinition, type OperationErrorStatus, } from './types.js';
|
|
8
|
+
export { OperationError, defineOperation, type Operation, type OperationContext, type OperationDefinition, type OperationExecutionOptions, type OperationErrorStatus, type OperationProgress, } from './types.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { type OperationExecutionOptions } from './types.js';
|
|
1
2
|
export interface OperationInvoker {
|
|
2
|
-
invoke(name: string, input: Record<string, unknown
|
|
3
|
+
invoke(name: string, input: Record<string, unknown>, options?: OperationExecutionOptions): Promise<unknown>;
|
|
3
4
|
}
|
|
4
5
|
/**
|
|
5
6
|
* The agent-presence label for a transport: `PMX_CANVAS_AGENT_SOURCE` lets a
|
|
@@ -14,7 +15,7 @@ export declare class LocalOperationInvoker implements OperationInvoker {
|
|
|
14
15
|
private readonly proxiedRead;
|
|
15
16
|
/** `source` labels this caller's agent presence ('mcp', 'sdk', …). */
|
|
16
17
|
constructor(source?: string, allowExternalMcp?: boolean);
|
|
17
|
-
invoke(name: string, input: Record<string, unknown
|
|
18
|
+
invoke(name: string, input: Record<string, unknown>, options?: OperationExecutionOptions): Promise<unknown>;
|
|
18
19
|
}
|
|
19
20
|
/** Builds the HTTP request from the op's route template (`:id` from input, GET flags to query). */
|
|
20
21
|
export declare class HttpOperationInvoker implements OperationInvoker {
|
|
@@ -24,5 +25,5 @@ export declare class HttpOperationInvoker implements OperationInvoker {
|
|
|
24
25
|
private readonly proxiedRead;
|
|
25
26
|
/** `source` labels this caller's agent presence on the server ('cli', 'mcp', …). */
|
|
26
27
|
constructor(baseUrl: string, source?: string, allowExternalMcp?: boolean);
|
|
27
|
-
invoke(name: string, rawInput: Record<string, unknown
|
|
28
|
+
invoke(name: string, rawInput: Record<string, unknown>, options?: OperationExecutionOptions): Promise<unknown>;
|
|
28
29
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP's output is the FORMATTER projection, never the larger HTTP payload.
|
|
3
|
+
* `result` wraps prose/arrays without pretending they are JSON objects. Each
|
|
4
|
+
* operation validates its stable fields; loose payloads preserve full:true and
|
|
5
|
+
* extensible node/app data. No schema advertises an unconstrained root record.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
|
|
9
|
+
export declare function operationOutputSchema(operations: string[]): z.ZodObject<{
|
|
10
|
+
result: z.ZodUnion<readonly [...z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>[], z.ZodObject<{
|
|
11
|
+
operation: z.ZodNull;
|
|
12
|
+
outcome: z.ZodLiteral<"error">;
|
|
13
|
+
data: z.ZodObject<{
|
|
14
|
+
message: z.ZodString;
|
|
15
|
+
}, z.core.$strict>;
|
|
16
|
+
}, z.core.$strict>]>;
|
|
17
|
+
}, z.core.$strict>;
|
|
18
|
+
export declare function structuredOperationResult(operation: string, formatted: CallToolResult): CallToolResult;
|
|
19
|
+
export declare function operationToolError(error: unknown): CallToolResult;
|
|
20
|
+
export declare function operationToolAnnotations(toolName: string): ToolAnnotations;
|
|
@@ -12,6 +12,8 @@ export interface OperationToolHost extends OperationMcpToolHost {
|
|
|
12
12
|
recordContextRead(read: ContextReadInput): Promise<void>;
|
|
13
13
|
}
|
|
14
14
|
export declare function registerOperationTools(server: McpServer, getHost: () => Promise<OperationToolHost>): void;
|
|
15
|
+
/** Registry metadata only: never boots a canvas or records a content read. */
|
|
16
|
+
export declare function registerOperationHelpTool(server: McpServer): void;
|
|
15
17
|
/**
|
|
16
18
|
* Register composite (action-discriminated) MCP tools (plan-006). Each action
|
|
17
19
|
* dispatches to a registered operation, reusing that op's `mcp.buildInput` and
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Operation } from './types.js';
|
|
1
|
+
import { type Operation, type OperationExecutionOptions } from './types.js';
|
|
2
2
|
export declare function registerOperation(op: Operation): void;
|
|
3
3
|
export declare function getOperation(name: string): Operation;
|
|
4
4
|
export declare function listOperations(): Operation[];
|
|
@@ -12,7 +12,7 @@ export declare function getOperationEventEmitter(): OperationEventEmitter | null
|
|
|
12
12
|
export declare function isEmitSuppressed(): boolean;
|
|
13
13
|
/** Suppress this call chain's per-entry frames; the batch emits its final frame afterward. */
|
|
14
14
|
export declare function runWithSuppressedEmits<T>(fn: () => Promise<T>): Promise<T>;
|
|
15
|
-
export interface ExecuteOperationMeta {
|
|
15
|
+
export interface ExecuteOperationMeta extends OperationExecutionOptions {
|
|
16
16
|
/**
|
|
17
17
|
* Skip the synthesized auto-ghost: set by the workbench's own HTTP calls
|
|
18
18
|
* (a human dragging a node is not agent activity) and by canvas.batch for
|
|
@@ -20,7 +20,17 @@ export declare class OperationError extends Error {
|
|
|
20
20
|
readonly details?: Record<string, unknown>;
|
|
21
21
|
constructor(message: string, status?: OperationErrorStatus, details?: Record<string, unknown>);
|
|
22
22
|
}
|
|
23
|
-
export interface
|
|
23
|
+
export interface OperationProgress {
|
|
24
|
+
progress: number;
|
|
25
|
+
total?: number;
|
|
26
|
+
message?: string;
|
|
27
|
+
}
|
|
28
|
+
/** Cooperative cancellation: completed writes are never rolled back. */
|
|
29
|
+
export interface OperationExecutionOptions {
|
|
30
|
+
signal?: AbortSignal;
|
|
31
|
+
onProgress?: (progress: OperationProgress) => void | Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
export interface OperationContext extends OperationExecutionOptions {
|
|
24
34
|
/** Emit a workbench SSE event (e.g. extra `canvas-layout-update` frames, focus, viewport). */
|
|
25
35
|
emit(event: string, payload?: Record<string, unknown>): void;
|
|
26
36
|
}
|
|
@@ -53,7 +63,7 @@ export interface OperationMcpToolHost {
|
|
|
53
63
|
* restore summary).
|
|
54
64
|
*/
|
|
55
65
|
invoker(): {
|
|
56
|
-
invoke(name: string, input: Record<string, unknown
|
|
66
|
+
invoke(name: string, input: Record<string, unknown>, options?: OperationExecutionOptions): Promise<unknown>;
|
|
57
67
|
};
|
|
58
68
|
}
|
|
59
69
|
export interface OperationMcpTool {
|
|
@@ -80,6 +80,8 @@ export interface PrimaryWorkbenchCanvasPromptRequest {
|
|
|
80
80
|
contextNodeIds: string[];
|
|
81
81
|
}
|
|
82
82
|
type PrimaryWorkbenchCanvasPromptHandler = (request: PrimaryWorkbenchCanvasPromptRequest) => Promise<void>;
|
|
83
|
+
/** In-process invalidation observers share the same events as daemon SSE clients. */
|
|
84
|
+
export declare function onWorkbenchEvent(listener: (event: string) => void): () => void;
|
|
83
85
|
export declare function setPrimaryWorkbenchAutoOpenEnabled(enabled: boolean): void;
|
|
84
86
|
export declare function isPrimaryWorkbenchAutoOpenEnabled(): boolean;
|
|
85
87
|
export declare function hasWorkbenchSubscribers(): boolean;
|
|
@@ -37,6 +37,7 @@ export declare function checkWebpageHop(originScope: AddressScope, hopScope: Add
|
|
|
37
37
|
export declare function fetchWebpageSnapshot(inputUrl: string, options?: {
|
|
38
38
|
resolveHost?: ResolveHost;
|
|
39
39
|
timeoutMs?: number;
|
|
40
|
+
signal?: AbortSignal;
|
|
40
41
|
}): Promise<WebpageSnapshot>;
|
|
41
42
|
export declare function getWebpageFetchErrorDetails(error: unknown): {
|
|
42
43
|
message: string;
|
package/docs/api-reference.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
## MCP Server
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
25 tools: 18 action-discriminated composites (`canvas_import`, `canvas_board`, `canvas_node`, `canvas_render`, `canvas_edge`, `canvas_group`, `canvas_history`, `canvas_view`, `canvas_query`, `canvas_webview`, `canvas_app`, `canvas_snapshot`, `canvas_ax_state`, `canvas_ax_work`, `canvas_ax_gate`, `canvas_ax_timeline`, `canvas_ax_delivery`, `canvas_intent`) plus 7 standalone tools (`canvas_help`, `canvas_batch`, `canvas_pin_nodes`, `canvas_invoke_command`, `canvas_ax_interaction`, `canvas_ingest_activity`, `canvas_screenshot`). `canvas_help { op }` returns one MCP registry operation's public arguments and guidance without accessing the canvas; omit `op` to list names. `canvas_import` is the agent half of the human-consented attachment workflow: agents list/read requested imports, submit reviewable Markdown, or report unavailable; they cannot request, cancel, or commit. The 57 legacy single-purpose tools the composites replaced were removed in v0.3.0; v0.4.0 shipped the `canvas_snapshot` composite and removed the 6 deprecated snapshot standalones. Prefer composites for new MCP calls; see `docs/mcp.md` for the authoritative tool list and the legacy-to-composite migration reference.
|
|
10
10
|
|
|
11
11
|
### Agent-assisted document imports
|
|
12
12
|
|
|
@@ -18,7 +18,7 @@ The `diagram` action of `canvas_app` is a thin preset in `src/server/diagram-pre
|
|
|
18
18
|
|
|
19
19
|
15 static canvas resources: `canvas://boards`, `canvas://pinned-context`, `canvas://schema`, `canvas://layout`, `canvas://summary`, `canvas://spatial-context`, `canvas://history`, `canvas://code-graph`, `canvas://ax`, `canvas://ax-context`, `canvas://ax-timeline`, `canvas://ax-work`, `canvas://ax-pending-steering`, `canvas://ax-delivery`, `canvas://skills`; two canvas resource templates: `canvas://context{?budget,consumer,since}` and `canvas://graph{?focus,depth}`. Bundled skills additionally register per-skill `canvas://skills/<name>` resources and the `skill://{name}/{+path}` file template.
|
|
20
20
|
|
|
21
|
-
Resource change notifications:
|
|
21
|
+
Resource change notifications: subscribe to each live URI to receive `notifications/resources/updated` when canvas state or knowledge policies change. Notifications invalidate cached data without reading it. Subscriptions belong to the connection; subscribe again after reconnecting. See [Resource subscriptions](mcp.md#resource-subscriptions-010).
|
|
22
22
|
|
|
23
23
|
### AX Primitives (host-agnostic)
|
|
24
24
|
|
package/docs/cli.md
CHANGED
|
@@ -100,7 +100,7 @@ Tours persist with the board and snapshots, participate in undo, and clear with
|
|
|
100
100
|
the board. A file containing `null` resets the tour: when none is saved, groups
|
|
101
101
|
are sorted by y, then x, then ID. A saved empty `stops` array deliberately has no
|
|
102
102
|
stops. SDK: `canvas.setTour(tourOrNull)` / `canvas.getTour()`, which returns
|
|
103
|
-
|
|
103
|
+
`{ tour, derived, position }` as of 0.10; read stops from `.tour.stops`.
|
|
104
104
|
|
|
105
105
|
### Driving a tour (agents)
|
|
106
106
|
|
package/docs/http-api.md
CHANGED
|
@@ -3,6 +3,37 @@
|
|
|
3
3
|
REST endpoints for all canvas operations + an SSE event stream. Works from
|
|
4
4
|
any language. Default base URL: `http://localhost:4313`.
|
|
5
5
|
|
|
6
|
+
## Operation cancellation and progress (0.10)
|
|
7
|
+
|
|
8
|
+
Registry-backed operation routes use the request's abort signal. Disconnecting
|
|
9
|
+
stops supported AX waits, cancels webpage fetching and prevents later batch
|
|
10
|
+
operations from starting. Completed writes remain. Cancellation is cooperative:
|
|
11
|
+
external app builds/runtime calls and local WebView captures cannot be interrupted
|
|
12
|
+
mid-call. A standalone cancelled operation returns HTTP 499 with
|
|
13
|
+
`{ "ok": false, "cancelled": true, "error": "Operation cancelled." }` when the
|
|
14
|
+
connection still permits a response. An interrupted batch retains completed
|
|
15
|
+
`results` and `refs` in its partial-failure body and adds `cancelled: true`.
|
|
16
|
+
Disconnected clients must inspect state before retrying; they may never receive
|
|
17
|
+
that body. Cancellation is not rollback.
|
|
18
|
+
|
|
19
|
+
Send `Accept: application/x-ndjson` to opt into batch and supported AX wait progress
|
|
20
|
+
over the operation response stream. Each newline-delimited JSON frame is one of:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{"type":"progress","progress":{"progress":1,"total":3,"message":"node.add"}}
|
|
24
|
+
{"type":"result","status":200,"body":{"ok":true,"results":[],"refs":{}}}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The examples show frame shapes, not one complete batch. The terminal `result`
|
|
28
|
+
frame carries the ordinary operation status and body; the stream's HTTP 200 does
|
|
29
|
+
not establish operation success. Without this header, routes keep their ordinary
|
|
30
|
+
JSON status/body. Early validation errors may still be ordinary JSON. The
|
|
31
|
+
in-process and HTTP operation invokers accept optional `{ signal, onProgress }`;
|
|
32
|
+
the HTTP invoker negotiates this stream only when given a progress callback.
|
|
33
|
+
|
|
34
|
+
AX wait routes accept `timeoutMs` as well as the direct-HTTP `waitMs` parameter;
|
|
35
|
+
`timeoutMs` takes precedence when both are supplied.
|
|
36
|
+
|
|
6
37
|
## Knowledge lifecycle data (plan 017 slice 1)
|
|
7
38
|
|
|
8
39
|
The slice-1 data contract now also drives the workbench, due engine and qualified agent context.
|
package/docs/mcp.md
CHANGED
|
@@ -1,10 +1,92 @@
|
|
|
1
1
|
# MCP reference
|
|
2
2
|
|
|
3
|
-
PMX Canvas ships an MCP stdio server with **
|
|
3
|
+
PMX Canvas ships an MCP stdio server with **25 tools**, **15 static canvas
|
|
4
4
|
resources**, and two canvas resource templates, plus per-skill resources at
|
|
5
5
|
`canvas://skills/<name>` and the `skill://{name}/{+path}` template. The server emits
|
|
6
|
-
`notifications/resources/updated` when canvas state changes
|
|
7
|
-
|
|
6
|
+
`notifications/resources/updated` to subscribed connections when canvas state changes.
|
|
7
|
+
This uses MCP SDK v1, not SDK v2.
|
|
8
|
+
|
|
9
|
+
## Operation help (0.10)
|
|
10
|
+
|
|
11
|
+
Call `canvas_help {}` for the sorted registry names exposed through MCP, then
|
|
12
|
+
`canvas_help { op: "node.add" }` for one operation's public `tool`, `description`
|
|
13
|
+
and JSON `inputSchema`. The schema includes required fields, public field names
|
|
14
|
+
and constant routing selectors (`action`, and `kind` for gates). For example,
|
|
15
|
+
`ax.approval.request` maps to `canvas_ax_gate` with `kind: "approval"`,
|
|
16
|
+
`action: "request"` and the optional `approvalAction` field.
|
|
17
|
+
|
|
18
|
+
Text contains the JSON result; structured content wraps it in `{ result }`.
|
|
19
|
+
Unknown names, internal/human-only operations and non-registry tools such as
|
|
20
|
+
`canvas_screenshot` return text-only `isError`; use `tools/list` for those tools.
|
|
21
|
+
Help reads registry metadata only: it never starts a canvas, writes state, records
|
|
22
|
+
a content read or advances a cursor. It is read-only and idempotent.
|
|
23
|
+
|
|
24
|
+
Help derives its schema and guidance from the operation registry, not from live
|
|
25
|
+
board state. Handlers still enforce conditional requirements and authorization.
|
|
26
|
+
Existing input schemas stay in `tools/list`; help does not enable lazy discovery
|
|
27
|
+
in hosts. Repeated equivalent output branches are grouped within each tool,
|
|
28
|
+
preserving operation/payload validation and partial-error receipts.
|
|
29
|
+
|
|
30
|
+
## Tool results and effect hints (0.10)
|
|
31
|
+
|
|
32
|
+
All 25 tools advertise an object `outputSchema`. Registry-dispatched tools return
|
|
33
|
+
`structuredContent.result = { operation, outcome, data }`. `operation` names the
|
|
34
|
+
dispatched action (for example `node.add`), `outcome` is `success`, `error` or
|
|
35
|
+
`partial`, and `data` is the existing compact tool result. Prose results use
|
|
36
|
+
`data.message`. Exceptions use `operation: null`, `outcome: "error"` and
|
|
37
|
+
`data.message`; this does not guarantee that nothing changed before the exception.
|
|
38
|
+
Batch failures retain completed `results` and `refs`, with `partial` when at least
|
|
39
|
+
one entry completed. Check both `isError` and the outcome before using a result.
|
|
40
|
+
|
|
41
|
+
The three handwritten tools keep direct structured objects: `canvas_ax_interaction`
|
|
42
|
+
returns its accepted interaction, `canvas_ingest_activity` its event and reaction
|
|
43
|
+
records, and `canvas_screenshot` capture metadata alongside model-visible image
|
|
44
|
+
content. Their errors are text-only `isError` replies. Existing model-facing text
|
|
45
|
+
and compact/full projections remain unchanged; structured results do not introduce
|
|
46
|
+
additional full-card or UI payloads. Inspect the advertised schema for each tool.
|
|
47
|
+
|
|
48
|
+
All tools declare `readOnlyHint`, `destructiveHint`, `idempotentHint` and
|
|
49
|
+
`openWorldHint`. Composite hints cover every action, not only their read actions.
|
|
50
|
+
`canvas_query` is not read-only because context reads can advance a durable
|
|
51
|
+
consumer cursor. Hints describe effects; they grant no permission or retry guarantee.
|
|
52
|
+
|
|
53
|
+
## Cancellation and progress (0.10)
|
|
54
|
+
|
|
55
|
+
MCP cancellation reaches the operation layer in both local and daemon-attached
|
|
56
|
+
connections. Supported AX waits release their listeners and timers immediately;
|
|
57
|
+
batches stop before the next operation and keep completed writes. Webpage fetches
|
|
58
|
+
receive the signal and stop before writing fetched content after cancellation.
|
|
59
|
+
Cancellation does not roll back a created node or other completed mutations.
|
|
60
|
+
If webpage creation already committed, its receipt retains `fetch.cancelled: true`.
|
|
61
|
+
External app builds/runtime calls and local WebView captures are not interruptible
|
|
62
|
+
mid-call; do not treat cancellation as proof that those side effects stopped.
|
|
63
|
+
|
|
64
|
+
Calls supplying `_meta.progressToken` receive `notifications/progress` at batch
|
|
65
|
+
entry boundaries and supported AX wait start/completion, with `progress`, optional
|
|
66
|
+
`total`, optional `message` and the same token. This works over the daemon bridge
|
|
67
|
+
as well as local stdio. No token means
|
|
68
|
+
no progress notifications. A host that aborts its connection may not receive a
|
|
69
|
+
partial result; inspect canvas state before retrying. See the
|
|
70
|
+
[HTTP streaming contract](http-api.md#operation-cancellation-and-progress-010).
|
|
71
|
+
|
|
72
|
+
## Resource subscriptions (0.10)
|
|
73
|
+
|
|
74
|
+
The server advertises `resources.subscribe`. Send `resources/subscribe` with an
|
|
75
|
+
exact live URI, then `resources/unsubscribe` to stop. Subscriptions belong to the
|
|
76
|
+
connection and disappear on close; reconnecting clients must subscribe again.
|
|
77
|
+
|
|
78
|
+
Live resources are `canvas://layout`, `boards`, `summary`, `context`, `graph`,
|
|
79
|
+
`spatial-context`, `history`, `code-graph`, `pinned-context`, `ax`, `ax-context`,
|
|
80
|
+
`ax-timeline`, `ax-work`, `ax-pending-steering` and `ax-delivery` (each with the
|
|
81
|
+
`canvas://` prefix). Parameterized context and graph URIs are supported, for example
|
|
82
|
+
`canvas://context?consumer=my-agent&budget=3000`; notifications echo the exact
|
|
83
|
+
subscribed URI. Static schema and bundled skill resources do not support subscriptions.
|
|
84
|
+
|
|
85
|
+
Notifications invalidate cached data, not deliver it. Read the resource when needed.
|
|
86
|
+
They can be broader than the underlying change, and daemon reconnection invalidates
|
|
87
|
+
subscribed resources to cover missed events. Notification delivery does not record
|
|
88
|
+
a context read or advance a consumer cursor. Explicit `resources/read` works without
|
|
89
|
+
subscriptions, including on hosts that do not use this capability.
|
|
8
90
|
|
|
9
91
|
> **Consolidation complete (plan-006/008).** The MCP surface shrank from 84
|
|
10
92
|
> tools to 22: 16 action-discriminated **composites** (recommended — see
|
|
@@ -83,12 +165,12 @@ Add to your agent's MCP config:
|
|
|
83
165
|
}
|
|
84
166
|
```
|
|
85
167
|
|
|
86
|
-
The canvas auto-starts on first
|
|
168
|
+
The canvas auto-starts on first canvas operation, not on `canvas_help`.
|
|
87
169
|
|
|
88
170
|
## Private MCP App preview
|
|
89
171
|
|
|
90
172
|
`pmx-canvas --mcp-app` runs a **separate, experimental stdio profile**; the
|
|
91
|
-
|
|
173
|
+
25-tool `--mcp` profile above is separate. Build from this checkout first:
|
|
92
174
|
|
|
93
175
|
```bash
|
|
94
176
|
bun run build
|
|
@@ -358,7 +440,7 @@ Single-card and layout reads record delivered content, not incident relations.
|
|
|
358
440
|
Use a complete graph or brief relation entry to acknowledge those relations.
|
|
359
441
|
Reads never mark full card content read or
|
|
360
442
|
switch the workbench. Pull needed cards in full separately.
|
|
361
|
-
|
|
443
|
+
These reads add no tools beyond the catalog listed above.
|
|
362
444
|
|
|
363
445
|
Library search is `canvas_query { action: "search", query: "auth", scope:
|
|
364
446
|
"library" }`. It returns board/card IDs and never switches the active board.
|
|
@@ -491,13 +573,14 @@ agent intends to publish its own cursor or attention target.
|
|
|
491
573
|
|
|
492
574
|
## Standalone tools
|
|
493
575
|
|
|
494
|
-
|
|
576
|
+
7 tools that intentionally stay outside the composites — folding them would
|
|
495
577
|
hurt (distinct callers, binary payloads, trust-boundary or execution-intent
|
|
496
578
|
semantics). See [Migration reference](#migration-reference) below for the
|
|
497
579
|
legacy tools the composites replaced.
|
|
498
580
|
|
|
499
581
|
| Tool | Description |
|
|
500
582
|
|------|-------------|
|
|
583
|
+
| `canvas_help` | List MCP registry operations or fetch one operation's public arguments and guidance (`op` optional); no canvas access |
|
|
501
584
|
| `canvas_batch` | Run a batch of canvas operations with `$ref` support |
|
|
502
585
|
| `canvas_pin_nodes` | Pin nodes to include in agent context (`nodeIds`, `mode` set/add/remove, optional `reason` shown to the human) |
|
|
503
586
|
| `canvas_invoke_command` | Invoke a registry command (`pmx.plan`, `pmx.execute`, `pmx.promote-context`, `pmx.summarize`, `pmx.review`); records a `command` agent-event, unknown names rejected |
|
|
@@ -703,20 +786,9 @@ interaction against the node's effective capabilities.
|
|
|
703
786
|
|
|
704
787
|
## Change notifications
|
|
705
788
|
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
- Pin changes notify `canvas://pinned-context`, `canvas://ax`, and `canvas://ax-context`
|
|
710
|
-
- AX focus changes notify `canvas://ax` and `canvas://ax-context`
|
|
711
|
-
- Canvas-bound AX mutations (work items, approval gates, review annotations,
|
|
712
|
-
host capability) notify `canvas://ax`, `canvas://ax-work`, and `canvas://ax-context`
|
|
713
|
-
- AX timeline mutations (agent-events, evidence, steering) notify
|
|
714
|
-
`canvas://ax-timeline` and `canvas://ax-context`
|
|
715
|
-
- All mutations notify `canvas://layout`, `canvas://summary`,
|
|
716
|
-
`canvas://spatial-context`, `canvas://history`, `canvas://code-graph`, and `canvas://graph`
|
|
717
|
-
|
|
718
|
-
This closes the human-to-agent loop: spatial curation in the browser becomes
|
|
719
|
-
an immediate signal in the agent's context.
|
|
789
|
+
Notifications require an explicit subscription to each live resource URI. See
|
|
790
|
+
[Resource subscriptions](#resource-subscriptions-010) for connection lifetime,
|
|
791
|
+
reconnection and broad cache invalidation. Receiving a notification is not a content read.
|
|
720
792
|
|
|
721
793
|
## Codex App Adapter
|
|
722
794
|
|