MCPServer spec

The basic spec for a Dapr MCPServer resource

The MCPServer is a Dapr resource that declares a connection to an MCP (Model Context Protocol) server. Dapr loads these at startup, discovers the server’s tools, and registers built-in durable workflow orchestrations for each one: dapr.internal.mcp.<server>.ListTools for tool discovery and dapr.internal.mcp.<server>.CallTool.<tool> per discovered tool for durable tool execution. Callers invoke them through the standard Dapr Workflow API.

Format

Exactly one of streamableHTTP, sse, or stdio must be set under endpoint.

Streamable HTTP transport

apiVersion: dapr.io/v1alpha1
kind: MCPServer
metadata:
  name: <NAME>
spec:
  ignoreErrors: <REPLACE-WITH-BOOL> # Optional. When true, daprd keeps running if this MCPServer fails to load.
  endpoint:
    streamableHTTP:
      url: <REPLACE-WITH-URL> # Required. The endpoint URL of the MCP server.
      protocolVersion: <REPLACE-WITH-VERSION> # Optional. MCP spec version (e.g. "2025-06-18").
      timeout: <REPLACE-WITH-TIMEOUT> # Optional. Per-call deadline (e.g. "30s").
      headers: # Optional
        - name: <REPLACE-WITH-HEADER-NAME>
          value: <REPLACE-WITH-HEADER-VALUE>
        - name: <REPLACE-WITH-HEADER-NAME>
          secretKeyRef:
            name: <REPLACE-WITH-SECRET-NAME>
            key: <REPLACE-WITH-SECRET-KEY>
      auth: # Optional
        secretStore: <REPLACE-WITH-SECRETSTORE>
        oauth2:
          issuer: <REPLACE-WITH-TOKEN-ENDPOINT>
          clientID: <REPLACE-WITH-CLIENT-ID> # Optional. OAuth2 client identifier.
          audience: <REPLACE-WITH-AUDIENCE>
          scopes:
            - <REPLACE-WITH-SCOPE>
          secretKeyRef:
            name: <REPLACE-WITH-SECRET-NAME>
            key: <REPLACE-WITH-SECRET-KEY>
        spiffe:
          jwt:
            header: <REPLACE-WITH-HEADER-NAME>
            headerValuePrefix: <REPLACE-WITH-PREFIX>
            audience: <REPLACE-WITH-AUDIENCE>
  middleware: # Optional
    beforeCallTool:
      - workflow:
          workflowName: <REPLACE-WITH-WORKFLOW-NAME>
          appID: <REPLACE-WITH-APP-ID> # Optional. Remote app.
        mutate: <REPLACE-WITH-BOOL> # Optional. When true, hook return value replaces the arguments.
    afterCallTool:
      - workflow:
          workflowName: <REPLACE-WITH-WORKFLOW-NAME>
        mutate: <REPLACE-WITH-BOOL> # Optional. When true, hook return value replaces the result.
    beforeListTools:
      - workflow:
          workflowName: <REPLACE-WITH-WORKFLOW-NAME>
    afterListTools:
      - workflow:
          workflowName: <REPLACE-WITH-WORKFLOW-NAME>
        mutate: <REPLACE-WITH-BOOL> # Optional. When true, hook return value replaces the result.
  catalog: # Optional. Informational only.
    displayName: <REPLACE-WITH-DISPLAY-NAME>
    description: <REPLACE-WITH-DESCRIPTION>
    owner:
      team: <REPLACE-WITH-TEAM>
      contact: <REPLACE-WITH-CONTACT>
    tags:
      - <REPLACE-WITH-TAG>
    links:
      docs: <REPLACE-WITH-URL>
scopes: # Optional
  - <REPLACE-WITH-SCOPED-APPIDS>

SSE transport

apiVersion: dapr.io/v1alpha1
kind: MCPServer
metadata:
  name: <NAME>
spec:
  endpoint:
    sse:
      url: <REPLACE-WITH-URL>
      protocolVersion: <REPLACE-WITH-VERSION> # Optional
      timeout: <REPLACE-WITH-TIMEOUT> # Optional
      headers: # Optional. Same format as streamableHTTP.
        - name: <REPLACE-WITH-HEADER-NAME>
          value: <REPLACE-WITH-HEADER-VALUE>
      auth: # Optional. Same format as streamableHTTP.
        secretStore: <REPLACE-WITH-SECRETSTORE>

Stdio transport

This is not supported in Kubernetes-hosted modes.

apiVersion: dapr.io/v1alpha1
kind: MCPServer
metadata:
  name: <NAME>
spec:
  endpoint:
    stdio:
      command: <REPLACE-WITH-COMMAND> # Required.
      args: # Optional
        - <REPLACE-WITH-ARG>
      env: # Optional
        - name: <REPLACE-WITH-ENV-NAME>
          value: <REPLACE-WITH-ENV-VALUE>
        - name: <REPLACE-WITH-ENV-NAME>
          secretKeyRef:
            name: <REPLACE-WITH-SECRET-NAME>
            key: <REPLACE-WITH-SECRET-KEY>

Spec fields

Top-level

FieldRequiredDetailsExample
ignoreErrorsNWhen true, daprd keeps running if this MCPServer fails validation or secret resolution. When false (default), such failures cause daprd to exit gracefully.true
endpointYThe transport and target of the MCP server. See Endpoint below.
middlewareNOptional workflow hooks invoked around tool and list operations. See Middleware fields below.
catalogNInformational governance metadata. See Catalog fields below.

Endpoint

FieldRequiredDetailsExample
endpoint.streamableHTTPN*Configuration for the streamable HTTP transport.See format above
endpoint.sseN*Configuration for the legacy SSE transport.See format above
endpoint.stdioN*Configuration for the stdio subprocess transport.See format above

* Exactly one of streamableHTTP, sse, or stdio must be set.

Streamable HTTP / SSE fields

FieldRequiredDetailsExample
urlYThe endpoint URL of the MCP server."https://mcp.example.com/"
protocolVersionNMCP spec version in date format. When unset, the SDK negotiates automatically."2025-06-18"
timeoutNPer-call deadline for MCP requests."30s"
headersNHTTP headers injected on all outbound requests. Supports value, secretKeyRef, and envRef.name: "Authorization" secretKeyRef.name: "my-secret" secretKeyRef.key: "token"
authNAuthentication configuration. See auth fields below.

Auth fields

FieldRequiredDetailsExample
auth.secretStoreNDapr secret store for resolving secretKeyRef entries in headers. Defaults to "kubernetes"."my-secret-store"
auth.oauth2.issuerY (if oauth2)Token endpoint of the authorization server."https://auth.example.com/token"
auth.oauth2.clientIDNOAuth2 client identifier sent to the token endpoint. Required by RFC 6749 for standard client_credentials flow; may be left empty for non-standard flows."my-client-id"
auth.oauth2.audienceNAudience claim for the token request."mcp://payments"
auth.oauth2.scopesNScopes requested in the token.["read", "write"]
auth.oauth2.secretKeyRefNReference to the client secret in the secret store.name: "oauth-secret" key: "clientSecret"
auth.spiffe.jwt.headerY (if spiffe)HTTP header name to inject the JWT into."Authorization"
auth.spiffe.jwt.headerValuePrefixNString prepended to the JWT value."Bearer "
auth.spiffe.jwt.audienceY (if spiffe)Intended audience for the JWT."mcp://payments"

Stdio fields

FieldRequiredDetailsExample
stdio.commandYThe executable to run."npx"
stdio.argsNCommand-line arguments.["-y", "@modelcontextprotocol/server-filesystem"]
stdio.envNEnvironment variables for the subprocess. Supports value, secretKeyRef, and envRef.name: "API_KEY" value: "secret"

Middleware fields

Middleware hooks are executed in array order. Error behavior differs by hook type:

  • beforeCallTool errors abort the chain; the workflow completes with CallToolResult{isError: true} so the caller can self-correct.
  • beforeListTools errors abort the chain and the error is returned.
  • afterCallTool errors fail the workflow — these hooks can act as authorization gates that block the response.
  • afterListTools errors are logged but do not affect the result.
FieldRequiredDetailsExample
middleware.beforeCallToolNHooks invoked before each CallTool.See format above
middleware.afterCallToolNHooks invoked after each CallTool.See format above
middleware.beforeListToolsNHooks invoked before each ListTools.See format above
middleware.afterListToolsNHooks invoked after each ListTools.See format above

Each hook entry:

FieldRequiredDetailsExample
workflow.workflowNameYName of the workflow to invoke."rbac-check"
workflow.appIDNTarget a remote Dapr app. When unset, runs locally."auth-service"
mutateNWhen true, the hook’s return value replaces the data flowing through the pipeline (arguments for beforeCallTool; result for afterCallTool and afterListTools). When false (default), the hook is observe-only. Not supported on beforeListTools.true

Catalog fields

Catalog fields are purely informational and have no effect on runtime behavior.

FieldRequiredDetailsExample
catalog.displayNameNHuman-readable display name."Payments MCP"
catalog.descriptionNDescription of the MCP server."Payment processing tools"
catalog.owner.teamNTeam responsible for the MCP server."platform-team"
catalog.owner.contactNContact information."platform@example.com"
catalog.tagsNTags for categorization.["payments", "production"]
catalog.linksNNamed URLs (docs, runbook, dashboard).docs: "https://..."