@grackle-ai/mcp
v0.195.0
Published
MCP (Model Context Protocol) server for Grackle — translates MCP tool calls to ConnectRPC
Downloads
2,998
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 | 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) |
| 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) |
Document Tools
Open files in the user's Grackle document pane (live docs v0, #1396). Unlike widgets, show_file carries a URI reference rather than baked content — the web reads the file over the AHP resource bridge and live-refreshes it as the file changes on disk.
| Tool | Description | Parameters |
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- |
| show_file | Open a read-only, live-updating view of a file (absolute path) in the user's document pane. Markdown renders richly; other text/code renders with highlighting. | path (string) |
Component & Widget Tools
MCP Apps UI rendered inline by capable hosts (and always by Grackle's own chat pane via the broker).
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.
| 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) |
| 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) |
| component_update | Update a registered component's source/name/description/props schema; bumps its version. | id (string), source/name/description/propsSchema (optional) |
| component_list | List the reusable components registered in the workspace. | — |
| 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) |
| 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) |
| 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) |
| 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) |
| widget_show | Render a one-off raw-HTML body inline, without persisting it. | body (string), props (object, optional) |
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.
Grackle's own context-free components (Button, Callout, Spinner, Skeleton, Tooltip, …) are already in the runtime scope and are surfaced by component_search as built-ins (builtin: true) with their prop schemas — so agents discover and compose them in JSX rather than re-authoring them.
Composition — components reference each other. A grackle-react component's body can use another registered component as a JSX tag (<RevenueChart period="Q1"/>). At render time the server scans the body for capitalized tags, resolves the ones matching a workspace component (built-ins excluded), and recurses — a mini-bundler over the registry graph — shipping the resolved dependency sources to the runtime, which composes them into scope. References are late-bound: a reference resolves to the dependency's current version, so updating a shared component updates every consumer. Resolution is workspace-scoped, cycle-safe, and bounded (depth/count/size); only grackle-react components compose (raw-HTML can't). Applies to component_render, component_show, and promoted render_<name> tools alike.
Promoted components → dynamic render_<name> tools. Calling component_promote on a registered component surfaces it as its own MCP tool named render_<name> (the name is slugged to [A-Za-z0-9_]), whose inputSchema is the component's propsSchema — so it's natively discoverable in tools/list and its props are typed and validated. These tools are synthesized per workspace for scoped sessions and reflect the current promoted set on each tools/list; they render identically to component_render ("many tools, one resource"). When a workspace's promoted set changes (promote/demote, or a promoted component edited), the server pushes notifications/tools/list_changed to that workspace's live sessions so conformant clients re-list automatically (the server advertises the tools.listChanged capability). Like the other registry render tools they rely on the in-process broker, so they're listed only when the MCP server is co-located with the Grackle server (not on the standalone npx @grackle-ai/mcp server). They're authorized by registry ownership (the caller's workspace must own the component), not the static tool allowlist. On a name collision the most-recently-updated component wins.
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.
Cross-Task / Cross-Session Authorization
Beyond the per-persona allowlist, tools that target a specific task or session are authorized centrally and fail closed for scoped (agent) callers: a non-root agent may only act on its own descendant tasks/sessions. This covers the mutating tools (task_update, task_delete, task_resume, task_complete, task_start, session_kill, session_resume, session_attach, session_send_input) — an agent cannot delete a sibling's task or kill another agent's session even if it learns the ID. Read tools that resolve a record by ID (task_show, schedule_show) are gated by workspace membership; a caller with no workspace may read only workspaceless records. The root/system task (the central orchestrator) is exempt. When a task is deleted, its scoped tokens are revoked; complete/stop do not revoke (the task can be resumed and resume reuses the original token), so those tokens expire via their TTL.
Requirements
- Node.js >= 22
- A running Grackle server (
@grackle-ai/cli)
License
MIT
