Scrydon
SDKsPacks & Authoring SDKAuthoring: MCP Servers

MCP Servers

Ship a governed MCP server definition inside a Scrydon Pack and understand its approval, availability, and transport lifecycle

This artifact ships inside a Pack. For the shared lifecycle — pack build, upload, install — see Packs & Authoring SDK.

An MCP server content entry lets a pack ship a fully-configured Model Context Protocol server — its transport, endpoint (or launch command), and advertised tools — as JSON-serializable configuration. Applying the pack registers the server at organization scope. An explicit admin install or a signed source registers it as approved; a non-interactive unsigned source sync registers it as pending for review. No one hand-enters URLs or commands.

Unlike an integration, an MCP server carries no code artifact — the manifest is the whole definition, so it travels inline in the pack with no bundle.tar.gz.

Author with defineMcpServer

mcp-server-github/manifest.ts
import { defineMcpServer } from "@scrydon/sdk-authoring/mcp-servers/define";

export default defineMcpServer({
  // Stable kebab slug — the idempotency key. Renaming `name` later is safe;
  // changing `id` registers a new server.
  id: "github-mcp",
  name: "GitHub MCP",
  description: "Issue and PR tools for GitHub repositories.",
  transport: "streamable-http",
  url: "https://mcp.example.com/github",
  // Advertised tools → the registry allowlist. Live discovery still happens at
  // connect time; this is the governance surface.
  tools: ["search_issues", "create_issue"],
});

stdio is currently registration-only. It cannot become organization-default, be installed or enabled in a workspace, or execute. Runtime support requires the governed MCP plane introduced by PR #2140 and a separately reviewed stdio dispatcher on that plane; merging the plane alone does not enable stdio. Registered stdio entries remain visible and removable.

A stdio server declares a command (and optional args / envVarKeys) instead of a url:

export default defineMcpServer({
  id: "everything",
  name: "Everything",
  transport: "stdio",
  command: "npx",
  args: ["-y", "@modelcontextprotocol/server-everything"],
  envVarKeys: ["API_KEY"],
});

Fields

FieldRequiredNotes
idStable lowercase kebab slug. The idempotency key — keep it stable across versions.
nameDisplay name. Must be unique within the org.
descriptionShown in the registry UI.
transport"streamable-http" or "stdio".
urlfor HTTPEndpoint for streamable-http.
command / argsfor stdioLaunch command for stdio.
envVarKeysNames reserved for the future governed stdio dispatcher. Values are never inlined; the current runtime does not execute stdio.
toolsAdvertised tool names → the registry allowlist.
authReference-only auth config — see below. Omit it and the server registers with no special auth.

Authentication (auth)

Authentication ships by reference, never as an embedded token. The auth field is a small subset of the registry's auth model for packaged streamable HTTP servers that run headless or from a workflow with no user present:

kindUse
"none"No auth header.
"static_header"Send the configured static headers map, whose {{secret}} placeholders are resolved from the workspace secret store at run time. (envVarKeys is the separate stdio-env mechanism, not header values.)
"oauth_client_credentials"Service-to-service OAuth 2.1. Requires tokenUrl, clientId, and clientSecretRef (a workspace-secret reference, never the secret itself); optional scopes, audience, resource, useBasicAuth.
defineMcpServer({
  id: "github-mcp",
  name: "GitHub MCP",
  transport: "streamable-http",
  url: "https://mcp.example.com/github",
  auth: {
    kind: "oauth_client_credentials",
    tokenUrl: "https://idp.example.com/oauth/token",
    clientId: "scrydon-github-mcp",
    clientSecretRef: "github-mcp-client-secret", // resolved from the workspace secret store
    scopes: ["repo"],
  },
});

Do not put secrets in the manifest. The delegated, per-user modes (oauth_authorization_code, managed_ema) are intentionally not available to packs — they need a user present, which a triggered/background run does not have.

Pack layout

Place each server in its own subdir; reference it from pack.json:

pack.json
{
  "contents": [
    { "kind": "mcp-server", "path": "mcp-server-github", "version": "1.0.0", "required": true }
  ],
  "installOrder": ["mcp-server"]
}
mcp-server-github/
  manifest.json   # the defineMcpServer output (no bundle.tar.gz)

A pack may ship several MCP servers — give each its own mcp-server-<slug>/ subdir.

Lifecycle

Build & apply — run pack build, then install the pack or synchronize its source. An explicit admin install or signed source creates an approved registry row. A non-interactive unsigned sync creates a pending row.
Review when pending — an organization admin reviews and approves pending content. Approval accepts the definition into the organization registry; it does not make stdio executable.
Make remote HTTP available — a workspace admin can add an approved streamable-http server. A signed-in organization admin may instead make it available by default across the organization. A workspace can remove a default server to create an explicit opt-out, then add it again to reverse that choice. Configuring a default server materializes the workspace's overrides.
Re-apply safely — applying the same (organization, pack, source id) updates one registry row in place and preserves its governance status. Renaming name while keeping id updates that row; changing id registers a different source entry.

A pack cannot overwrite a server it does not own: if the org already has a server with the same name that was hand-created or shipped by a different pack, the install refuses that entry rather than clobbering it.

Registered servers surface on the Packs page under Contributes → MCP servers. Approved streamable HTTP servers can then appear in organization settings and the workspace Marketplace according to their availability policy.

On this page

On this page