@grackle-ai/mcp 0.131.0 → 0.132.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.
Files changed (55) hide show
  1. package/README.md +99 -99
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/mcp-server.d.ts.map +1 -1
  5. package/dist/mcp-server.js +74 -20
  6. package/dist/mcp-server.js.map +1 -1
  7. package/dist/scope-enforcement.d.ts.map +1 -1
  8. package/dist/scope-enforcement.js.map +1 -1
  9. package/dist/standalone.js +1 -1
  10. package/dist/standalone.js.map +1 -1
  11. package/dist/tool-registry.d.ts.map +1 -1
  12. package/dist/tool-registry.js.map +1 -1
  13. package/dist/tools/component.d.ts.map +1 -1
  14. package/dist/tools/component.js +128 -27
  15. package/dist/tools/component.js.map +1 -1
  16. package/dist/tools/credential.d.ts.map +1 -1
  17. package/dist/tools/credential.js +7 -3
  18. package/dist/tools/credential.js.map +1 -1
  19. package/dist/tools/env.d.ts.map +1 -1
  20. package/dist/tools/env.js +8 -18
  21. package/dist/tools/env.js.map +1 -1
  22. package/dist/tools/escalation.d.ts.map +1 -1
  23. package/dist/tools/escalation.js +15 -4
  24. package/dist/tools/escalation.js.map +1 -1
  25. package/dist/tools/ipc.d.ts.map +1 -1
  26. package/dist/tools/ipc.js +109 -23
  27. package/dist/tools/ipc.js.map +1 -1
  28. package/dist/tools/logs.d.ts.map +1 -1
  29. package/dist/tools/logs.js +23 -5
  30. package/dist/tools/logs.js.map +1 -1
  31. package/dist/tools/persona.d.ts.map +1 -1
  32. package/dist/tools/persona.js +8 -2
  33. package/dist/tools/persona.js.map +1 -1
  34. package/dist/tools/schedule.d.ts.map +1 -1
  35. package/dist/tools/schedule.js +7 -2
  36. package/dist/tools/schedule.js.map +1 -1
  37. package/dist/tools/session.d.ts.map +1 -1
  38. package/dist/tools/session.js +42 -10
  39. package/dist/tools/session.js.map +1 -1
  40. package/dist/tools/task.d.ts.map +1 -1
  41. package/dist/tools/task.js +52 -32
  42. package/dist/tools/task.js.map +1 -1
  43. package/dist/tools/token.d.ts.map +1 -1
  44. package/dist/tools/token.js +20 -6
  45. package/dist/tools/token.js.map +1 -1
  46. package/dist/tools/usage.d.ts.map +1 -1
  47. package/dist/tools/usage.js +9 -3
  48. package/dist/tools/usage.js.map +1 -1
  49. package/dist/tools/workpad.d.ts.map +1 -1
  50. package/dist/tools/workpad.js +38 -8
  51. package/dist/tools/workpad.js.map +1 -1
  52. package/dist/tools/workspace.d.ts.map +1 -1
  53. package/dist/tools/workspace.js +7 -27
  54. package/dist/tools/workspace.js.map +1 -1
  55. package/package.json +5 -4
package/README.md CHANGED
@@ -34,13 +34,13 @@ The MCP server listens on `http://127.0.0.1:7435/mcp` by default.
34
34
 
35
35
  All configuration is via environment variables:
36
36
 
37
- | Variable | Default | Description |
38
- |----------|---------|-------------|
39
- | `GRACKLE_MCP_PORT` | `7435` | Port the MCP server listens on |
40
- | `GRACKLE_HOST` | `127.0.0.1` | Bind address (must be a loopback address) |
41
- | `GRACKLE_URL` | `http://127.0.0.1:7434` | URL of the Grackle gRPC server to connect to |
42
- | `GRACKLE_API_KEY` | *(auto-loaded)* | API key for authenticating with the gRPC server. If not set, reads from `~/.grackle/api-key` |
43
- | `LOG_LEVEL` | `info` | Logging level (`debug`, `info`, `warn`, `error`) |
37
+ | Variable | Default | Description |
38
+ | ------------------ | ----------------------- | -------------------------------------------------------------------------------------------- |
39
+ | `GRACKLE_MCP_PORT` | `7435` | Port the MCP server listens on |
40
+ | `GRACKLE_HOST` | `127.0.0.1` | Bind address (must be a loopback address) |
41
+ | `GRACKLE_URL` | `http://127.0.0.1:7434` | URL of the Grackle gRPC server to connect to |
42
+ | `GRACKLE_API_KEY` | _(auto-loaded)_ | API key for authenticating with the gRPC server. If not set, reads from `~/.grackle/api-key` |
43
+ | `LOG_LEVEL` | `info` | Logging level (`debug`, `info`, `warn`, `error`) |
44
44
 
45
45
  ## Programmatic Usage
46
46
 
@@ -102,16 +102,16 @@ The MCP server exposes a rich set of tools organized into groups. Each tool vali
102
102
 
103
103
  Manage compute environments where agents run (Docker, SSH, Codespace, local).
104
104
 
105
- | Tool | Description | Parameters |
106
- |------|-------------|------------|
107
- | `env_list` | List all registered environments with status, adapter type, and runtime. | *(none)* |
108
- | `env_list_docker_containers` | List running Docker containers that can be attached to (Docker adapter attach mode). | *(none)* |
109
- | `env_add` | Register a new environment. The `adapterConfig` fields depend on `adapterType` (see below). For the Docker adapter, set `adapterConfig.attach` to an existing container name/ID to attach instead of creating one. | `displayName` (string), `adapterType` (`local` \| `ssh` \| `codespace` \| `docker`), `adapterConfig?` (object), `githubAccountId?` (string, codespace/docker) |
110
- | `env_provision` | Provision an environment — start resources, install the agent, and connect. | `environmentId` (string), `force?` (boolean) |
111
- | `env_stop` | Stop a running environment without destroying its resources. | `environmentId` (string) |
112
- | `env_destroy` | Destroy an environment's backing resources (e.g., delete the container). | `environmentId` (string) |
113
- | `env_remove` | Remove an environment registration. Must be stopped first. | `environmentId` (string) |
114
- | `env_wake` | Wake a stopped environment by re-provisioning it. | `environmentId` (string) |
105
+ | Tool | Description | Parameters |
106
+ | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
107
+ | `env_list` | List all registered environments with status, adapter type, and runtime. | _(none)_ |
108
+ | `env_list_docker_containers` | List running Docker containers that can be attached to (Docker adapter attach mode). | _(none)_ |
109
+ | `env_add` | Register a new environment. The `adapterConfig` fields depend on `adapterType` (see below). For the Docker adapter, set `adapterConfig.attach` to an existing container name/ID to attach instead of creating one. | `displayName` (string), `adapterType` (`local` \| `ssh` \| `codespace` \| `docker`), `adapterConfig?` (object), `githubAccountId?` (string, codespace/docker) |
110
+ | `env_provision` | Provision an environment — start resources, install the agent, and connect. | `environmentId` (string), `force?` (boolean) |
111
+ | `env_stop` | Stop a running environment without destroying its resources. | `environmentId` (string) |
112
+ | `env_destroy` | Destroy an environment's backing resources (e.g., delete the container). | `environmentId` (string) |
113
+ | `env_remove` | Remove an environment registration. Must be stopped first. | `environmentId` (string) |
114
+ | `env_wake` | Wake a stopped environment by re-provisioning it. | `environmentId` (string) |
115
115
 
116
116
  `env_add` is a discriminated union on `adapterType` — the tool's input schema advertises the exact `adapterConfig` fields valid for each adapter, and unknown fields are rejected. Pick the adapter that matches how the environment is reached:
117
117
 
@@ -124,125 +124,125 @@ Manage compute environments where agents run (Docker, SSH, Codespace, local).
124
124
 
125
125
  Manage AI agent sessions — spawn, monitor, interact, and terminate.
126
126
 
127
- | Tool | Description | Parameters |
128
- |------|-------------|------------|
129
- | `session_spawn` | Spawn a new agent session with a prompt and optional model config. | `environmentId` (string), `prompt` (string), `maxTurns?` (int), `personaId?` (string), `workingDirectory?` (string) |
130
- | `session_resume` | Resume a stopped agent session. | `sessionId` (string) |
131
- | `session_status` | List sessions with optional filtering by environment and status. | `environmentId?` (string), `all?` (boolean, default false) |
132
- | `session_kill` | Terminate a running session. Hard kill by default; graceful=true sends SIGTERM. | `sessionId` (string), `graceful?` (boolean, default false) |
133
- | `session_attach` | Stream events from a running session for a limited duration. | `sessionId` (string), `timeoutSeconds?` (int, default 30, max 300), `maxEvents?` (int) |
134
- | `session_send_input` | Send a text message to a session waiting for user input. | `sessionId` (string), `text` (string) |
127
+ | Tool | Description | Parameters |
128
+ | -------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
129
+ | `session_spawn` | Spawn a new agent session with a prompt and optional model config. | `environmentId` (string), `prompt` (string), `maxTurns?` (int), `personaId?` (string), `workingDirectory?` (string) |
130
+ | `session_resume` | Resume a stopped agent session. | `sessionId` (string) |
131
+ | `session_status` | List sessions with optional filtering by environment and status. | `environmentId?` (string), `all?` (boolean, default false) |
132
+ | `session_kill` | Terminate a running session. Hard kill by default; graceful=true sends SIGTERM. | `sessionId` (string), `graceful?` (boolean, default false) |
133
+ | `session_attach` | Stream events from a running session for a limited duration. | `sessionId` (string), `timeoutSeconds?` (int, default 30, max 300), `maxEvents?` (int) |
134
+ | `session_send_input` | Send a text message to a session waiting for user input. | `sessionId` (string), `text` (string) |
135
135
 
136
136
  ### Workspace Tools
137
137
 
138
138
  Manage workspaces that group tasks, agents, and repositories.
139
139
 
140
- | Tool | Description | Parameters |
141
- |------|-------------|------------|
142
- | `workspace_list` | List all workspaces with names, descriptions, repos, and status. | `environmentId?` (string) |
143
- | `workspace_create` | Create a new workspace. | `name` (string), `environmentId` (string), `description?` (string), `repoUrl?` (string), `workingDirectory?` (string), `useWorktrees?` (boolean), `defaultPersonaId?` (string) |
144
- | `workspace_get` | Get full details of a workspace by ID. | `workspaceId` (string) |
145
- | `workspace_update` | Update a workspace's name, description, repo, or settings. | `workspaceId` (string), `name?`, `description?`, `repoUrl?`, `environmentId?`, `workingDirectory?`, `useWorktrees?`, `defaultPersonaId?` |
146
- | `workspace_archive` | Archive a workspace, marking it as inactive. | `workspaceId` (string) |
147
- | `workspace_link_environment` | Link an additional environment to a workspace's pool. | `workspaceId` (string), `environmentId` (string) |
148
- | `workspace_unlink_environment` | Remove a linked environment from a workspace's pool. | `workspaceId` (string), `environmentId` (string) |
140
+ | Tool | Description | Parameters |
141
+ | ------------------------------ | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
142
+ | `workspace_list` | List all workspaces with names, descriptions, repos, and status. | `environmentId?` (string) |
143
+ | `workspace_create` | Create a new workspace. | `name` (string), `environmentId` (string), `description?` (string), `repoUrl?` (string), `workingDirectory?` (string), `useWorktrees?` (boolean), `defaultPersonaId?` (string) |
144
+ | `workspace_get` | Get full details of a workspace by ID. | `workspaceId` (string) |
145
+ | `workspace_update` | Update a workspace's name, description, repo, or settings. | `workspaceId` (string), `name?`, `description?`, `repoUrl?`, `environmentId?`, `workingDirectory?`, `useWorktrees?`, `defaultPersonaId?` |
146
+ | `workspace_archive` | Archive a workspace, marking it as inactive. | `workspaceId` (string) |
147
+ | `workspace_link_environment` | Link an additional environment to a workspace's pool. | `workspaceId` (string), `environmentId` (string) |
148
+ | `workspace_unlink_environment` | Remove a linked environment from a workspace's pool. | `workspaceId` (string), `environmentId` (string) |
149
149
 
150
150
  ### Task Tools
151
151
 
152
152
  Create, manage, and run tasks within workspaces. Supports hierarchical task trees and dependency gating.
153
153
 
154
- | Tool | Description | Parameters |
155
- |------|-------------|------------|
156
- | `task_list` | List tasks with optional search and status filters. | `workspaceId?` (string), `search?` (string), `status?` (string: `not_started`, `working`, `paused`, `complete`, `failed`) |
157
- | `task_search` | Fuzzy search tasks by title or description, ranked by relevance. Returns results with a `relevanceScore` (0.0–1.0, higher = better match). Prefer this over `task_list` when matching approximate descriptions. | `query` (string), `workspaceId?` (string), `limit?` (number, default 10), `status?` (string) |
158
- | `task_create` | Create a new task with dependencies and parent hierarchy. | `workspaceId?` (string), `title` (string), `description?` (string), `dependsOn?` (string[]), `parentTaskId?` (string), `canDecompose?` (boolean), `defaultPersonaId?` (string) |
159
- | `task_show` | Get full details of a task. | `taskId` (string) |
160
- | `task_update` | Update a task's title, description, status, or dependencies. | `taskId` (string), `title?`, `description?`, `status?` (enum), `dependsOn?` (string[]), `sessionId?` (string) |
161
- | `task_start` | Start a task by spawning an agent session. Supports IPC pipe modes. | `taskId` (string), `personaId?` (string), `environmentId?` (string), `notes?` (string), `pipe?` (`sync` \| `async` \| `detach`) |
162
- | `task_delete` | Permanently delete a task. | `taskId` (string) |
163
- | `task_complete` | Mark a task as complete (sticky status). | `taskId` (string) |
164
- | `task_resume` | Resume the latest session for a task. | `taskId` (string) |
154
+ | Tool | Description | Parameters |
155
+ | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
156
+ | `task_list` | List tasks with optional search and status filters. | `workspaceId?` (string), `search?` (string), `status?` (string: `not_started`, `working`, `paused`, `complete`, `failed`) |
157
+ | `task_search` | Fuzzy search tasks by title or description, ranked by relevance. Returns results with a `relevanceScore` (0.0–1.0, higher = better match). Prefer this over `task_list` when matching approximate descriptions. | `query` (string), `workspaceId?` (string), `limit?` (number, default 10), `status?` (string) |
158
+ | `task_create` | Create a new task with dependencies and parent hierarchy. | `workspaceId?` (string), `title` (string), `description?` (string), `dependsOn?` (string[]), `parentTaskId?` (string), `canDecompose?` (boolean), `defaultPersonaId?` (string) |
159
+ | `task_show` | Get full details of a task. | `taskId` (string) |
160
+ | `task_update` | Update a task's title, description, status, or dependencies. | `taskId` (string), `title?`, `description?`, `status?` (enum), `dependsOn?` (string[]), `sessionId?` (string) |
161
+ | `task_start` | Start a task by spawning an agent session. Supports IPC pipe modes. | `taskId` (string), `personaId?` (string), `environmentId?` (string), `notes?` (string), `pipe?` (`sync` \| `async` \| `detach`) |
162
+ | `task_delete` | Permanently delete a task. | `taskId` (string) |
163
+ | `task_complete` | Mark a task as complete (sticky status). | `taskId` (string) |
164
+ | `task_resume` | Resume the latest session for a task. | `taskId` (string) |
165
165
 
166
166
  ### Persona Tools
167
167
 
168
168
  Manage agent personas — reusable templates defining system prompt, runtime, and model.
169
169
 
170
- | Tool | Description | Parameters |
171
- |------|-------------|------------|
172
- | `persona_list` | List all available personas. | *(none)* |
170
+ | Tool | Description | Parameters |
171
+ | ---------------- | --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
172
+ | `persona_list` | List all available personas. | _(none)_ |
173
173
  | `persona_create` | Create a new persona template (`agent` or `script` type). | `name` (string), `systemPrompt?` (string), `description?` (string), `runtime?` (string), `model?` (string), `maxTurns?` (int), `type?` (`agent` \| `script`), `script?` (string) |
174
- | `persona_show` | Get full details of a persona. | `personaId` (string) |
175
- | `persona_edit` | Update an existing persona. | `personaId` (string), `name?`, `systemPrompt?`, `description?`, `runtime?`, `model?`, `maxTurns?`, `type?`, `script?` |
176
- | `persona_delete` | Delete a persona permanently. | `personaId` (string) |
174
+ | `persona_show` | Get full details of a persona. | `personaId` (string) |
175
+ | `persona_edit` | Update an existing persona. | `personaId` (string), `name?`, `systemPrompt?`, `description?`, `runtime?`, `model?`, `maxTurns?`, `type?`, `script?` |
176
+ | `persona_delete` | Delete a persona permanently. | `personaId` (string) |
177
177
 
178
178
  ### Knowledge Graph Tools
179
179
 
180
180
  Search a semantic knowledge graph across sessions and task context.
181
181
 
182
- | Tool | Description | Parameters |
183
- |------|-------------|------------|
184
- | `knowledge_search` | Find how related/prior work in the workspace was approached. Semantic search over the knowledge graph (tasks, sessions, transcript chunks). | `query` (string), `limit?` (int, max 50), `workspaceId?` (string), `expand?` (boolean), `expandDepth?` (int, max 5) |
185
- | `knowledge_get_node` | Retrieve a specific node by ID with optional neighbor expansion. | `id` (string), `expand?` (boolean), `expandDepth?` (int, max 5) |
186
- | `knowledge_create_node` | Create a new knowledge entry (decision, insight, concept, snippet). | `title` (string), `content` (string), `category?` (string), `tags?` (string[]), `workspaceId?` (string), `edges?` (array of `{toId, type}`) |
182
+ | Tool | Description | Parameters |
183
+ | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
184
+ | `knowledge_search` | Find how related/prior work in the workspace was approached. Semantic search over the knowledge graph (tasks, sessions, transcript chunks). | `query` (string), `limit?` (int, max 50), `workspaceId?` (string), `expand?` (boolean), `expandDepth?` (int, max 5) |
185
+ | `knowledge_get_node` | Retrieve a specific node by ID with optional neighbor expansion. | `id` (string), `expand?` (boolean), `expandDepth?` (int, max 5) |
186
+ | `knowledge_create_node` | Create a new knowledge entry (decision, insight, concept, snippet). | `title` (string), `content` (string), `category?` (string), `tags?` (string[]), `workspaceId?` (string), `edges?` (array of `{toId, type}`) |
187
187
 
188
188
  ### IPC Tools
189
189
 
190
190
  Inter-process communication between parent and child agent sessions.
191
191
 
192
- | Tool | Description | Parameters |
193
- |------|-------------|------------|
194
- | `ipc_spawn` | Spawn a child agent session with an IPC pipe. | `prompt` (string), `pipe` (`sync` \| `async` \| `detach`), `environmentId` (string), `personaId?` (string), `maxTurns?` (int) |
195
- | `ipc_write` | Write a message to a child session via a file descriptor. | `fd` (int), `message` (string) |
196
- | `ipc_close` | Close a file descriptor, optionally stopping the child. | `fd` (int) |
197
- | `ipc_terminate` | Send SIGTERM to a child session via its fd for graceful shutdown. | `fd` (int) |
198
- | `ipc_list_fds` | List your open file descriptors (IPC connections). | *(none)* |
199
- | `ipc_list_streams` | List all active IPC streams with subscriber details and buffer depth. | *(none)* |
200
- | `ipc_create_stream` | Create a named stream for inter-session communication. Returns an rw fd. | `name` (string), `selfEcho?` (boolean, default `false`) |
201
- | `ipc_attach` | Grant another session access to a stream you hold an fd on. | `fd` (int), `targetSessionId` (string), `permission?` (`r` \| `w` \| `rw`), `deliveryMode?` (`sync` \| `async` \| `detach`) |
202
- | `ipc_share_stream` | Share a stream with your parent session. Auto-discovers the parent via the inherited pipe fd, grants access, and sends a `[stream-ref]` notification through the pipe. | `fd?` (int) or `streamName?` (string; exactly one required), `permission?` (`r` \| `w` \| `rw`), `deliveryMode?` (`sync` \| `async` \| `detach`) |
192
+ | Tool | Description | Parameters |
193
+ | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
194
+ | `ipc_spawn` | Spawn a child agent session with an IPC pipe. | `prompt` (string), `pipe` (`sync` \| `async` \| `detach`), `environmentId` (string), `personaId?` (string), `maxTurns?` (int) |
195
+ | `ipc_write` | Write a message to a child session via a file descriptor. | `fd` (int), `message` (string) |
196
+ | `ipc_close` | Close a file descriptor, optionally stopping the child. | `fd` (int) |
197
+ | `ipc_terminate` | Send SIGTERM to a child session via its fd for graceful shutdown. | `fd` (int) |
198
+ | `ipc_list_fds` | List your open file descriptors (IPC connections). | _(none)_ |
199
+ | `ipc_list_streams` | List all active IPC streams with subscriber details and buffer depth. | _(none)_ |
200
+ | `ipc_create_stream` | Create a named stream for inter-session communication. Returns an rw fd. | `name` (string), `selfEcho?` (boolean, default `false`) |
201
+ | `ipc_attach` | Grant another session access to a stream you hold an fd on. | `fd` (int), `targetSessionId` (string), `permission?` (`r` \| `w` \| `rw`), `deliveryMode?` (`sync` \| `async` \| `detach`) |
202
+ | `ipc_share_stream` | Share a stream with your parent session. Auto-discovers the parent via the inherited pipe fd, grants access, and sends a `[stream-ref]` notification through the pipe. | `fd?` (int) or `streamName?` (string; exactly one required), `permission?` (`r` \| `w` \| `rw`), `deliveryMode?` (`sync` \| `async` \| `detach`) |
203
203
 
204
204
  ### Log Tools
205
205
 
206
206
  Retrieve session logs — raw events, formatted transcripts, or live tails.
207
207
 
208
- | Tool | Description | Parameters |
209
- |------|-------------|------------|
208
+ | Tool | Description | Parameters |
209
+ | ---------- | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
210
210
  | `logs_get` | Retrieve session logs in raw, transcript, or live-tail mode. | `sessionId` (string), `transcript?` (boolean), `tail?` (boolean), `timeoutSeconds?` (int, default 10, max 60), `maxEvents?` (int) |
211
211
 
212
212
  ### Token Tools
213
213
 
214
214
  Manage secrets that are auto-forwarded to environments.
215
215
 
216
- | Tool | Description | Parameters |
217
- |------|-------------|------------|
218
- | `token_list` | List configured tokens (values are never returned). | *(none)* |
219
- | `token_set` | Set a token for auto-forwarding to environments. | `name` (string), `value` (string), `type?` (`env_var` \| `file`), `envVar?` (string), `filePath?` (string) |
220
- | `token_delete` | Delete a configured token. | `name` (string) |
216
+ | Tool | Description | Parameters |
217
+ | -------------- | --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
218
+ | `token_list` | List configured tokens (values are never returned). | _(none)_ |
219
+ | `token_set` | Set a token for auto-forwarding to environments. | `name` (string), `value` (string), `type?` (`env_var` \| `file`), `envVar?` (string), `filePath?` (string) |
220
+ | `token_delete` | Delete a configured token. | `name` (string) |
221
221
 
222
222
  ### Credential Provider Tools
223
223
 
224
224
  Configure which credential providers (Claude, GitHub, Copilot, Codex) are auto-forwarded.
225
225
 
226
- | Tool | Description | Parameters |
227
- |------|-------------|------------|
228
- | `credential_provider_list` | List current provider configuration. | *(none)* |
229
- | `credential_provider_set` | Set a provider mode. | `provider` (`claude` \| `github` \| `copilot` \| `codex`), `value` (`off` \| `on` \| `subscription` \| `api_key`) |
226
+ | Tool | Description | Parameters |
227
+ | -------------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------- |
228
+ | `credential_provider_list` | List current provider configuration. | _(none)_ |
229
+ | `credential_provider_set` | Set a provider mode. | `provider` (`claude` \| `github` \| `copilot` \| `codex`), `value` (`off` \| `on` \| `subscription` \| `api_key`) |
230
230
 
231
231
  ### Config Tools
232
232
 
233
233
  Read and write global configuration settings.
234
234
 
235
- | Tool | Description | Parameters |
236
- |------|-------------|------------|
237
- | `config_get_default_persona` | Get the default persona for new sessions. | *(none)* |
235
+ | Tool | Description | Parameters |
236
+ | ---------------------------- | ----------------------------------------- | -------------------- |
237
+ | `config_get_default_persona` | Get the default persona for new sessions. | _(none)_ |
238
238
  | `config_set_default_persona` | Set the default persona for new sessions. | `personaId` (string) |
239
239
 
240
240
  ### Usage Tools
241
241
 
242
242
  Query aggregated token usage and cost data.
243
243
 
244
- | Tool | Description | Parameters |
245
- |------|-------------|------------|
244
+ | Tool | Description | Parameters |
245
+ | ----------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
246
246
  | `usage_get` | Get token usage and cost for a session, task, task tree, workspace, or environment. | `scope` (`session` \| `task` \| `task_tree` \| `workspace` \| `environment`), `id` (string) |
247
247
 
248
248
  ### Component & Widget Tools
@@ -251,17 +251,17 @@ Query aggregated token usage and cost data.
251
251
 
252
252
  `show_hello_widget` is the Grackle-served demo: it references a static `ui://` resource and appears in `tools/list` **only** when the host advertises the `io.modelcontextprotocol/ui` extension. The **component registry** tools (#1269) let an agent author and reuse components at runtime; they are ordinary scoped tools (always listed) and the rendered output is captured by the broker into the session's chat.
253
253
 
254
- | Tool | Description | Parameters |
255
- |------|-------------|------------|
256
- | `show_hello_widget` | Display the Grackle hello widget — a minimal interactive MCP Apps UI that echoes the provided message. | `message` (string, optional) |
257
- | `component_register` | Register a reusable component in the workspace. `source` is JSX (`grackle-react`, default) or HTML (`mcp-app-html`). Returns the component id. | `name` (string), `source` (string), `rendererKind` (optional), `description` (optional), `propsSchema` (JSON Schema string, optional) |
258
- | `component_update` | Update a registered component's source/name/description/props schema; bumps its version. | `id` (string), `source`/`name`/`description`/`propsSchema` (optional) |
259
- | `component_list` | List the reusable components registered in the workspace. | — |
260
- | `component_search` | Keyword-search registered components **and** Grackle's built-in components by name/description. Find a component to reuse before authoring. `builtin:true` results are composed in JSX; others are rendered via `component_render`. | `query` (string), `limit` (optional), `workspaceId` (auto) |
261
- | `component_promote` | Promote a registered component to its own `render_<name>` MCP tool (or demote with `promoted:false`). Resolve by `id` or `name`. | `id` (optional), `name` (optional), `promoted` (optional, default `true`) |
262
- | `component_render` | Render a registered component inline (by `id` or `name`), optionally passing `props`. Props are validated against the component's `propsSchema`. | `id` (optional), `name` (optional), `props` (object, optional) |
263
- | `component_show` | Render a one-off React/JSX component inline against the Grackle component library (no persistence). `source` calls `render(<Component {...props}/>)`; `React`, `props`, and Grackle components are in scope. | `source` (string), `props` (object, optional) |
264
- | `widget_show` | Render a one-off raw-HTML body inline, without persisting it. | `body` (string), `props` (object, optional) |
254
+ | Tool | Description | Parameters |
255
+ | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
256
+ | `show_hello_widget` | Display the Grackle hello widget — a minimal interactive MCP Apps UI that echoes the provided message. | `message` (string, optional) |
257
+ | `component_register` | Register a reusable component in the workspace. `source` is JSX (`grackle-react`, default) or HTML (`mcp-app-html`). Returns the component id. | `name` (string), `source` (string), `rendererKind` (optional), `description` (optional), `propsSchema` (JSON Schema string, optional) |
258
+ | `component_update` | Update a registered component's source/name/description/props schema; bumps its version. | `id` (string), `source`/`name`/`description`/`propsSchema` (optional) |
259
+ | `component_list` | List the reusable components registered in the workspace. | — |
260
+ | `component_search` | Keyword-search registered components **and** Grackle's built-in components by name/description. Find a component to reuse before authoring. `builtin:true` results are composed in JSX; others are rendered via `component_render`. | `query` (string), `limit` (optional), `workspaceId` (auto) |
261
+ | `component_promote` | Promote a registered component to its own `render_<name>` MCP tool (or demote with `promoted:false`). Resolve by `id` or `name`. | `id` (optional), `name` (optional), `promoted` (optional, default `true`) |
262
+ | `component_render` | Render a registered component inline (by `id` or `name`), optionally passing `props`. Props are validated against the component's `propsSchema`. | `id` (optional), `name` (optional), `props` (object, optional) |
263
+ | `component_show` | Render a one-off React/JSX component inline against the Grackle component library (no persistence). `source` calls `render(<Component {...props}/>)`; `React`, `props`, and Grackle components are in scope. | `source` (string), `props` (object, optional) |
264
+ | `widget_show` | Render a one-off raw-HTML body inline, without persisting it. | `body` (string), `props` (object, optional) |
265
265
 
266
266
  Components are **workspace-scoped**: a session may only register/render components in its own workspace (the `workspaceId` is taken from the session's scoped token). A component's `propsSchema` (a JSON Schema) is validated at register, and render-time `props` are validated against it (via zod's `fromJSONSchema`). Renderers run in the cross-origin sandbox: `mcp-app-html` allows inline scripts (`script-src 'unsafe-inline'`); `grackle-react` runs the React runtime that transpiles + evaluates JSX (`script-src 'unsafe-eval'`) — both kept safe by the iframe origin isolation + restricted `connect-src`.
267
267
 
@@ -316,12 +316,12 @@ Each persona can define an `allowed_mcp_tools` list that restricts which MCP too
316
316
 
317
317
  Predefined presets are available for convenience (via CLI `--mcp-tools-preset` or the web UI):
318
318
 
319
- | Preset | Description |
320
- |--------|-------------|
321
- | `default` | The 25-tool default scoped set (backward compatible) |
322
- | `worker` | Subset of default — no task creation capabilities |
319
+ | Preset | Description |
320
+ | -------------- | ------------------------------------------------------------------------- |
321
+ | `default` | The 25-tool default scoped set (backward compatible) |
322
+ | `worker` | Subset of default — no task creation capabilities |
323
323
  | `orchestrator` | Default + task management, session spawning, persona creation, scheduling |
324
- | `admin` | Full access to all available tools |
324
+ | `admin` | Full access to all available tools |
325
325
 
326
326
  Scoped tokens also enforce workspace isolation — agents can only see tasks within their own workspace. Subtasks created by a scoped agent are automatically parented to the agent's own task. Tool calls to non-permitted tools return an error with a descriptive message listing the available tools.
327
327
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAGrF,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EACL,iBAAiB,EAAE,UAAU,EAAE,iBAAiB,EAChD,sBAAsB,EAAE,sBAAsB,EAC9C,yBAAyB,EAAE,0BAA0B,EACrD,sBAAsB,GACvB,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAGrF,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,sBAAsB,EACtB,yBAAyB,EACzB,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,kBAAkB,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAK1D,OAAO,EACL,iBAAiB,EAAE,UAAU,EAAE,iBAAiB,EAChD,sBAAsB,EAAE,sBAAsB,EAC9C,yBAAyB,EAAE,0BAA0B,EACrD,sBAAsB,GACvB,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAK1D,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,sBAAsB,EACtB,yBAAyB,EACzB,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,kBAAkB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"AAEA,OAAO,IAAI,MAAM,WAAW,CAAC;AAoB7B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD,OAAO,KAAK,EAAE,cAAc,EAA8B,MAAM,oBAAoB,CAAC;AAsBrF;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAC/B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IACP,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,KACE,IAAI,CAAC;AAEV,0CAA0C;AAC1C,MAAM,WAAW,gBAAgB;IAC/B,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;IACf,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,UAAU,CAAC,EAAE,cAAc,EAAE,EAAE,CAAC;IAChC,6FAA6F;IAC7F,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC;;;;;;OAMG;IACH,0BAA0B,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;CACpF;AAwDD,iGAAiG;AACjG;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAS1G;AAiYD;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,EAC9C,WAAW,EAAE,MAAM,GAClB,MAAM,EAAE,CAQV;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAsHtE;AA+BD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAC7C,SAAS,EAAE,OAAO,GACjB,MAAM,CASR"}
1
+ {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"AAEA,OAAO,IAAI,MAAM,WAAW,CAAC;AAyB7B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD,OAAO,KAAK,EAAE,cAAc,EAA8B,MAAM,oBAAoB,CAAC;AAyBrF;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAC/B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IACP,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,KACE,IAAI,CAAC;AAEV,0CAA0C;AAC1C,MAAM,WAAW,gBAAgB;IAC/B,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;IACf,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,UAAU,CAAC,EAAE,cAAc,EAAE,EAAE,CAAC;IAChC,6FAA6F;IAC7F,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC;;;;;;OAMG;IACH,0BAA0B,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;CACpF;AAwDD,iGAAiG;AACjG;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,GAClB,UAAU,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAW9C;AAydD;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,EAC9C,WAAW,EAAE,MAAM,GAClB,MAAM,EAAE,CAQV;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC,MAAM,CA8ItE;AA+BD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAC7C,SAAS,EAAE,OAAO,GACjB,MAAM,CAWR"}
@@ -5,7 +5,7 @@ import { dirname, join } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { createClient } from "@connectrpc/connect";
7
7
  import { createGrpcTransport } from "@connectrpc/connect-node";
8
- import { grackle, ROOT_TASK_ID, RENDER_TOOL_PREFIX, selectPromotedRenderTools } from "@grackle-ai/common";
8
+ import { grackle, ROOT_TASK_ID, RENDER_TOOL_PREFIX, selectPromotedRenderTools, } from "@grackle-ai/common";
9
9
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
10
10
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
11
11
  import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, isInitializeRequest, McpError, ErrorCode, } from "@modelcontextprotocol/sdk/types.js";
@@ -190,7 +190,9 @@ async function createMcpServerInstance(grpcClients, authContext, assetBaseUrl, b
190
190
  }
191
191
  let components;
192
192
  try {
193
- const resp = await grpcClients.orchestration.listComponents({ workspaceId: authContext.workspaceId });
193
+ const resp = await grpcClients.orchestration.listComponents({
194
+ workspaceId: authContext.workspaceId,
195
+ });
194
196
  components = resp.components;
195
197
  }
196
198
  catch (err) {
@@ -207,7 +209,12 @@ async function createMcpServerInstance(grpcClients, authContext, assetBaseUrl, b
207
209
  name: toolName,
208
210
  description: `Render the "${c.name}" component (v${c.version}) inline. Promoted from this workspace's component registry; its inputSchema is the component's prop schema.`,
209
211
  inputSchema: dynamicRenderInputSchema(c.propsSchema),
210
- annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
212
+ annotations: {
213
+ readOnlyHint: true,
214
+ destructiveHint: false,
215
+ idempotentHint: true,
216
+ openWorldHint: false,
217
+ },
211
218
  });
212
219
  }
213
220
  return defs;
@@ -220,13 +227,18 @@ async function createMcpServerInstance(grpcClients, authContext, assetBaseUrl, b
220
227
  * by registry ownership, NOT the static/persona allowlist.
221
228
  */
222
229
  async function handleDynamicRender(name, rawArgs) {
223
- const unknownTool = { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
230
+ const unknownTool = {
231
+ content: [{ type: "text", text: `Unknown tool: ${name}` }],
232
+ isError: true,
233
+ };
224
234
  if (authContext.type !== "scoped" || !authContext.workspaceId) {
225
235
  return unknownTool;
226
236
  }
227
237
  let components;
228
238
  try {
229
- const resp = await grpcClients.orchestration.listComponents({ workspaceId: authContext.workspaceId });
239
+ const resp = await grpcClients.orchestration.listComponents({
240
+ workspaceId: authContext.workspaceId,
241
+ });
230
242
  components = resp.components;
231
243
  }
232
244
  catch (error) {
@@ -241,7 +253,12 @@ async function createMcpServerInstance(grpcClients, authContext, assetBaseUrl, b
241
253
  // reject a non-object payload (array/string/null) before it reaches the render.
242
254
  if (typeof rawArgs !== "object" || rawArgs === null || Array.isArray(rawArgs)) {
243
255
  return {
244
- content: [{ type: "text", text: JSON.stringify({ error: "arguments must be an object of props", code: "INVALID_ARGUMENT" }, null, 2) }],
256
+ content: [
257
+ {
258
+ type: "text",
259
+ text: JSON.stringify({ error: "arguments must be an object of props", code: "INVALID_ARGUMENT" }, null, 2),
260
+ },
261
+ ],
245
262
  isError: true,
246
263
  };
247
264
  }
@@ -249,7 +266,15 @@ async function createMcpServerInstance(grpcClients, authContext, assetBaseUrl, b
249
266
  const validationErr = propsValidationError(match.propsSchema, props);
250
267
  if (validationErr) {
251
268
  return {
252
- content: [{ type: "text", text: JSON.stringify({ error: `props do not match the component's propsSchema: ${validationErr}`, code: "INVALID_ARGUMENT" }, null, 2) }],
269
+ content: [
270
+ {
271
+ type: "text",
272
+ text: JSON.stringify({
273
+ error: `props do not match the component's propsSchema: ${validationErr}`,
274
+ code: "INVALID_ARGUMENT",
275
+ }, null, 2),
276
+ },
277
+ ],
253
278
  isError: true,
254
279
  };
255
280
  }
@@ -282,7 +307,9 @@ async function createMcpServerInstance(grpcClients, authContext, assetBaseUrl, b
282
307
  // path for the standalone MCP server, where the client renders the
283
308
  // widget itself.
284
309
  const uiOn = publishWidgetEvent !== undefined || hostSupportsUiApps(server.getClientCapabilities());
285
- const staticTools = uiOn ? visibleToolDefs : visibleToolDefs.filter((t) => !uiToolNames.has(t.name));
310
+ const staticTools = uiOn
311
+ ? visibleToolDefs
312
+ : visibleToolDefs.filter((t) => !uiToolNames.has(t.name));
286
313
  // Dynamic render_<name> tools render only via the in-process broker capture
287
314
  // (they have no readable ui:// resource), so list them ONLY when the broker is
288
315
  // active — never in standalone/ui-host mode where a host would resources/read
@@ -341,9 +368,18 @@ async function createMcpServerInstance(grpcClients, authContext, assetBaseUrl, b
341
368
  };
342
369
  }
343
370
  const available = visibleToolNames;
344
- logger.warn({ tool: name, authType: authContext.type, personaId: authContext.type === "scoped" ? authContext.personaId : undefined }, "Tool call rejected by scope: %s", name);
371
+ logger.warn({
372
+ tool: name,
373
+ authType: authContext.type,
374
+ personaId: authContext.type === "scoped" ? authContext.personaId : undefined,
375
+ }, "Tool call rejected by scope: %s", name);
345
376
  return {
346
- content: [{ type: "text", text: `Tool "${name}" is not permitted for this session. Available tools: ${available}` }],
377
+ content: [
378
+ {
379
+ type: "text",
380
+ text: `Tool "${name}" is not permitted for this session. Available tools: ${available}`,
381
+ },
382
+ ],
347
383
  isError: true,
348
384
  };
349
385
  }
@@ -365,7 +401,15 @@ async function createMcpServerInstance(grpcClients, authContext, assetBaseUrl, b
365
401
  : undefined;
366
402
  if (requestedWorkspaceId !== undefined && requestedWorkspaceId !== boundWorkspace) {
367
403
  return {
368
- content: [{ type: "text", text: JSON.stringify({ error: "workspaceId does not match the authenticated workspace", code: "PERMISSION_DENIED" }, null, 2) }],
404
+ content: [
405
+ {
406
+ type: "text",
407
+ text: JSON.stringify({
408
+ error: "workspaceId does not match the authenticated workspace",
409
+ code: "PERMISSION_DENIED",
410
+ }, null, 2),
411
+ },
412
+ ],
369
413
  isError: true,
370
414
  };
371
415
  }
@@ -382,12 +426,20 @@ async function createMcpServerInstance(grpcClients, authContext, assetBaseUrl, b
382
426
  }
383
427
  // Enforce workspace scoping: verify task belongs to the caller's workspace.
384
428
  // Skip check when caller has no workspace (root task agents can see any task).
385
- if (name === "task_show" && authContext.workspaceId && typeof rawArgs.taskId === "string" && rawArgs.taskId) {
429
+ if (name === "task_show" &&
430
+ authContext.workspaceId &&
431
+ typeof rawArgs.taskId === "string" &&
432
+ rawArgs.taskId) {
386
433
  try {
387
434
  const task = await grpcClients.orchestration.getTask({ id: rawArgs.taskId });
388
435
  if ((task.workspaceId || undefined) !== authContext.workspaceId) {
389
436
  return {
390
- content: [{ type: "text", text: JSON.stringify({ error: "Task belongs to a different workspace", code: "PERMISSION_DENIED" }, null, 2) }],
437
+ content: [
438
+ {
439
+ type: "text",
440
+ text: JSON.stringify({ error: "Task belongs to a different workspace", code: "PERMISSION_DENIED" }, null, 2),
441
+ },
442
+ ],
391
443
  isError: true,
392
444
  };
393
445
  }
@@ -460,7 +512,7 @@ export function sessionIdsForWorkspace(authContexts, workspaceId) {
460
512
  * and Server instance, tracked by session ID.
461
513
  */
462
514
  export function createMcpServer(options) {
463
- const { bindHost, mcpPort, grpcPort, apiKey, authorizationServerUrl, toolGroups, publishWidgetEvent, mcpOrigin, onComponentChangeSubscribe } = options;
515
+ const { bindHost, mcpPort, grpcPort, apiKey, authorizationServerUrl, toolGroups, publishWidgetEvent, mcpOrigin, onComponentChangeSubscribe, } = options;
464
516
  // Trusted, browser-facing MCP origin for broker-captured widgets (their
465
517
  // `<script src>` + CSP allowlist). Derived from server config — NOT the request
466
518
  // `Host` header, which a hostile MCP client could spoof to point widget assets
@@ -469,12 +521,10 @@ export function createMcpServer(options) {
469
521
  const dialableMcpHost = bindHost === "0.0.0.0" || bindHost === "::" ? "127.0.0.1" : bindHost;
470
522
  const brokerAssetOrigin = mcpOrigin ?? `http://${dialableMcpHost}:${mcpPort}`;
471
523
  /** Parsed auth server URL, used for dynamic derivation of authorization_servers. */
472
- const parsedAuthServerUrl = authorizationServerUrl
473
- ? new URL(authorizationServerUrl)
474
- : undefined;
524
+ const parsedAuthServerUrl = authorizationServerUrl ? new URL(authorizationServerUrl) : undefined;
475
525
  /** Effective port (explicit or protocol default). */
476
526
  const authServerPort = parsedAuthServerUrl
477
- ? (parsedAuthServerUrl.port || (parsedAuthServerUrl.protocol === "https:" ? "443" : "80"))
527
+ ? parsedAuthServerUrl.port || (parsedAuthServerUrl.protocol === "https:" ? "443" : "80")
478
528
  : undefined;
479
529
  /** Scheme to use for derived auth URLs (preserves https when configured). */
480
530
  const authServerScheme = parsedAuthServerUrl?.protocol ?? "http:";
@@ -494,7 +544,9 @@ export function createMcpServer(options) {
494
544
  for (const sid of sessionIdsForWorkspace(authContexts, workspaceId)) {
495
545
  const srv = mcpServers.get(sid);
496
546
  if (srv) {
497
- srv.sendToolListChanged().catch((err) => logger.warn({ sessionId: sid, err }, "sendToolListChanged failed (non-fatal)"));
547
+ srv
548
+ .sendToolListChanged()
549
+ .catch((err) => logger.warn({ sessionId: sid, err }, "sendToolListChanged failed (non-fatal)"));
498
550
  }
499
551
  }
500
552
  };
@@ -602,7 +654,9 @@ async function parseBody(req) {
602
654
  * Host header is missing or unparseable.
603
655
  */
604
656
  export function resolveAssetBaseUrl(hostHeader, forwardedProto, encrypted) {
605
- const rawProto = Array.isArray(forwardedProto) ? forwardedProto[0] : forwardedProto;
657
+ const rawProto = Array.isArray(forwardedProto)
658
+ ? forwardedProto[0]
659
+ : forwardedProto;
606
660
  const proto = rawProto?.split(",")[0]?.trim();
607
661
  const scheme = proto && proto.length > 0 ? proto : encrypted ? "https" : "http";
608
662
  try {