Skip to content

feat(mcp): add SSE transport, tools command, and multi-client install support#102

Merged
moshloop merged 16 commits into
mainfrom
pr/mcp-improvements
May 27, 2026
Merged

feat(mcp): add SSE transport, tools command, and multi-client install support#102
moshloop merged 16 commits into
mainfrom
pr/mcp-improvements

Conversation

@moshloop
Copy link
Copy Markdown
Member

@moshloop moshloop commented May 5, 2026

Summary by CodeRabbit

  • New Features

    • Custom actions can accept an optional positional ID.
    • CLI now renders richer error types through the standard output formatting pipeline.
  • Bug Fixes

    • Warning task status now terminates tasks and freezes end time.
  • Improvements

    • OpenAPI generation is configurable and avoids redundant list subcommands.
    • Server exposes handlers to mount OpenAPI, entities, and health endpoints.
  • Documentation

    • README rewritten into a shorter, focused introduction with usage examples.
  • Tests

    • Added tests for rich-error detection, optional-ID actions, and terminal task status.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9e47f03e-5546-4320-b9c6-7902df16bb4c

📥 Commits

Reviewing files that changed from the base of the PR and between b9f1a94 and 419452b.

⛔ Files ignored due to path filters (1)
  • examples/go.sum is excluded by !**/*.sum
📒 Files selected for processing (2)
  • README.md
  • examples/go.mod

Walkthrough

This PR enhances command error handling with rich error rendering, adds optional positional ID arguments for entity actions with round-trippable flag serialization, treats task warning status as terminal, improves RPC entity-root handling to avoid duplicate endpoints, enables config-driven OpenAPI generation, and exposes SwaggerServer public methods for external HTTP mux composition. Dependency versions are also updated across the main and indirect require blocks.

Changes

Command Error Handling and Entity Action Improvements

Layer / File(s) Summary
Renderable error detection and format-driven rendering
cobra_command.go, cobra_command_test.go
New renderableError helper walks error unwrap chains to detect renderable values; AddNamedCommand runner routes matched errors through Flags.ParseFormatSpec -> PrintAndWriteSinks; non-renderable errors use structured logging with skip-report level.
Entity actions with optional ID and flag serialization
entity.go, entity_filters_test.go
Adds flagMapValue to serialize pflag slice values as CSV for round-tripping; introduces ActionInfo.OptionalID and actionSpec.WithOptionalID() so actions can accept an optional positional id; command generation code updated to honor optional-id and use flagMapValue across list, ID-based, body, bulk-action, and filter flows.

Task Status and RPC/OpenAPI

Layer / File(s) Summary
Terminal state handling for task warnings
task/task.go, task/task_status_test.go
Task.SetStatus treats StatusWarning as terminal (sets endTime, cancels context); adds test asserting endTime frozen and stable durations after terminal transition.
Entity-root command handling
rpc/converter.go
shouldConvertCommand skips redundant entity "list" subcommands when parent is runnable and marked as an entity-root; inferHTTPMethod returns GET for entity-root commands lacking a verb to avoid POST collisions.
Config-driven OpenAPI generation
rpc/openapi.go
Adds GenerateFromCobraWithConfig accepting an optional *Config (nil -> DefaultConfig()); existing GenerateFromCobra delegates to it for compatibility.
SwaggerServer public composition methods
rpc/serve.go
SwaggerServer stores a converterCfg derived from executor PathPrefix and exposes HandleOpenAPIJSON, HandleOpenAPIYAML, HandleEntities, HandleHealth, ConverterConfig(), and RegisterExecutionRoutes(); JSON/YAML handlers use the stored config.

Documentation and Dependencies

Layer / File(s) Summary
README and examples
README.md, examples/go.mod
README rewritten to a concise introduction, usage snippets, schema example, package map, and condensed dev instructions; examples/go.mod bumps many indirect pins.
Module dependency version upgrades
go.mod
Main require adds github.com/fatih/color and bumps multiple direct deps and golang.org/x/*; indirect require block updated for AWS SDK v2, OpenTelemetry, Google genproto, Kubernetes modules, and various utility libraries.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is completely empty; no content was provided by the author. The template requires a brief description, type of change selection, testing confirmation, and checklist items, none of which are present. Add a detailed PR description following the provided template, including a brief summary of changes, type of change, testing status, and completion of the provided checklist items.
Docstring Coverage ⚠️ Warning Docstring coverage is 43.62% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The PR title describes SSE transport, tools command, and multi-client install support for MCP, which aligns with the file changes shown in the summary (mcp/ files modified, cobra_command.go, entity.go, rpc/ files, and others supporting infrastructure).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pr/mcp-improvements
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch pr/mcp-improvements

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (1)
api/code_test.go (1)

272-285: ⚡ Quick win

Tighten this test to actually exercise the fallback path.

This assertion set can pass even when XML formatting succeeds, so it doesn’t prove panic/failed-format recovery. Consider validating formatXMLBestEffort with an input that deterministically hits fallback (or rename the test to avoid panic-specific semantics).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/code_test.go` around lines 272 - 285, The test currently can pass even
when XML formatting succeeds; update it to deterministically exercise the
fallback path by either (A) calling formatXMLBestEffort directly with a crafted
input that will trigger the fallback (e.g., an input that the XML formatter will
fail on or that you special-case in formatXMLBestEffort for tests) and asserting
it returns the original unformatted string, then verify Code.HTML() uses Chroma
highlighting for that content, or (B) rename the test to remove "PanicFallsBack"
if you don't want to assert fallback behavior; reference the existing
TestCodeHTML_XMLFormatterPanicFallsBackToHighlightedContent, Code.HTML(), and
formatXMLBestEffort when making the change so the test deterministically
verifies the fallback path (or is renamed to match its assertions).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cobra_command.go`:
- Around line 291-293: The renderableError routine currently only follows the
single-error chain via errors.Unwrap(e) and thus misses causes inside
multi-error joins; update renderableError to detect and traverse both single
Unwrap() error and multi Unwrap() []error cases (or replace the loop with an
errors.As-style search) so api.TryTypedValue targets are found in joined
errors—specifically, modify the loop that checks api.TryTypedValue(e) to also,
when present, call Unwrap() []error and recursively inspect each child (or use
errors.As against the concrete type that TryTypedValue expects) to ensure all
renderable causes are discovered.

In `@examples/uber_demo/main.go`:
- Around line 1304-1313: showStackTrace reuses headersOnlyOpts (which includes
clicky.WithStackInclude("com.example.")) for NativeFrames, filtering out
non-com.example frames like sun.reflect.Native Method; fix by creating a
separate nativeOpts without WithStackInclude (e.g., nativeOpts :=
[]api.StackTraceOption{} and if opts.Max > 0 append
clicky.WithMaxStackFrames(opts.Max)), and use
clicky.StackTrace(javaNullPointerTrace, nativeOpts...) for the NativeFrames
return value instead of reusing headersOnlyOpts; keep headersOnlyOpts for
WithoutSource.

In `@formatters/html_formatter.go`:
- Around line 201-203: The type-assertion branch that handles
in.(*api.StackTrace) must guard against a typed nil before calling HTML(): check
that trace != nil after the assertion and return an appropriate value (e.g.,
fallback or nil, error) instead of calling trace.HTML() when trace is nil;
update the branch that currently returns f.wrapHTMLBody(trace.HTML()), nil to
first verify trace != nil and only then call trace.HTML(), referencing the
api.StackTrace type, the HTML() method, the trace local variable, and
f.wrapHTMLBody to locate and fix the code.

In `@Makefile`:
- Around line 8-10: The Makefile change swapped lazy-assignment (?=) for
immediate expansion (:=) on GIT_COMMIT, BUILD_DATE and LDFLAGS which would
clobber environment/cli overrides; restore the conditional behavior by keeping
?= for GIT_COMMIT and BUILD_DATE (or, if you need immediate expansion, guard the
change with an origin check like ifeq ($(origin GIT_COMMIT),undefined) before
assigning :=) and ensure LDFLAGS is only set in a guarded way so it doesn’t
overwrite an externally provided value; reference the variables GIT_COMMIT,
BUILD_DATE and LDFLAGS to locate and update the assignments.

In `@mcp/command.go`:
- Around line 279-280: The code unconditionally copies boolean zero-values from
initial.Security into config.Security (via config.Security.RequireConfirmation =
initial.Security.RequireConfirmation and config.Security.AuditLog =
initial.Security.AuditLog in NewCommandWithConfig), which overwrites persisted
settings when a partial Config is passed; change the model so presence can be
detected (e.g., make Security.RequireConfirmation and Security.AuditLog pointer
bools or add explicit "set" flags on the Security struct) and then update
NewCommandWithConfig to only assign these fields when the initial value is
present (non-nil or the corresponding "set" flag is true), leaving existing
config.Security values intact otherwise.

In `@mcp/discover_tools.go`:
- Around line 48-60: renderToolText currently dereferences tool and
tool.InputSchema without checks causing panics for nil entries; add guards at
the start of renderToolText to handle a nil *ToolDefinition and a nil
InputSchema: if tool is nil, append a short "No definition available" (or
similar) message and return; if tool.InputSchema is nil, treat properties as
empty (return "No parameters.") instead of indexing into it. Update references
to tool.Description and tool.InputSchema.Properties accordingly so the function
fails soft rather than crashing.

In `@mcp/install.go`:
- Around line 66-69: The code is using rootCmd.Use (which may include
args/placeholders) for identity/path lookup; change usages to the canonical
command name by calling rootCmd.Name() instead: set serverName := rootCmd.Name()
and pass rootCmd.Name() into resolveBinaryPath instead of rootCmd.Use (locate
these in the install flow where serverName and the resolveBinaryPath call are
defined).

In `@mcp/server.go`:
- Around line 330-339: The sameOriginOrNoOrigin function currently only compares
the parsed Origin host to r.Host which allows mismatched schemes; update it to
also derive the request scheme (use "https" when r.TLS != nil else "http") and
compare u.Scheme to that scheme in addition to comparing u.Host to r.Host. Use
case-insensitive comparison for scheme (e.g., strings.EqualFold) and keep using
strings.EqualFold for host comparison so both scheme and host must match; keep
the existing early-return behavior for empty Origin and parse errors.

In `@rpc/openapi_serve_integration_test.go`:
- Around line 789-795: The test currently picks an ephemeral port with
freeTCPPort and then starts the server via exec.Command(binaryPath, "openapi",
"serve", ...) which closes the listener before the child binds, leading to
TOCTOU flakiness; modify the startup in the test to wrap server launch (the
exec.Command + start/wait-for-bind sequence) in a retry loop: call freeTCPPort
to choose a port, attempt to start the server process (using the same args that
include "--port" and "--enable-executor"), detect bind/startup failure (e.g.,
process exits quickly or connection to 127.0.0.1:port is refused), kill/cleanup
the failed process, then pick a new port and retry a few times before failing
the test; apply the same retry logic around the other startup site referenced
(lines ~854-862) so intermittent "address already in use" errors are avoided.

---

Nitpick comments:
In `@api/code_test.go`:
- Around line 272-285: The test currently can pass even when XML formatting
succeeds; update it to deterministically exercise the fallback path by either
(A) calling formatXMLBestEffort directly with a crafted input that will trigger
the fallback (e.g., an input that the XML formatter will fail on or that you
special-case in formatXMLBestEffort for tests) and asserting it returns the
original unformatted string, then verify Code.HTML() uses Chroma highlighting
for that content, or (B) rename the test to remove "PanicFallsBack" if you don't
want to assert fallback behavior; reference the existing
TestCodeHTML_XMLFormatterPanicFallsBackToHighlightedContent, Code.HTML(), and
formatXMLBestEffort when making the change so the test deterministically
verifies the fallback path (or is renamed to match its assertions).
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f593e2c4-8611-4534-b809-cedd1c110de7

📥 Commits

Reviewing files that changed from the base of the PR and between 8479a4f and 9f46982.

⛔ Files ignored due to path filters (2)
  • examples/enitity/webapp/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • examples/uber_demo/go.sum is excluded by !**/*.sum
📒 Files selected for processing (49)
  • .gitignore
  • Makefile
  • api/code.go
  • api/code_test.go
  • api/diff.go
  • api/diff_test.go
  • api/stacktrace.go
  • api/stacktrace_java.go
  • api/stacktrace_test.go
  • cobra_command.go
  • cobra_command_test.go
  • entity.go
  • entity_filters_test.go
  • examples/enitity/main.go
  • examples/enitity/webapp/package.json
  • examples/enitity/webapp/pnpm-workspace.yaml
  • examples/enitity/webapp/src/App.tsx
  • examples/enitity/webapp/src/index.css
  • examples/enitity/webapp/src/main.tsx
  • examples/enitity/webapp/tsconfig.json
  • examples/enitity/webapp/vite.config.ts
  • examples/go.mod
  • examples/uber_demo/main.go
  • flags.go
  • flags_test.go
  • formatters/html_formatter.go
  • formatters/html_react_formatter.go
  • formatters/html_react_formatter_test.go
  • go.mod
  • mcp/builder.go
  • mcp/builder_test.go
  • mcp/command.go
  • mcp/command_test.go
  • mcp/config.go
  • mcp/discover_tools.go
  • mcp/discover_tools_test.go
  • mcp/install.go
  • mcp/install_test.go
  • mcp/prompts.go
  • mcp/registry.go
  • mcp/registry_test.go
  • mcp/server.go
  • mcp/sse_test.go
  • rpc/converter.go
  • rpc/openapi.go
  • rpc/openapi_serve_integration_test.go
  • rpc/serve.go
  • task/task.go
  • task/task_status_test.go
💤 Files with no reviewable changes (1)
  • examples/enitity/webapp/src/index.css

Comment thread cobra_command.go
Comment on lines +291 to +293
for e := err; e != nil; e = errors.Unwrap(e) {
if api.TryTypedValue(e) != nil {
return e, true
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In Go (1.20+), does errors.Unwrap traverse errors that implement Unwrap() []error (e.g., errors.Join or fmt.Errorf with multiple %w), or only Unwrap() error?

💡 Result:

In Go (1.20+), the errors.Unwrap function only traverses errors that implement the Unwrap error method [1][2]. It does not traverse errors that implement Unwrap []error (such as those created by errors.Join) [1][3]. If you call errors.Unwrap on an error that implements only Unwrap []error, it will return nil [1][2]. While the errors.Is and errors.As functions are designed to handle both Unwrap error and Unwrap []error (performing a depth-first search through the error tree for the latter) [4][2][5], the errors.Unwrap function remains restricted to the standard linked-list style of unwrapping [1][3]. If you need to access multiple errors joined together, you must perform a type assertion to the interface that provides the Unwrap []error method [6]: if uw, ok:= err.(interface{ Unwrap []error }); ok { errs:= uw.Unwrap // process the slice of errors }

Citations:


Handle joined/multi-error unwrapping in renderableError
renderableError walks only errors.Unwrap(e) (single Unwrap() error chain), so it will miss renderable causes reachable via Unwrap() []error (e.g., errors.Join(...) or fmt.Errorf with multiple %w). Switch to an errors.As-based approach for api.TryTypedValue’s target type, or explicitly traverse interface{ Unwrap() []error } in addition to Unwrap() error to keep rich error formatting consistent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cobra_command.go` around lines 291 - 293, The renderableError routine
currently only follows the single-error chain via errors.Unwrap(e) and thus
misses causes inside multi-error joins; update renderableError to detect and
traverse both single Unwrap() error and multi Unwrap() []error cases (or replace
the loop with an errors.As-style search) so api.TryTypedValue targets are found
in joined errors—specifically, modify the loop that checks api.TryTypedValue(e)
to also, when present, call Unwrap() []error and recursively inspect each child
(or use errors.As against the concrete type that TryTypedValue expects) to
ensure all renderable causes are discovered.

Comment on lines +1304 to +1313
headersOnlyOpts := []api.StackTraceOption{clicky.WithStackInclude("com.example.")}
if opts.Max > 0 {
headersOnlyOpts = append(headersOnlyOpts, clicky.WithMaxStackFrames(opts.Max))
}

return StackTraceShowcase{
WithSource: clicky.StackTrace(javaSampleTrace, resolvedOpts...),
WithoutSource: clicky.StackTrace(javaNullPointerTrace, headersOnlyOpts...),
NativeFrames: clicky.StackTrace(javaNullPointerTrace, headersOnlyOpts...),
}, nil
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify that NativeFrames reuses filtered options and that the fixture includes native/unknown frames.
rg -n 'headersOnlyOpts|NativeFrames|WithStackInclude|javaNullPointerTrace|Native Method|Unknown Source|sun\.reflect' examples/uber_demo/main.go

Repository: flanksource/clicky

Length of output: 941


🏁 Script executed:

# Inspect how clicky.WithStackInclude is implemented and how it filters frames in StackTrace.
rg -n "func\s+WithStackInclude|WithStackInclude\(" -S . 
rg -n "WithStackInclude" -S . --glob='*.go'

Repository: flanksource/clicky

Length of output: 1265


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Print the relevant implementation + option usage in stacktrace.go
sed -n '1,220p' api/stacktrace.go
echo "----"
sed -n '220,520p' api/stacktrace.go

Repository: flanksource/clicky

Length of output: 15377


Fix NativeFrames filtering in showStackTrace

api.WithStackInclude restricts frame display (and source resolution) to classes matching the given prefixes. showStackTrace builds headersOnlyOpts with clicky.WithStackInclude("com.example.") and reuses it for both WithoutSource and NativeFrames (so frames from javaNullPointerTrace under sun.reflect.*—including Native Method / Unknown Source—won’t appear in NativeFrames).

💡 Suggested fix
 	headersOnlyOpts := []api.StackTraceOption{clicky.WithStackInclude("com.example.")}
+	nativeFrameOpts := []api.StackTraceOption{}
 	if opts.Max > 0 {
 		headersOnlyOpts = append(headersOnlyOpts, clicky.WithMaxStackFrames(opts.Max))
+		nativeFrameOpts = append(nativeFrameOpts, clicky.WithMaxStackFrames(opts.Max))
 	}
 
 	return StackTraceShowcase{
 		WithSource:    clicky.StackTrace(javaSampleTrace, resolvedOpts...),
 		WithoutSource: clicky.StackTrace(javaNullPointerTrace, headersOnlyOpts...),
-		NativeFrames:  clicky.StackTrace(javaNullPointerTrace, headersOnlyOpts...),
+		NativeFrames:  clicky.StackTrace(javaNullPointerTrace, nativeFrameOpts...),
 	}, nil
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
headersOnlyOpts := []api.StackTraceOption{clicky.WithStackInclude("com.example.")}
if opts.Max > 0 {
headersOnlyOpts = append(headersOnlyOpts, clicky.WithMaxStackFrames(opts.Max))
}
return StackTraceShowcase{
WithSource: clicky.StackTrace(javaSampleTrace, resolvedOpts...),
WithoutSource: clicky.StackTrace(javaNullPointerTrace, headersOnlyOpts...),
NativeFrames: clicky.StackTrace(javaNullPointerTrace, headersOnlyOpts...),
}, nil
headersOnlyOpts := []api.StackTraceOption{clicky.WithStackInclude("com.example.")}
nativeFrameOpts := []api.StackTraceOption{}
if opts.Max > 0 {
headersOnlyOpts = append(headersOnlyOpts, clicky.WithMaxStackFrames(opts.Max))
nativeFrameOpts = append(nativeFrameOpts, clicky.WithMaxStackFrames(opts.Max))
}
return StackTraceShowcase{
WithSource: clicky.StackTrace(javaSampleTrace, resolvedOpts...),
WithoutSource: clicky.StackTrace(javaNullPointerTrace, headersOnlyOpts...),
NativeFrames: clicky.StackTrace(javaNullPointerTrace, nativeFrameOpts...),
}, nil
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/uber_demo/main.go` around lines 1304 - 1313, showStackTrace reuses
headersOnlyOpts (which includes clicky.WithStackInclude("com.example.")) for
NativeFrames, filtering out non-com.example frames like sun.reflect.Native
Method; fix by creating a separate nativeOpts without WithStackInclude (e.g.,
nativeOpts := []api.StackTraceOption{} and if opts.Max > 0 append
clicky.WithMaxStackFrames(opts.Max)), and use
clicky.StackTrace(javaNullPointerTrace, nativeOpts...) for the NativeFrames
return value instead of reusing headersOnlyOpts; keep headersOnlyOpts for
WithoutSource.

Comment on lines +201 to +203
if trace, ok := in.(*api.StackTrace); ok {
return f.wrapHTMLBody(trace.HTML()), nil
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate relevant files
ls -R
rg -n "type StackTrace|func \\(.*StackTrace\\) HTML\\(" -S . || true
rg -n "html_formatter\\.go" -S . || true
fd -a "html_formatter.go" . || true

# Show the exact formatter code around the snippet lines
FILE="formatters/html_formatter.go"
if [ -f "$FILE" ]; then
  echo "---- $FILE (context around lines 160-240) ----"
  nl -ba "$FILE" | sed -n '160,240p'
fi

# Find api.StackTrace definition and HTML method implementation
# (Try common layouts first by searching for "type StackTrace" and "HTML()" closely)
echo "---- Search for api.StackTrace definition ----"
rg -n --hidden --no-ignore -S "type StackTrace struct|type StackTrace" . | head -n 50 || true

# Print the file(s) containing the HTML method for StackTrace
echo "---- Search for StackTrace.HTML ----"
rg -n --hidden --no-ignore -S "func \\(.*StackTrace\\) HTML\\(" . | head -n 50 || true
rg -n --hidden --no-ignore -S "func \\(\\*?api\\.StackTrace\\) HTML\\(" . | head -n 50 || true
rg -n --hidden --no-ignore -S "HTML\\(\\)\\s*string" . | head -n 50 || true

# If we found any HTML method, print its surrounding lines
# (Derive likely paths from ripgrep matches)
matches=$(rg -n --hidden --no-ignore -S "func \\(.*StackTrace\\) HTML\\(" . | awk -F: '{print $1}' | head -n 5)
for m in $matches; do
  [ -f "$m" ] && echo "---- $m (around HTML) ----" && nl -ba "$m" | sed -n '1,220p'
done

Repository: flanksource/clicky

Length of output: 8188


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="formatters/html_formatter.go"
echo "---- $FILE lines 190-215 ----"
sed -n '190,215p' "$FILE" | cat -n

echo "---- $FILE lines 201-203 only ----"
sed -n '198,206p' "$FILE" | cat -n

echo "---- api/stacktrace.go: StackTrace.HTML receiver ----"
sed -n '1,120p' api/stacktrace.go | cat -n
rg -n "func \\(s StackTrace\\) HTML\\(" api/stacktrace.go || true

echo "---- api/stacktrace.go around HTML() ----"
HTML_LINE=$(rg -n "func \\(s StackTrace\\) HTML\\(" api/stacktrace.go | head -n1 | cut -d: -f1 || true)
if [ -n "${HTML_LINE:-}" ]; then
  start=$((HTML_LINE-10))
  end=$((HTML_LINE+10))
  sed -n "${start},${end}p" api/stacktrace.go | cat -n
fi

Repository: flanksource/clicky

Length of output: 8164


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for nil handling around StackTrace in formatter tests
rg -n "StackTrace" formatters/tests -S || true
rg -n "\\*api\\.StackTrace" -S . || true
rg -n "in\\.\\(\\*api\\.StackTrace\\)|in\\.\\(api\\.StackTrace\\)" -S formatters/html_formatter.go || true

# Search for constructing *api.StackTrace and passing nil somewhere
rg -n "new\\(api\\.StackTrace\\)|&api\\.StackTrace|\\*api\\.StackTrace" -S . || true

# Search for typed-nil patterns in tests
rg -n "var .*\\*api\\.StackTrace = nil|\\(\\*api\\.StackTrace\\)\\(nil\\)|\\*api\\.StackTrace\\)\\(nil\\)" -S . || true

Repository: flanksource/clicky

Length of output: 443


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "StackTrace" formatters/tests -S || true
rg -n "\\*api\\.StackTrace" -S . || true
rg -n "in\\.\\(\\*api\\.StackTrace\\)|in\\.\\(api\\.StackTrace\\)" -S formatters/html_formatter.go || true

rg -n "new\\(api\\.StackTrace\\)|&api\\.StackTrace|\\*api\\.StackTrace" -S . || true

rg -n "var .*\\*api\\.StackTrace = nil|\\(\\*api\\.StackTrace\\)\\(nil\\)|\\*api\\.StackTrace\\)\\(nil\\)" -S . || true

Repository: flanksource/clicky

Length of output: 443


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "StackTrace" formatters/tests -S || true
rg -n "\\*api\\.StackTrace" -S . || true
rg -n "in\\.\\(\\*api\\.StackTrace\\)|in\\.\\(api\\.StackTrace\\)" -S formatters/html_formatter.go || true

rg -n "new\\(api\\.StackTrace\\)|&api\\.StackTrace|\\*api\\.StackTrace" -S . || true

rg -n "var .*\\*api\\.StackTrace = nil|\\(\\*api\\.StackTrace\\)\\(nil\\)|\\*api\\.StackTrace\\)\\(nil\\)" -S . || true

Repository: flanksource/clicky

Length of output: 443


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="formatters/html_react_formatter.go"
echo "---- $FILE lines 230-270 ----"
sed -n '230,270p' "$FILE" | cat -n

Repository: flanksource/clicky

Length of output: 1419


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find wrapHTMLBody definition
rg -n "wrapHTMLBody" formatters/html_formatter.go formatters/*.go | head -n 50

FILE="formatters/html_formatter.go"
# Show definition area
if rg -n "func \\(f \\*?htmlFormatter\\) wrapHTMLBody|wrapHTMLBody\\(" "$FILE" >/dev/null; then
  LINE=$(rg -n "wrapHTMLBody" "$FILE" | head -n 1 | cut -d: -f1)
  start=$((LINE-30)); end=$((LINE+30))
  sed -n "${start},${end}p" "$FILE" | cat -n
else
  echo "wrapHTMLBody not found in $FILE"
fi

# Inspect other nil-pointer handling patterns in formatters/html_formatter.go
rg -n "if .*== nil" formatters/html_formatter.go | head -n 100
rg -n "return \"\", nil" formatters/html_formatter.go | head -n 50
rg -n "return nil" formatters/html_formatter.go | head -n 50

Repository: flanksource/clicky

Length of output: 2890


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find wrapHTMLBody definition
rg -n "wrapHTMLBody" formatters/html_formatter.go formatters/*.go | head -n 50

FILE="formatters/html_formatter.go"
# Show definition area
if rg -n "wrapHTMLBody\\(" "$FILE" >/dev/null; then
  LINE=$(rg -n "wrapHTMLBody\\(" "$FILE" | head -n 1 | cut -d: -f1)
  start=$((LINE-40)); end=$((LINE+40))
  sed -n "${start},${end}p" "$FILE" | cat -n
else
  echo "wrapHTMLBody not found in $FILE"
fi

# Inspect other nil-pointer handling patterns in formatters/html_formatter.go
echo "---- nil checks ----"
rg -n "== nil" "$FILE" | head -n 100 || true
echo "---- empty string returns ----"
rg -n "return \"\", nil" "$FILE" | head -n 50 || true

Repository: flanksource/clicky

Length of output: 3687


Guard nil *api.StackTrace before calling HTML()

api.StackTrace.HTML() uses a value receiver (func (s StackTrace) HTML() string), so trace.HTML() on a typed-nil *api.StackTrace panics due to the implicit dereference. Add a nil check in the in.(*api.StackTrace) branch.

Proposed fix
 	if trace, ok := in.(*api.StackTrace); ok {
+		if trace == nil {
+			return "", nil
+		}
 		return f.wrapHTMLBody(trace.HTML()), nil
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if trace, ok := in.(*api.StackTrace); ok {
return f.wrapHTMLBody(trace.HTML()), nil
}
if trace, ok := in.(*api.StackTrace); ok {
if trace == nil {
return "", nil
}
return f.wrapHTMLBody(trace.HTML()), nil
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@formatters/html_formatter.go` around lines 201 - 203, The type-assertion
branch that handles in.(*api.StackTrace) must guard against a typed nil before
calling HTML(): check that trace != nil after the assertion and return an
appropriate value (e.g., fallback or nil, error) instead of calling trace.HTML()
when trace is nil; update the branch that currently returns
f.wrapHTMLBody(trace.HTML()), nil to first verify trace != nil and only then
call trace.HTML(), referencing the api.StackTrace type, the HTML() method, the
trace local variable, and f.wrapHTMLBody to locate and fix the code.

Comment thread Makefile
Comment on lines +8 to +10
GIT_COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
BUILD_DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
LDFLAGS ?= -X main.commit=$(GIT_COMMIT) -X main.date=$(BUILD_DATE)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verifies whether BUILD_DATE is re-evaluated within a single make invocation.
make -f Makefile -s --eval $'print-build-date:\n\t@echo first=$(BUILD_DATE)\n\t@sleep 1\n\t@echo second=$(BUILD_DATE)' print-build-date

Repository: flanksource/clicky

Length of output: 107


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Makefile (lines 1-80) ==="
nl -ba Makefile | sed -n '1,80p'

echo
echo "=== Matches for key vars ==="
rg -n "GIT_COMMIT|BUILD_DATE|LDFLAGS|ldflags" Makefile || true

Repository: flanksource/clicky

Length of output: 153


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Makefile (first 120 lines) ==="
cat -n Makefile | sed -n '1,120p'

echo
echo "=== rg hits for key vars ==="
rg -n "GIT_COMMIT|BUILD_DATE|LDFLAGS|ldflags" Makefile || true

Repository: flanksource/clicky

Length of output: 2841


Preserve conditional override behavior when changing expansion mode

BUILD_DATE/GIT_COMMIT/LDFLAGS are set with ?=, so changing them to := would overwrite values supplied via environment/make command line. Also, LDFLAGS is only used once (in the build target), so recursive re-evaluation isn’t a major practical issue here. If deterministic stamping is required, use := only when the variables are undefined (e.g., guard with ifeq ($(origin ...),undefined)), rather than replacing ?= outright.

🧰 Tools
🪛 checkmake (0.3.2)

[warning] 10-10: Variable "BUILD_DATE" possibly contains a timestamp and should be simply expanded.

(timestampexpanded)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 8 - 10, The Makefile change swapped lazy-assignment
(?=) for immediate expansion (:=) on GIT_COMMIT, BUILD_DATE and LDFLAGS which
would clobber environment/cli overrides; restore the conditional behavior by
keeping ?= for GIT_COMMIT and BUILD_DATE (or, if you need immediate expansion,
guard the change with an origin check like ifeq ($(origin GIT_COMMIT),undefined)
before assigning :=) and ensure LDFLAGS is only set in a guarded way so it
doesn’t overwrite an externally provided value; reference the variables
GIT_COMMIT, BUILD_DATE and LDFLAGS to locate and update the assignments.

Comment thread mcp/command.go
Comment on lines +279 to +280
config.Security.RequireConfirmation = initial.Security.RequireConfirmation
config.Security.AuditLog = initial.Security.AuditLog
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Avoid unconditional overwrite of security booleans from partial initial config.

Line 279 and Line 280 always copy initial bool zero-values. If a caller passes a partial Config to NewCommandWithConfig, this can unintentionally disable confirmation/audit settings loaded from disk.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mcp/command.go` around lines 279 - 280, The code unconditionally copies
boolean zero-values from initial.Security into config.Security (via
config.Security.RequireConfirmation = initial.Security.RequireConfirmation and
config.Security.AuditLog = initial.Security.AuditLog in NewCommandWithConfig),
which overwrites persisted settings when a partial Config is passed; change the
model so presence can be detected (e.g., make Security.RequireConfirmation and
Security.AuditLog pointer bools or add explicit "set" flags on the Security
struct) and then update NewCommandWithConfig to only assign these fields when
the initial value is present (non-nil or the corresponding "set" flag is true),
leaving existing config.Security values intact otherwise.

Comment thread mcp/discover_tools.go
Comment on lines +48 to +60
func renderToolText(name string, tool *ToolDefinition) api.Text {
t := api.Text{}.
Append(name, "font-bold text-yellow-400").
Append("\n")

if tool.Description != "" {
t = t.Append(tool.Description, "text-gray-300").Append("\n")
}

props := tool.InputSchema.Properties
if len(props) == 0 {
return t.Append("No parameters.\n\n", "italic text-gray-500")
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard against nil tool definitions in renderer.

Line 53 assumes tool is non-nil. A nil entry in the input map will panic during discovery rendering; fail soft instead of crashing.

Proposed fix
 func renderToolText(name string, tool *ToolDefinition) api.Text {
 	t := api.Text{}.
 		Append(name, "font-bold text-yellow-400").
 		Append("\n")
 
+	if tool == nil {
+		return t.Append("Tool definition unavailable.\n\n", "italic text-gray-500")
+	}
+
 	if tool.Description != "" {
 		t = t.Append(tool.Description, "text-gray-300").Append("\n")
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func renderToolText(name string, tool *ToolDefinition) api.Text {
t := api.Text{}.
Append(name, "font-bold text-yellow-400").
Append("\n")
if tool.Description != "" {
t = t.Append(tool.Description, "text-gray-300").Append("\n")
}
props := tool.InputSchema.Properties
if len(props) == 0 {
return t.Append("No parameters.\n\n", "italic text-gray-500")
}
func renderToolText(name string, tool *ToolDefinition) api.Text {
t := api.Text{}.
Append(name, "font-bold text-yellow-400").
Append("\n")
if tool == nil {
return t.Append("Tool definition unavailable.\n\n", "italic text-gray-500")
}
if tool.Description != "" {
t = t.Append(tool.Description, "text-gray-300").Append("\n")
}
props := tool.InputSchema.Properties
if len(props) == 0 {
return t.Append("No parameters.\n\n", "italic text-gray-500")
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mcp/discover_tools.go` around lines 48 - 60, renderToolText currently
dereferences tool and tool.InputSchema without checks causing panics for nil
entries; add guards at the start of renderToolText to handle a nil
*ToolDefinition and a nil InputSchema: if tool is nil, append a short "No
definition available" (or similar) message and return; if tool.InputSchema is
nil, treat properties as empty (return "No parameters.") instead of indexing
into it. Update references to tool.Description and tool.InputSchema.Properties
accordingly so the function fails soft rather than crashing.

Comment thread mcp/install.go
Comment on lines +66 to 69
serverName := rootCmd.Use

binPath, err := os.Executable()
binPath, err := resolveBinaryPath(rootCmd.Use)
if err != nil {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use rootCmd.Name() for identity/path lookup instead of rootCmd.Use.

Use can contain usage text (arguments/placeholders), which is unsafe for config keys and LookPath. Use the canonical command name.

Suggested fix
-			serverName := rootCmd.Use
+			serverName := rootCmd.Name()

-			binPath, err := resolveBinaryPath(rootCmd.Use)
+			binPath, err := resolveBinaryPath(rootCmd.Name())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
serverName := rootCmd.Use
binPath, err := os.Executable()
binPath, err := resolveBinaryPath(rootCmd.Use)
if err != nil {
serverName := rootCmd.Name()
binPath, err := resolveBinaryPath(rootCmd.Name())
if err != nil {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mcp/install.go` around lines 66 - 69, The code is using rootCmd.Use (which
may include args/placeholders) for identity/path lookup; change usages to the
canonical command name by calling rootCmd.Name() instead: set serverName :=
rootCmd.Name() and pass rootCmd.Name() into resolveBinaryPath instead of
rootCmd.Use (locate these in the install flow where serverName and the
resolveBinaryPath call are defined).

Comment thread mcp/server.go
Comment on lines +330 to +339
func sameOriginOrNoOrigin(r *http.Request) bool {
origin := r.Header.Get("Origin")
if origin == "" {
return true
}
u, err := url.Parse(origin)
if err != nil || u.Host == "" {
return false
}
return strings.EqualFold(u.Host, r.Host)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Tighten same-origin validation to include scheme, not just host.

This currently allows Origin values with a different scheme as long as host/port match. For CSRF-style checks, compare both scheme and host.

Suggested fix
 func sameOriginOrNoOrigin(r *http.Request) bool {
 	origin := r.Header.Get("Origin")
 	if origin == "" {
 		return true
 	}
 	u, err := url.Parse(origin)
 	if err != nil || u.Host == "" {
 		return false
 	}
-	return strings.EqualFold(u.Host, r.Host)
+	reqScheme := "http"
+	if r.TLS != nil {
+		reqScheme = "https"
+	}
+	return strings.EqualFold(u.Host, r.Host) && strings.EqualFold(u.Scheme, reqScheme)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func sameOriginOrNoOrigin(r *http.Request) bool {
origin := r.Header.Get("Origin")
if origin == "" {
return true
}
u, err := url.Parse(origin)
if err != nil || u.Host == "" {
return false
}
return strings.EqualFold(u.Host, r.Host)
func sameOriginOrNoOrigin(r *http.Request) bool {
origin := r.Header.Get("Origin")
if origin == "" {
return true
}
u, err := url.Parse(origin)
if err != nil || u.Host == "" {
return false
}
reqScheme := "http"
if r.TLS != nil {
reqScheme = "https"
}
return strings.EqualFold(u.Host, r.Host) && strings.EqualFold(u.Scheme, reqScheme)
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mcp/server.go` around lines 330 - 339, The sameOriginOrNoOrigin function
currently only compares the parsed Origin host to r.Host which allows mismatched
schemes; update it to also derive the request scheme (use "https" when r.TLS !=
nil else "http") and compare u.Scheme to that scheme in addition to comparing
u.Host to r.Host. Use case-insensitive comparison for scheme (e.g.,
strings.EqualFold) and keep using strings.EqualFold for host comparison so both
scheme and host must match; keep the existing early-return behavior for empty
Origin and parse errors.

Comment on lines +789 to +795
port := freeTCPPort(t)

// Start the server with fixed port and executor enabled
// Start the server with executor enabled.
cmd := exec.Command(binaryPath, "openapi", "serve",
"--port", fmt.Sprintf("%d", port),
"--enable-executor",
"--host", "localhost")
"--host", "127.0.0.1")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid TOCTOU flakiness in ephemeral port selection.

Line 789 reserves a port via freeTCPPort, but Lines 857-859 close the listener before the child process binds. Another process can grab that port in between, causing intermittent address already in use test failures. Add a retry loop around server startup (pick a new port and retry on bind/startup failure) to make this deterministic.

Also applies to: 854-862

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rpc/openapi_serve_integration_test.go` around lines 789 - 795, The test
currently picks an ephemeral port with freeTCPPort and then starts the server
via exec.Command(binaryPath, "openapi", "serve", ...) which closes the listener
before the child binds, leading to TOCTOU flakiness; modify the startup in the
test to wrap server launch (the exec.Command + start/wait-for-bind sequence) in
a retry loop: call freeTCPPort to choose a port, attempt to start the server
process (using the same args that include "--port" and "--enable-executor"),
detect bind/startup failure (e.g., process exits quickly or connection to
127.0.0.1:port is refused), kill/cleanup the failed process, then pick a new
port and retry a few times before failing the test; apply the same retry logic
around the other startup site referenced (lines ~854-862) so intermittent
"address already in use" errors are avoided.

@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 26, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedgolang/​github.com/​flanksource/​commons@​v1.51.371100100100100
Addedgolang/​golang.org/​x/​tools@​v0.43.075100100100100
Updatedgolang/​github.com/​mattn/​go-sqlite3@​v1.14.30 ⏵ v1.14.389610010075100

View full report

@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 26, 2026

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

View full report

moshloop added 14 commits May 27, 2026 08:25
Add support for including a hidden _id column in table rows for wrapped entities (entityWithID). The _id column is automatically added to the Columns() output and included in Row() and PrettyRow() data, but marked as hidden so it doesn't appear as a visible column in the UI.

This allows the _id metadata to be available in row data while keeping the table display clean. Updates the HTML React formatter to handle cells that exist in row data but not in the column definitions.

Adds comprehensive test coverage for all entity types (TableProvider, PrettyRow, and plain structs) to verify the _id column is properly included in the output data but hidden from the visible columns.

Refs: entity wrapping, table formatting
Introduce comprehensive stack trace support with language-agnostic parsing, styled rendering, and extensible source resolution. Adds StackTrace, StackFrame types and ParseJavaStackTrace parser to api package, with public convenience wrappers in clicky root. Includes support for frame filtering, context lines, and max frame truncation.

Also adds MultiFilter type for comma-separated flag values with include/exclude semantics, and fixes field value assignment to support type conversion in flags package.

Updates cache debug output to use task.GatedStderr() instead of os.Stderr to prevent log lines from breaking interactive renderer frame accounting. Fixes recursive struct handling in OpenAPI schema generation by tracking visited types.

Refs: stack trace rendering, source context, Java exception parsing
…port

Add shiki syntax highlighter and transformers to webapp dependencies for code block rendering. Implement comprehensive stack trace parsing and display with source resolution for Java exceptions. Add new demo showcases for code samples, label badges, documentation links, and parsed stack traces with configurable context and filtering. Update import paths and module resolution to use published clicky-ui distribution. Reorganize webapp navigation with semantic HTML and icon support.

Breaking changes:
- Update TypeScript path aliases to reference dist files instead of src
- Change clicky-ui import to use published api-explorer module
- Update CSS import to use distributed styles.css

Refs: Stack trace rendering feature, syntax highlighting integration
Introduce a Builder pattern for configuring MCP servers with a fluent API (NewMcpServer, WithExclude, WithInclude, AutoExpose, IgnoreParams, WithFormat, Build, Command).

Add a built-in 'discover-tools' MCP tool that returns a formatted catalogue of all registered tools with their parameters, defaults, and constraints. Supports multiple output formats (markdown, ansi, plain) via FormatOptions.

Add IgnoredParamRule and IgnoredParams config to strip parameters from MCP tool schemas (MCP-only, does not affect OpenAPI). Add Format config to apply server-wide format/color overrides to tool execution.

Refactor config path functions to be per-application (GetConfigPathFor, GetPromptsPathFor) so multiple clicky-based MCP servers don't share config files. Maintain backward compatibility with legacy GetConfigPath/GetPromptsPath.

Remove the special 'discover-tools' prompt and its inline handling from prompts.go and command.go, replacing it with the dedicated MCP tool. Remove Verbose flag from CommandOptions (use clicky's existing --loglevel/-v instead).

Includes comprehensive tests for Builder, IgnoredParams application, discover-tools rendering, and registry builtins.
… support

Implement Server-Sent Events (SSE) transport alongside stdio for MCP servers, enabling Claude Desktop and other clients to connect via HTTP. Add `mcp tools` subcommand to preview tool catalogue with format options. Expand `mcp install` to support Claude, Codex, Gemini, Copilot, and Cursor clients with per-client config writers (JSON for most, TOML for Codex). Refactor config merging into reusable `loadCommandConfig` and `mergeInitialConfig` helpers to support both serve and tools commands. Remove built-in discover-tools tool in favor of dedicated `mcp tools` command for cleaner separation of concerns. Add comprehensive tests for SSE round-trip, install permutations across clients/transports, and config merging logic.
Remove unused module entries from go.sum that are no longer referenced in the project. This reduces dependency bloat and improves build clarity.

Also add examples/enitity/enitity to .gitignore to exclude the compiled binary from version control.
Add Diff type to api package supporting multiple output formats (plain, ANSI, HTML, Markdown) for rendering unified diffs between strings. Implement grouped flag help output in flags package with category-based organization (Logging, Tasks, Format) via FlagCategoryAnnotation. Add BindAllFlagsToCommand helper to bind flags and install grouped usage template. Update cobra_command.go error logging to use %w format and adjust skip level. Move fatih/color and go-difflib from indirect to direct dependencies in go.mod.
Add GIT_COMMIT and BUILD_DATE variables to Makefile that are injected into the binary at build time using ldflags. This allows the binary to report its commit hash and build timestamp.

Also reorganize imports in example webapp to consolidate EntityExplorerApp import and remove unused path aliases from tsconfig and vite config.
…nization

Extract repeated logic into reusable helper functions across multiple modules:

- api/diff.go: Replace color library calls with ansiStyle() helper for ANSI formatting
- api/stacktrace.go: Extract frameHasSource() and frameSourceLineNumber() to reduce duplication in source line handling
- mcp/command.go: Improve tools command format handling to respect configured defaults
- mcp/server.go: Extract flag manipulation helpers (setCommandFlag, lookupCommandFlag, resetCommandState) and add origin validation for SSE endpoints
- mcp/install.go: Improve port handling and symlink resolution error handling
- flags_test.go: Replace sectionAfter() with more robust flagSection() that stops at next heading
- rpc/openapi_serve_integration_test.go: Use dynamic port allocation instead of fixed port

Also includes:
- Security: Add CORS origin validation and request size limits to SSE server
- Accessibility: Replace role="tab" with aria-current in webapp navigation
- Test coverage: Add tests for explicit source line numbers and configured format handling
- Code quality: Improve error handling and reduce code duplication
Custom entity actions previously always required a positional <id>
argument (cobra.ExactArgs(1)), even when the action's target is supplied
entirely through flags. WithOptionalID() relaxes the generated command
to cobra.MaximumNArgs(1), shows [id] instead of <id> in usage, and skips
the "id is required" check in the action DataFunc. get/delete commands
are unaffected.
…ter paths

Add renderableError to detect and render errors implementing clicky interfaces (Pretty/Textable/Tree*) through the format pipeline instead of collapsing to Error(). This allows rich error formatting to honor --format flags.

Add GenerateFromCobraWithConfig to support custom converter configs (path prefix, default method) when generating OpenAPI specs, ensuring generated paths match registered routes. Store converterCfg in SwaggerServer to reuse the same config for executor initialization and spec regeneration.

Export handler methods (HandleOpenAPIJSON, HandleOpenAPIYAML, HandleEntities, HandleHealth, RegisterExecutionRoutes) and ConverterConfig() to allow callers to compose custom mux patterns and merge multiple OpenAPI specs.

Fix entity-root command handling: skip duplicate list subcommands when parent is runnable, and infer GET method for entity-root commands (no verb, has entity annotation).

Refs: improved error UX and OpenAPI spec consistency with executor routes
StatusWarning should be a terminal status that freezes the task's endTime and cancels its context, preventing the duration from continuing to tick after the task completes.

Before this fix, Warning() left endTime zero, causing getDuration() to keep returning time.Now()-startTime on every render, producing an ever-growing elapsed counter even after the task's goroutine had returned.

Adds regression test to verify all terminal states (Success, Failed, Warning) properly freeze endTime and cancel the task context.
Update Go module dependencies including:
- flanksource packages (commons, gomplate, is-healthy, captain)
- AWS SDK v2 packages
- Kubernetes packages (api, client-go, apimachinery, apiextensions-apiserver, klog)
- golang.org packages (crypto, sync, sys, term, text, tools, mod, net, oauth2, exp)
- OpenTelemetry packages
- Various other indirect dependencies

These updates include bug fixes, security patches, and feature improvements across the dependency tree.
Update Go module dependencies including:
- AWS SDK v2 components (ini → v4a)
- charmbracelet packages (golden, xpty, conpty)
- aymanbagabas/go-udiff (0.3.1 → 0.4.1)
- Various other transitive dependencies
- Remove unused flanksource/captain dependency

These updates bring in bug fixes, performance improvements, and security patches from upstream projects.
@moshloop moshloop force-pushed the pr/mcp-improvements branch from 08d242d to b9f1a94 Compare May 27, 2026 05:25
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 27, 2026

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 8 file(s) based on 9 unresolved review comments.

A stacked PR containing fixes has been created.

  • Stacked PR: #104
  • Files modified:
  • cobra_command.go
  • examples/uber_demo/main.go
  • formatters/html_formatter.go
  • mcp/command.go
  • mcp/discover_tools.go
  • mcp/install.go
  • mcp/server.go
  • rpc/openapi_serve_integration_test.go

Time taken: 6m 2s

moshloop added 2 commits May 27, 2026 11:38
Replace comprehensive 1100+ line README with concise 280-line version that:

- Leads with clear value proposition and module path
- Provides quick install and CLI usage examples
- Includes focused library usage examples for formatting, tasks, flags, OpenAPI/MCP, and middleware
- Adds schema formatting section with example
- Reorganizes package map for easier navigation
- Consolidates development, testing, and examples sections
- Removes redundant detailed documentation in favor of inline code examples
- Maintains all essential information while improving readability

This restructuring makes the README more accessible to new users while preserving reference material for advanced usage.
Update multiple indirect dependencies to their latest versions including:
- flanksource/commons v1.51.0 → v1.51.3
- cert-manager/cert-manager v1.19.4 → v1.20.0
- charmbracelet/colorprofile v0.4.2 → v0.4.3
- flanksource/gomplate/v3 v3.24.77 → v3.24.78
- flanksource/is-healthy v1.0.86 → v1.0.87
- goccy/go-json v0.10.5 → v0.10.6
- golang/groupcache v0.0.0-20210331224755-41bb18bfe9da → v0.0.0-20241129210726-2c02b8208cf8
- itchyny/gojq v0.12.18 → v0.12.19
- itchyny/timefmt-go v0.1.7 → v0.1.8
- lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 → v0.0.0-20251013123823-9fd1530e3ec3
- mattn/go-runewidth v0.0.20 → v0.0.21
- ohler55/ojg v1.28.0 → v1.28.1
- olekukonko/tablewriter v1.1.3 → v1.1.4
- power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c → v0.0.0-20240221224432-82ca36839d55
- shoenig/go-m1cpu v0.1.6 → v0.1.7
- tklauser/go-sysconf v0.3.12 → v0.3.16
- tklauser/numcpus v0.6.1 → v0.11.0
- go.opentelemetry.io/otel v1.41.0 → v1.42.0
- go.opentelemetry.io/otel/trace v1.41.0 → v1.42.0
- go.yaml.in/yaml/v2 v2.4.3 → v2.4.4
- golang.org/x/crypto v0.48.0 → v0.49.0
- golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa → v0.0.0-20260312153236-7ab1446f8b90
- golang.org/x/net v0.51.0 → v0.52.0
- golang.org/x/sync v0.19.0 → v0.20.0
- golang.org/x/sys v0.41.0 → v0.42.0
- golang.org/x/term v0.40.0 → v0.41.0
- golang.org/x/text v0.34.0 → v0.35.0
- google.golang.org/genproto/googleapis/api and rpc
- k8s.io packages v0.35.2 → v0.35.4
- k8s.io/klog/v2 v2.130.1 → v2.140.0
- sigs.k8s.io/gateway-api v1.5.0 → v1.5.1
@moshloop moshloop merged commit 73dd9f9 into main May 27, 2026
15 of 16 checks passed
@moshloop moshloop deleted the pr/mcp-improvements branch May 27, 2026 09:13
@flankbot
Copy link
Copy Markdown

🎉 This PR is included in version 1.21.10

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants