Skip to content

Commit 73bdd38

Browse files
Add MCP Headless for fully unattended flow (#582)
* incomplete - wip * Updated package definition and readme; expose to mainworld using toolPreloadBridge * upgraded the version to 1.2.4 for both app and packages * ignore Kilo AI files * wip on pp-api-access * working pp api code * removed debug code * Added agentInvokable to tool manifest plus schema converter helper function * mcp server with auth created and connection tested * wip: agent tool registry * fix: name passed to the mcp client * wired up the agent call with launch invocation * working mcp sync * some styling fixes * Reformat the language on the connection selection modals * update the pptb config and associated plumbing plus some minor fixes * types and some minor edits * doc updates, comment updates and minor tweaks * enabled tray menu for MCP and moved all dispersed items into one tab called MCP Server with MCP icon * init headless mcp - cli * headless invocation wiring * Headless CLI invoked and response provided * add buttons to quickly setup mcp for Claude Desktop and VSCode
1 parent 4736543 commit 73bdd38

20 files changed

Lines changed: 1848 additions & 28 deletions
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
## Plan: Fully Unattended MCP Tool Execution (Headless Entry)
2+
3+
This plan adds a pure Node.js headless execution path for MCP-driven tool calls, while reusing the existing MCP and invocation architecture and avoiding duplicate runtime pathways.
4+
5+
### Scope
6+
7+
- Add a CLI/headless entrypoint that runs without Electron UI.
8+
- Add a headless execution mode to MCP call flow.
9+
- Require explicit tool opt-in using `invocation.headless: true` in `pptb.config.json`.
10+
- Reuse existing registry, schema conversion, connection/auth, and invocation logging where possible.
11+
- Validate using MCP Inspector.
12+
13+
### Non-Goals
14+
15+
- No automatic conversion of UI tools to headless execution.
16+
- No replacement of existing windowed invocation behavior.
17+
- No streaming transport in v1 (polling only for long-running jobs).
18+
19+
### Phase 1: CLI Foundation
20+
21+
1. Create `src/cli/index.ts`, `src/cli/constants.ts`, `src/cli/utils.ts`.
22+
1. Add `bin` entry in `package.json` for `pptb-cli`.
23+
1. Add dedicated build target (`tsconfig.cli.json`) and compile `dist/cli/index.js`.
24+
1. Keep implementation minimal and safe until headless manager is introduced.
25+
26+
### Phase 2: MCP Protocol Extension
27+
28+
1. Extend MCP request envelope with `executionMode: "headless"`.
29+
1. Keep existing default behavior as `windowed` for backward compatibility.
30+
1. Define response model for async job-based execution (`jobId`, `statusUrl`, `status`).
31+
32+
### Phase 3: Headless Invocation Runtime
33+
34+
1. Add `headlessToolInvocationManager` to run and track headless jobs.
35+
1. Enforce opt-in: only tools with `invocation.headless: true` are callable in headless mode.
36+
1. Add deterministic timeout handling and status transitions.
37+
38+
### Phase 4: Auth and Connection Strategy
39+
40+
1. Do not expose `connectionId` externally.
41+
1. Accept caller-provided auth token in MCP request metadata/body or connection name that is created in PPTB.
42+
1. If auth token is provided, inject token into a constrained headless tool API surface.
43+
1. If connection name is provided, authenticate using existing connection and inject token into headless tool API surface.
44+
45+
### Phase 5: Progress and Status
46+
47+
1. Implement polling endpoint for long-running executions.
48+
1. Return progress metadata and final result via status endpoint.
49+
1. Keep transport stateless and MCP Inspector-friendly.
50+
51+
### Phase 6: Documentation
52+
53+
1. Update `docs/MCP_IMPLEMENTATION.md` with headless request/response contract.
54+
1. Add dedicated net-new doc under `docs/` describing architecture changes.
55+
1. Add author guidance for implementing `invokeHeadless(...)` in tools.
56+
57+
### Phase 7: Validation (Manual validation)
58+
59+
1. Start headless server via CLI.
60+
1. Validate `list-tools` includes headless-eligible tools only.
61+
1. Validate `call-tool` with `executionMode=headless`.
62+
1. Validate status polling, timeout, and error paths.
63+
1. Confirm existing windowed mode remains unchanged.
64+
65+
### Reuse Map (No Duplication)
66+
67+
- Reuse: `src/main/mcp/agentToolRegistry.ts` for tool discovery.
68+
- Reuse: `src/main/mcp/schemaConverter.ts` for schema consistency.
69+
- Reuse: `src/main/mcp/agentInvocationLogger.ts` for audit trail.
70+
- Reuse: `src/main/mcp/mcpServer.ts` as primary request router (extended, not duplicated).
71+
- Reuse: existing invocation metadata patterns and correlation IDs.
72+
73+
### Deliverables
74+
75+
- CLI/headless bootstrap scaffold.
76+
- Headless execution manager.
77+
- MCP protocol extension for headless mode.
78+
- Polling endpoint for progress and results.
79+
- Net-new implementation documentation.
80+
- Manual verification checklist for MCP Inspector.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# MCP Headless Unattended Execution - Net New Change
2+
3+
## What is New
4+
5+
This change introduces a **headless entry path** for MCP-based tool execution so automation clients can invoke tools without opening Electron windows.
6+
7+
## Why This Exists
8+
9+
Current MCP integration launches windowed tool instances and depends on UI interaction. For unattended automation and CI workflows, that model is not sufficient.
10+
11+
## Net New Components
12+
13+
- `src/cli/index.ts`: Node.js CLI entry for headless operation.
14+
- `src/cli/constants.ts`: CLI defaults and exit codes.
15+
- `src/cli/utils.ts`: argument parsing, env loading, and command helpers.
16+
- `tsconfig.cli.json`: dedicated TypeScript compile target for CLI output.
17+
- `package.json` updates:
18+
- `bin.pptb-cli` mapped to `dist/cli/index.js`
19+
- `build:cli` script
20+
- `build` now compiles CLI artifact after Electron build
21+
22+
## Runtime Behavior (Current Stage)
23+
24+
This initial implementation stage provides the CLI scaffold and build integration. Headless tool execution orchestration and MCP routing extensions are implemented in subsequent phases.
25+
26+
## Target Behavior (Next Stages)
27+
28+
- MCP `call-tool` accepts `executionMode: "headless"`.
29+
- Only tools explicitly declaring `agents.headless: true` are eligible.
30+
- A job-based response model returns `jobId` and status endpoint for polling.
31+
- Authentication supports either caller-provided token (`authToken`) or server-side resolution from saved `connectionName` (no external `connectionId` exposure).
32+
33+
## Reused Existing Architecture
34+
35+
The headless implementation is designed to extend (not duplicate) existing architecture:
36+
37+
- Tool discovery and eligibility: `agentToolRegistry`
38+
- Schema alignment: `schemaConverter`
39+
- Invocation audit trail: `agentInvocationLogger`
40+
- MCP protocol entrypoint: `mcpServer`
41+
42+
## Verification Approach
43+
44+
Testing is performed using MCP Inspector:
45+
46+
1. Start headless entry (`pptb-cli serve ...`).
47+
1. Verify tool discovery includes only headless-capable tools when requested.
48+
1. Validate headless invocation success and failure paths.
49+
1. Validate timeout and progress polling contract.
50+
51+
## Compatibility Guarantees
52+
53+
- Existing windowed MCP/tool invocation flow remains unchanged.
54+
- Existing UI-driven and inter-tool invocation behavior is preserved.
55+
- Headless mode is opt-in per tool and does not alter non-headless tools.

docs/MCP_IMPLEMENTATION.md

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@ This document covers how Power Platform ToolBox exposes tools to external automa
1010
- [Agent Contract](#agent-contract)
1111
- [MCP Invocation Envelope](#mcp-invocation-envelope)
1212
- [Mode Semantics](#mode-semantics)
13+
- [Execution Mode Semantics](#execution-mode-semantics)
1314
- [Tool Runtime Context](#tool-runtime-context)
1415
- [Implementation Notes](#implementation-notes)
1516
- [Validation and Troubleshooting](#validation-and-troubleshooting)
1617

1718
## Overview
1819

19-
External automation agents can invoke selected PPTB tools through the MCP server. PPTB keeps the execution windowed for now, but the agent boundary is explicit and separate from PPTB-to-PPTB tool invocation.
20+
External automation agents can invoke selected PPTB tools through the MCP server. PPTB supports windowed execution and now includes a headless execution contract for unattended flows.
2021

2122
## Agent Contract
2223

@@ -75,13 +76,75 @@ MCP callers can pass PPTB-specific invocation metadata under `arguments.__pptb`.
7576
Supported metadata:
7677

7778
- `mode`: `"one-way"` or `"two-way"`.
79+
- `executionMode`: `"windowed"` or `"headless"`.
7880
- `timeoutMs`: positive number in milliseconds.
81+
- `authToken`: optional caller-provided token for headless execution contexts.
82+
- `connectionName`: optional saved PPTB connection name. MCP resolves and refreshes tokens server-side when possible.
7983

8084
## Mode Semantics
8185

8286
- `two-way`: MCP waits for the callee to call `returnData(...)` and validates the result against `returnTopic`.
8387
- `one-way`: MCP returns an immediate accepted response and does not wait for a payload from the callee.
8488

89+
## Execution Mode Semantics
90+
91+
- `windowed`: existing BrowserView launch behavior.
92+
- `headless`: MCP returns a job acknowledgement with `jobId` and `jobStatusPath`.
93+
94+
For headless + invocation `mode`:
95+
96+
- `headless` + `two-way`: MCP waits for job completion and returns the final tool payload directly (schema-aligned) when successful.
97+
- `headless` + `one-way`: MCP returns immediate acceptance metadata (`jobId`, `statusUrl`) and callers poll status endpoints as needed.
98+
99+
Headless runtime contract:
100+
101+
- Tool package must expose `invokeHeadless(input, context)` from a discovered entry file.
102+
- Entry discovery order:
103+
1. `agents.headlessEntry` in `pptb.config.json`
104+
2. `dist/headless.js`
105+
3. `headless.js`
106+
4. `package.json.main`
107+
- `invokeHeadless` must return a JSON object payload matching `returnTopic` when two-way semantics are expected.
108+
109+
Example headless acceptance payload:
110+
111+
```json
112+
{
113+
"status": "accepted",
114+
"executionMode": "headless",
115+
"mode": "two-way",
116+
"jobId": "f5a79f96-3d4f-4f60-a151-4d2d3069f2ef",
117+
"jobStatusPath": "/mcp/jobs/f5a79f96-3d4f-4f60-a151-4d2d3069f2ef",
118+
"statusUrl": "/mcp/jobs/f5a79f96-3d4f-4f60-a151-4d2d3069f2ef/status",
119+
"jobStatus": "pending",
120+
"timeoutMs": 120000,
121+
"hasAuthToken": true,
122+
"authSource": "provided-token",
123+
"connectionName": "optional-when-using-connection-name"
124+
}
125+
```
126+
127+
Job status endpoint:
128+
129+
- `GET /mcp/jobs/{jobId}` or `GET /mcp/jobs/{jobId}/status` (requires `X-MCP-Auth-Token`)
130+
- Returns job state (`pending`, `in_progress`, `completed`, `failed`) and result/error fields when available.
131+
132+
Headless `context` shape passed to `invokeHeadless`:
133+
134+
```json
135+
{
136+
"toolId": "tool-id",
137+
"toolName": "friendly-name",
138+
"invocationMode": "one-way|two-way",
139+
"authToken": "optional-token",
140+
"updateProgress": "function(percent, message)",
141+
"logger": {
142+
"info": "function(message)",
143+
"error": "function(message)"
144+
}
145+
}
146+
```
147+
85148
## Tool Runtime Context
86149

87150
When a tool is launched by MCP, `toolboxAPI.invocation.getLaunchContext()` returns the prefill data. If present, invocation metadata is attached under `__pptb`.

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33
"version": "1.2.4",
44
"description": "A universal desktop app that contains multiple tools to ease the customization and configuration of Power Platform",
55
"main": "dist/main/index.js",
6+
"bin": {
7+
"pptb-cli": "dist/cli/index.js"
8+
},
69
"scripts": {
710
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.renderer.json",
8-
"build": "pnpm run typecheck && vite build",
11+
"build": "pnpm run typecheck && vite build && pnpm run build:cli",
12+
"build:cli": "tsc -p tsconfig.cli.json",
913
"build:debug": "vite build --mode development",
1014
"dev": "vite",
1115
"watch": "vite build --watch",

src/cli/constants.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* CLI-specific constants for headless operation mode
3+
*/
4+
5+
export const CLI_CONSTANTS = {
6+
/**
7+
* Default port for headless MCP server
8+
*/
9+
DEFAULT_MCP_PORT: 7340,
10+
11+
/**
12+
* Default hostname for headless MCP server
13+
*/
14+
DEFAULT_MCP_HOST: "127.0.0.1",
15+
16+
/**
17+
* Default timeout for headless tool invocation (in milliseconds)
18+
*/
19+
DEFAULT_TOOL_TIMEOUT_MS: 300000, // 5 minutes
20+
21+
/**
22+
* Default job cleanup TTL (in milliseconds) - how long to keep completed jobs
23+
*/
24+
DEFAULT_JOB_CLEANUP_TTL_MS: 3600000, // 1 hour
25+
26+
/**
27+
* Job polling check interval (in milliseconds)
28+
*/
29+
JOB_CLEANUP_CHECK_INTERVAL_MS: 60000, // 1 minute
30+
31+
/**
32+
* Maximum number of concurrent job executions
33+
*/
34+
MAX_CONCURRENT_JOBS: 10,
35+
36+
/**
37+
* Log levels for CLI
38+
*/
39+
LOG_LEVELS: {
40+
DEBUG: "debug",
41+
INFO: "info",
42+
WARN: "warn",
43+
ERROR: "error",
44+
} as const,
45+
};
46+
47+
/**
48+
* CLI Exit codes for error handling
49+
*/
50+
export const EXIT_CODES = {
51+
SUCCESS: 0,
52+
GENERAL_ERROR: 1,
53+
INVALID_ARGUMENTS: 2,
54+
AUTHENTICATION_FAILED: 3,
55+
TOOL_NOT_FOUND: 4,
56+
HEADLESS_NOT_SUPPORTED: 5,
57+
TOOL_EXECUTION_FAILED: 6,
58+
} as const;
59+
60+
/**
61+
* CLI command definitions
62+
*/
63+
export const CLI_COMMANDS = {
64+
SERVE: "serve",
65+
INVOKE: "invoke",
66+
JOB_STATUS: "job-status",
67+
CONFIG: "config",
68+
HELP: "help",
69+
VERSION: "version",
70+
} as const;

0 commit comments

Comments
 (0)