For the complete documentation index, see llms.txt. This page is also available as Markdown.

Plugin Configuration

Overview

The mcpd daemon supports a plugin subsystem for extending request/response processing.

This page covers configuring plugins. To build one, see Writing a Plugin.


Plugin Categories

Plugin execution order

Within each category, plugins execute in the order they appear in the configuration file.

Plugins are organized into categories and execute during specific phases of the request lifecycle.

Categories execute in the order shown below for both request and response phases.

Order
Category
Purpose
Execution

1

observability

Collect metrics and traces (non-blocking)

Parallel

2

authentication

Validate client identity

Sequential

3

authorization

Verify permissions after authentication

Sequential

4

rate_limiting

Enforce request rate limits

Sequential

5

validation

Check request/response structure and content

Sequential

6

content

Transform request/response payloads

Sequential

7

audit

Log compliance and security events

Sequential


Plugin Execution Flows

Plugins can execute during one or both flows/phases:

  • request: Executes during the request phase

  • response: Executes during the response phase


Configuration Format


Plugin Directory

Plugins are native executables. [plugins].dir is the directory mcpd scans to find them, and every plugin's name must match a binary in that directory.

Field
Type
Required
Description

dir

string

Yes, if any plugins

Directory containing the plugin binaries

When scanning the directory, mcpd only considers regular files with the execute bit set. Subdirectories, dotfiles, and non-executable files are skipped silently, so a plugin whose binary lost its execute permission looks identical to one that was never there.

Both problems are caught at startup rather than at request time:

If you see the second error and the file is definitely there, check ls -l for the execute bit before anything else.


Plugin Fields

Field
Type
Required
Description

name

string

Yes

Name of the plugin binary in the plugins directory

commit_hash

string

No

SHA/hash for validating plugin version

required

boolean

No

Whether plugin failure should block the request

flows

array

Yes

Execution phases: ["request"], ["response"], or both


Execution Order

Plugins execute in the order they appear in the configuration file within their category.

During the request phase, jwt-auth executes first, followed by api-key-auth.


Required Plugins

Mark plugins as required when their successful execution is critical:

Failure Behavior

When a required plugin fails, mcpd returns:

  • Status: 500 Internal Server Error

  • Header: Mcpd-Error-Type with one of:

    • request-pipeline-failure - Plugin failed during request processing (before upstream call)

    • response-pipeline-failure - Plugin failed during response processing (after upstream call)

Response Pipeline Execution

The response pipeline runs on all upstream responses, regardless of status (200 OK, 500 error, etc.). This ensures critical plugins (PII redaction, audit logging, security headers) run consistently.

Optional Plugin Behavior

When required is not specified or set to false:

  • Plugin errors (crashes, exceptions): Logged as warnings, pipeline continues.

  • Plugin rejections (returning Continue=false): Pipeline respects the rejection and stops processing, except:

    • Observability category only: Pipeline ignores optional plugin rejections and continues (necessary for parallel execution model).


Content Mutation

Content Plugin Behavior

Only plugins in the content category may mutate requests or responses. Modified content is passed to the next plugin in the chain.

Content plugins modify the request by setting the modified request in their response. Other plugin categories can only observe or reject requests.

Example Content Plugin Flow

The encryption plugin processes the request first and may modify it. The modified request is then passed to the compression plugin.


Observability Plugin Execution

Parallel Execution

Observability plugins run in parallel and cannot modify requests or responses.

Observability plugins are designed for metrics collection, tracing, and monitoring. They execute concurrently for performance.

Required Observability Plugins

If any observability plugin is marked as required, request processing waits for all observability plugins to complete before aggregating results. If any required observability plugin fails, the request is rejected after all have completed.

In this example, both metrics and tracing run in parallel, but the request will be rejected if metrics fails (once metrics and tracing have completed).


Multiple Plugins Per Category

You can configure multiple plugins within the same category. They execute in the order defined:

Request processing order: jwt-authapi-key-authoauth2


Minimal Configuration

Plugins are optional. A configuration file without plugins is valid:


Complete Example

Execution Flow

Request Phase

  1. jwt-auth (authentication) - sequential

  2. rbac (authorization) - sequential

  3. token-bucket (rate_limiting) - sequential

  4. schema-validator (validation) - sequential

  5. encryption (content) - sequential

  6. prometheus-metrics + distributed-tracing (observability) - parallel

Response Phase

  1. schema-validator (validation) - sequential

  2. encryption (content) - sequential

  3. prometheus-metrics + distributed-tracing (observability) - parallel

  4. compliance-logger (audit) - sequential


Running Plugins in Docker

A containerized mcpd cannot see plugin binaries on the host unless the directory is bind mounted. Mount it and point [plugins].dir at the path inside the container:

The image runs as the non-root mcpd user, so the mounted binaries must be readable and executable by that user, not only by whoever owns them on the host. The mount is shown read-only because mcpd only needs to execute the plugins, never write to them.

Architecture and libc compatibility

Plugins are separate executables that mcpd launches and talks to over gRPC, so each one must be built for the OS, architecture, and C library of whatever runs mcpd — which is the container image, not your laptop, whenever mcpd itself is containerized.

The published image is multi-arch — mzdotai/mcpd:v0.4.0 ships both linux/amd64 and linux/arm64 — so Docker pulls the variant matching your host, and the plugin must be built for that architecture. It is also Alpine-based (musl), so a plugin dynamically linked against glibc will not run even at the correct architecture. For Go plugins, build a static binary for the architecture Docker pulled:

Run docker image inspect mzdotai/mcpd:v0.4.0 --format '{{.Architecture}}' if you are unsure which one you have, or if you pinned a platform with --platform. CGO_ENABLED=0 produces a static binary and sidesteps the glibc/musl question entirely; if you need cgo, build against musl.

The failure is easy to misread, because discovery succeeds and only the launch fails:

Symptom
Cause

exec format error

Wrong architecture or OS for the running platform

no such file or directory, but the binary exists

Dynamically linked against a libc the image lacks (typically glibc on musl)

permission denied

Execute bit set, but not executable by the mcpd user (wrong owner/group), or unreadable

A binary with no execute bit at all never reaches this stage — it is skipped during discovery and produces the "plugin … not found in directory" startup error described above instead.

The second row is genuinely confusing: the kernel reports the missing interpreter, not the missing binary. Check with file plugins/jwt-auth — it is portable and reports "statically linked" vs "dynamically linked". (ldd is Linux-only, so it is unavailable on the macOS host you may be cross-compiling from, and glibc's ldd prints "not a dynamic executable" for a correct CGO_ENABLED=0 binary.)


Validation

Plugin configurations are validated when the daemon starts or during hot reload. Common validation errors:

  • Empty plugin name

  • Missing or empty flows array

  • Invalid flow values (must be request or response)

  • Duplicate flow values

  • Plugin directory missing, or configured plugin not found in it (see Plugin Directory)

For runtime plugin failures or binary checks, see Troubleshooting.

Last updated