@grackle-ai/mcp
v0.117.0
Published
MCP (Model Context Protocol) server for Grackle — translates MCP tool calls to ConnectRPC
Maintainers
Readme
@grackle-ai/mcp
MCP (Model Context Protocol) server for Grackle — exposes Grackle's full capabilities as MCP tools so any AI agent can manage environments, spawn sessions, orchestrate tasks, and share knowledge.
This package translates MCP tool calls into ConnectRPC requests to the Grackle server. It implements the MCP Streamable HTTP transport and supports multiple concurrent client sessions.
Installation
npm install @grackle-ai/mcpOr run the standalone server directly:
npx @grackle-ai/mcpQuick Start
The MCP server connects to an already-running Grackle server. Start the Grackle server first, then launch the MCP server:
# 1. Start the Grackle server (installs the CLI if needed)
npx @grackle-ai/cli serve
# 2. Start the MCP server (reads the API key automatically)
npx @grackle-ai/mcpThe MCP server listens on http://127.0.0.1:7435/mcp by default.
Configuration
All configuration is via environment variables:
| Variable | Default | Description |
|----------|---------|-------------|
| GRACKLE_MCP_PORT | 7435 | Port the MCP server listens on |
| GRACKLE_HOST | 127.0.0.1 | Bind address (must be a loopback address) |
| GRACKLE_URL | http://127.0.0.1:7434 | URL of the Grackle gRPC server to connect to |
| GRACKLE_API_KEY | (auto-loaded) | API key for authenticating with the gRPC server. If not set, reads from ~/.grackle/api-key |
| LOG_LEVEL | info | Logging level (debug, info, warn, error) |
Programmatic Usage
The package also exports createMcpServer for embedding the MCP server in your own application:
import { createMcpServer } from "@grackle-ai/mcp";
const server = createMcpServer({
bindHost: "127.0.0.1",
mcpPort: 7435,
grpcPort: 7434,
apiKey: "your-api-key",
});
server.listen(7435, "127.0.0.1", () => {
console.log("MCP server ready");
});Authentication
The MCP server supports three authentication modes:
- API key — Full access. Pass as
Authorization: Bearer <api-key>. - OAuth — Full access. Token issued by the Grackle OAuth authorization server.
- Scoped token — Limited tool access. Issued to agents working on a specific task. Only a subset of tools is available (see Scoped Access below).
Client Configuration
Claude Desktop / Claude Code
Add to your MCP configuration (claude_desktop_config.json or .mcp.json):
{
"mcpServers": {
"grackle": {
"url": "http://127.0.0.1:7435/mcp",
"headers": {
"Authorization": "Bearer <your-api-key>"
}
}
}
}Any MCP-compatible client
Point your client at http://127.0.0.1:7435/mcp using the Streamable HTTP transport with a Bearer token in the Authorization header.
Tool Reference
The MCP server exposes a rich set of tools organized into groups. Each tool validates its inputs against a strict schema and returns structured JSON results.
Environment Tools
Manage compute environments where agents run (Docker, SSH, Codespace, local).
| Tool | Description | Parameters |
|------|-------------|------------|
| env_list | List all registered environments with status, adapter type, and runtime. | (none) |
| env_list_docker_containers | List running Docker containers that can be attached to (Docker adapter attach mode). | (none) |
| 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) |
| env_provision | Provision an environment — start resources, install the agent, and connect. | environmentId (string), force? (boolean) |
| env_stop | Stop a running environment without destroying its resources. | environmentId (string) |
| env_destroy | Destroy an environment's backing resources (e.g., delete the container). | environmentId (string) |
| env_remove | Remove an environment registration. Must be stopped first. | environmentId (string) |
| env_wake | Wake a stopped environment by re-provisioning it. | environmentId (string) |
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:
local— a PowerLine already running on this machine.adapterConfig(all optional):host,port.ssh— any host reachable over SSH. This is also how you attach to an already-running container that exposes an SSH endpoint.adapterConfig:host(required),user?,sshPort?(default 22),identityFile?,sshOptions?(string map),localPort?,env?(string map).codespace— an existing GitHub Codespace.adapterConfig:codespaceName(required, fromgh codespace list),localPort?,env?(string map). Optional top-levelgithubAccountIdselects a stored GitHub account forgh.docker— spawn a new container from an image, or attach to an existing one.adapterConfig(all optional):attach(existing container name/ID — when set, Grackle never creates/stops/removes the container andimage/repo/volumesare ignored; useenv_list_docker_containersto discover candidates),image(defaultgrackle-powerline:latest),containerName,repo(owner/repoor HTTPS URL),volumes(string array),gpus,localPort,env(string map). Optional top-levelgithubAccountIdauthenticatesghfor private repo clones.
Session Tools
Manage AI agent sessions — spawn, monitor, interact, and terminate.
| Tool | Description | Parameters |
|------|-------------|------------|
| session_spawn | Spawn a new agent session with a prompt and optional model config. | environmentId (string), prompt (string), maxTurns? (int), personaId? (string), workingDirectory? (string) |
| session_resume | Resume a stopped agent session. | sessionId (string) |
| session_status | List sessions with optional filtering by environment and status. | environmentId? (string), all? (boolean, default false) |
| session_kill | Terminate a running session. Hard kill by default; graceful=true sends SIGTERM. | sessionId (string), graceful? (boolean, default false) |
| session_attach | Stream events from a running session for a limited duration. | sessionId (string), timeoutSeconds? (int, default 30, max 300), maxEvents? (int) |
| session_send_input | Send a text message to a session waiting for user input. | sessionId (string), text (string) |
Workspace Tools
Manage workspaces that group tasks, agents, and repositories.
| Tool | Description | Parameters |
|------|-------------|------------|
| workspace_list | List all workspaces with names, descriptions, repos, and status. | environmentId? (string) |
| workspace_create | Create a new workspace. | name (string), environmentId (string), description? (string), repoUrl? (string), workingDirectory? (string), useWorktrees? (boolean), defaultPersonaId? (string) |
| workspace_get | Get full details of a workspace by ID. | workspaceId (string) |
| workspace_update | Update a workspace's name, description, repo, or settings. | workspaceId (string), name?, description?, repoUrl?, environmentId?, workingDirectory?, useWorktrees?, defaultPersonaId? |
| workspace_archive | Archive a workspace, marking it as inactive. | workspaceId (string) |
| workspace_link_environment | Link an additional environment to a workspace's pool. | workspaceId (string), environmentId (string) |
| workspace_unlink_environment | Remove a linked environment from a workspace's pool. | workspaceId (string), environmentId (string) |
Task Tools
Create, manage, and run tasks within workspaces. Supports hierarchical task trees and dependency gating.
| Tool | Description | Parameters |
|------|-------------|------------|
| task_list | List tasks with optional search and status filters. | workspaceId? (string), search? (string), status? (string: not_started, working, paused, complete, failed) |
| 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) |
| 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) |
| task_show | Get full details of a task. | taskId (string) |
| task_update | Update a task's title, description, status, or dependencies. | taskId (string), title?, description?, status? (enum), dependsOn? (string[]), sessionId? (string) |
| 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) |
| task_delete | Permanently delete a task. | taskId (string) |
| task_complete | Mark a task as complete (sticky status). | taskId (string) |
| task_resume | Resume the latest session for a task. | taskId (string) |
Persona Tools
Manage agent personas — reusable templates defining system prompt, runtime, and model.
| Tool | Description | Parameters |
|------|-------------|------------|
| persona_list | List all available personas. | (none) |
| 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) |
| persona_show | Get full details of a persona. | personaId (string) |
| persona_edit | Update an existing persona. | personaId (string), name?, systemPrompt?, description?, runtime?, model?, maxTurns?, type?, script? |
| persona_delete | Delete a persona permanently. | personaId (string) |
Knowledge Graph Tools
Search a semantic knowledge graph across sessions and task context.
| Tool | Description | Parameters |
|------|-------------|------------|
| knowledge_search | Semantic search over the knowledge graph using natural language. | query (string), limit? (int, max 50), workspaceId? (string), expand? (boolean), expandDepth? (int, max 5) |
| knowledge_get_node | Retrieve a specific node by ID with optional neighbor expansion. | id (string), expand? (boolean), expandDepth? (int, max 5) |
| 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}) |
IPC Tools
Inter-process communication between parent and child agent sessions.
| Tool | Description | Parameters |
|------|-------------|------------|
| ipc_spawn | Spawn a child agent session with an IPC pipe. | prompt (string), pipe (sync | async | detach), environmentId (string), personaId? (string), maxTurns? (int) |
| ipc_write | Write a message to a child session via a file descriptor. | fd (int), message (string) |
| ipc_close | Close a file descriptor, optionally stopping the child. | fd (int) |
| ipc_terminate | Send SIGTERM to a child session via its fd for graceful shutdown. | fd (int) |
| ipc_list_fds | List your open file descriptors (IPC connections). | (none) |
| ipc_list_streams | List all active IPC streams with subscriber details and buffer depth. | (none) |
| ipc_create_stream | Create a named stream for inter-session communication. Returns an rw fd. | name (string), selfEcho? (boolean, default false) |
| 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) |
| 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) |
Log Tools
Retrieve session logs — raw events, formatted transcripts, or live tails.
| Tool | Description | Parameters |
|------|-------------|------------|
| 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) |
Token Tools
Manage secrets that are auto-forwarded to environments.
| Tool | Description | Parameters |
|------|-------------|------------|
| token_list | List configured tokens (values are never returned). | (none) |
| token_set | Set a token for auto-forwarding to environments. | name (string), value (string), type? (env_var | file), envVar? (string), filePath? (string) |
| token_delete | Delete a configured token. | name (string) |
Credential Provider Tools
Configure which credential providers (Claude, GitHub, Copilot, Codex) are auto-forwarded.
| Tool | Description | Parameters |
|------|-------------|------------|
| credential_provider_list | List current provider configuration. | (none) |
| credential_provider_set | Set a provider mode. | provider (claude | github | copilot | codex), value (off | on | subscription | api_key) |
Config Tools
Read and write global configuration settings.
| Tool | Description | Parameters |
|------|-------------|------------|
| config_get_default_persona | Get the default persona for new sessions. | (none) |
| config_set_default_persona | Set the default persona for new sessions. | personaId (string) |
Usage Tools
Query aggregated token usage and cost data.
| Tool | Description | Parameters |
|------|-------------|------------|
| 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) |
Widget Tools
MCP Apps UI widgets — interactive HTML rendered inline by capable hosts (and always by Grackle's own chat pane via the broker).
show_hello_widget is the Grackle-served demo widget: it references a static ui:// resource and appears in tools/list only when the host advertises the io.modelcontextprotocol/ui extension. The widget registry tools let an agent author and render its own widgets at runtime; they are ordinary scoped tools (always listed) and the rendered widget is captured by the broker into the session's chat. component_show renders agent-authored React/JSX against Grackle's own component library via a sandboxed React runtime (#1268).
| Tool | Description | Parameters |
|------|-------------|------------|
| show_hello_widget | Display the Grackle hello widget — a minimal interactive MCP Apps UI that echoes the provided message. | message (string, optional) |
| widget_register | Register a reusable widget (HTML body) in the workspace so it can be re-rendered with different data. Returns the widget id. | name (string), body (string), description (string, optional), propsSchema (string, optional) |
| widget_update | Update a registered widget's body/name/description/props schema; bumps its version. | id (string), body/name/description/propsSchema (optional) |
| widget_list | List the reusable widgets registered in the workspace. | — |
| widget_render | Render a registered widget inline (by id or name), optionally passing props (data). | id (string, optional), name (string, optional), props (object, optional) |
| widget_show | Render a one-off widget inline from an inline HTML body, without persisting it. | body (string), props (object, optional) |
| component_show | Render a React/JSX component inline against the Grackle component library (no persistence). source is JSX that calls render(<Component {...props}/>); React, props, and Grackle components are in scope. | source (string), props (object, optional) |
Widgets are workspace-scoped: a session may only register/render widgets in its own workspace (the workspaceId is taken from the session's scoped token). Agent-authored bodies render in the cross-origin sandbox with inline scripts allowed (script-src 'unsafe-inline'), isolated by the iframe origin + a restricted connect-src. component_show additionally runs in a sandboxed React runtime that transpiles + evaluates the JSX (script-src 'unsafe-eval'), kept safe by the same origin isolation.
MCP Apps (UI widgets)
Grackle's MCP server is a conformant MCP Apps (SEP-1865) provider. Hosts that support MCP Apps can fetch and render interactive HTML widgets inline.
How it works:
Capability negotiation — A host advertises support during
initializevia theio.modelcontextprotocol/uiextension (withmimeTypesincludingtext/html;profile=mcp-app). The server detects this and only lists Widget Tools to capable hosts; other clients see the data-only tools.Resources — The server declares the
resourcescapability and implementsresources/listandresources/read. Widget UIs are served asui://…resources with MIMEtext/html;profile=mcp-app.Tool ↔ resource link — A widget tool carries
_meta.ui.resourceUri(and the legacy_meta["ui/resourceUri"]) pointing at itsui://resource. The host reads the resource and renders it, passing the tool's input and result into the widget.Widget assets — The widget's browser scripts are served (unauthenticated, since they are non-sensitive static JS) from
/widgets/<name>/…on the MCP server's HTTP origin.Grackle chat-pane capture — When an agent in a Grackle session calls a widget tool, the MCP server also pushes a self-contained "widget" event (resource HTML + tool input/result) into that session's event stream, so the widget renders inline in Grackle's own chat UI — independent of whether the agent runtime preserves MCP
_meta. This covers both the staticshow_hello_widgetand the agent-authored registry (widget_register/widget_render/widget_show), whose render descriptor the broker reads from the tool result. (This in-process capture only runs when the MCP server is co-located with the Grackle server; the standalonenpx @grackle-ai/mcpserver does not emit chat widget events.)
Note: the widget's scripts load from the MCP server's origin, so a host whose sandbox CSP forbids cross-origin scripts won't render them. Grackle's own chat pane allows the MCP origin in its sandbox CSP, so widgets render there.
The current built-in widget is show_hello_widget (resource ui://grackle/hello-widget). Try it with the MCP Inspector, Claude Desktop, or Grackle's own chat.
Scoped Access
When an agent authenticates with a scoped token (issued automatically when a task session is started), tool access is controlled by the task's persona configuration.
Persona-Scoped Tool Filtering
Each persona can define an allowed_mcp_tools list that restricts which MCP tools its agents can use. When a scoped token connects:
- The server looks up the persona's
allowed_mcp_toolsfrom the token'spersonaIdclaim. - If the persona defines a non-empty tool list, only those tools are exposed via
tools/list. - If the persona has no explicit tool list (empty
allowed_mcp_tools), the default scoped set is used:task_create,task_list,task_show,task_start,task_completesession_attach,session_send_inputpersona_list,persona_showipc_spawn,ipc_write,ipc_close,ipc_terminate,ipc_list_fds,ipc_create_stream,ipc_attach,ipc_share_streamknowledge_search,knowledge_get_nodelogs_getworkpad_write,workpad_readschedule_list,schedule_show
Preset Tool Sets
Predefined presets are available for convenience (via CLI --mcp-tools-preset or the web UI):
| Preset | Description |
|--------|-------------|
| default | The 25-tool default scoped set (backward compatible) |
| worker | Subset of default — no task creation capabilities |
| orchestrator | Default + task management, session spawning, persona creation, scheduling |
| admin | Full access to all available tools |
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.
Requirements
- Node.js >= 22
- A running Grackle server (
@grackle-ai/cli)
License
MIT
