mcp

package
v0.5.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 8, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package mcp exposes osctrl's read surface to Model Context Protocol clients, so an LLM agent can inspect a fleet — nodes, environments, query results, and the osquery schema — without being handed the raw REST API.

The tool set here is deliberately read-only. Nothing in this package schedules a query, mutates a node, or touches user or service configuration; write tools are gated behind a separate opt-in and are not part of this package yet.

Authorization

This package performs no authorization of its own. Every call goes through a Backend, and the only Backend today is *apiclient.OsctrlAPI talking to osctrl-api with a user's Bearer token — so osctrl-api's existing per-environment RBAC is what actually constrains the agent. A token that cannot see an environment gets the same empty results an operator with that token would get. Give the MCP server a service user scoped to exactly what the agent should read.

Untrusted content

Hostnames, process names, file paths, and query result rows originate on monitored endpoints, which are precisely the machines an attacker might control. Everything this package returns is data, never instructions. Tool descriptions say so explicitly, because that text is what the model actually reads.

Index

Constants

View Source
const ServerName = "osctrl"

ServerName is what MCP clients see in the initialize handshake.

Variables

This section is empty.

Functions

func NewServer

func NewServer(b Backend, version string, opts ...Option) *sdk.Server

NewServer builds the osctrl MCP server. Read-only unless WithWrites is passed. version is reported in the initialize handshake — pass the build version so operators can correlate an agent session with a release.

The returned server is not yet listening; call Run with a transport.

Types

type Backend

type Backend interface {
	GetEnvironments() ([]environments.TLSEnvironment, error)
	GetStats() (apiclient.StatsResponse, error)

	GetNodes(env, target string) ([]nodes.OsqueryNode, error)
	GetNode(env, identifier string) (nodes.OsqueryNode, error)
	GetNodePosture(env, uuid string) ([]posture.NodePosture, error)
	GetNodePostureScore(env, uuid string) (posture.PostureScore, error)

	GetOsqueryTables() ([]types.OsqueryTable, error)

	GetQueries(target, env string) ([]queries.DistributedQuery, error)
	GetQueryResults(env, name string, page, pageSize int) (types.QueryResultsResponse, error)
	GetSavedQueries(env string) ([]types.SavedQueryView, error)
}

Backend is the slice of osctrl the MCP tools need.

Narrow on purpose. *apiclient.OsctrlAPI satisfies it as-is, and keeping the surface this small means the tools can be tested against a fake without an HTTP server — and lets a future in-process implementation (MCP mounted inside osctrl-api) skip the network hop without touching any tool code.

type EnvironmentStats

type EnvironmentStats struct {
	Name          string `json:"name"`
	TotalNodes    int64  `json:"total_nodes"`
	ActiveNodes   int64  `json:"active_nodes"`
	InactiveNodes int64  `json:"inactive_nodes"`
	Linux         int64  `json:"linux"`
	Darwin        int64  `json:"darwin"`
	Windows       int64  `json:"windows"`
	Other         int64  `json:"other"`
}

EnvironmentStats is the per-environment row of fleet_stats.

type EnvironmentSummary

type EnvironmentSummary struct {
	UUID     string `json:"uuid"`
	Name     string `json:"name"`
	Hostname string `json:"hostname"`
	Type     string `json:"type"`
}

EnvironmentSummary is the projection of environments.TLSEnvironment that tools return.

The projection is a security boundary, not a formatting nicety: TLSEnvironment carries Secret, EnrollSecretPath, RemoveSecretPath and Certificate. Returning the struct as-is would put live enrollment secrets into an LLM context window — and, from there, into whatever transcript store the client keeps. Add fields here deliberately.

type NodeDetail

type NodeDetail struct {
	NodeSummary
	Localname      string    `json:"localname"`
	Username       string    `json:"username"`
	OsqueryUser    string    `json:"osquery_user"`
	CPU            string    `json:"cpu"`
	Memory         string    `json:"memory"`
	HardwareSerial string    `json:"hardware_serial"`
	ConfigHash     string    `json:"config_hash"`
	DaemonHash     string    `json:"daemon_hash"`
	BytesReceived  int       `json:"bytes_received"`
	FirstSeen      time.Time `json:"first_seen"`
}

NodeDetail extends NodeSummary with the fields worth a second call.

type NodePosture

type NodePosture struct {
	TotalScore int      `json:"total_score"`
	RiskLevel  string   `json:"risk_level"`
	PassCount  int      `json:"pass_count"`
	WarnCount  int      `json:"warn_count"`
	FailCount  int      `json:"fail_count"`
	Categories []string `json:"categories"`
}

NodePosture is the posture projection returned when include_posture is set.

type NodeSummary

type NodeSummary struct {
	UUID            string    `json:"uuid"`
	Hostname        string    `json:"hostname"`
	Platform        string    `json:"platform"`
	PlatformVersion string    `json:"platform_version"`
	OsqueryVersion  string    `json:"osquery_version"`
	IPAddress       string    `json:"ip_address"`
	Environment     string    `json:"environment"`
	LastSeen        time.Time `json:"last_seen"`
}

NodeSummary is the compact node projection used by search_nodes.

type Option

type Option func(*options)

Option configures the server built by NewServer.

func WithWrites

func WithWrites(w WriteBackend) Option

WithWrites registers the mutating tools, backed by w.

Opt-in by construction: NewServer without this returns a read-only server, so no configuration mistake or refactor can quietly hand an agent the ability to schedule queries. Callers gate it on an explicit operator setting.

type QuerySummary

type QuerySummary struct {
	Name       string    `json:"name"`
	Query      string    `json:"query"`
	Creator    string    `json:"creator"`
	Executions int       `json:"executions"`
	Errors     int       `json:"errors"`
	Expected   int       `json:"expected"`
	Active     bool      `json:"active"`
	Completed  bool      `json:"completed"`
	Expired    bool      `json:"expired"`
	CreatedAt  time.Time `json:"created_at"`
}

QuerySummary is the projection of a distributed query.

type SavedQuerySummary

type SavedQuerySummary struct {
	Name  string `json:"name"`
	Query string `json:"query"`
}

SavedQuerySummary is the projection of a saved (reusable) query.

type TableColumn

type TableColumn struct {
	Name        string `json:"name"`
	Type        string `json:"type"`
	Description string `json:"description"`
	// Required marks a column osquery will not scan without: a query that
	// omits it in the WHERE clause returns zero rows rather than an error.
	Required bool `json:"required"`
	Index    bool `json:"index"`
	Hidden   bool `json:"hidden"`
}

TableColumn describes one column of an osquery table.

type TableSummary

type TableSummary struct {
	Name        string   `json:"name"`
	Description string   `json:"description"`
	Platforms   []string `json:"platforms"`
	Evented     bool     `json:"evented"`
}

TableSummary is one row of list_osquery_tables — enough to pick a table, not enough to write a query. get_table_schema supplies the columns.

type WriteBackend

type WriteBackend interface {
	RunQuery(env, query string, uuids, hosts, platforms, tags []string, hidden bool, exp int) (types.ApiQueriesResponse, error)
	ExpireQuery(env, name string) (types.ApiGenericResponse, error)
	CompleteQuery(env, name string) (types.ApiGenericResponse, error)
	TagNode(env, identifier, tag string, tagType uint, custom string) error
}

WriteBackend is the mutating slice of osctrl, kept separate from Backend so the write tools cannot be registered by accident: NewServer takes a Backend and stays read-only unless a caller also passes WithWrites.

As with Backend, nothing here performs authorization. RunQuery needs QueryLevel on the environment (and CarveLevel too if the SQL touches carves); TagNode needs AdminLevel. Those checks belong to osctrl-api.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL