Pickaxe Learn

API Reference

Internal Pickaxe MCP

First-party Pickaxe MCP servers, native tools, schemas, and call contracts.


Related In Learn

Actions

Connect your agents to external tools, APIs, and other agents so they can take real actions.

Open Learn

Pickaxe runs first-party MCP servers that expose Pickaxe-owned capabilities to managed agent runtimes. Some of the same first-party tools are also exposed to the standard runtime through its native tool bridge. This page documents only those internal tools and their runtime exposure.

It does not document third-party MCP servers that a builder can attach to an agent, the tools provided by those servers, or the Studio APIs used to connect them.

Internal server inventory

MCP serverPurposeFirst-party tools
pickaxeSession-aware tools for the current Pickaxe runpickaxe_info, search, conditional send_email_to_user, enabled Pickaxe Action tools, and conditional parent-page tools
Per-Pickaxe agent-host serverPublished Pickaxe tools for an imported/hosted agentpickaxe_manifest, enabled Pickaxe Action tools, and search_pickaxe_knowledge_base when knowledge exists
pickaxe_followupsPickaxe-managed reminders and scheduled chat follow-upsschedule_followup, list_scheduled_followups, cancel_scheduled_followup
pickaxe_cron_mirrorDashboard mirror for native OpenClaw cron jobsrecord_openclaw_cron, list_openclaw_crons

Tool discovery is authoritative. The Action and parent-page portions of the surface are dynamic, so clients should call tools/list after connecting instead of hard-coding the complete list.

In normal engineering conversation, “the internal Pickaxe MCP” means the core server registered as pickaxe. The other entries above are separate Pickaxe-owned servers used by specific managed runtimes.

Calling an internal MCP tool

The core and agent-host servers use MCP over Streamable HTTP. The follow-up and cron-mirror endpoints implement the same MCP initialization, discovery, and call methods as stateless JSON-RPC-over-HTTP handlers. A client initializes the connection, lists tools, and calls a discovered tool by name.

import asyncio
import os

from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

MCP_URL = os.environ["PICKAXE_MCP_URL"]
MCP_TOKEN = os.environ.get("PICKAXE_MCP_TOKEN", "")

async def main():
    headers = (
        {"Authorization": f"Bearer {MCP_TOKEN}"}
        if MCP_TOKEN
        else None
    )

    async with streamablehttp_client(
        MCP_URL,
        headers=headers,
        timeout=30,
        sse_read_timeout=300,
    ) as (read_stream, write_stream, _):
        async with ClientSession(read_stream, write_stream) as session:
            await session.initialize()

            discovered = await session.list_tools()
            for tool in discovered.tools:
                print(tool.name, tool.description, tool.inputSchema)

            result = await session.call_tool("pickaxe_info", {})
            print(result.model_dump())

asyncio.run(main())

The MCP sequence is:

  1. initialize
  2. notifications/initialized
  3. tools/list
  4. tools/call with { "name": "<tool>", "arguments": { ... } }

The MCP SDK manages response framing and any MCP session headers. The URL is not a conventional REST tool endpoint.

Core pickaxe server

Managed Claude and OpenClaw runtimes register this server under the name pickaxe. The standard runtime does not attach the whole server; it can receive selected first-party tools through its native function-tool bridge.

The internal URL shape is:

https://<pickaxe-mcp-host>/mcp/<pickaxe_id>?sessionId=<session_id>
  • sessionId is required.
  • userIdentifier or user_identifier can supply a fallback identity when no stored submission context exists.
  • Managed runtimes can append compatibility or page-context markers such as mcpToolsVersion and parentPageCapturedAt.
  • The URL is generated internally. Do not treat a session ID as a public API credential or hard-code the underlying Modal hostname.

The server reconstructs the live submission context when available. That gives its tools access to the current Pickaxe, user identity, uploaded files, knowledge document IDs, memory rules, metadata, and usage tracking.

Core tool summary

ToolAvailabilityPurpose
pickaxe_infoAlwaysReturn metadata about the current internal MCP session
searchAlwaysRetrieve relevant Pickaxe knowledge, uploaded-file content, and permitted user memory
send_email_to_userWhen the current user has an email and the Pickaxe has an email deploymentSend completed content to the current user and start a replyable email conversation
<action.name>One per enabled Pickaxe ActionExecute the Action with the live run context
pickaxe_click_parent_page_elementsWhen parent-page interaction is enabled and click is allowedQueue clicks against captured host-page elements
pickaxe_parent_page_actionWhen parent-page interaction is enabled and the mode is not suggestQueue a validated fill, select, check, scroll, reload, navigate, or other allowed page action

An internal tools/list response can also contain wrappers named after attached third-party MCP servers. Those wrappers are configuration-derived external integrations and are deliberately outside this page's scope.

pickaxe_info

Returns basic metadata and the parent-page capabilities available in this session.

Arguments

{}

Result

{
  "sessionId": "session-123",
  "pickaxeId": "support-agent",
  "title": "Support Agent",
  "description": "Answers product questions and handles support workflows.",
  "parentPageEnabled": true,
  "parentPageMode": "confirm",
  "parentPageAllowedActions": ["click", "scroll", "reload"],
  "parentPageTools": [
    "pickaxe_click_parent_page_elements",
    "pickaxe_parent_page_action"
  ],
  "emailToolAvailable": true,
  "emailTools": ["send_email_to_user"]
}

parentPageTools is empty when the embed has not opted in, no usable page context exists, no action is allowed, or the interaction mode is suggest.

Call

result = await session.call_tool("pickaxe_info", {})

Searches all retrieval sources available to the current run:

  • the Pickaxe knowledge base;
  • documents uploaded in the conversation;
  • user memory, when the session's origin and user context allow it.

Arguments

{
  "query": "What does our refund policy say about annual plans?"
}

query is a required string.

Result

The result is a string assembled from matching sources. It can contain:

  • <knowledge_base>...</knowledge_base>
  • <user_uploaded_document_content>...</user_uploaded_document_content>
  • <user_memory>...</user_memory>

An empty string means retrieval returned no matching context. Retrieval exceptions are converted to the literal string Document search failed.

The tool also records used document IDs, memory IDs, knowledge-source information, and source categories in the current submission.

Call

result = await session.call_tool(
    "search",
    {"query": "What is the annual-plan refund policy?"},
)

send_email_to_user

Sends complete, user-facing content to the current user through the Pickaxe's existing email deployment. It is available to both runtime families:

  • Managed Claude and OpenClaw runtimes discover and call it through the already-registered core pickaxe MCP server.
  • Standard, non-agentic runtimes receive the same send_email_to_user contract as a first-party native function tool. The submission stream intercepts the call, invokes the same session-bound email executor, returns the tool result to the model, and removes the tool before final regeneration so the response cannot send twice.

Neither path attaches a separate email MCP server.

The tool appears in tools/list only when all of the following are true:

  • the current session resolves either to an existing conversation for the same Pickaxe or to trusted current runtime user context (including on the first response before the source conversation is saved);
  • the current user resolves to an email address;
  • the Pickaxe has a public email deployment with a configured sender address.

If any condition stops being true, the core server's session-aware cache signature changes and the tool is removed on the next request. pickaxe_info.emailToolAvailable and pickaxe_info.emailTools report the same availability for managed runtimes. The standard runtime performs the equivalent eligibility check while constructing each provider request and omits both the tool schema and its system instructions when email delivery is unavailable.

Arguments

{
  "subject": "Project update",
  "message": "Here is the final project update you requested."
}
ArgumentRequiredContract
subjectYesConcise email subject, with a maximum of 200 characters
messageYesComplete final email body, with Markdown support and a 20,000-character maximum

There is deliberately no to, recipient, or email-address argument. The recipient is derived from the current session identity, so the tool cannot contact third parties or use an address supplied in the conversation.

Call

result = await session.call_tool(
    "send_email_to_user",
    {
        "subject": "Project update",
        "message": "Here is the final project update you requested.",
    },
)

Result

{
  "success": true,
  "sent": true,
  "deploymentId": "email-deployment-123",
  "sessionId": "email-deployment-123-<new-id>",
  "sourceSessionId": "source-chat-session-123",
  "subject": "Project update",
  "recipient": "current_user",
  "replyExpected": true
}

Every successful call creates a separate Pickaxe conversation with originType: EMAIL. The outbound message receives a new RFC Message-Id, and Pickaxe stores that Message-Id with the new session. When the user replies, the inbound email's In-Reply-To or References header maps the reply back to that email session, so the conversation continues from the email rather than the source chat.

Internally, both runtime paths delegate execution to the Pickaxe API's session-bound email executor. The executor revalidates the session or trusted current runtime context, current user, and deployment before sending; records the assistant message and outbound email event through the normal agent-inbound delivery path; and returns failures as tool errors. The internal transport URL is not another server that agent runtimes must configure.

Dynamic Pickaxe Action tools

Every enabled Pickaxe Action is registered as an MCP tool.

PropertyContract
Tool nameThe Action's internal name
DescriptionThe Action's description
ArgumentsOne keyword argument per Action input, using the input id
Required argumentsInputs with isRequired: true
Argument typesStrings in the session-aware core server
ResultThe Action executor's result, or No result when the executor returned no result field

Example for an Action named create_support_ticket:

result = await session.call_tool(
    "create_support_ticket",
    {
        "subject": "Unable to access the billing portal",
        "priority": "high",
    },
)

The Action receives the live Pickaxe ID, session ID, user identity, metadata, uploaded-file context, and stored credentials. Its Action ID is persisted in the submission's used-tool data.

pickaxe_click_parent_page_elements

Exposed only when:

  • the embed supplied sanitized parent-page context;
  • parent-page interaction is enabled;
  • the mode is not suggest;
  • click is one of the allowed actions.

Arguments

{
  "targetIds": ["el_apply_discount"],
  "reason": "Apply the discount selected by the user"
}
  • targetIds (string[], required): IDs copied exactly from parentPage.elements.
  • reason (string, optional): Short explanation. It defaults to Click requested parent-page elements.

The server converts each target into a click action, validates the target and captured selector, rejects disabled or unknown elements, and queues the action for the active embed.

pickaxe_parent_page_action

Exposed when parent-page interaction is active, at least one action is allowed, and the mode is not suggest.

Arguments

{
  "actions": [
    {
      "kind": "fill",
      "targetId": "el_company_name",
      "value": "Pickaxe",
      "reason": "Fill the company name requested by the user"
    }
  ]
}

Send the next single interaction per call. Wait for refreshed page context before performing another step.

FieldRequiredMeaning
kindYesAn action permitted by the current page context
reasonYesShort user-facing reason
targetIdFor element actionsExact ID from parentPage.elements
valueFor fill and selectValue to enter or select
urlFor navigateDestination URL; clicking a captured link is preferred

The complete implementation supports click, fill, select, check, uncheck, scroll, reload, and navigate. The current page's allowlist is enforced on every call. If no explicit allowlist exists, the safe defaults are click, scroll, and reload.

Successful calls return a queue acknowledgement:

{
  "success": true,
  "accepted": true,
  "actionCount": 1,
  "outboxIds": ["outbox-123"],
  "message": "The parent-page action sequence was accepted and will be streamed to the active embed for immediate execution."
}

accepted means validated and queued. It does not prove that the browser completed the action.

Per-Pickaxe agent-host server

The agent-host runtime can create a generated first-party MCP server for a published Pickaxe. Its stable URL shape is:

https://<provider-gateway>/external/pickaxe/mcp/<pickaxe_id>/mcp/

The provider gateway can require Authorization: Bearer <internal-token>. Managed callers can also forward x-pickaxe-generation-id, x-pickaxe-session-id, and x-pickaxe-user-id so Action and knowledge calls retain the correct run context.

Only the Pickaxe-owned tools are covered below. Generated passthrough tools for attached third-party MCP servers are outside scope.

pickaxe_manifest

Returns the generated first-party tool-surface summary.

result = await session.call_tool("pickaxe_manifest", {})
{
  "pickaxeId": "support-agent",
  "workspaceId": "workspace-123",
  "title": "Support Agent",
  "actionCount": 2,
  "subagentTargetCount": 1,
  "workspaceAgentServerCount": 1,
  "workspaceAgentToolCount": 1,
  "attachedMcpServerCount": 0,
  "attachedMcpToolCount": 0,
  "knowledgeDocumentCount": 12
}

The attached-MCP counts can be nonzero in a real manifest, but those integrations are not first-party tools and are not documented here.

Generated Action tools

Enabled Pickaxe Actions are exposed directly.

  • The name prefers name, then displayName, then actionId.
  • Duplicate names receive an index suffix.
  • Input names are normalized to lowercase Python-safe identifiers and mapped back to the original Action input IDs during execution.
  • Integer, number, and boolean Action inputs retain those types; other inputs become strings.
  • Optional inputs default to null.

Use tools/list for the final generated name and schema.

search_pickaxe_knowledge_base

Present only when the Pickaxe has enabled knowledge documents.

Arguments

{
  "query": "What is the cancellation policy?",
  "knowledge_budget": 10000,
  "knowledge_tokens": 750,
  "relevance_threshold": 60,
  "chat_input_length": 1000
}

Only query is required. Omitted numeric values fall back to the Pickaxe's RAG settings.

The result includes normalized text, the raw retrieval response, and the configured document count. With live request headers, the raw response can include Pickaxe knowledge, conversation-upload chunks, user memory, source information, and used document or memory IDs.

pickaxe_followups server

This is a separate internal MCP server for Pickaxe-managed reminders and scheduled messages. Its URL shape is:

https://<pickaxe-api-host>/mcp/followups/<pickaxe_id>?contextRef=<signed_context_ref>

The runtime supplies a signed context reference or session context and, when configured, an internal bearer. Calls without valid Pickaxe chat context are rejected.

schedule_followup

Schedules a one-time or recurring assistant message in the current Pickaxe chat.

Important arguments:

ArgumentMeaning
messageExact later message for static delivery, or a short label/fallback for generate delivery
deliveryModestatic or generate
generationPromptRequired for generated delivery; hidden prompt executed on each run
atISO-8601 first-delivery timestamp
delaySeconds, delayMinutesRelative first-delivery delay
everySeconds, everyMinutes, everyMsRecurring interval; when supplied alone, also determines the first delivery
weeklyDayOfWeekWeekly day, where Monday is 0 and Sunday is 6
weeklyHour, weeklyMinute, timezoneWeekly wall-clock schedule
nameOptional dashboard label
jobIdOptional caller correlation ID
deleteAfterRunDelete a one-time job after delivery

At least one first-delivery schedule is required: an absolute timestamp, a relative delay, a recurring interval, or a complete weekly schedule.

Static example:

result = await session.call_tool(
    "schedule_followup",
    {
        "message": "Go shopping.",
        "delayMinutes": 5,
        "deliveryMode": "static",
    },
)

Generated recurring example:

result = await session.call_tool(
    "schedule_followup",
    {
        "name": "Daily product tip",
        "message": "Daily product tip",
        "deliveryMode": "generate",
        "generationPrompt": "Generate one new concise product tip for the user.",
        "delayMinutes": 1,
        "everyMinutes": 1440,
    },
)

The structured result contains the job ID, status, first delivery time, recurrence fields, delivery mode, and session association.

list_scheduled_followups

Lists active scheduled follow-ups for the current Pickaxe chat.

result = await session.call_tool("list_scheduled_followups", {})

The structured result contains count and a followups array with job IDs, messages, status, schedule, recurrence, timezone, and delivery metadata.

cancel_scheduled_followup

Cancels one job or all active jobs in the current chat.

result = await session.call_tool(
    "cancel_scheduled_followup",
    {
        "jobId": "sf_123",
        "reason": "User cancelled the reminder",
    },
)
  • Pass jobId to cancel one job.
  • Pass cancelAll: true, or omit jobId, to cancel all active follow-ups in the current chat.

The structured result reports cancelledCount and the affected job IDs.

pickaxe_cron_mirror server

This companion server mirrors native OpenClaw cron state into Pickaxe so scheduled jobs can appear in the Pickaxe dashboard. It does not execute or schedule the native cron itself.

Its URL shape is:

https://<pickaxe-api-host>/mcp/openclaw-crons/<pickaxe_id>?sessionId=<session_id>

Managed OpenClaw runtimes also send the external session, runtime, user, submission, origin, and deployment context needed to associate the mirror with the correct chat. When configured, the endpoint requires its internal bearer.

record_openclaw_cron

Creates, updates, or cancels a Pickaxe mirror after the runtime has already changed the native OpenClaw cron.

Key arguments:

ArgumentMeaning
operationupsert or cancel; defaults to upsert
providerJobIdNative OpenClaw job ID
jobIdOptional mirror correlation ID when no provider ID exists
name, descriptionDisplay metadata
messageFixed user-facing message or generated-delivery label
deliveryModestatic or generate
generationPromptPrompt used for generated fallback delivery
at, nextRunAt, scheduledAtAbsolute schedule metadata
delaySeconds, delayMinutesRelative schedule metadata
everySeconds, everyMinutes, everyMsRecurrence metadata
cronExpression, timezoneNative cron schedule metadata
rawOptional original provider payload
result = await session.call_tool(
    "record_openclaw_cron",
    {
        "operation": "upsert",
        "providerJobId": "openclaw-cron-1",
        "name": "Stretch reminder",
        "message": "Stretch.",
        "deliveryMode": "static",
        "everyMinutes": 30,
    },
)

To cancel, delete the native OpenClaw cron first, then call the tool with operation: "cancel" and its providerJobId or mirror jobId.

list_openclaw_crons

Lists active OpenClaw cron mirror records for the current Pickaxe chat.

result = await session.call_tool("list_openclaw_crons", {})

The result includes count and a crons array with native provider IDs, mirror IDs, status, schedule, recurrence, delivery mode, and session metadata. Use the returned provider ID when modifying or deleting the actual native cron.

Lifecycle and errors

  • The core pickaxe server caches a tool surface by Pickaxe and session. A new session or host restart is required to guarantee that changed Action configuration is reloaded.
  • The agent-host server publishes a stable gateway URL backed by a temporary sandbox. Clients should tolerate cold starts and rediscover tools after reconnecting.
  • Parent-page tools can appear or disappear as the captured page context and interaction mode change.
  • The email tool can appear or disappear as the session identity or Pickaxe email deployment changes. Always use tools/list instead of assuming it is available.
  • 400 Missing required query parameter: sessionId means the core URL omitted its required session.
  • 404 Pickaxe '<id>' not found means the core server could not resolve the Pickaxe.
  • 401 invalid_internal_bearer means an internal gateway or companion server rejected its configured bearer.
  • Tool results with success: false indicate that MCP transport succeeded but validation or the underlying first-party executor failed.