MCP Middleware Integration
Add DRS verification to an MCP server. The Go middleware verifies the
X-DRS-Bundle header before your business handler runs.
How it works
MCP client
│ POST /mcp/tools/call
│ X-DRS-Bundle: <base64url(JSON bundle)>
▼
drs-verify/pkg/middleware.MCPMiddleware
│ decode base64url
│ parse JSON bundle
│ run verify.Chain (blocks A–F)
▼ VALID
business handler
If verification fails:
- missing bundle:
401 - malformed base64url/JSON:
400 - invalid chain:
403
Go integration
If your MCP-facing server is in Go, wrap the route with
middleware.MCPMiddleware or middleware.OptionalMCPMiddleware.
package main
import (
"log"
"net/http"
"time"
"github.com/drs-protocol/drs-verify/pkg/middleware"
"github.com/drs-protocol/drs-verify/pkg/resolver"
"github.com/drs-protocol/drs-verify/pkg/verify"
)
func main() {
res, err := resolver.New(10_000, time.Hour)
if err != nil {
log.Fatal(err)
}
deps := verify.Deps{
Resolver: res,
}
mux := http.NewServeMux()
// 1) Define your normal business logic handler.
mcpBusinessHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 3) Read verification context after middleware has validated the bundle.
ctx := middleware.GetVerificationContext(r.Context())
if ctx == nil {
http.Error(w, "missing verification context", http.StatusForbidden)
return
}
// Example: make authorization/usage decisions with verified identity.
// ctx.RootPrincipal, ctx.ChainDepth, ctx.LeafPolicy
w.WriteHeader(http.StatusOK)
})
// 2) Wrap your business handler with MCP middleware.
mux.Handle("/mcp/", middleware.MCPMiddleware(deps,
mcpBusinessHandler,
))
log.Fatal(http.ListenAndServe(":8080", mux))
}
Use OptionalMCPMiddleware only when DRS is advisory and your business handler can
safely process requests without a bundle.
TypeScript / pure JSON-RPC integration
If your MCP traffic is pure JSON-RPC rather than HTTP-terminated, use the
TypeScript wrapper packages in packages/drs-mcp-client and
packages/drs-mcp-server.
- client side: injects the bundle into
params._meta["X-DRS-Bundle"] - server side: decodes the same base64url string and posts the decoded bundle to
/verify
This is the Shape 2 transport described in docs/drs-source-of-truth.md.
Testing your integration
# Valid bundle — expect exit code 0
DRS_VERIFY_URL=http://localhost:8080 pnpm exec drs verify bundle.json
# Missing bundle — expect 401
curl -X POST http://localhost:8080/mcp/tools/call \
-H "Content-Type: application/json" \
-d '{"tool":"web_search","query":"test"}'
# Malformed bundle — expect 400
curl -X POST http://localhost:8080/mcp/tools/call \
-H "X-DRS-Bundle: !!!not-base64url!!!" \
-H "Content-Type: application/json" \
-d '{"tool":"web_search","query":"test"}'