agent-portal-2 0.1.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/.continue/agents/new-config.yaml +22 -0
- package/AGENT_STEERING.md +36 -0
- package/ARCHITECTURE.md +13 -0
- package/CHANGELOG.md +97 -0
- package/CLI.md +38 -0
- package/CONTRIBUTING.md +55 -0
- package/INSTALLATION.md +58 -0
- package/LICENSE +60 -0
- package/PLUGIN_SYSTEM.md +33 -0
- package/PYTHON_SDK.md +22 -0
- package/QUICKSTART.md +19 -0
- package/README.md +385 -0
- package/RELEASE_NOTES_v0.1.0.md +281 -0
- package/ROADMAP.md +3 -0
- package/RUNTIME.md +44 -0
- package/SAFETY_MODEL.md +24 -0
- package/TESTING.md +35 -0
- package/TROUBLESHOOTING.md +30 -0
- package/UPGRADE_GUIDE.md +288 -0
- package/VS_CODE_EXTENSION.md +47 -0
- package/agent-portal.config.json +20 -0
- package/apps/desktop/agent-portal-desktop.zip +0 -0
- package/apps/desktop/fixtures/local-workflow.html +151 -0
- package/apps/desktop/package.json +18 -0
- package/apps/desktop/src/main.ts +117 -0
- package/apps/desktop/tsconfig.json +8 -0
- package/apps/vscode-extension/LICENSE +60 -0
- package/apps/vscode-extension/README.md +20 -0
- package/apps/vscode-extension/media/agent-portal-logo.png +0 -0
- package/apps/vscode-extension/package.json +149 -0
- package/apps/vscode-extension/src/extension.ts +614 -0
- package/apps/vscode-extension/tsconfig.json +12 -0
- package/assets/branding/agent-portal-logo.png +0 -0
- package/connectors/chatgpt-tools/README.md +9 -0
- package/connectors/claude-mcp-server/README.md +9 -0
- package/connectors/gemini-connector/README.md +9 -0
- package/connectors/rest-websocket-api/README.md +9 -0
- package/docs/MCP_SERVER.md +68 -0
- package/docs/architecture.md +214 -0
- package/docs/roadmap.md +125 -0
- package/package.json +21 -0
- package/packages/agent-portal-mcp/README.md +12 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/__init__.py +3 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/bridge/__init__.py +1 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/bridge/runtime_client.py +180 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/cli.py +32 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/doctor.py +71 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/schemas/__init__.py +1 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/schemas/actions.py +17 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/schemas/results.py +24 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/schemas/risk.py +20 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/security/__init__.py +1 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/security/policy.py +27 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/server.py +148 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/tool_registry.py +58 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/tools/__init__.py +1 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/tools/browser.py +89 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/tools/common.py +98 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/tools/inspection.py +93 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/tools/navigation.py +93 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/tools/reports.py +34 -0
- package/packages/agent-portal-mcp/agent_portal_mcp/tools/steering.py +93 -0
- package/packages/agent-portal-mcp/pyproject.toml +20 -0
- package/packages/agent-portal-mcp/tests/test_doctor.py +20 -0
- package/packages/agent-portal-mcp/tests/test_mcp_server.py +161 -0
- package/packages/core/package.json +15 -0
- package/packages/core/src/index.ts +1842 -0
- package/packages/core/tsconfig.json +8 -0
- package/packages/mcp-server/package.json +15 -0
- package/packages/mcp-server/src/index.ts +73 -0
- package/packages/mcp-server/tsconfig.json +8 -0
- package/packages/sdk/package.json +15 -0
- package/packages/sdk/src/index.ts +544 -0
- package/packages/sdk/tsconfig.json +8 -0
- package/plugins/README.md +16 -0
- package/plugins/agent-portal-browser/plugin.json +19 -0
- package/plugins/agent-portal-python/plugin.json +16 -0
- package/plugins/agent-portal-skills/plugin.json +19 -0
- package/plugins/agent-portal-vscode/plugin.json +27 -0
- package/plugins/example-runtime-plugin/README.md +3 -0
- package/plugins/example-runtime-plugin/plugin.json +20 -0
- package/plugins/plugin.schema.json +53 -0
- package/python/README.md +18 -0
- package/python/agent_portal/__init__.py +5 -0
- package/python/agent_portal/__main__.py +5 -0
- package/python/agent_portal/browser.py +393 -0
- package/python/agent_portal/cli.py +164 -0
- package/python/agent_portal/config.py +31 -0
- package/python/agent_portal/doctor.py +165 -0
- package/python/agent_portal/exceptions.py +39 -0
- package/python/agent_portal/logging_utils.py +33 -0
- package/python/agent_portal/metrics.py +309 -0
- package/python/agent_portal/models.py +160 -0
- package/python/agent_portal/plugin_system.py +42 -0
- package/python/agent_portal/rate_limit.py +253 -0
- package/python/agent_portal/runtime.py +739 -0
- package/python/agent_portal/server.py +351 -0
- package/python/agent_portal/validation.py +299 -0
- package/python/pyproject.toml +29 -0
- package/python/tests/test_config.py +24 -0
- package/python/tests/test_doctor.py +19 -0
- package/python/tests/test_metrics.py +180 -0
- package/python/tests/test_rate_limit.py +237 -0
- package/python/tests/test_runtime.py +122 -0
- package/python/tests/test_server.py +53 -0
- package/python/tests/test_validation.py +170 -0
- package/releases/desktop/agent-portal-desktop/README.md +378 -0
- package/releases/desktop/agent-portal-desktop/RELEASE_NOTES.md +14 -0
- package/releases/desktop/agent-portal-desktop/assets/branding/agent-portal-logo.png +0 -0
- package/releases/desktop/agent-portal-desktop/fixtures/local-workflow.html +151 -0
- package/releases/desktop/agent-portal-desktop/launch-agent-portal.bat +4 -0
- package/releases/desktop/agent-portal-desktop.zip +0 -0
- package/releases/python/agent_portal-0.0.2-py3-none-any.whl +0 -0
- package/releases/python/agent_portal-0.0.2.tar.gz +0 -0
- package/scripts/package_desktop.mjs +117 -0
- package/scripts/release_python.py +46 -0
- package/tests/plugin-manifest.test.mjs +26 -0
- package/tests/runtime.test.mjs +41 -0
- package/tests/vscode-extension.test.mjs +22 -0
- package/tsconfig.base.json +16 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# MCP Server
|
|
2
|
+
|
|
3
|
+
## What MCP Is
|
|
4
|
+
|
|
5
|
+
MCP, or Model Context Protocol, is a structured way for AI clients to discover and call tools through a standard interface.
|
|
6
|
+
|
|
7
|
+
## Why Agent Portal Uses MCP
|
|
8
|
+
|
|
9
|
+
Agent Portal already has a local runtime, policy engine, browser control layer, reporting, and steering controls. MCP turns those capabilities into a consistent tool surface that other AI clients can connect to without custom one-off integrations.
|
|
10
|
+
|
|
11
|
+
## Start The Runtime
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
agent-portal start
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Start The MCP Server
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
agent-portal mcp start
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
or:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
agent-portal-mcp start
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Available Tool Groups
|
|
30
|
+
|
|
31
|
+
- Browser
|
|
32
|
+
- Navigation
|
|
33
|
+
- Inspection
|
|
34
|
+
- Agent Steering
|
|
35
|
+
- Reports
|
|
36
|
+
|
|
37
|
+
## Security Model
|
|
38
|
+
|
|
39
|
+
- localhost-first runtime URL by default
|
|
40
|
+
- optional bearer token through `AGENT_PORTAL_TOKEN` or `agent-portal.config.json`
|
|
41
|
+
- risky actions are classified before execution
|
|
42
|
+
- blocked actions are never auto-executed
|
|
43
|
+
- approval-required actions stay in the queue until approved
|
|
44
|
+
- secret tokens are redacted from MCP errors
|
|
45
|
+
|
|
46
|
+
## Approval Flow
|
|
47
|
+
|
|
48
|
+
1. A risky MCP tool proposes an action through the Agent Portal runtime.
|
|
49
|
+
2. The runtime applies its policy engine and assigns a risk level.
|
|
50
|
+
3. Safe actions can auto-execute.
|
|
51
|
+
4. Higher-risk actions become `pending_approval`.
|
|
52
|
+
5. `approve_action` can approve and execute a queued action.
|
|
53
|
+
6. `reject_action` rejects the queued action.
|
|
54
|
+
|
|
55
|
+
## Example Tool Calls
|
|
56
|
+
|
|
57
|
+
- `browser_open`
|
|
58
|
+
- `navigate_to_url`
|
|
59
|
+
- `click_element`
|
|
60
|
+
- `capture_screenshot`
|
|
61
|
+
- `get_action_queue`
|
|
62
|
+
- `generate_report`
|
|
63
|
+
|
|
64
|
+
## Troubleshooting
|
|
65
|
+
|
|
66
|
+
- If the runtime is offline, start it with `agent-portal start`.
|
|
67
|
+
- If token auth is enabled, set `AGENT_PORTAL_TOKEN`.
|
|
68
|
+
- If tools are not visible, run `agent-portal mcp doctor`.
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# Agent Portal Architecture
|
|
2
|
+
|
|
3
|
+
## Product Shape
|
|
4
|
+
|
|
5
|
+
Agent Portal is best treated as a platform, not a single app. The architecture needs to support:
|
|
6
|
+
|
|
7
|
+
- local-first execution
|
|
8
|
+
- visual awareness
|
|
9
|
+
- controlled actions
|
|
10
|
+
- multi-agent coordination
|
|
11
|
+
- replayable sessions
|
|
12
|
+
- durable memory
|
|
13
|
+
- explicit permissions
|
|
14
|
+
|
|
15
|
+
## Core Layers
|
|
16
|
+
|
|
17
|
+
### 1. Desktop Shell
|
|
18
|
+
|
|
19
|
+
Responsibilities:
|
|
20
|
+
|
|
21
|
+
- native window management
|
|
22
|
+
- embedded browser surfaces
|
|
23
|
+
- agent console UI
|
|
24
|
+
- session inspector
|
|
25
|
+
- settings and permissions
|
|
26
|
+
|
|
27
|
+
Recommended implementation path:
|
|
28
|
+
|
|
29
|
+
- start with Electron for speed and ecosystem reach
|
|
30
|
+
- evaluate Tauri later if footprint becomes a major constraint
|
|
31
|
+
|
|
32
|
+
### 2. Agent Runtime
|
|
33
|
+
|
|
34
|
+
Responsibilities:
|
|
35
|
+
|
|
36
|
+
- spawn and isolate agents
|
|
37
|
+
- manage task state
|
|
38
|
+
- coordinate multi-agent execution
|
|
39
|
+
- stream events to the UI
|
|
40
|
+
- attach tools and permissions
|
|
41
|
+
|
|
42
|
+
Key concepts:
|
|
43
|
+
|
|
44
|
+
- agent definitions
|
|
45
|
+
- task queue
|
|
46
|
+
- execution policies
|
|
47
|
+
- event bus
|
|
48
|
+
- cancellation and recovery
|
|
49
|
+
|
|
50
|
+
### 3. Vision Pipeline
|
|
51
|
+
|
|
52
|
+
Responsibilities:
|
|
53
|
+
|
|
54
|
+
- capture screenshots
|
|
55
|
+
- read DOM structure
|
|
56
|
+
- parse accessibility trees
|
|
57
|
+
- run OCR
|
|
58
|
+
- detect actionable UI elements
|
|
59
|
+
- emit state diffs over time
|
|
60
|
+
|
|
61
|
+
Output contract:
|
|
62
|
+
|
|
63
|
+
- normalized `VisualSnapshot`
|
|
64
|
+
- element list with labels, selectors, roles, and bounds
|
|
65
|
+
- changed/appeared/disappeared annotations
|
|
66
|
+
|
|
67
|
+
### 3.5 Vision Core
|
|
68
|
+
|
|
69
|
+
Responsibilities:
|
|
70
|
+
|
|
71
|
+
- fuse screenshots, DOM, accessibility, console, and network evidence
|
|
72
|
+
- classify the current interface
|
|
73
|
+
- infer likely user intent
|
|
74
|
+
- generate root-cause hypotheses when flows fail
|
|
75
|
+
- hand structured context to goal planning and memory
|
|
76
|
+
|
|
77
|
+
Initial implementation path:
|
|
78
|
+
|
|
79
|
+
- heuristics and typed contracts first
|
|
80
|
+
- model-assisted reasoning layer second
|
|
81
|
+
- confidence scoring and self-healing action selection third
|
|
82
|
+
|
|
83
|
+
### 4. Browser Control Layer
|
|
84
|
+
|
|
85
|
+
Responsibilities:
|
|
86
|
+
|
|
87
|
+
- navigation
|
|
88
|
+
- clicking
|
|
89
|
+
- typing
|
|
90
|
+
- waiting
|
|
91
|
+
- file upload and download
|
|
92
|
+
- script execution
|
|
93
|
+
- trace capture
|
|
94
|
+
|
|
95
|
+
Recommended implementation path:
|
|
96
|
+
|
|
97
|
+
- Playwright as the first execution backend
|
|
98
|
+
- adapter abstraction so Selenium or remote browsers can be added later
|
|
99
|
+
|
|
100
|
+
### 5. Desktop Control Layer
|
|
101
|
+
|
|
102
|
+
Responsibilities:
|
|
103
|
+
|
|
104
|
+
- window discovery
|
|
105
|
+
- input simulation
|
|
106
|
+
- native app inspection
|
|
107
|
+
- application-specific adapters
|
|
108
|
+
|
|
109
|
+
Recommended implementation path:
|
|
110
|
+
|
|
111
|
+
- define the abstraction now
|
|
112
|
+
- ship browser-first before broad desktop automation
|
|
113
|
+
- add Windows-first adapters for VS Code, Terminal, and File Explorer
|
|
114
|
+
|
|
115
|
+
### 6. Memory Engine
|
|
116
|
+
|
|
117
|
+
Responsibilities:
|
|
118
|
+
|
|
119
|
+
- persist project context
|
|
120
|
+
- store recent findings
|
|
121
|
+
- keep reusable workflows
|
|
122
|
+
- retain user and team preferences
|
|
123
|
+
|
|
124
|
+
Storage model:
|
|
125
|
+
|
|
126
|
+
- workspace metadata
|
|
127
|
+
- task history
|
|
128
|
+
- vector or semantic memory later
|
|
129
|
+
- durable file-backed logs immediately
|
|
130
|
+
|
|
131
|
+
### 6.5 Portal Graph
|
|
132
|
+
|
|
133
|
+
Responsibilities:
|
|
134
|
+
|
|
135
|
+
- map pages, links, and recurring flows
|
|
136
|
+
- keep a remembered topology of the app
|
|
137
|
+
- support self-healing navigation when selectors change
|
|
138
|
+
- provide reusable structure for future agents
|
|
139
|
+
|
|
140
|
+
### 7. Session Recorder
|
|
141
|
+
|
|
142
|
+
Responsibilities:
|
|
143
|
+
|
|
144
|
+
- append action timeline
|
|
145
|
+
- attach screenshots and console logs
|
|
146
|
+
- reconstruct replay views
|
|
147
|
+
- generate bug reports
|
|
148
|
+
|
|
149
|
+
Initial storage approach:
|
|
150
|
+
|
|
151
|
+
- append-only event log
|
|
152
|
+
- screenshot references
|
|
153
|
+
- per-session manifest JSON
|
|
154
|
+
|
|
155
|
+
### 8. Security Manager
|
|
156
|
+
|
|
157
|
+
Responsibilities:
|
|
158
|
+
|
|
159
|
+
- tool permissions
|
|
160
|
+
- file and network boundaries
|
|
161
|
+
- secrets handling
|
|
162
|
+
- action approvals
|
|
163
|
+
- auditability
|
|
164
|
+
|
|
165
|
+
This is a product boundary, not a bolt-on feature.
|
|
166
|
+
|
|
167
|
+
## Monorepo Strategy
|
|
168
|
+
|
|
169
|
+
`packages/core`
|
|
170
|
+
|
|
171
|
+
- shared contracts
|
|
172
|
+
- runtime state shapes
|
|
173
|
+
- orchestration primitives
|
|
174
|
+
|
|
175
|
+
`packages/sdk`
|
|
176
|
+
|
|
177
|
+
- external developer API
|
|
178
|
+
- stable ergonomic wrapper over runtime actions
|
|
179
|
+
|
|
180
|
+
`packages/mcp-server`
|
|
181
|
+
|
|
182
|
+
- tool-facing surface for agent frameworks
|
|
183
|
+
- command validation
|
|
184
|
+
- capability exposure
|
|
185
|
+
|
|
186
|
+
`apps/desktop`
|
|
187
|
+
|
|
188
|
+
- first-party desktop operator experience
|
|
189
|
+
- live state inspection
|
|
190
|
+
- future visual workspace UI
|
|
191
|
+
|
|
192
|
+
## Suggested First Vertical Slice
|
|
193
|
+
|
|
194
|
+
Build the smallest end-to-end system that proves the concept:
|
|
195
|
+
|
|
196
|
+
1. Launch desktop shell
|
|
197
|
+
2. Open browser page
|
|
198
|
+
3. Capture screenshot and DOM
|
|
199
|
+
4. Detect clickable elements
|
|
200
|
+
5. Execute one click or type action
|
|
201
|
+
6. Record the session timeline
|
|
202
|
+
7. Generate a simple report
|
|
203
|
+
|
|
204
|
+
If this loop feels great, the rest of the platform has a solid foundation.
|
|
205
|
+
|
|
206
|
+
## Phase 3 Direction
|
|
207
|
+
|
|
208
|
+
The next platform shift is from action execution to understanding:
|
|
209
|
+
|
|
210
|
+
1. Capture multimodal evidence
|
|
211
|
+
2. Classify the interface and workflow
|
|
212
|
+
3. Generate a goal plan from intent
|
|
213
|
+
4. Write understanding into memory
|
|
214
|
+
5. Reuse graph and memory across future sessions
|
package/docs/roadmap.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Agent Portal Roadmap
|
|
2
|
+
|
|
3
|
+
## Phase 1: Foundation
|
|
4
|
+
|
|
5
|
+
Goal:
|
|
6
|
+
Ship a browser-first local runtime that can observe, act, and report.
|
|
7
|
+
|
|
8
|
+
Deliverables:
|
|
9
|
+
|
|
10
|
+
- desktop shell scaffold
|
|
11
|
+
- agent runtime contracts
|
|
12
|
+
- browser adapter abstraction
|
|
13
|
+
- Playwright integration
|
|
14
|
+
- session event log
|
|
15
|
+
- screenshot capture
|
|
16
|
+
- simple report generation
|
|
17
|
+
|
|
18
|
+
Success criteria:
|
|
19
|
+
|
|
20
|
+
- an agent can open a local app, inspect it, perform a small workflow, and produce a replayable action history
|
|
21
|
+
|
|
22
|
+
## Phase 2: Visual Intelligence
|
|
23
|
+
|
|
24
|
+
Goal:
|
|
25
|
+
Make the agent reliably understand what it sees.
|
|
26
|
+
|
|
27
|
+
Deliverables:
|
|
28
|
+
|
|
29
|
+
- DOM and accessibility tree fusion
|
|
30
|
+
- OCR pipeline
|
|
31
|
+
- UI element classification
|
|
32
|
+
- visual diffing
|
|
33
|
+
- confidence scoring for actions
|
|
34
|
+
|
|
35
|
+
Success criteria:
|
|
36
|
+
|
|
37
|
+
- the agent can explain what changed on screen and choose the right target more consistently than raw selectors alone
|
|
38
|
+
|
|
39
|
+
## Phase 3: Agent Intelligence Layer
|
|
40
|
+
|
|
41
|
+
Codename:
|
|
42
|
+
Project Aperture
|
|
43
|
+
|
|
44
|
+
Goal:
|
|
45
|
+
Move from browser control to interface understanding, goal planning, and durable project memory.
|
|
46
|
+
|
|
47
|
+
Deliverables:
|
|
48
|
+
|
|
49
|
+
- `VisionCore` for unified page understanding
|
|
50
|
+
- `GoalPlanner` for turning intent into execution steps
|
|
51
|
+
- `PortalGraph` for remembered application structure
|
|
52
|
+
- memory records for previous findings and plans
|
|
53
|
+
- project awareness detection for frameworks and services
|
|
54
|
+
- root-cause hypothesis generation from console and network evidence
|
|
55
|
+
|
|
56
|
+
Success criteria:
|
|
57
|
+
|
|
58
|
+
- the agent can explain what page it is on, what the user is trying to do, what likely failed, and what to do next
|
|
59
|
+
|
|
60
|
+
## Phase 4: Multi-Agent Collaboration
|
|
61
|
+
|
|
62
|
+
Goal:
|
|
63
|
+
Allow specialized agents to work together inside one project workspace.
|
|
64
|
+
|
|
65
|
+
Deliverables:
|
|
66
|
+
|
|
67
|
+
- shared task board
|
|
68
|
+
- agent-to-agent event bus
|
|
69
|
+
- role-specific permission sets
|
|
70
|
+
- shared memory context
|
|
71
|
+
- result handoff model
|
|
72
|
+
|
|
73
|
+
Success criteria:
|
|
74
|
+
|
|
75
|
+
- a QA agent can find an issue, a frontend agent can fix it, and a reporter agent can summarize the result in one session
|
|
76
|
+
|
|
77
|
+
## Phase 5: Desktop Control
|
|
78
|
+
|
|
79
|
+
Goal:
|
|
80
|
+
Expand beyond browser-only automation.
|
|
81
|
+
|
|
82
|
+
Deliverables:
|
|
83
|
+
|
|
84
|
+
- window discovery
|
|
85
|
+
- native input dispatch
|
|
86
|
+
- app adapters for VS Code, Terminal, and File Explorer
|
|
87
|
+
- screenshot plus accessibility inspection for desktop apps
|
|
88
|
+
|
|
89
|
+
Success criteria:
|
|
90
|
+
|
|
91
|
+
- agents can complete a mixed workflow spanning editor, terminal, browser, and local files
|
|
92
|
+
|
|
93
|
+
## Phase 6: Platform Surface
|
|
94
|
+
|
|
95
|
+
Goal:
|
|
96
|
+
Turn Agent Portal into an ecosystem others can build on.
|
|
97
|
+
|
|
98
|
+
Deliverables:
|
|
99
|
+
|
|
100
|
+
- public SDKs
|
|
101
|
+
- MCP server
|
|
102
|
+
- CLI tools
|
|
103
|
+
- plugin marketplace
|
|
104
|
+
- API and WebSocket surfaces
|
|
105
|
+
|
|
106
|
+
Success criteria:
|
|
107
|
+
|
|
108
|
+
- third-party developers can create agents, plugins, and workflows without modifying the core app
|
|
109
|
+
|
|
110
|
+
## Phase 7: Enterprise and Reality Mode
|
|
111
|
+
|
|
112
|
+
Goal:
|
|
113
|
+
Differentiate with trust, resilience, and adversarial testing.
|
|
114
|
+
|
|
115
|
+
Deliverables:
|
|
116
|
+
|
|
117
|
+
- shared team workspaces
|
|
118
|
+
- permissions and audit logs
|
|
119
|
+
- SSO and deployment modes
|
|
120
|
+
- reality mode stress behaviors
|
|
121
|
+
- policy-driven autonomous QA
|
|
122
|
+
|
|
123
|
+
Success criteria:
|
|
124
|
+
|
|
125
|
+
- teams can safely run persistent agents against real products with clear oversight and reproducible evidence
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-portal-2",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Desktop-native operating environment for AI agents.",
|
|
6
|
+
"workspaces": [
|
|
7
|
+
"apps/*",
|
|
8
|
+
"packages/*"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "npm run build --workspace @agent-portal/core && npm run build --workspace @agent-portal/sdk && npm run build --workspace @agent-portal/mcp-server && npm run build --workspace @agent-portal/desktop && npm run build --workspace apps/vscode-extension",
|
|
12
|
+
"dev": "npm run dev --workspace @agent-portal/desktop",
|
|
13
|
+
"check": "npm run build --workspace @agent-portal/core && npm run typecheck --workspace @agent-portal/core && npm run typecheck --workspace @agent-portal/sdk && npm run typecheck --workspace @agent-portal/mcp-server && npm run typecheck --workspace @agent-portal/desktop && npm run typecheck --workspace apps/vscode-extension",
|
|
14
|
+
"test": "python -m unittest discover -s python/tests -v && python -m unittest discover -s packages/agent-portal-mcp/tests -v && npm run build && node --test tests/*.test.mjs",
|
|
15
|
+
"release:python": "python scripts/release_python.py",
|
|
16
|
+
"release:desktop": "node scripts/package_desktop.mjs"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"typescript": "^5.9.2"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Agent Portal MCP Server
|
|
2
|
+
|
|
3
|
+
This package exposes Agent Portal through a local MCP-compatible stdio server.
|
|
4
|
+
|
|
5
|
+
It connects to the local Agent Portal runtime and turns browser, inspection,
|
|
6
|
+
steering, and report operations into structured MCP tools.
|
|
7
|
+
|
|
8
|
+
Start it with:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
agent-portal-mcp start
|
|
12
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__all__ = []
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import time
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
8
|
+
from urllib.error import HTTPError, URLError
|
|
9
|
+
from urllib.request import Request, urlopen
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class RuntimeClientError(RuntimeError):
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AgentPortalRuntimeClient:
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
runtime_url: str = "http://127.0.0.1:8765",
|
|
20
|
+
token: str | None = None,
|
|
21
|
+
retries: int = 2,
|
|
22
|
+
timeout_seconds: float = 4.0,
|
|
23
|
+
) -> None:
|
|
24
|
+
self.runtime_url = runtime_url.rstrip("/")
|
|
25
|
+
self.token = token or self._load_token()
|
|
26
|
+
self.retries = retries
|
|
27
|
+
self.timeout_seconds = timeout_seconds
|
|
28
|
+
|
|
29
|
+
def health(self) -> dict[str, Any]:
|
|
30
|
+
return self.get("/health")
|
|
31
|
+
|
|
32
|
+
def status(self) -> dict[str, Any]:
|
|
33
|
+
return self.get("/status")
|
|
34
|
+
|
|
35
|
+
def propose_action(
|
|
36
|
+
self,
|
|
37
|
+
action_type: str,
|
|
38
|
+
reason: str,
|
|
39
|
+
target: str | None = None,
|
|
40
|
+
payload: str | None = None,
|
|
41
|
+
risk_level: str = "low",
|
|
42
|
+
) -> dict[str, Any]:
|
|
43
|
+
return self.post(
|
|
44
|
+
"/control/propose-action",
|
|
45
|
+
{
|
|
46
|
+
"actionType": action_type,
|
|
47
|
+
"reason": reason,
|
|
48
|
+
"target": target,
|
|
49
|
+
"payload": payload,
|
|
50
|
+
"riskLevel": risk_level,
|
|
51
|
+
},
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def approve_action(self, action_id: str, execute: bool = False) -> dict[str, Any]:
|
|
55
|
+
return self.post("/control/approve-action", {"actionId": action_id, "execute": execute})
|
|
56
|
+
|
|
57
|
+
def reject_action(self, action_id: str, reason: str) -> dict[str, Any]:
|
|
58
|
+
return self.post("/control/reject-action", {"actionId": action_id, "reason": reason})
|
|
59
|
+
|
|
60
|
+
def action_queue(self) -> dict[str, Any]:
|
|
61
|
+
return self.post("/control/action-queue", {})
|
|
62
|
+
|
|
63
|
+
def set_goal(self, goal: str) -> dict[str, Any]:
|
|
64
|
+
return self.post("/control/goal", {"goal": goal})
|
|
65
|
+
|
|
66
|
+
def current_goal(self) -> dict[str, Any]:
|
|
67
|
+
return self.post("/control/goal/current", {})
|
|
68
|
+
|
|
69
|
+
def pause(self) -> dict[str, Any]:
|
|
70
|
+
return self.post("/control/pause", {})
|
|
71
|
+
|
|
72
|
+
def resume(self) -> dict[str, Any]:
|
|
73
|
+
return self.post("/control/resume", {})
|
|
74
|
+
|
|
75
|
+
def stop(self) -> dict[str, Any]:
|
|
76
|
+
return self.post("/control/stop", {})
|
|
77
|
+
|
|
78
|
+
def set_action_mode(self, mode: str) -> dict[str, Any]:
|
|
79
|
+
return self.post("/control/action-mode", {"mode": mode})
|
|
80
|
+
|
|
81
|
+
def browser_start(self) -> dict[str, Any]:
|
|
82
|
+
return self.post("/browser/start", {})
|
|
83
|
+
|
|
84
|
+
def browser_status(self) -> dict[str, Any]:
|
|
85
|
+
return self.post("/browser/status", {})
|
|
86
|
+
|
|
87
|
+
def browser_close(self) -> dict[str, Any]:
|
|
88
|
+
return self.post("/browser/close", {})
|
|
89
|
+
|
|
90
|
+
def browser_refresh(self) -> dict[str, Any]:
|
|
91
|
+
return self.post("/browser/refresh", {})
|
|
92
|
+
|
|
93
|
+
def browser_back(self) -> dict[str, Any]:
|
|
94
|
+
return self.post("/browser/back", {})
|
|
95
|
+
|
|
96
|
+
def browser_forward(self) -> dict[str, Any]:
|
|
97
|
+
return self.post("/browser/forward", {})
|
|
98
|
+
|
|
99
|
+
def capture(self, label: str = "capture") -> dict[str, Any]:
|
|
100
|
+
return self.post("/browser/capture", {"label": label})
|
|
101
|
+
|
|
102
|
+
def read_text(self, selector: str, reason: str) -> dict[str, Any]:
|
|
103
|
+
return self.post("/browser/read-text", {"selector": selector, "reason": reason})
|
|
104
|
+
|
|
105
|
+
def read_dom(self) -> dict[str, Any]:
|
|
106
|
+
return self.post("/browser/read-dom", {})
|
|
107
|
+
|
|
108
|
+
def read_accessibility_tree(self) -> dict[str, Any]:
|
|
109
|
+
return self.post("/browser/read-accessibility-tree", {})
|
|
110
|
+
|
|
111
|
+
def read_console_errors(self) -> dict[str, Any]:
|
|
112
|
+
return self.post("/browser/read-console-errors", {})
|
|
113
|
+
|
|
114
|
+
def read_network_failures(self) -> dict[str, Any]:
|
|
115
|
+
return self.post("/browser/read-network-failures", {})
|
|
116
|
+
|
|
117
|
+
def inspect(self) -> dict[str, Any]:
|
|
118
|
+
return self.post("/browser/inspect", {})
|
|
119
|
+
|
|
120
|
+
def inspect_element(self, selector: str) -> dict[str, Any]:
|
|
121
|
+
return self.post("/browser/inspect-element", {"selector": selector})
|
|
122
|
+
|
|
123
|
+
def generate_report(self) -> dict[str, Any]:
|
|
124
|
+
return self.post("/report/generate", {})
|
|
125
|
+
|
|
126
|
+
def list_reports(self) -> dict[str, Any]:
|
|
127
|
+
return self.post("/report/list", {})
|
|
128
|
+
|
|
129
|
+
def read_report(self, report_name: str) -> dict[str, Any]:
|
|
130
|
+
return self.post("/report/read", {"report": report_name})
|
|
131
|
+
|
|
132
|
+
def export_report(self, report_name: str, destination: str | None = None) -> dict[str, Any]:
|
|
133
|
+
return self.post("/report/export", {"report": report_name, "destination": destination})
|
|
134
|
+
|
|
135
|
+
def get(self, route: str) -> dict[str, Any]:
|
|
136
|
+
return self._request(route, method="GET")
|
|
137
|
+
|
|
138
|
+
def post(self, route: str, payload: dict[str, Any]) -> dict[str, Any]:
|
|
139
|
+
return self._request(route, method="POST", payload=payload)
|
|
140
|
+
|
|
141
|
+
def _request(
|
|
142
|
+
self,
|
|
143
|
+
route: str,
|
|
144
|
+
method: str,
|
|
145
|
+
payload: dict[str, Any] | None = None,
|
|
146
|
+
) -> dict[str, Any]:
|
|
147
|
+
url = f"{self.runtime_url}{route}"
|
|
148
|
+
data = json.dumps(payload or {}).encode("utf8") if method == "POST" else None
|
|
149
|
+
headers = {"Content-Type": "application/json"}
|
|
150
|
+
if self.token:
|
|
151
|
+
headers["Authorization"] = f"Bearer {self.token}"
|
|
152
|
+
|
|
153
|
+
last_error: Exception | None = None
|
|
154
|
+
for attempt in range(self.retries + 1):
|
|
155
|
+
try:
|
|
156
|
+
request = Request(url, data=data, headers=headers, method=method)
|
|
157
|
+
with urlopen(request, timeout=self.timeout_seconds) as response:
|
|
158
|
+
return json.loads(response.read().decode("utf8"))
|
|
159
|
+
except (HTTPError, URLError) as exc:
|
|
160
|
+
last_error = exc
|
|
161
|
+
if attempt < self.retries:
|
|
162
|
+
time.sleep(0.2 * (attempt + 1))
|
|
163
|
+
continue
|
|
164
|
+
raise RuntimeClientError(
|
|
165
|
+
"Agent Portal runtime is not running. Start it with: agent-portal start"
|
|
166
|
+
) from last_error
|
|
167
|
+
|
|
168
|
+
def _load_token(self) -> str | None:
|
|
169
|
+
env_token = os.getenv("AGENT_PORTAL_TOKEN")
|
|
170
|
+
if env_token:
|
|
171
|
+
return env_token
|
|
172
|
+
config_path = Path.cwd() / "agent-portal.config.json"
|
|
173
|
+
if not config_path.exists():
|
|
174
|
+
return None
|
|
175
|
+
try:
|
|
176
|
+
raw = json.loads(config_path.read_text(encoding="utf8"))
|
|
177
|
+
except json.JSONDecodeError:
|
|
178
|
+
return None
|
|
179
|
+
token = raw.get("api_token")
|
|
180
|
+
return token if isinstance(token, str) and token else None
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
from dataclasses import asdict
|
|
6
|
+
|
|
7
|
+
from agent_portal_mcp.doctor import run_doctor
|
|
8
|
+
from agent_portal_mcp.server import AgentPortalMcpServer
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def main() -> None:
|
|
12
|
+
parser = argparse.ArgumentParser(prog="agent-portal-mcp")
|
|
13
|
+
parser.add_argument("--runtime-url", default="http://127.0.0.1:8765")
|
|
14
|
+
parser.add_argument("--json", action="store_true")
|
|
15
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
16
|
+
subparsers.add_parser("start")
|
|
17
|
+
subparsers.add_parser("doctor")
|
|
18
|
+
args = parser.parse_args()
|
|
19
|
+
|
|
20
|
+
if args.command == "start":
|
|
21
|
+
AgentPortalMcpServer(runtime_url=args.runtime_url).serve_stdio()
|
|
22
|
+
return
|
|
23
|
+
|
|
24
|
+
result = run_doctor(runtime_url=args.runtime_url)
|
|
25
|
+
payload = {"checks": [asdict(check) for check in result.checks]}
|
|
26
|
+
if args.json:
|
|
27
|
+
print(json.dumps(payload, indent=2))
|
|
28
|
+
return
|
|
29
|
+
for check in result.checks:
|
|
30
|
+
print(f"{check.status.upper():7} {check.name}: {check.details}")
|
|
31
|
+
if check.suggested_fix:
|
|
32
|
+
print(f" fix: {check.suggested_fix}")
|