Documentation
¶
Overview ¶
Package mcp implements the Model Context Protocol tool surface for Eshu.
ToolDefinition aliases the dependency-neutral toolcontract definition. The cloud and documentation child packages own their registration definitions without importing this parent package. ReadOnlyTools remains the sole ordered assembler; routing, dispatch, transport, authorization, and query execution remain owned here.
MCP tools dispatch into the same HTTP query handlers that power the public HTTP API, so a tool response and the corresponding HTTP query response share truth. Dispatch gives each handler request a bounded child context with a deterministic 30s default and propagates parent cancellation, so handlers must honor r.Context rather than starting unbounded work; dispatch timeout and cancellation failures are returned as MCP error results with structured content. Dispatch also enforces a response-size budget (defaultToolResponseByteBudget) as a tool-agnostic hub throttle: a response whose serialized size exceeds the budget is replaced with a small bounded envelope carrying error code mcp_response_over_budget plus budget accounting and narrowing guidance, so a single heavy graph-returning tool cannot blow the model context budget. Per-route token budgets still apply first.
In HTTP mode the transport is wrapped with the caller-supplied credential middleware when the server is constructed with WithTransportAuth (issue #5168): the GET /sse and POST /mcp/message endpoints run every JSON-RPC method (initialize, tools/list, tools/call, ping) through the same middleware that guards /api/v0/*, instead of being mounted with none. When that middleware fails a request closed -- for example a shared-token (ESHU_API_KEY) deployment receiving a request with no or a wrong credential -- the caller gets a bare 401 that discloses nothing about the tool catalog or server metadata. Each SSE session is also bound to the credential that opened it; a POST to that session whose credential resolves to a different principal is rejected with 403. Denials increment eshu_dp_mcp_transport_auth_denied_total, labeled by mcp_method and reason. This wrap does not by itself close the headerless bypass for a scoped-token-only or OIDC-only deployment (shared ESHU_API_KEY unset): the shared credential middleware still passes a headerless request through on an empty shared token, and that per-request enforcement is finished by the companion auth-headerless-bypass hardening (under #5161). The stdio transport is never wrapped -- it keeps its process and filesystem trust boundary. Helpers in this package normalize tool arguments, including shared slice and identifier helpers in dispatch_args.go, build request bodies for the underlying handler, and parse canonical response envelopes. Citation tools stay in this transport layer and delegate source hydration to the query package rather than reading storage directly; the advertised citation schema caps input at 500 handles. The find_code adapter forwards the caller's public page limit unchanged and preserves count, limit, and truncated from /api/v0/code/search inside the canonical data envelope; only the query layer performs the limit-plus-one probe used to determine truncation. Structural inventory and security investigation tools also stay transport-only and delegate inventory filtering, import dependency investigation, call graph metrics, or redacted finding generation to the query package; their tool definitions live in tools_structural_inventory.go, tools_import_dependencies.go, tools_call_graph_metrics.go, and tools_security.go. Import-dependency dispatch forwards scope and paging unchanged; the query handler owns the 25,000-row candidate ceiling and scope-narrowing response. The get_capability_catalog tool forwards to /api/v0/capabilities and preserves the embedded role, grant, data-class, permission-family, and per-capability authorization metadata from the query response. The get_surface_inventory tool forwards to /api/v0/surface-inventory and preserves collector source-to-read-surface contracts so MCP callers see the same fact-kind provenance, proof gates, fixture refs, and truth profiles as HTTP and console callers. Package-registry and supply-chain tools follow the same rule and keep their route builders in dedicated dispatch files, so bounded package, version, dependency, correlation, source-only advisory evidence, vulnerability finding, explanation, SBOM, and attestation attachment requests stay thin; SBOM attachment tools forward repository_id to the query layer so repository scope returns reducer-owned image/SBOM missing evidence instead of becoming an unscoped aggregate. repository, service, and workload advisory scopes are forwarded to HTTP so the query layer can derive advisory anchors from reducer-owned impact findings without promoting provider-alert-only evidence; SBOM attachment tools forward repository_id to the query layer so unsupported repository scope is rejected there instead of becoming an unscoped aggregate. Supply-chain schemas preserve ambiguous-subject outcomes instead of hiding non-canonical evidence. The supply-chain impact tool exposes include_suppressed and suppression_state inputs so callers can opt in to VEX/operator-suppressed findings and audit suppression reason, source, justification, expiration, and evidence reference per row. Work-item tools expose bounded Jira source facts as ticket-first evidence while preserving the source-only boundary around PR, commit, deploy, runtime, image, and service truth. Documentation tools forward repo, target_kind, target_id, and service_id filters to the HTTP read models and preserve coverage, related_facts, and missing_evidence fields so raw documentation target facts are not collapsed into admissible findings. Documentation fact lists also preserve bounded page metadata (`count`, `limit`, `truncated`, `missing_evidence`, `states`, and `next_cursor` on truncated pages). Any hosted governance or semantic capability status tool stays transport-only too: governance forwards to the redacted policy-mode and aggregate readback route, while semantic status reports no-provider mode as unavailable and configured provider profiles as redacted, source-policy-gated metadata. Deterministic indexing, reducer, API, MCP, and documentation fact paths remain unaffected by either optional status readback. Semantic evidence tools follow the same transport-only boundary: they forward to HTTP routes that list durable documentation observations or non-canonical code hints with truth basis, provider profile, prompt version, redaction version, policy state, freshness, and admission or corroboration state. They do not expose raw prompts, credentials, provider responses, or inject code hints into deterministic graph-truth tools. Component extension tools follow the same transport-only boundary: they forward inventory and diagnostics requests to HTTP registry readback routes, preserve the canonical envelope, and do not expose server-local manifest paths or activation config paths. Query playbook and investigation workflow tools are catalog-only dispatch surfaces: they forward to HTTP static resolvers that describe bounded call plans and missing-evidence-driven next calls without executing those calls or reading tenant data. Relationship-story tools forward min_confidence unchanged to the query layer so the HTTP handler owns confidence-floor validation and filtering. Relationship-story responses preserve the HTTP per-row provenance block in structuredContent; MCP does not reinterpret confidence, truth, freshness, or bounded-result metadata. Any change that alters request or response shape must update the MCP guide, the HTTP API reference where the route is shared, and the handler tests in the same change. list_reducer_input_invalid_facts (issue #4630) resolves 1:1 to POST /api/v0/admin/input-invalid-facts/query, mirroring list_dead_letter_work_items: scope_id, generation_id, limit, and timeout_ms are required, optional domain/fact_kind filters pass through unchanged, and the response is the durable reducer_input_invalid_facts read model rather than a raw fact payload. list_codeowners_ownership (issue #5419 Phase 4) resolves 1:1 to GET /api/v0/codeowners/ownership: it forwards repository_id, limit, and the three-part after_order_index/after_pattern/after_ref keyset cursor unchanged and preserves the effective_owner field the HTTP handler resolves from manifest-vs-codeowners precedence, so a scoped caller sees the same bounded empty-ownership shape over MCP that the HTTP route returns for an out-of-grant repository.
Index ¶
- func InProcessMessageHandler(queryHandler http.Handler, logger *slog.Logger) http.Handler
- func IsRoutePathParamSegment(segment string) bool
- func LoadFactKindRegistryReadSurfaces(path string) (map[string]string, error)
- func RunReadOnlyTool(ctx context.Context, handler http.Handler, toolName string, ...) (*query.ResponseEnvelope, any, bool, error)
- func SplitAPIRouteSurface(surface string) (method string, segments []string, ok bool)
- type Server
- type ServerOption
- type ToolDefinition
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func InProcessMessageHandler ¶
InProcessMessageHandler returns an http.Handler that processes MCP JSON-RPC messages backed by the given query handler. It is the exported replay seam for R-9 (#4111): the handler can be driven via httptest without a network server, so mcpreplay records and asserts MCP tool responses offline.
The returned handler uses the standalone-POST path of handleHTTPMessage (no SSE session, no sessionId query parameter). Every call is synchronous: the JSON-RPC response is written directly to the HTTP response body and returned to the caller. This matches the standalone-POST behavior a client gets when posting to /mcp/message without a sessionId; the SSE-linked path (202 Accepted + channel delivery) is not exercised.
logger may be nil; a discard logger is substituted to avoid noise in test output. The discard logger satisfies the nil-guard inside NewServer, so the server is always initialised with a valid logger.
func IsRoutePathParamSegment ¶
IsRoutePathParamSegment reports whether segment is a "{param}"-style template placeholder.
Exported so cmd/api's mounted-route-parity gate can substitute a literal dummy token for each param segment when building a synthetic request path (see doc comment on LoadFactKindRegistryReadSurfaces).
func LoadFactKindRegistryReadSurfaces ¶
LoadFactKindRegistryReadSurfaces reads the family-level read_surface field from specs/fact-kind-registry.v1.yaml, keyed by family name. Families with no read_surface or the "none" sentinel are omitted. A missing or malformed file is an error: this is the fact-kind side of the #5335 read-surface consumer-existence gate's denominator, so a silent empty read would falsely report every family as covered.
Exported (not test-only) so cmd/api's mounted-route-parity gate (#5359 P1 fix) can load the same claimed-route set the documented-inventory gate here checks, and additionally verify each one resolves on the actually-mounted *http.ServeMux -- something only a cmd/api-resident test can construct, since newRouter's DI wiring lives in package main and cannot be imported.
func RunReadOnlyTool ¶
func RunReadOnlyTool( ctx context.Context, handler http.Handler, toolName string, args map[string]any, authHeader string, logger *slog.Logger, ) (*query.ResponseEnvelope, any, bool, error)
RunReadOnlyTool invokes a read-only MCP tool in-process without an HTTP round-trip.
It is a thin exported seam over the unexported dispatchTool function, intended for the Ask Eshu engine and similar callers that need to invoke read capabilities programmatically without going through the network stack.
Constraints:
- Only routes that resolveRoute recognises are supported; mutation tools are not reachable through this function but callers should not rely on that as a safety boundary — use an appropriately scoped handler.
- The handler must be safe for concurrent use; RunReadOnlyTool makes a single synchronous ServeHTTP call per invocation.
- Scope and authentication are threaded via ctx and authHeader, exactly as they are for the normal MCP transport path.
Returns (envelope, value, isError, nil) on a successful dispatch. When the tool response is a canonical ResponseEnvelope, envelope is non-nil and value is nil. When the tool response is plain JSON (e.g. list_collectors), envelope is nil and value carries the decoded payload. Returns (nil, nil, false, err) when the tool name is unknown or the dispatch fails before a response is produced.
func SplitAPIRouteSurface ¶
SplitAPIRouteSurface splits a "METHOD /path" surface name into an uppercase HTTP method and slash-separated path segments with the trailing slash stripped, for positional route-template matching. ok is false for a malformed surface (no method/path separator).
Exported so cmd/api's mounted-route-parity gate can turn a claimed read_surface literal into a synthetic *http.Request path (see doc comment on LoadFactKindRegistryReadSurfaces).
Types ¶
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the Go MCP server that dispatches tool calls to internal HTTP handlers.
func NewServer ¶
NewServer creates an MCP server backed by the given HTTP handler. The handler should have all /api/v0/* query routes mounted.
func (*Server) Handler ¶
Handler returns the full HTTP mux RunHTTP would serve -- GET /sse, POST /mcp/message, GET /health, and (via base) the shared runtime admin routes and /api/v0/* query passthrough -- without binding a real listener. It lets a caller (an embedding host, or a test exercising the real transport-auth composition end-to-end with httptest.NewServer) drive the transport surface directly instead of going through RunHTTP's blocking http.Server.ListenAndServe.
func (*Server) Run ¶
Run starts the stdio JSON-RPC transport. It reads from stdin and writes to stdout. Blocks until ctx is cancelled or stdin is closed.
func (*Server) RunHTTP ¶
RunHTTP starts the MCP server as an HTTP service listening on addr. It exposes:
- GET /sse — SSE transport (sends endpoint event, then keepalives)
- POST /mcp/message — JSON-RPC endpoint (works standalone or with SSE session)
- GET /health — k8s probes
- shared runtime admin routes from the provided base mux
- /api/v0/* — query API passthrough
Blocks until ctx is cancelled.
type ServerOption ¶
type ServerOption func(*Server)
ServerOption configures optional Server construction-time behavior.
func WithTransportAuth ¶
func WithTransportAuth(middleware func(http.Handler) http.Handler) ServerOption
WithTransportAuth authenticates the MCP HTTP transport itself -- GET /sse session establishment and every POST /mcp/message method (initialize, tools/list, tools/call, ping) -- with middleware, rather than relying on tools/call's incidental internal re-dispatch through an authed handler (issue #5168). Callers should pass the SAME credential chain used for /api/v0/* routes (see cmd/mcp-server/wiring.go) so a credential that can call a tool can also establish a session and list the catalog, and a credential that cannot is refused uniformly. A nil middleware (the default) leaves the transport unauthenticated.
type ToolDefinition ¶
type ToolDefinition = toolcontract.ToolDefinition
ToolDefinition describes one MCP tool exposed to clients.
It aliases the dependency-neutral toolcontract definition so registration families can move below internal/mcp without importing their parent package.
func ReadOnlyTools ¶
func ReadOnlyTools() []ToolDefinition
ReadOnlyTools returns all read-only MCP tool definitions.
Source Files
¶
- dispatch.go
- dispatch_admission_decisions.go
- dispatch_args.go
- dispatch_ask.go
- dispatch_budget.go
- dispatch_cicd.go
- dispatch_cicd_aggregates.go
- dispatch_cloud_inventory.go
- dispatch_cloud_runtime_drift.go
- dispatch_code_flow.go
- dispatch_codeowners.go
- dispatch_container_image_aggregates.go
- dispatch_documentation.go
- dispatch_documentation_aggregates.go
- dispatch_ecosystem.go
- dispatch_envelope.go
- dispatch_freshness.go
- dispatch_iac.go
- dispatch_impact.go
- dispatch_infra_resource_aggregates.go
- dispatch_infra_search.go
- dispatch_investigation_packets.go
- dispatch_investigation_workflows.go
- dispatch_kubernetes.go
- dispatch_observability_coverage.go
- dispatch_package_registry.go
- dispatch_package_registry_aggregates.go
- dispatch_query_playbooks.go
- dispatch_relationship_edges.go
- dispatch_relationships.go
- dispatch_repositories.go
- dispatch_repository_files.go
- dispatch_sbom_attachment_aggregates.go
- dispatch_secrets_iam.go
- dispatch_security_alert_aggregates.go
- dispatch_semantic_evidence.go
- dispatch_semantic_search.go
- dispatch_service_catalog.go
- dispatch_service_selector.go
- dispatch_status.go
- dispatch_supply_chain.go
- dispatch_supply_chain_aggregates.go
- dispatch_timeout.go
- dispatch_values.go
- dispatch_visualization.go
- doc.go
- kind_disclosure_ledger.go
- kind_real_consumer.go
- kind_real_consumer_decode_calls.go
- kind_real_consumer_dispatch.go
- kind_real_consumer_named_store.go
- kind_real_consumer_postgres_reader.go
- kind_real_consumer_query_slice.go
- read_surface_consumer_existence.go
- read_surface_factkind.go
- read_surface_grandfather.go
- read_surface_query_proof.go
- read_surface_route_serves_data.go
- route_serves_data_registry.go
- route_serves_data_registry_check.go
- route_serves_data_registry_routes.go
- route_serves_data_registry_routes_2.go
- run_readonly.go
- server.go
- server_sse.go
- summaries.go
- summaries_families.go
- tools_admission_decisions.go
- tools_ask.go
- tools_call_graph_metrics.go
- tools_cicd.go
- tools_cicd_aggregates.go
- tools_code_flow.go
- tools_code_quality.go
- tools_code_topic.go
- tools_codebase.go
- tools_codebase_relationships.go
- tools_codebase_story.go
- tools_codeowners.go
- tools_collector_extraction_readiness.go
- tools_component_extensions.go
- tools_container_image_aggregates.go
- tools_content.go
- tools_context.go
- tools_contract_impact.go
- tools_cross_repo_dead_code.go
- tools_dead_code.go
- tools_ecosystem.go
- tools_fact_schema_version.go
- tools_freshness.go
- tools_graph_summary_packet.go
- tools_iac.go
- tools_import_dependencies.go
- tools_incident_context.go
- tools_infra_resource_aggregates.go
- tools_infra_search.go
- tools_investigation_packets.go
- tools_investigation_workflows.go
- tools_kubernetes.go
- tools_observability_coverage.go
- tools_package_registry.go
- tools_package_registry_aggregates.go
- tools_prechange_impact.go
- tools_query_playbooks.go
- tools_reachability.go
- tools_relationship_edges.go
- tools_repository_files.go
- tools_repository_language.go
- tools_route_to_caller.go
- tools_runtime.go
- tools_sbom_attachment_aggregates.go
- tools_secrets_iam.go
- tools_security.go
- tools_security_alert_aggregates.go
- tools_semantic_evidence.go
- tools_semantic_search.go
- tools_service_catalog.go
- tools_service_intelligence.go
- tools_structural_inventory.go
- tools_supply_chain.go
- tools_supply_chain_aggregates.go
- tools_visualization.go
- tools_work_item.go
- transport_auth.go
- transport_auth_metrics.go
- types.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package cloudtools defines the MCP registrations for cloud inventory and runtime-drift reads.
|
Package cloudtools defines the MCP registrations for cloud inventory and runtime-drift reads. |
|
Package doctools defines the MCP registrations for documentation reads.
|
Package doctools defines the MCP registrations for documentation reads. |
|
Package toolcontract defines the dependency-neutral MCP tool registration contract shared by the transport root and domain registration packages.
|
Package toolcontract defines the dependency-neutral MCP tool registration contract shared by the transport root and domain registration packages. |