Minor release. The indexer named composite types but could not describe their shape: every declaration was truncated at the first brace, so a struct symbol carried only its `type X struct` header and an interface symbol only its `type X interface` header. Field names, field types, and — most painfully — struct tags such as `env:"EINHERJAR_PG_HOST"` were dropped, as were the method sets of every port interface. An assistant could be told that `db-postgres` has a `Config` and a `Provider`, but not what env vars configure the one or what methods the other requires. This change captures both. internal/index (schema): - Symbol gains two optional fields. `fields` ([]Field) carries a struct's field set — name, type, raw struct tag (surrounding backticks stripped), doc comment, and an `embedded` marker. `methods` ([]Method) carries an interface's method set — name, signature without the leading `func`, and doc comment, including embedded interfaces. Both are omitempty and absent for every other kind. - SchemaVersion is deliberately unchanged. The two additions are additive and omitempty, so an older consumer parses the new index unchanged; per the existing rule the constant only bumps on a breaking format change. internal/index (builder): - collectSymbols now inspects each type's TypeSpec and, for a *ast.StructType or *ast.InterfaceType, fills the new Symbol members. A grouped field declaration (`x, y int`) yields one Field per name; an embedded field or interface yields an entry with an empty name. - New helpers: typeSpecType (underlying type expr of a lone type spec), extractFields, extractIfaceMethods, fieldDoc (doc comment or trailing line comment), and nodeString — a non-truncating printer used for field types, tags, and method signatures, distinct from formatNode which keeps truncating to produce the one-line header. internal/index (search): - matches() now also tests the query against struct field names, field types, and struct tags, and against interface method names and signatures. A query like an env-var key or a method name now resolves to the type that declares it. internal/tools: - get_symbol and search_symbols descriptions updated to advertise the new struct-field and interface-method coverage. No input/output schema change beyond the additive Symbol fields, which get_symbol already returns whole. internal/index (tests): - New builder_test.go — the package previously had no tests. Builds a temporary module fixture and asserts capture of struct fields (with tags and docs), embedded fields, interface methods (with signatures and docs), embedded interfaces, and discovery of a struct by one of its struct tags (the failure mode that motivated the change). Docs: - CHANGELOG.md gains an [Unreleased] entry; README.md tool table updated to state that get_symbol returns struct fields and interface methods and that search_symbols matches fields, tags, and methods. No new dependencies. The committed data/index.json placeholder is untouched — the index is regenerated at image build (Dockerfile runs cmd/indexer), so a deployment must be rebuilt to serve the richer index; a server still running the prior image keeps serving the older, member-less one. Reviewed-on: #1 Co-authored-by: Rene Nochebuena Guerrero <rene@nochebuena.dev> Co-committed-by: Rene Nochebuena Guerrero <rene@nochebuena.dev>
43 lines
1.5 KiB
Go
43 lines
1.5 KiB
Go
package tools
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"code.nochebuena.dev/einherjar/mcp/internal/index"
|
|
"github.com/modelcontextprotocol/go-sdk/mcp"
|
|
)
|
|
|
|
type getSymbolInput struct {
|
|
Module string `json:"module" jsonschema:"the module name, e.g. core"`
|
|
Name string `json:"name" jsonschema:"the symbol name; for methods use Type.Method"`
|
|
SubPackage string `json:"subPackage,omitempty" jsonschema:"narrow to a specific sub-package, e.g. launcher"`
|
|
}
|
|
|
|
type getSymbolOutput struct {
|
|
Matches []index.Symbol `json:"matches"`
|
|
}
|
|
|
|
func registerGetSymbol(s *mcp.Server, idx *index.Index) {
|
|
mcp.AddTool(s, &mcp.Tool{
|
|
Name: "get_symbol",
|
|
Description: "Fetch full signature, doc comment, and source location for one symbol. For a struct type the result includes its fields (name, type, struct tag, doc); for an interface type it includes its method set. Returns every match across sub-packages — use the subPackage filter when ambiguous.",
|
|
}, func(ctx context.Context, req *mcp.CallToolRequest, args getSymbolInput) (*mcp.CallToolResult, getSymbolOutput, error) {
|
|
m := idx.FindModule(args.Module)
|
|
if m == nil {
|
|
return errorResult("module not found: " + args.Module), getSymbolOutput{}, nil
|
|
}
|
|
out := getSymbolOutput{Matches: []index.Symbol{}}
|
|
for _, sym := range m.Symbols {
|
|
if !strings.EqualFold(sym.Name, args.Name) {
|
|
continue
|
|
}
|
|
if args.SubPackage != "" && sym.SubPackage != args.SubPackage {
|
|
continue
|
|
}
|
|
out.Matches = append(out.Matches, sym)
|
|
}
|
|
return jsonText(out), out, nil
|
|
})
|
|
}
|