Imported from eshu-hq/eshu (
go/cmd/mcp-server/AGENTS.md). Install upstream withnpx skills add eshu-hq/eshu --skill mcp-server. Copyright stays with the author.
AGENTS.md — cmd/mcp-server guidance for LLM assistants
Read first
go/cmd/mcp-server/README.md— pipeline position, lifecycle, configuration, and operational notesgo/cmd/mcp-server/wiring.go—wireAPI(env-var wiring, credential chain,mcpAuthWiring);go/cmd/mcp-server/wiring_router.go—newMCPQueryRouterandnewMCPQueryRouterWithSemanticEmbedding(handler composition);go/cmd/mcp-server/transport_auth_guard.go— the no-silent-open startup gate (#5168). Understand these before touching handler composition, env-var wiring, or transport authgo/cmd/mcp-server/main.go— transport selection and shutdown; understand theswitch transportbefore touching startup or signal handlinggo/internal/mcp/README.md— MCP tool dispatch, the SSE session model, and the protocol handlergo/internal/telemetry/instruments.goandcontract.go— metric and span names before adding new telemetry
Invariants this package enforces
- Validation before datastore —
wireAPIresolvesloadQueryProfile,loadGraphBackend, andResolveAPIKeybefore opening any connection (wiring.go:32). An invalid profile, backend, or key returns an error before any dial. - Postgres required —
wireAPIreturns an error if bothESHU_POSTGRES_DSNandESHU_CONTENT_STORE_DSNare empty. TheopenQueryGraphcall is skipped whenProfileLocalLightweightis active orESHU_DISABLE_NEO4Jis true (wiring.go:179). - IaC stores always wired —
newMCPQueryRouterWithSemanticEmbedding(wiring_router.go) always setsIaCHandler.ReachabilityandIaCHandler.Managementto Postgres-backed query adapters. Do not set either to nil. - No silent open mode over HTTP (#5168) — in
httpmode with no resolvable credential source (ESHU_API_KEY,ESHU_SCOPED_TOKENS_FILE, orESHU_AUTH_RESOURCE_URI),requireMCPHTTPCredentialSourceexits non-zero unlessESHU_MCP_ALLOW_UNAUTHENTICATED=true. Do not weaken this by counting the always-wired Postgres identity resolver as a credential source. stdio is never gated. - Governance mode gates transport admission, not just status readback —
wireAPIderivesquery.ScopedRoutePolicyForGovernanceModefromESHU_GOVERNANCE_MODEand threads it intobuildTransportAuthMiddleware. Underhosted_multi_tenant, or any mode the mapping does not recognize, an all-scope bearer is refused with a 403 atGET /sseandPOST /mcp/messagebeforeinitializeortools/list. Do not default that argument: the zero value ofquery.BrowserSessionRoutePolicyis fail-closed, so leaving it out refuses every all-scope token on a laptop as readily as in a hosted deployment. The refusal is counted asreason="route_policy"oneshu_dp_mcp_transport_auth_denied_total, never asunauthenticated. - MCP read tools must have matching query handlers —
newMCPQueryRouterWithSemanticEmbedding(wiring_router.go) wiresCICDHandlerandSupplyChainHandlerto their Postgres read models solist_ci_cd_run_correlations,list_supply_chain_impact_findings,list_security_alert_reconciliations, andlist_sbom_attestation_attachmentsdo not dispatch to 404 routes. - Auth on query routes —
query.AuthMiddlewarewraps thequery.APIRouterhandler before it is passed tomcp.NewServer. The MCP transport endpoints (/sse,/mcp/message,/health) handle auth separately inside the MCP transport mux. - stdio mode has no HTTP admin surface — the admin mux is passed to
NewServeronly in HTTP mode. Instdiomode the transport switch atmain.go:54does not callNewServerwith an admin mux, so those routes are not mounted. - Telemetry shutdown on background context —
telemetry.NewProviders(main.go:37) returns a providers value whoseShutdownis called withcontext.Background(), not with the cancelled root context, so traces flushed during shutdown complete.
Common changes and how to scope them
-
Add a new query handler → add a field to the
query.APIRouterstruct, wire it innewMCPQueryRouterWithSemanticEmbeddinginwiring_router.go, assert it inwiring_test.go, and add the matching tool ingo/internal/mcp/dispatch.go. Runcd go && go test ./cmd/mcp-server ./internal/mcp -count=1. Why: the compile-time assertions (query.Neo4jReadersatisfiesquery.GraphQuery,query.ContentReadersatisfiesquery.ContentStore—wiring.go:22) fail if the handler does not satisfy its interface; the dispatch route test ininternal/mcpfails if the route is missing. -
Change transport default → edit the fallback in
main.go:40and updatedoc.go. Rungo test ./cmd/mcp-server -count=1. Why:doc.godocuments the default and is read by the service description surface. -
Add a new env var → read it via
getenvinwireAPIormain, add it to the configuration table inREADME.md, and add a test inwiring_test.gothat asserts failure before datastore connection when the var is invalid. Why: all env validation must complete before datastore connections. -
Change the admin surface → touch
mountRuntimeSurfaceinwiring.goand update the corresponding test inruntime_surface_test.go. Why: the tests assert/healthz,/readyz,/metrics, and/admin/statusroutes are present and return correct shapes.
Failure modes and how to debug
-
Symptom: binary exits 1 immediately on startup → check structured log for
event_name=runtime.startup.failed; sub-causes are bad API key, bad profile, bad backend, Postgres dial failure, or telemetry init failure. -
Symptom: MCP client receives no tools → the server started in
stdiomode but the client is pointing at an HTTP URL, or vice versa; checkESHU_MCP_TRANSPORT. -
Symptom:
/healthzreturns 404 in stdio mode → by design; admin routes are only mounted in HTTP mode viaServer.RunHTTP. -
Symptom: MCP tool returns auth error on
/api/v0/*routes → API key missing or wrong;query.AuthMiddlewareenforces it on all/api/routes. -
Symptom:
ESHU_POSTGRES_DSNset but Postgres ping fails → check Postgres reachability and credentials;wireAPIwill return before Neo4j dial.
Anti-patterns specific to this package
-
Calling handler methods directly — do not call
query.RepositoryHandleror other handlers fromwiring.gooutside ofquery.APIRouter.Mount. All routing goes through theAPIRouter. -
Setting
ESHU_DISABLE_NEO4Jin production — this skips the Neo4j dial and limits query capability. It is intended for lightweight local profiles only. -
Confusing the two auth layers — as of #5168 the MCP transport endpoints (
GET /sse,POST /mcp/message) run through the credential middleware, viamcp.WithTransportAuthwired inwireAPI. The/api/*routes are protected separately byquery.AuthMiddlewareWithScopedTokensAndGovernanceAuditwrapping the query mux (theauthedHandlerpassed tomcp.NewServer). Both use the SAME credential chain; do not assume one covers the other's mount, and do not remove either wrap. Note the residual: a headerless request is refused only when a sharedESHU_API_KEYis set — a scoped-only/OIDC-only deployment still passes headerless requests through the shared-token dev-bypass until the companion auth-headerless-bypass hardening (under #5161) lands.
What NOT to change without an ADR
- The query handler composition in
newMCPQueryRouterWithSemanticEmbedding(wiring_router.go) — adding or removing handlers changes the MCP tool surface and must be coordinated withinternal/mcp/dispatch.gotool definitions anddocs/public/guides/mcp-guide.md. - Transport options for
ESHU_MCP_TRANSPORT— adding a new transport type changes the documented wire contract; seedocs/public/deployment/service-runtimes.md.