Documentation
¶
Overview ¶
Package mcp implements the Model Context Protocol server side for Coremetry. MCP is JSON-RPC 2.0 over an HTTP+SSE transport, designed so external LLM clients (Claude Desktop, Anthropic API tool-calling integrations, internal copilots) can discover and invoke a server's tools, list its resources, and read its prompt templates.
What Coremetry exposes (built up across v0.6.4–v0.6.7):
v0.6.4 — core protocol scaffolding: JSON-RPC framing,
HTTP+SSE transport, session lifecycle, initialize +
ping methods. tools/resources/prompts capabilities
advertised but their registries are empty.
v0.6.5 — tools/list + tools/call wired to a Coremetry tools
registry (list_services, search_logs, get_trace,
query_metric, list_problems, …). Salt-okunur —
mutation tool'u bugüne dek hiç eklenmedi (v0.9.14
audit'i: yazma gelirse audit_log source alanı şart).
v0.6.6 — resources/list + resources/read exposing
traces/logs/metrics as MCP resources.
v0.6.7 — prompts/list + prompts/get exposing Coremetry's
curated system prompts (Explain trace, Suggest
runbook, Compare deploys, …) as MCP prompts so an
external LLM can take the same systematic approach
an operator sees in /problems.
Auth: the HTTP handlers in this package are wrapped by the same auth middleware as /api/*. Browser sessions work via the JWT cookie; programmatic clients (Claude Desktop, internal LLMs) obtain a token via POST /api/auth/login then carry it in the Authorization: Bearer header. This avoids inventing a separate API key system — viewer/editor/admin roles apply to MCP calls exactly as they do to REST.
Transport choice: this implementation uses the original HTTP+SSE transport (MCP spec 2024-11-05). Newer Streamable-HTTP (2025-03-26) is similar but uses a single endpoint + session header; can layer it on later without breaking existing clients.
References:
Index ¶
- Constants
- func ExtractURITemplateValue(template, concrete string) string
- type CapPromptsBag
- type CapResourcesBag
- type CapToolsBag
- type ClientInfo
- type Error
- type Prompt
- type PromptArgument
- type PromptContent
- type PromptMessage
- type PromptRenderer
- type Request
- type Resource
- type ResourceReader
- type ResourceTemplate
- type Response
- type Server
- func (s *Server) HandleMessage(w http.ResponseWriter, r *http.Request)
- func (s *Server) HandleSSE(w http.ResponseWriter, r *http.Request)
- func (s *Server) HandleStreamable(w http.ResponseWriter, r *http.Request)
- func (s *Server) PromptCount() int
- func (s *Server) RegisterPrompt(p Prompt)
- func (s *Server) RegisterResource(r Resource)
- func (s *Server) RegisterResourceTemplate(rt ResourceTemplate)
- func (s *Server) RegisterTool(t Tool)
- func (s *Server) ResourceCount() (int, int)
- func (s *Server) SetToolCallGate(g ToolCallGate)
- func (s *Server) ToolCount() int
- type ServerCapabilities
- type ServerInfo
- type Tool
- type ToolCallGate
- type ToolHandler
Constants ¶
const ( ErrParse = -32700 ErrInvalidRequest = -32600 ErrMethodNotFound = -32601 ErrInvalidParams = -32602 ErrInternal = -32603 // ErrRateLimited (v0.9.14) — tools/call kapısının reddi; server- // error bandının tepesi. HTTP 429 yerine JSON-RPC hatası: LLM // tool-use döngüleri bunu sonuç olarak görür, bekleyip yeniden // dener. ErrRateLimited = -32000 )
Error codes — covers JSON-RPC base + MCP-specific.
const ProtocolVersion = "2024-11-05"
ProtocolVersion is what we advertise during initialize. Clients echoing a different version are negotiated against this — if the client's version isn't supported we still reply with ours per the MCP spec: "the server SHOULD respond with its own version" and let the client decide whether to proceed.
const ProtocolVersionStreamable = "2025-03-26"
ProtocolVersionStreamable — Streamable-HTTP transport'unun (v0.9.14) initialize yanıtında bildirdiği sürüm. SSE yolu 2024-11-05'te kalır; iki transport aynı dispatch gövdesini paylaşır, yalnız el-sıkışma sürümü ayrışır.
Variables ¶
This section is empty.
Functions ¶
func ExtractURITemplateValue ¶ added in v0.6.6
ExtractURITemplateValue pulls the placeholder value out of a concrete URI matched against its template. Exported so concrete Reader implementations don't have to re-implement the slicing. Returns "" if the template has no placeholder or the URI doesn't match.
Types ¶
type CapPromptsBag ¶
type CapPromptsBag struct {
ListChanged bool `json:"listChanged,omitempty"`
}
type CapResourcesBag ¶
type CapToolsBag ¶
type CapToolsBag struct {
// ListChanged: server emits notifications/tools/list_changed
// when its tool catalogue mutates. v0.6.4 returns false
// (tools registry is empty + immutable); v0.6.5 flips this
// if we ever support hot-loading tools.
ListChanged bool `json:"listChanged,omitempty"`
}
type ClientInfo ¶
type Error ¶
type Error struct {
Code int `json:"code"`
Message string `json:"message"`
Data json.RawMessage `json:"data,omitempty"`
}
Error follows JSON-RPC 2.0 — standard codes are -32700..-32603, implementation-defined server errors are -32099..-32000. MCP defines its own codes in the same -32xxx space which we hand out below.
type Prompt ¶ added in v0.6.7
type Prompt struct {
Name string
Description string
Arguments []PromptArgument
Renderer PromptRenderer
}
Prompt is a server-curated LLM prompt template. prompts/list surfaces them so the client can show "/coremetry-explain- trace [trace_id]" in its slash-command menu; prompts/get with args runs the Renderer to produce the final messages the client feeds to its model.
Coremetry's prompts close over chstore/logstore so calling "explain_trace" actually fetches the trace data and embeds it into the user message — the LLM doesn't have to make a follow-up tool call before reasoning. This is the same pattern as the in-app "✨ Explain" button, just exposed via MCP for external clients.
type PromptArgument ¶ added in v0.6.7
PromptArgument describes one input slot for prompts/get. Type is always implicitly string in the MCP spec; the description is what gets shown to the user when their client renders the argument form.
type PromptContent ¶ added in v0.6.7
PromptContent is the body of a message. Type is currently always "text" for Coremetry's prompts — image / resource content can layer on later.
type PromptMessage ¶ added in v0.6.7
type PromptMessage struct {
Role string `json:"role"`
Content PromptContent `json:"content"`
}
PromptMessage is one role+content pair the Renderer emits. MCP prompts can return system + user + assistant messages; the client typically replays them as the conversation seed.
type PromptRenderer ¶ added in v0.6.7
PromptRenderer takes the prompts/get arguments and returns the resolved message set. Errors bubble up as JSON-RPC errors. Receives the raw arg map so the renderer picks its own decode.
type Request ¶
type Request struct {
JSONRPC string `json:"jsonrpc"`
ID json.RawMessage `json:"id,omitempty"`
Method string `json:"method"`
Params json.RawMessage `json:"params,omitempty"`
}
Request is the incoming JSON-RPC message. ID is left as RawMessage so we can echo it back verbatim — clients send numbers, strings, or null per spec and we shouldn't coerce.
func (*Request) IsNotification ¶
IsNotification — JSON-RPC spec: a request without an id is a notification, no response expected. notifications/initialized is the canonical example.
type Resource ¶ added in v0.6.6
type Resource struct {
URI string
Name string
Description string
MimeType string
// Reader returns the content for this URI. ctx is the live
// request context; the URI is passed through unchanged so
// the same Reader can serve a template family.
Reader ResourceReader
}
Resource is a named read-only data reference. Where tools are "invoke an action with args", resources are "fetch the current state of <URI>". Browsers in Claude Desktop list resources as pinned references the user can click to attach; LLMs read them via resources/read.
URI scheme is opaque to the protocol — we use coremetry:// for everything Coremetry exposes (services, problems, etc.). MimeType hints how the client renders the read response; "application/json" is standard for our payloads.
type ResourceReader ¶ added in v0.6.6
ResourceReader is the function signature both concrete and templated resources share. uri is the full URI being read. Returns either a text payload or an error; binary blobs can layer on later if needed (image/png, audio, etc.) — the spec supports them via a `blob` field on the content envelope.
type ResourceTemplate ¶ added in v0.6.6
type ResourceTemplate struct {
URITemplate string
Name string
Description string
MimeType string
Reader ResourceReader
}
ResourceTemplate is a URI pattern with {placeholder} segments. LLMs match against the pattern to discover that "coremetry://service/{name}" can be parameterised. The Reader receives the concrete URI; its handler parses out the placeholder values.
type Response ¶
type Response struct {
JSONRPC string `json:"jsonrpc"`
ID json.RawMessage `json:"id,omitempty"`
Result json.RawMessage `json:"result,omitempty"`
Error *Error `json:"error,omitempty"`
}
Response is the outgoing reply. Either Result or Error is set, never both. omitempty on both fields keeps the wire form clean.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the MCP server. One instance per Coremetry process; holds the live session map + the registries that v0.6.5+ will populate.
The handler funcs HandleSSE + HandleMessage are wired onto the existing api.Server mux as /api/mcp/sse and /api/mcp/messages behind the standard auth middleware. Session state is in-memory only; a session is local to the pod the client first connected to. In distributed deploy + multi-replica api, a sticky-session LB rule (or session affinity at the ingress) is required — documented in v0.6.4's CHANGELOG.
func New ¶
New constructs an MCP server with the given serverInfo. Name + version surface in the initialize response — clients (and Claude Desktop's debug UI) display them.
func (*Server) HandleMessage ¶
func (s *Server) HandleMessage(w http.ResponseWriter, r *http.Request)
HandleMessage is the POST side of the transport. Client sends one JSON-RPC request; we respond synchronously via the SSE stream (not in the HTTP response body — per MCP spec, the POST returns 202 Accepted and the response rides the SSE channel).
This split lets the server send notifications + responses to unsolicited events back on the same SSE stream, which is what makes "live tool call" streaming work in v0.6.5+.
func (*Server) HandleSSE ¶
func (s *Server) HandleSSE(w http.ResponseWriter, r *http.Request)
HandleSSE implements the GET side of the HTTP+SSE transport. The first event emitted is an `endpoint` event whose data is the absolute path the client should POST messages to — including the session id query param. All subsequent events are `message` events carrying JSON-RPC responses for requests the client POSTed.
func (*Server) HandleStreamable ¶ added in v0.9.14
func (s *Server) HandleStreamable(w http.ResponseWriter, r *http.Request)
HandleStreamable — Streamable-HTTP transport'u (v0.9.14, MCP spec 2025-03-26), STATELESS kipte: tek POST = tek JSON-RPC isteği, yanıt DOĞRUDAN gövdede (SSE kanalı yok). Session hiç üretilmez (Mcp-Session-Id başlığı dönülmez) — istemci sessionless çalışır. Bu, çok-pod'lu kurulumdaki pod-lokal session kırılganlığını (audit EK BULGU) kökten çözer: her POST bağımsızdır, LB'de hangi pod'a düşerse düşsün. Claude Code'un birincil `--transport http` yolu budur; SSE yolu eski istemciler için aynen kalır.
func (*Server) PromptCount ¶ added in v0.6.7
PromptCount reports how many prompts are registered. Useful in boot logs so the operator can confirm the registry wired up.
func (*Server) RegisterPrompt ¶ added in v0.6.7
RegisterPrompt adds a prompt to the registry. Name uniqueness enforced — duplicate registration logs and overwrites.
func (*Server) RegisterResource ¶ added in v0.6.6
RegisterResource adds a concrete (fixed-URI) resource. URI uniqueness enforced — duplicate registration logs a warning and overwrites.
func (*Server) RegisterResourceTemplate ¶ added in v0.6.6
func (s *Server) RegisterResourceTemplate(rt ResourceTemplate)
RegisterResourceTemplate adds a URI-pattern resource. The pattern uses {placeholder} segments per RFC 6570 level 1 — we match prefix + suffix around each placeholder without pulling in a full URI Template engine. Good enough for the patterns Coremetry exposes (single placeholder near the end).
func (*Server) RegisterTool ¶ added in v0.6.5
RegisterTool adds a tool to the registry. Caller MUST do this before serving requests — there's no list_changed notification yet (tools/list returns a static snapshot). Last writer wins on a duplicate name; we log because that's almost certainly a bug.
func (*Server) ResourceCount ¶ added in v0.6.6
ResourceCount reports the static + template totals so boot logs can confirm registration. Returns (static, templates).
func (*Server) SetToolCallGate ¶ added in v0.9.14
func (s *Server) SetToolCallGate(g ToolCallGate)
SetToolCallGate wires the optional rate-limit gate. Boot'ta bir kez çağrılır (api.SetMCP), sonrasında değişmez.
type ServerCapabilities ¶
type ServerCapabilities struct {
Tools *CapToolsBag `json:"tools,omitempty"`
Resources *CapResourcesBag `json:"resources,omitempty"`
Prompts *CapPromptsBag `json:"prompts,omitempty"`
Logging *struct{} `json:"logging,omitempty"`
}
ServerCapabilities is what we tell the client we support. Each optional bag is "exists or doesn't" semantics — an empty struct signals "feature supported, no sub-features yet". As tools / resources / prompts come online in later releases the corresponding pointer gets non-nil.
v0.6.4 advertises tools/resources/prompts as supported (so clients run their listing dance against us) even though the registries are empty — keeps client codepaths warm and means the v0.6.5+ rollouts don't need a protocol bump.
type ServerInfo ¶
type Tool ¶ added in v0.6.5
type Tool struct {
Name string
Description string
InputSchema map[string]any
Handler ToolHandler
}
Tool is an MCP tool definition. Tools are the LLM's callable surface — discoverable via tools/list, invoked via tools/call. The input schema is a JSON Schema object the client uses to validate args before invocation (and to render a form UI in Claude Desktop / similar inspectors).
The handler receives the raw params JSON as a RawMessage — concrete tool implementations decode into their own typed args struct. Return value is anything json.Marshal-able; the server wraps it in the tools/call response envelope.
Schema example (mirrors JSON Schema draft-2020-12 enough for every MCP client):
InputSchema: map[string]any{
"type": "object",
"properties": map[string]any{
"service": map[string]any{"type": "string"},
"range_ns": map[string]any{"type": "integer", "minimum": 0},
},
"required": []string{"service"},
}
type ToolCallGate ¶ added in v0.9.14
ToolCallGate — tools/call öncesi çağrılır; hata dönerse çağrı JSON-RPC -32000 ile reddedilir (HTTP 429 DEĞİL: istemci kütüphaneleri JSON-RPC hatasını LLM'e tool sonucu olarak gösterir, model bekleyip devam edebilir). initialize/tools/list/prompts kapı dışıdır (ucuz keşif).
type ToolHandler ¶ added in v0.6.5
ToolHandler runs one tools/call invocation. Returns a value the server marshals into the response, OR an error which is converted into a JSON-RPC error with code ErrInternal. The raw args are passed through so the handler picks its own decode (tagged struct, manual map dispatch, etc.).