mcp connection
Some checks failed
CI / fixture (push) Has been cancelled
CI / test (push) Has been cancelled

This commit is contained in:
2026-09-22 10:58:02 +05:30
parent 4e1f746b22
commit f2aa3b3ad8
53 changed files with 12515 additions and 37 deletions

View File

@@ -409,18 +409,42 @@ func (r *Registry) DispatchApproved(ctx context.Context, tc Context, token strin
}, true
}
// ToolInfo is what a tool looks like to somebody choosing one, rather than to
// the model calling it.
// ToolInfo is what a tool looks like to somebody choosing one, and — since the
// MCP surface — to a client that must publish the schema before calling it.
//
// The InputSchema is deliberately absent: an author picks a capability, and the
// schema is the model's business. Effect is present because it is the one thing
// an author must understand — a write tool means their agent can propose
// changes, which a person will then be asked to approve.
// Effect is present because it is the one thing an author must understand: a
// write tool means their agent can propose changes, which a person will then be
// asked to approve.
//
// InputSchema used to be deliberately absent, on the reasoning that an author
// picks a capability and the schema is the model's business. That is still true
// of the authoring UI, which simply ignores the field. It stopped being true of
// the catalogue as a whole once a second consumer appeared: MCP's tools/list
// must publish a JSON Schema per tool, and the only alternative to carrying
// this one is maintaining a copy. A copy is a second definition of the same
// thing, and the way it fails is silent — a field renamed on the handler side
// leaves a schema that still validates and no longer matches, so the call
// succeeds and the argument is quietly ignored.
//
// Both new fields carry `omitempty`, but be clear about what that does and does
// not buy: every currently registered tool declares a schema and a byte cap, so
// GET /api/v1/tools genuinely does get larger — roughly 700 bytes per tool. The
// change is additive rather than invisible. It is compatible because JSON
// consumers ignore keys they do not read, and the one consumer that exists (the
// agent editor's tool picker) reads name, description and effect; `omitempty`
// covers the remaining case of a tool registered with neither field.
type ToolInfo struct {
Name string `json:"name"`
Description string `json:"description"`
Effect string `json:"effect"`
RequiresConfirmation bool `json:"requiresConfirmation"`
// InputSchema is the tool's JSON Schema, exactly as registered.
InputSchema map[string]any `json:"inputSchema,omitempty"`
// MaxResultBytes is the cap Dispatch truncates at, so a caller can state
// the limit rather than discover it by hitting it.
MaxResultBytes int `json:"maxResultBytes,omitempty"`
}
// Catalogue lists every registered tool, sorted, as choosable metadata.
@@ -440,6 +464,8 @@ func (r *Registry) Catalogue() []ToolInfo {
Description: t.Description,
Effect: string(t.Effect),
RequiresConfirmation: t.RequiresConfirmation,
InputSchema: t.InputSchema,
MaxResultBytes: t.MaxResultBytes,
})
}
sort.Slice(out, func(i, j int) bool { return out[i].Name < out[j].Name })