Skip to content

Add Model Context Protocol (MCP) server support#36

Merged
xenOs76 merged 6 commits into
mainfrom
feat/mcp
May 25, 2026
Merged

Add Model Context Protocol (MCP) server support#36
xenOs76 merged 6 commits into
mainfrom
feat/mcp

Conversation

@xenOs76

@xenOs76 xenOs76 commented May 25, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added an MCP server mode exposed via a new mcp CLI subcommand and shown in CLI help.
    • New MCP tools: validate configs, build CLI commands, generate JWKS, run requests, inspect certs and JWTs.
    • MCP prompts/resources to generate starter request configs and reference docs.
  • Documentation

    • New/expanded JSON schema, sample config and multiple example YAMLs demonstrating usage and options.
  • Bug Fixes

    • Certificate display now includes IP addresses when filtered.

Review Change Stack

@xenOs76 xenOs76 self-assigned this May 25, 2026
@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@xenOs76, we couldn't start this review because you've used your available PR reviews for now.

Your plan includes 1 review of capacity. Refill in 21 minutes and 45 seconds.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more review capacity refills, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than trial, open-source, and free plans. In all cases, review capacity refills continuously over time.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9cf1eaac-c0d5-4b31-8884-c48dbaebcabc

📥 Commits

Reviewing files that changed from the base of the PR and between ebc097b and 3ee3b4d.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (38)
  • .testcoverage.yml
  • README.md
  • assets/examples/https-wrench-k3s-anchor-and-aliases.yaml
  • assets/examples/https-wrench-proxyProtocolV2.yaml
  • go.mod
  • https-wrench.schema.json
  • internal/certinfo/certinfo.go
  • internal/certinfo/certinfo_handlers.go
  • internal/certinfo/certinfo_handlers_test.go
  • internal/certinfo/certinfo_test.go
  • internal/certinfo/common_handlers.go
  • internal/certinfo/main_test.go
  • internal/cmd/certinfo.go
  • internal/cmd/mcp.go
  • internal/cmd/mcp_test.go
  • internal/cmd/requests.go
  • internal/cmd/root.go
  • internal/cmd/root_test.go
  • internal/jwtinfo/jwtinfo_test.go
  • internal/mcp/assets/examples/https-wrench-k3s.yaml
  • internal/mcp/assets/examples/https-wrench-proxyProtocolV2.yaml
  • internal/mcp/assets/examples/https-wrench-response-certificates-filter.yaml
  • internal/mcp/assets/sample-config.yaml
  • internal/mcp/assets/schema.json
  • internal/mcp/coverage_test.go
  • internal/mcp/embed.go
  • internal/mcp/prompts.go
  • internal/mcp/resources.go
  • internal/mcp/server.go
  • internal/mcp/server_test.go
  • internal/mcp/tools.go
  • internal/mcp/tools_exec.go
  • internal/mcp/tools_exec_test.go
  • internal/requests/requests.go
  • internal/requests/requests_handlers.go
  • internal/requests/requests_handlers_print_test.go
  • internal/requests/requests_handlers_test.go
  • internal/requests/requests_test.go
📝 Walkthrough

Walkthrough

Adds a Model Context Protocol server to https-wrench with embedded schema/assets, MCP resources/prompts, tools for validation/template/CLI building and execution (requests, certinfo, jwtinfo, JWKS), a new mcp CLI subcommand, request/response writer plumbing, and extensive tests and examples.

Changes

MCP Server Feature

Layer / File(s) Summary
Documentation & examples
README.md, assets/examples/*, internal/mcp/assets/examples/*, internal/mcp/assets/sample-config.yaml
Adds README docs for mcp, Cursor usage snippet, and multiple example YAMLs demonstrating anchors/aliases, ProxyProtocolV2, and certificate filtering.
Module dependencies
go.mod
Adds github.com/modelcontextprotocol/go-sdk v1.6.1 and supporting indirect deps for MCP usage.
Schema & embedded assets
https-wrench.schema.json, internal/mcp/assets/schema.json, internal/mcp/embed.go
Defines RequestDefaults and schema contracts; embeds schema, sample config, and example YAMLs with resource URI constants and example mapping.
MCP server core & transports
internal/mcp/server.go
Implements Run (stdio), NewServer (wires instructions/resources/prompts/tools), and RunInMemory for tests.
Resources & prompts
internal/mcp/resources.go, internal/mcp/prompts.go
Registers static/dynamic resources (schema/docs/sample-config/examples) and prompt author_requests_config producing starter YAML and example hints.
Tools: validation, template, CLI builder
internal/mcp/tools.go
Implements validate_requests_config, requests_config_template, and build_cli_command with YAML parsing, validation rules, path parsing, and stable shell-quoting/flag ordering.
Tool executors
internal/mcp/tools_exec.go
Exec handlers for run_requests, certinfo, jwtinfo, and generate_jwks with input loading, validation, timeout contexts, MCP-aware file reading, and output capture.
CLI wiring and init behavior
internal/cmd/mcp.go, internal/cmd/root.go
Adds mcp Cobra subcommand and detects/skips normal config init when MCP is invoked.
Requests output refactor
internal/requests/requests.go, internal/requests/requests_handlers.go
Routes request and response printing through an io.Writer parameter and updates related printing/render methods and call sites.
Certinfo & password handling
internal/certinfo/certinfo_handlers.go, internal/certinfo/certinfo.go, internal/certinfo/common_handlers.go
Adds IPAddresses output rendering and new NoPasswordPromptReader to support non-interactive passphrase reads from stdin.
MCP server & tool tests (in-memory)
internal/mcp/server_test.go, internal/mcp/tools_exec_test.go
In-memory server tests for features, resources, prompts, tool executions, CLI building, and failure modes.
Unit tests & coverage
internal/mcp/coverage_test.go, other test updates, .testcoverage.yml
Adds many unit tests covering helpers, YAML loading/validation, CLI command building, JWT helpers, file-reader behavior, and raises coverage threshold to 95%.

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly Related PRs

Poem

🐰 I rabbit-hop through stdio streams, a tiny MCP delight,
I tuck schemas, prompts, and tools beneath the soft moonlight,
I build and validate, then run requests with care,
From README to tests my carrots dance in the air—
A little wrench, now MCP-ready, leaps into the night.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding Model Context Protocol (MCP) server support, which is the dominant feature across the changeset.
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 feat/mcp

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🧹 Nitpick comments (1)
internal/mcp/embed.go (1)

29-30: ⚡ Quick win

Avoid pointing $schema to moving main branch.

Using refs/heads/main makes editor validation drift over time relative to the running binary. Prefer a versioned/tagged schema URL (or serve the MCP schema URI directly in generated examples) so validation remains stable.

🤖 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 `@internal/mcp/embed.go` around lines 29 - 30, schemaCommentHeader currently
points the $schema URL to a moving ref ("refs/heads/main"); change it to a
stable, versioned or tagged schema URL (or to the MCP schema URI you serve) so
editor validation won't drift. Update the const schemaCommentHeader to use a
released tag or versioned path (or the generated MCP schema endpoint) instead of
"refs/heads/main" so the schema URL is immutable and matches the binary's
expected schema.
🤖 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 `@https-wrench.schema.json`:
- Around line 58-60: The JSON schema currently declares "clientTimeout" as
"type": "number" but runtime expects an integer (RequestConfig.ClientTimeout in
internal/requests/requests.go); change the schema for the "clientTimeout"
property to use "type": "integer" (and optionally add a "minimum": 0 if
non-negative is required) so validation matches the runtime contract and
prevents float values from being accepted.

In `@internal/mcp/assets/examples/https-wrench-proxyProtocolV2.yaml`:
- Line 14: Typo in the example request name: rename the example's name value
from "RequestOverProxyPtorocolV2" to "RequestOverProxyProtocolV2" (fixing
"Ptorocol" -> "Protocol") and update any references to this symbol in the same
YAML/example outputs so they remain consistent (look for the name key and any
example identifiers that reference RequestOverProxyPtorocolV2).

In `@internal/mcp/server_test.go`:
- Line 277: The current code does an unchecked type assertion on
res.Messages[0].Content to *sdkmcp.TextContent which can panic; change it to a
two-value assertion (e.g., content, ok :=
res.Messages[0].Content.(*sdkmcp.TextContent)) and if !ok call the test helper
(t.Fatalf or t.Fatalf-like) with a clear message including the actual type,
otherwise extract text := content.Text and continue; update any nearby uses of
the variable `text` accordingly.

In `@internal/mcp/tools_exec.go`:
- Around line 411-443: captureWithStdout is unsafe because it reassigns the
global os.Stdout (process-wide) and drains the read end only after fn returns,
which can deadlock; to fix, serialize stdout capture by introducing a
package-level mutex (e.g., stdoutMu) and protect the section that sets os.Stdout
and restores it, run fn while concurrently draining pipeR into stdoutBuf (start
a goroutine that io.Copy into stdoutBuf before calling fn), ensure pipeW is
closed after fn returns, wait for the copy goroutine to finish (e.g.,
sync.WaitGroup or channel), then restore os.Stdout and merge stdoutBuf and
writerBuf into combined as before; reference captureWithStdout, fn, pipeR/pipeW,
os.Stdout, stdoutBuf, writerBuf, and combined to locate the changes.
- Around line 167-200: The functions executeRunRequests and executeCertinfo
ignore the passed context (they use _), so timeouts/cancellations aren’t
enforced; change each function to use the provided ctx and run the long-running
work under a context-aware wrapper (e.g., implement or use the suggested
runWithContext generic helper) so captureWithStdout and requests.HandleRequests
(or any long-running cert ops) execute inside runWithContext(ctx, func() (T,
error) { ... }); update the calls where you currently do
captureWithStdout(func(w io.Writer) error { ... }) to run that body inside the
runWithContext wrapper and return ctx.Err() on cancellation, and ensure
requests.HandleRequests or the cert handlers receive a context if they support
it (or are cancelled by the wrapper) so timeouts are properly enforced.

In `@internal/mcp/tools.go`:
- Around line 242-258: The template emits raw string scalars (variables name,
method, transport, hostname, and each path p) directly into YAML which can break
parsing for values containing special characters; update the writers in
internal/mcp/tools.go that call fmt.Fprintf/Fprintln for "name",
"requestMethod", "transportOverrideUrl", "hosts"->"name", and each "uriList"
entry to emit quoted, escaped YAML-safe scalars (e.g. use strconv.Quote or a
YAML marshaler to produce a quoted string) instead of raw %s so all interpolated
values are safely quoted/escaped; leave the boolean insecure emission unchanged.

In `@internal/requests/requests_handlers_print_test.go`:
- Around line 17-18: TestPrintResponseData (and the other test at 60-76) is
unsafely mutating global os.Stdout while running t.Parallel(), causing flaky
tests; fix it by removing the global stdout swap or by refactoring to avoid
global mutation: either (A) remove t.Parallel() from TestPrintResponseData and
the other stdout-swapping test so they run serially, or (B, preferred) change
the code under test (PrintResponseData) to accept an io.Writer (or add an
overload/helper that accepts io.Writer) and update the tests to pass a
bytes.Buffer (or io.Pipe) to capture output instead of reassigning os.Stdout;
ensure any temporary stdout replacement is eliminated so no global state is
mutated during parallel runs.

---

Nitpick comments:
In `@internal/mcp/embed.go`:
- Around line 29-30: schemaCommentHeader currently points the $schema URL to a
moving ref ("refs/heads/main"); change it to a stable, versioned or tagged
schema URL (or to the MCP schema URI you serve) so editor validation won't
drift. Update the const schemaCommentHeader to use a released tag or versioned
path (or the generated MCP schema endpoint) instead of "refs/heads/main" so the
schema URL is immutable and matches the binary's expected schema.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3ccb890c-f292-4a0b-bc69-eccf7474a6fe

📥 Commits

Reviewing files that changed from the base of the PR and between ebc097b and 51316cd.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (26)
  • README.md
  • assets/examples/https-wrench-k3s-anchor-and-aliases.yaml
  • go.mod
  • https-wrench.schema.json
  • internal/certinfo/certinfo_handlers.go
  • internal/cmd/mcp.go
  • internal/cmd/mcp_test.go
  • internal/cmd/root.go
  • internal/cmd/root_test.go
  • internal/jwtinfo/jwtinfo_test.go
  • internal/mcp/assets/examples/https-wrench-k3s.yaml
  • internal/mcp/assets/examples/https-wrench-proxyProtocolV2.yaml
  • internal/mcp/assets/examples/https-wrench-response-certificates-filter.yaml
  • internal/mcp/assets/sample-config.yaml
  • internal/mcp/assets/schema.json
  • internal/mcp/coverage_test.go
  • internal/mcp/embed.go
  • internal/mcp/prompts.go
  • internal/mcp/resources.go
  • internal/mcp/server.go
  • internal/mcp/server_test.go
  • internal/mcp/tools.go
  • internal/mcp/tools_exec.go
  • internal/mcp/tools_exec_test.go
  • internal/requests/requests_handlers_print_test.go
  • internal/requests/requests_test.go

Comment thread https-wrench.schema.json
"fmt"
"io"
"maps"
"net/http"

Copy link
Copy Markdown

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 external network dependency in the nil-reader test.

This test should be hermetic; using example.com makes it flaky if validation order changes and a request is attempted.

Suggested fix
 import (
 	"bytes"
 	"context"
 	"encoding/base64"
 	"fmt"
 	"io"
 	"maps"
 	"net/http"
+	"net/http/httptest"
 	"os"
 	"strings"
 	"testing"
 	"time"
@@
 func TestRequestToken_nilReadAll(t *testing.T) {
 	t.Parallel()
 
+	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
+		w.WriteHeader(http.StatusOK)
+		_, _ = w.Write([]byte(`{"access_token":"x"}`))
+	}))
+	defer srv.Close()
+
 	_, err := RequestToken(
 		context.Background(),
-		"http://example.com/token",
+		srv.URL,
 		map[string]string{"grant_type": "client_credentials"},
-		&http.Client{},
+		srv.Client(),
 		nil,
 	)
 	require.Error(t, err)
 	require.ErrorContains(t, err, "nil body reader")
 }

Also applies to: 260-272

Comment thread internal/mcp/assets/examples/https-wrench-proxyProtocolV2.yaml Outdated
Comment thread internal/mcp/server_test.go Outdated
Comment thread internal/mcp/tools_exec.go Outdated
Comment thread internal/mcp/tools_exec.go Outdated
Comment thread internal/mcp/tools.go Outdated
Comment thread internal/requests/requests_handlers_print_test.go
xenOs76 and others added 2 commits May 25, 2026 12:21
it is the probable cause of random test failure in Github CI
Route requests verbose output through the HandleRequests writer instead of
replacing os.Stdout, and skip terminal passphrase prompts for readers that
declare NoPasswordPrompt (MCP and test mocks).

Co-authored-by: Cursor <cursoragent@cursor.com>
@xenOs76 xenOs76 changed the title Feat/mcp Add Model Context Protocol (MCP) server support May 25, 2026
Enforce handler timeouts via runWithContext, quote generated YAML scalars,
tighten clientTimeout schema to integer, fix example typo, stabilize the
embedded $schema URI, and harden tests (safe type assertion, local jwt URL).

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/cmd/mcp_test.go (1)

11-33: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Parallel subtests still race on global os.Args.

Line 26 runs subtests in parallel while Lines 28-33 mutate os.Args. That can cause cross-subtest interference and flaky outcomes.

Suggested fix
 for _, tt := range tests {
 	t.Run(tt.name, func(t *testing.T) {
-		t.Parallel()
-
 		oldArgs := os.Args
 
 		t.Cleanup(func() { os.Args = oldArgs })
 
 		os.Args = tt.args
 		require.Equal(t, tt.want, isMCPCommand())
 	})
 }
🤖 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 `@internal/cmd/mcp_test.go` around lines 11 - 33, The subtests call
t.Parallel() while mutating the global os.Args which causes races; fix by making
the subtests run serially (remove the t.Parallel() call inside the anonymous
subtest) or, if you need parallelism, serialize access to os.Args by guarding
modifications/restores with a mutex around the os.Args assignment and
require.Equal call; locate the anonymous subtest where t.Parallel() is invoked,
the os.Args assignments and t.Cleanup, and the isMCPCommand() invocation to
apply the change.
🤖 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 `@internal/mcp/tools_exec.go`:
- Around line 169-176: The wrapper returns on ctx.Done() but the underlying
executors keep running because runRequestsExec and certinfoExec don't accept a
context and HTTP requests are created without one; fix by adding a context
parameter and propagating it: change runRequestsExec(...) and certinfoExec(...)
to runRequestsExec(ctx context.Context, ...) and certinfoExec(ctx
context.Context, ...), update executeRunRequests and executeCertinfo to call
runWithContext with a function that forwards the ctx into those executors, and
update internal/requests to create requests with http.NewRequestWithContext(ctx,
...) (and ensure reqClient.client.Do(req) uses that request) so in-flight HTTP
work is cancelled when the tool context is done.

---

Outside diff comments:
In `@internal/cmd/mcp_test.go`:
- Around line 11-33: The subtests call t.Parallel() while mutating the global
os.Args which causes races; fix by making the subtests run serially (remove the
t.Parallel() call inside the anonymous subtest) or, if you need parallelism,
serialize access to os.Args by guarding modifications/restores with a mutex
around the os.Args assignment and require.Equal call; locate the anonymous
subtest where t.Parallel() is invoked, the os.Args assignments and t.Cleanup,
and the isMCPCommand() invocation to apply the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5bc3404c-0b5f-45de-91d5-9787e4124cc8

📥 Commits

Reviewing files that changed from the base of the PR and between 51316cd and aa22215.

📒 Files selected for processing (20)
  • .testcoverage.yml
  • assets/examples/https-wrench-proxyProtocolV2.yaml
  • https-wrench.schema.json
  • internal/certinfo/certinfo.go
  • internal/certinfo/common_handlers.go
  • internal/certinfo/main_test.go
  • internal/cmd/mcp_test.go
  • internal/jwtinfo/jwtinfo_test.go
  • internal/mcp/assets/examples/https-wrench-proxyProtocolV2.yaml
  • internal/mcp/assets/schema.json
  • internal/mcp/coverage_test.go
  • internal/mcp/embed.go
  • internal/mcp/server_test.go
  • internal/mcp/tools.go
  • internal/mcp/tools_exec.go
  • internal/requests/requests.go
  • internal/requests/requests_handlers.go
  • internal/requests/requests_handlers_print_test.go
  • internal/requests/requests_handlers_test.go
  • internal/requests/requests_test.go
✅ Files skipped from review due to trivial changes (2)
  • .testcoverage.yml
  • assets/examples/https-wrench-proxyProtocolV2.yaml

Comment thread internal/mcp/tools_exec.go
Thread cancellation from MCP tool timeouts into HandleRequests,
http.NewRequestWithContext, and certinfo DialContext handshakes.
Remove parallel os.Args mutation in TestIsMCPCommand subtests.

Co-authored-by: Cursor <cursoragent@cursor.com>
@xenOs76

xenOs76 commented May 25, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown
✅ Actions performed

Full review triggered.

@xenOs76 xenOs76 merged commit b29b38a into main May 25, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant