Steerd API

MCP server

Connect an MCP client and query your Steerd data in natural language.

The Public API also speaks the Model Context Protocol (MCP). Point an MCP-capable client (Claude Desktop, IDE assistants, and others) at the endpoint and it can read and update your Steerd data through tools, authenticated by the same strd_ API key as REST and GraphQL. Every tool is scoped to your key's team and permissions.

Endpoint & authentication

The endpoint is POST /api/public/v1/mcp over streamable HTTP, on the app origin for your environment:

EnvironmentBase URL
Local developmenthttp://localhost:3100
Staginghttps://app.staging.steerd.io
Productionhttps://app.steerd.io

So a local client connects to http://localhost:3100/api/public/v1/mcp and production is https://app.steerd.io/api/public/v1/mcp. A strd_ key authenticates only against the environment it was created in.

Requests require a bearer token:

Authorization: Bearer strd_<key>

The token resolves your team and the tools you may call. Create a key in the Steerd app under Settings → API keys, granting only the scopes the integration needs (see authentication). A key handed to an assistant can read everything its scopes allow, so prefer a least-privilege key.

Connect a client

Use the base URL for your environment (see the table above). The examples below use production; for local development swap in http://localhost:3100, and for staging https://app.staging.steerd.io.

Clients that support remote MCP servers over HTTP can use the URL and header directly:

{
  "mcpServers": {
    "steerd": {
      "url": "https://app.steerd.io/api/public/v1/mcp",
      "headers": { "Authorization": "Bearer strd_YOUR_KEY" }
    }
  }
}

For a client that only speaks stdio, bridge to the remote server with mcp-remote:

{
  "mcpServers": {
    "steerd": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://app.steerd.io/api/public/v1/mcp",
        "--header",
        "Authorization: Bearer strd_YOUR_KEY"
      ]
    }
  }
}

Tools

Tools mirror the REST and GraphQL resources and return the same public projections (no team_id, and so on). Names follow a verb_object convention.

  • List and get: list_<resource> and, where available, get_<resource> for organizations, contacts, employees, projects, tasks, activities, assignments, and cvs. Tasks, activities, and assignments are list only.
  • Documents and attachments: list_documents/get_document and list_attachments (by parent entity). Metadata only, no file bytes.
  • Search: a global search that matches across the resource types your key can read.
  • Time entries: list_time_entries, get_time_entry, and get_time_summary. These honor your role: a time tool reflects exactly what its key's creator may see and do in the app, and refuses when that access is revoked.
  • Create and update: create_<resource> and update_<resource> for organizations, contacts, employees, projects, tasks, and cvs; create_activity and create_assignment (create only); and create_time_entry/update_time_entry. Plus archive_project and restore_project. Write tools require a <resource>:write scope and validate exactly as REST does.

Each tool mirrors the same team-scoping, validation, and public projections as the equivalent REST request.

List results are paged

List tools return at most 25 items by default and 50 at most. To page, pass the nextCursor from a result back as the cursor argument, the same cursor connection REST and GraphQL use.

What is not a tool

  • No delete. Destructive deletes are never exposed to an assistant. To set a project aside, use archive_project (and restore_project to bring it back); for permanent deletion, use the REST or GraphQL API, or the app.
  • Writes are at-least-once. A retried create_ call may create a duplicate; there is no idempotency key on MCP writes yet.
  • Documents and attachments are metadata only. Their bytes are binary and are not returned through MCP. get_document returns the record; fetch the bytes from the REST download endpoint with the same key.
  • No uploads. File uploads are multipart and go through REST.

A note on trust

An assistant reads your CRM data through these tools, and some of that data is free text that other people wrote (a project note, an incoming request, a contact's details). Treat tool results as data, not instructions. Grant write scopes only when the integration needs them, and keep the key least-privilege, so a surprising or manipulated result can only ever do what the key's scopes allow.

Errors

Tool errors carry a stable machine code (forbidden, not_found, bad_request, limit_reached, internal) and a safe message. A limit_reached error includes which plan limit was hit, so an assistant can suggest an upgrade rather than retry. See errors for the shared code list.

On this page