Skip to main content

kind: Integration

What it is

kind: Integration declares one connected MCP server — either a remote streamable-http endpoint (e.g. Linear’s hosted MCP) or a locally spawned stdio process (e.g. npx -y @some/mcp-server). It is the standalone authoring surface for the case where you want one integration declared once and shared across many crews (scope: workspace), or want to declare a crew-scoped integration outside the bulkier kind: Crew document. The legacy inline mcp_servers: block nested under a crew (see Crew and Workspace) still works and remains the most ergonomic shape for bundling integrations with a crew definition. kind: Integration is the inverse: declare once, scope explicitly. The kind is implemented in internal/manifest/kinds/integration.go.

Scope picks the table

A single scope: discriminator chooses where the row lands: crew scope requires crew_slug; workspace scope rejects it (a crew_slug under workspace scope is treated as an authoring mistake and fails loudly).

slug == name

metadata.slug MUST equal metadata.name — the server keys MCP-server uniqueness on name within the (workspace, crew) tuple, but every cross-kind reference uses slug, so the manifest forces the two to match (the same convention Label uses).

env vs env_mapping

Two env-related maps both land in the same env_json column:
  • env — plain static environment variables (e.g. NODE_ENV: production). The value is the literal string the MCP process sees.
  • env_mapping — the credential-indirection layer. Keys are the env-var the MCP server expects; values are the workspace credential’s name (conventionally identical, but can differ — e.g. {GITHUB_PERSONAL_ACCESS_TOKEN: GH_TOKEN}). At agent run time the resolver looks up each credential by name and substitutes the value before the MCP process starts.
On key collision, env wins (a literal value beats a credential reference for the same key).

YAML schema

Field reference

Examples

Remote (streamable-http), workspace scope

Local (stdio), crew scope

Static env plus a credential reference

CLI reference

Integrations have both a declarative manifest surface (the apply / export flow) and a dedicated imperative crewship integration command group (registered as integrationCmd in cmd/crewship/cmd_integration.go). The imperative commands are handy for one-off break-glass work; the manifest path is the version-controlled complement. Workspace-scoped commands: Crew-scoped CRUD lives under the crew subcommand: Agent-binding subcommands (bind, unbind, agent-bindings <agent-slug>, resolve <agent-slug>) and the per-tool tools / per-binding agent groups round out the surface. The declarative flow:

REST endpoint mapping

Endpoints used:

Validation rules

IntegrationDocument.Validate enforces:
  • apiVersion / kind, when set, equal crewship/v1 / Integration.
  • metadata.name and metadata.slug are non-empty, and slug == name.
  • transport is required and one of streamable-http | stdio.
  • streamable-http requires a non-empty endpoint; stdio requires a non-empty command.
  • scope, when set, is workspace | crew.
  • crew_slug is required iff scope: crew and rejected under scope: workspace.
  • env / env_mapping have no empty keys; env_mapping has no empty values; args has no empty entries.
  • When WorkspaceContext carries crew data, a crew-scoped crew_slug must reference a declared or remote crew.

Apply behavior

ApplyUpsert (default)

  • No remote on this scope → ActionCreate: POST to the workspace or crew endpoint.
  • Remote on the matching scope, fields drift → ActionUpdate: a sparse PATCH. args_json / env_json are compared after JSON normalisation so key-reordering doesn’t produce phantom drift.
  • Remote matches exactly → ActionUnchanged.

Scope change (workspace ↔ crew)

The two scopes are different tables and there is no “move” endpoint, so a changed scope emits a Delete + Create pair, both visible in the dry-run with a “scope change” note. The delete cascades any agent bindings on the old row — review the plan before re-running with --yes.

Round-trip via export

crewship export workspace calls ExportIntegrations, which walks both the workspace scope and every crew’s crew scope, decoding args_json back into spec.args and env_json back into spec.env. Env lossiness: the server has no column distinguishing literal env from credential-reference env_mapping (both live in env_json), so every entry comes back under spec.env on export. If you need the env_mapping shape preserved, keep your source YAML as the source of truth and re-export to a side file rather than overwriting the original. Output is sorted by scope, then crew, then slug for stable diffs.

See also

  • Crew — can declare integrations inline via mcp_servers:.
  • Connector — install-only OAuth connectors (Linear, GitHub, …).
  • Recipe — catalog installs that may bundle integrations.
  • Backend: internal/api/workspace_integrations.go, internal/api/crew_integrations.go.
  • This kind’s Go implementation: internal/manifest/kinds/integration.go.