Documentation
¶
Overview ¶
Package tool defines the DML tool components and their registry. Each tool implements the Tool interface; Enabled(flags) decides whether it is registered with the MCP server (invariant I8). CostGated marks tools whose execution must pass the cost gate (invariant I4). Tools construct relalg.IR, which codegen renders; they never build SQL by hand, keeping queries inject-proof.
Index ¶
- Constants
- Variables
- func DecisionIDFromContext(ctx context.Context) string
- func NewDecisionID() string
- func ProcedureToolName(entityName string) string
- func VisibleKeys(e entity.Entity, visible []string) [][]string
- func WithDecisionID(ctx context.Context, id string) context.Context
- func WrapDBError(err error) error
- type AggregateTool
- type AmbiguousFieldScopeError
- type BeginTransactionTool
- type CacheTarget
- type CommitTransactionTool
- type ConstraintViolationError
- type Context
- type CostGated
- type CreateTool
- type DataSource
- type DeleteTool
- type Denial
- type DescribeTool
- type ExecuteTool
- type Info
- type Limits
- type ProcedureTool
- type ReadTool
- type Registry
- type Result
- type RollbackTransactionTool
- type Tool
- type TransactionManager
- func (m *TransactionManager) Begin(ctx context.Context, beginner store.TxBeginner, session, role string, ...) (string, error)
- func (m *TransactionManager) Close()
- func (m *TransactionManager) Commit(ctx context.Context, token, session, role string, subject map[string]any) ([]CacheTarget, error)
- func (m *TransactionManager) Configuration() (time.Duration, int)
- func (m *TransactionManager) DB(token, session, role string, subject map[string]any, datasource string) (store.DB, error)
- func (m *TransactionManager) MarkDirty(token, session, role string, subject map[string]any, datasource string, ...) error
- func (m *TransactionManager) Rollback(ctx context.Context, token, session, role string, subject map[string]any) error
- func (m *TransactionManager) RollbackSession(session string)
- func (m *TransactionManager) Validate(token, session, role string, subject map[string]any) error
- type UpdateTool
- type WriteTracker
Constants ¶
const ( CodeEntityNotFound = "ENTITY_NOT_FOUND" CodeInvalidInput = "INVALID_INPUT" CodeDMLToolsDisabled = "DML_TOOLS_DISABLED" CodeUnsafeWrite = "UNSAFE_WRITE" CodeDatabaseError = "DATABASE_ERROR" CodeCostExceeded = "COST_EXCEEDED" CodeBudgetExceeded = "BUDGET_EXCEEDED" CodeTransactionNotFound = "TRANSACTION_NOT_FOUND" CodeTransactionScope = "TRANSACTION_SCOPE" CodeTransactionCapacity = "TRANSACTION_CAPACITY" CodeAmbiguousFieldScope = "AMBIGUOUS_FIELD_SCOPE" CodeConstraintViolation = "CONSTRAINT_VIOLATION" CodeDatasourceForbidden = "DATASOURCE_FORBIDDEN" )
Stable machine codes for business-level rejections. Retryable means a revised request could succeed under the caller's current privileges; hints may only tighten or equivalently rewrite the request, never widen it.
Variables ¶
var ( // ErrEntityNotFound is returned when the requested entity is unknown. ErrEntityNotFound = errors.New("tool: entity not found") ErrUnauthorized = errors.New("tool: unauthorized") // ErrInvalidInput is returned for malformed tool input. ErrInvalidInput = errors.New("tool: invalid input") // ErrDMLToolsDisabled is returned when an entity is not exposed to the // generic entity tools. ErrDMLToolsDisabled = errors.New("tool: entity DML tools disabled") // ErrUnsafeWrite is returned when an update/delete lacks a PK-scoped filter. ErrUnsafeWrite = errors.New("tool: unsafe write without primary-key filter") // ErrDuplicateTool is returned by NewRegistry for duplicate tool names. ErrDuplicateTool = errors.New("tool: duplicate name") // ErrDatabase identifies errors returned by the database driver. ErrDatabase = errors.New("tool: database error") // ErrConstraintViolation is a write rejected by a database constraint. ErrConstraintViolation = errors.New("tool: constraint violation") // ErrDatasourceForbidden is a statement the datasource's account may not // run: a missing database privilege or a read-only server. ErrDatasourceForbidden = errors.New("tool: the datasource connection is not permitted to do this") )
Sentinel errors. Business errors (Unauthorized/NotFound/UnsafeWrite/Cost) are mapped by x/mcpserver to IsError results; protocol errors to JSON-RPC.
Functions ¶
func DecisionIDFromContext ¶ added in v0.1.5
DecisionIDFromContext returns the decision ID attached by RunTool, or "".
func NewDecisionID ¶ added in v0.1.5
func NewDecisionID() string
NewDecisionID returns a 128-bit random identifier correlating one tool call's MCP response, audit event, and trace span.
func ProcedureToolName ¶
ProcedureToolName returns a stable MCP-safe name. The prefix separates procedure tools from built-ins; the hash prevents normalization collisions.
func VisibleKeys ¶ added in v0.1.11
VisibleKeys lists the entity's identity keys whose every column is among visible, the fields a caller can use to address one row.
func WithDecisionID ¶ added in v0.1.5
WithDecisionID attaches a decision ID to ctx for hooks and telemetry.
func WrapDBError ¶
WrapDBError classifies a database driver error while preserving its cause: a refused privilege becomes ErrDatasourceForbidden, anything else ErrDatabase. Neither reports the driver message to clients.
Types ¶
type AggregateTool ¶
type AggregateTool struct{}
AggregateTool runs an aggregate query (cost-gated).
func (AggregateTool) CostGated ¶
func (AggregateTool) CostGated()
func (AggregateTool) Info ¶
func (AggregateTool) Info() Info
func (AggregateTool) Run ¶
func (AggregateTool) Run(ctx context.Context, input json.RawMessage, tc Context) (Result, error)
type AmbiguousFieldScopeError ¶ added in v0.1.11
AmbiguousFieldScopeError reports that no single grant covers every field a request uses. FieldScopes are field sets the caller can already read, so exposing them is not a side channel. It unwraps to ErrUnauthorized.
func (*AmbiguousFieldScopeError) Error ¶ added in v0.1.11
func (e *AmbiguousFieldScopeError) Error() string
func (*AmbiguousFieldScopeError) Unwrap ¶ added in v0.1.11
func (e *AmbiguousFieldScopeError) Unwrap() error
type BeginTransactionTool ¶
type BeginTransactionTool struct{}
func (BeginTransactionTool) Info ¶
func (BeginTransactionTool) Info() Info
func (BeginTransactionTool) Run ¶
func (BeginTransactionTool) Run(ctx context.Context, input json.RawMessage, tc Context) (Result, error)
type CacheTarget ¶ added in v0.1.11
CacheTarget names the cached reads a write invalidates: Relation of Database, or all of Database when Relation is empty (see cache.Cache).
type CommitTransactionTool ¶
type CommitTransactionTool struct{}
func (CommitTransactionTool) Enabled ¶
func (CommitTransactionTool) Enabled(f config.ToolFlags) bool
func (CommitTransactionTool) Info ¶
func (CommitTransactionTool) Info() Info
func (CommitTransactionTool) Run ¶
func (CommitTransactionTool) Run(ctx context.Context, input json.RawMessage, tc Context) (Result, error)
type ConstraintViolationError ¶ added in v0.1.11
ConstraintViolationError reports a write the database rejected for violating a constraint. Fields lists the violating columns the caller may see; the constraint name and the database message are never included.
func (*ConstraintViolationError) Error ¶ added in v0.1.11
func (e *ConstraintViolationError) Error() string
func (*ConstraintViolationError) Unwrap ¶ added in v0.1.11
func (e *ConstraintViolationError) Unwrap() error
type Context ¶
type Context struct {
Role string // principal key: a role name, or "user:<name>" for a user
User string // configured user name, empty on the role path
UserRoles []string // the user's roles, for audit
Subject map[string]any // caller attributes for row-level ${subject.x} policies
Session string // MCP session ID when the transport provides one
DecisionID string // per-call ID correlating response, audit, and trace
DB store.DB
Dialect dialect.Dialect
Registry *entity.Registry
Authorizer rbac.Authorizer
Masker mask.Masker
Gate cost.Gate
Cache cache.Cache[[]map[string]any]
Engine *engine.Engine
Auditor audit.Auditor
Hooks *hook.Hooks
Limits
Feedback cost.FeedbackStore
Analyze cost.AnalyzePolicy
DataSource string
Sources map[string]DataSource
Budget budget.Manager
BudgetLimits budget.Limits
Transactions *TransactionManager
Writes *WriteTracker
TxBeginners map[string]store.TxBeginner
Transaction string
// contains filtered or unexported fields
}
Context carries per-request dependencies (injected, no mutable global state).
type CostGated ¶
type CostGated interface {
Tool
CostGated()
}
CostGated marks a tool whose execution must pass the cost gate.
type CreateTool ¶
type CreateTool struct{}
CreateTool inserts one record.
func (CreateTool) Info ¶
func (CreateTool) Info() Info
func (CreateTool) Run ¶
func (CreateTool) Run(ctx context.Context, input json.RawMessage, tc Context) (Result, error)
type DataSource ¶
type DataSource struct {
DB store.DB
Write store.DB
Execute store.DB
ReadTx store.TxBeginner
ReadAfterWrite time.Duration
Dialect dialect.Dialect
Gate cost.Gate
Analyze cost.AnalyzePolicy
}
DataSource is the per-entity execution route: DB is the read connection; Write and Execute, when set, serve writes and procedure calls (see connectionFor), and ReadTx begins read-only transactions.
type DeleteTool ¶
type DeleteTool struct{}
DeleteTool deletes records (cost-gated, off by default).
func (DeleteTool) CostGated ¶
func (DeleteTool) CostGated()
func (DeleteTool) Info ¶
func (DeleteTool) Info() Info
func (DeleteTool) Run ¶
func (DeleteTool) Run(ctx context.Context, input json.RawMessage, tc Context) (Result, error)
type Denial ¶ added in v0.1.5
type Denial struct {
Code string `json:"code"`
Reason string `json:"reason"`
Retryable bool `json:"retryable"`
Constraints map[string]any `json:"constraints,omitempty"`
Hints []string `json:"hints,omitempty"`
DecisionID string `json:"decisionId"`
}
Denial is the stable, machine-readable rejection contract returned to MCP clients for business-level errors. Field names and code values are part of the public tool contract: adding a new optional field or a new code is a compatible change; renaming or removing either is breaking.
type DescribeTool ¶
type DescribeTool struct{}
DescribeTool lists entities or one entity's fields.
func (DescribeTool) Enabled ¶
func (DescribeTool) Enabled(f config.ToolFlags) bool
Enabled implements Tool.
func (DescribeTool) Run ¶
func (DescribeTool) Run(ctx context.Context, input json.RawMessage, tc Context) (Result, error)
Run implements Tool.
type ExecuteTool ¶
type ExecuteTool struct{}
ExecuteTool calls a stored procedure.
func (ExecuteTool) CostGated ¶
func (ExecuteTool) CostGated()
func (ExecuteTool) Info ¶
func (ExecuteTool) Info() Info
func (ExecuteTool) Run ¶
func (ExecuteTool) Run(ctx context.Context, input json.RawMessage, tc Context) (Result, error)
type Info ¶
type Info struct {
Name string
Description string
InputSchema json.RawMessage
ReadOnly bool
// Action is the audited action; read, aggregate and execute also size the
// budget reservation.
Action string
}
Info is a tool's static metadata, mapped to an MCP tool definition.
type Limits ¶ added in v0.1.11
type Limits struct {
Timeout time.Duration
MaxRows int64
MaxProcedureRows int64
MaxReturnedBytes int64
MaxINListSize int
MaxFilterConditions int
MaxGroupByFields int
MaxAggregates int
MaxExpand int
CacheMaxEntryRows int
CacheMaxEntryBytes int64
TransactionBeginTimeout time.Duration
TransactionCommitTimeout time.Duration
TransactionRollbackTimeout time.Duration
}
Limits are the configured per-call limits; zero means unlimited (or, for the transaction timeouts, the query Timeout).
type ProcedureTool ¶
ProcedureTool exposes one configured procedure as an independent MCP tool. It accepts the procedure parameters directly and delegates execution to the same implementation as execute_entity.
func FindProcedureTool ¶ added in v0.1.11
func FindProcedureTool(reg *entity.Registry, name string) (ProcedureTool, bool)
FindProcedureTool returns the exposed procedure tool named name.
func ProcedureTools ¶ added in v0.1.11
func ProcedureTools(reg *entity.Registry) []ProcedureTool
ProcedureTools returns the procedures exposed as their own tools: trusted procedures configured with a custom tool.
func (ProcedureTool) CostGated ¶
func (ProcedureTool) CostGated()
func (ProcedureTool) Enabled ¶
func (ProcedureTool) Enabled(config.ToolFlags) bool
Enabled implements Tool. Procedure tools are registered independently of the generic tool flags.
func (ProcedureTool) Run ¶
func (t ProcedureTool) Run(ctx context.Context, input json.RawMessage, tc Context) (Result, error)
Run implements Tool.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry holds an immutable set of tools.
func NewRegistry ¶
NewRegistry builds a Registry, rejecting duplicate tool names.
type Result ¶
type Result struct {
Content []map[string]any
ReturnedRows int64
ReturnedBytes int64
EstimatedScannedRows int64
// Grants lists covering grant IDs for audit; it is not sent to clients.
Grants []string
}
Result is a tool's outcome: the rows returned to the agent plus usage for budgets and audit.
func RunTool ¶
RunTool executes a tool with the cross-cutting wiring that must apply to every call regardless of transport: lifecycle hooks, bounded concurrency + backpressure + circuit breaking + (for read-only tools) singleflight via the engine, and best-effort audit. Transports (x/mcpserver) call this instead of Tool.Run directly, keeping the wiring in the core where it is unit-testable. A nil Engine/Auditor/Hooks each degrade to a no-op.
type RollbackTransactionTool ¶
type RollbackTransactionTool struct{}
func (RollbackTransactionTool) Enabled ¶
func (RollbackTransactionTool) Enabled(f config.ToolFlags) bool
func (RollbackTransactionTool) Info ¶
func (RollbackTransactionTool) Info() Info
func (RollbackTransactionTool) Run ¶
func (RollbackTransactionTool) Run(ctx context.Context, input json.RawMessage, tc Context) (Result, error)
type Tool ¶
type Tool interface {
Info() Info
Enabled(flags config.ToolFlags) bool
Run(ctx context.Context, input json.RawMessage, tc Context) (Result, error)
}
Tool is a single DML capability.
func DefaultTools ¶
func DefaultTools() []Tool
DefaultTools returns the entity and explicit transaction tool instances.
type TransactionManager ¶
type TransactionManager struct {
// contains filtered or unexported fields
}
TransactionManager owns bounded, expiring explicit transaction handles. Tokens are unguessable and additionally bound to role, subject, and source.
func NewTransactionManager ¶
func NewTransactionManager(ttl time.Duration, maxOpen int) *TransactionManager
func (*TransactionManager) Close ¶
func (m *TransactionManager) Close()
func (*TransactionManager) Commit ¶
func (m *TransactionManager) Commit( ctx context.Context, token, session, role string, subject map[string]any, ) ([]CacheTarget, error)
Commit commits and returns the cache targets the transaction wrote. The list is returned only after a successful commit so callers can invalidate global read caches without rollback pollution.
func (*TransactionManager) Configuration ¶
func (m *TransactionManager) Configuration() (time.Duration, int)
Configuration returns the immutable limits used by this manager.
func (*TransactionManager) MarkDirty ¶
func (m *TransactionManager) MarkDirty( token, session, role string, subject map[string]any, datasource string, targets ...CacheTarget, ) error
MarkDirty records the cache targets a write inside a transaction changed.
func (*TransactionManager) Rollback ¶
func (m *TransactionManager) Rollback(ctx context.Context, token, session, role string, subject map[string]any) error
Rollback rolls back the transaction.
func (*TransactionManager) RollbackSession ¶
func (m *TransactionManager) RollbackSession(session string)
RollbackSession rolls back all handles owned by a disconnected non-empty transport session. Token-only transports use TTL and App.Close instead.
type UpdateTool ¶
type UpdateTool struct{}
UpdateTool updates records (cost-gated).
func (UpdateTool) CostGated ¶
func (UpdateTool) CostGated()
func (UpdateTool) Info ¶
func (UpdateTool) Info() Info
func (UpdateTool) Run ¶
func (UpdateTool) Run(ctx context.Context, input json.RawMessage, tc Context) (Result, error)
type WriteTracker ¶ added in v0.1.11
type WriteTracker struct {
// contains filtered or unexported fields
}
WriteTracker remembers when each session last wrote to each datasource, so its reads can follow its writes for a datasource's readAfterWrite window. A nil tracker records nothing.
func NewWriteTracker ¶ added in v0.1.11
func NewWriteTracker() *WriteTracker
NewWriteTracker returns an empty tracker.
func (*WriteTracker) Forget ¶ added in v0.1.11
func (w *WriteTracker) Forget(session string)
Forget drops a closed session.
func (*WriteTracker) Recent ¶ added in v0.1.11
func (w *WriteTracker) Recent(session, datasource string, window time.Duration) bool
Recent reports whether session wrote to datasource within window.
func (*WriteTracker) Record ¶ added in v0.1.11
func (w *WriteTracker) Record(session, datasource string)
Record notes a write by session to datasource.
func (*WriteTracker) Wrote ¶ added in v0.1.11
func (w *WriteTracker) Wrote(session string) bool
Wrote reports whether session wrote anything recently enough to be remembered.
Source Files
¶
- cascade.go
- denial.go
- doc.go
- invalidation.go
- routing.go
- schema.go
- tool.go
- tool_audit.go
- tool_input.go
- tool_registry.go
- tools.go
- tools_aggregate.go
- tools_aggregate_impl.go
- tools_describe.go
- tools_describe_impl.go
- tools_execute.go
- tools_execute_impl.go
- tools_helpers.go
- tools_read.go
- tools_read_impl.go
- tools_write.go
- tools_write_impl.go
- transaction.go