Skip to content

feat(mcp): MCP-SAN + MCP-COV hardening#76

Merged
josealekhine merged 1 commit into
ActiveMemory:mainfrom
CoderMungan:feat/mcp-hardening-v2
May 10, 2026
Merged

feat(mcp): MCP-SAN + MCP-COV hardening#76
josealekhine merged 1 commit into
ActiveMemory:mainfrom
CoderMungan:feat/mcp-hardening-v2

Conversation

@CoderMungan
Copy link
Copy Markdown
Member

Closes #49, closes #50

Summary

Re-implementation of PR #52 adapted to the current codebase. Addresses
MCP-SAN (#49) sanitization requirements and MCP-COV (#50) coverage
requirements in full.


MCP-SAN (#49) — Sanitization layer

New packages

  • internal/sanitize: Content, Reflect, SessionID, StripControl, truncate
  • internal/config/sanitize: string/length constants (NullByte, DotDot, ForwardSlash, Backslash, HyphenReplace, MaxSessionIDLen)
  • internal/config/regex/sanitize: compiled regexes for Markdown structure chars and session ID unsafe chars

Config constants

Added to internal/config/mcp/cfg: MaxSourceLimit, MaxContentLen, MaxNameLen, MaxQueryLen, MaxCallerLen, MaxURILen

Error + text

  • internal/err/mcp: InputTooLong(field, maxLen) constructor
  • mcp.err-input-too-long and mcp.err-unknown-entry-type keys in embed/text and YAML

Applied sanitization

  • extract.EntryArgs: MaxContentLen guard → InputTooLong error
  • extract.SanitizedOpts: sanitizes all option fields
  • route/prompt/entry.buildEntry: sanitize.Content on every field value
  • route/tool/tool.go: sanitize.Content on content, sanitize.Reflect on query/caller, cap limit to MaxSourceLimit
  • route/tool/dispatch.go, route/prompt/dispatch.go, resource/dispatch.go: sanitize.Reflect for name/URI in unknown-branch paths

MCP-COV (#50) — Coverage expansion

New test files (12)

File Tests
internal/entity/mcp_session_test.go 10 (lifecycle + new methods)
internal/mcp/proto/schema_test.go 20 JSON round-trip tests
internal/mcp/server/def/tool/tool_test.go 9
internal/mcp/server/def/prompt/prompt_test.go 9
internal/mcp/server/extract/extract_test.go 8
internal/mcp/server/io/write_test.go 3
internal/mcp/server/out/out_test.go 8
internal/mcp/server/parse/parse_test.go 3
internal/mcp/server/stat/stat_test.go 2
internal/sanitize/sanitize_test.go 22

Extended: internal/mcp/server/server_test.go

Added 15 new tests covering all COV gaps:

  • TestServeNotificationIgnored — notification silently consumed
  • TestServeEmptyLines, TestServeParseErrorWriteFailure, TestServeDispatchWriteFailure
  • TestResourcesSubscribeInvalidJSON/EmptyURI, TestResourcesUnsubscribeInvalidJSON/EmptyURI
  • TestToolRemindWithActive, TestToolRemindFutureDated
  • TestToolDriftMissingFile
  • TestToolCompleteEmptyQuery, TestToolCompleteNoMatch
  • TestPromptAddLearning

CI

  • go build ./...
  • go test ./... ✅ (133 packages, 0 failures)
  • go vet ./...
  • golangci-lint run ✅ (0 issues)

Implements sanitization layer (MCP-SAN ActiveMemory#49) and coverage expansion
(MCP-COV ActiveMemory#50) for the MCP server.

Sanitization:
- Add internal/sanitize package: Content, Reflect, SessionID,
  StripControl, truncate helpers
- Add internal/config/sanitize constants (NullByte, DotDot, etc.)
- Add internal/config/regex/sanitize compiled regexes
- Add MaxSourceLimit, MaxContentLen, MaxNameLen, MaxQueryLen,
  MaxCallerLen, MaxURILen constants to internal/config/mcp/cfg
- Add InputTooLong error constructor in internal/err/mcp
- Add mcp.err-input-too-long and mcp.err-unknown-entry-type YAML keys
- Apply sanitize.Content in extract EntryArgs and prompt buildEntry
- Apply sanitize.Reflect for query, caller, name, URI in all
  tool/prompt/resource dispatch paths
- Cap source limit to MaxSourceLimit in tool handler

Coverage:
- internal/entity/mcp_session_test.go: 10 tests covering MCPSession
  lifecycle methods including PendingCount, RecordSessionStart,
  RecordContextLoaded, RecordDriftCheck, RecordContextWrite,
  IncrementCallsSinceWrite
- internal/mcp/server/server_test.go: 15+ new tests covering
  notification handling, subscribe/unsubscribe error paths,
  ctx_remind with active and future-dated reminders, ctx_drift
  missing-file violations, ctx_complete empty and non-matching query
- internal/mcp/proto/schema_test.go: JSON round-trip tests
- internal/mcp/server/def/{tool,prompt}/*_test.go: def count tests
- internal/mcp/server/{extract,io,out,parse,stat}/*_test.go: unit tests

Signed-off-by: CoderMungan <codermungan@gmail.com>
Copy link
Copy Markdown
Member

@josealekhine josealekhine left a comment

Choose a reason for hiding this comment

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

Minor fixes needed; but I'll take care of those.

Mostly around unicode parsing edge cases.

Thanks for the good work 🙏 .

@josealekhine josealekhine merged commit cf097a6 into ActiveMemory:main May 10, 2026
3 checks passed
omergk28 pushed a commit to omergk28/ctx that referenced this pull request May 11, 2026
Follow-up to PR ActiveMemory#76 (MCP-SAN + MCP-COV hardening) addressing three
issues surfaced during post-merge review:

1. truncate() now backs up to a UTF-8 rune boundary via utf8.RuneStart
   so byte-level cuts never produce invalid UTF-8. Reflect() and
   SessionID() delegate to the shared helper.

2. StripControl() now drops U+2028 (LINE SEPARATOR) and U+2029
   (PARAGRAPH SEPARATOR) explicitly. unicode.IsControl does not match
   these (categories Zl/Zp), yet Markdown renderers may treat them
   as line breaks — leaving them in opens a newline injection path
   through reflected content. Constants live in internal/config/sanitize.

3. SanitizedOpts now enforces MaxOptsFieldLen (4 KB) on context,
   rationale, consequence, lesson, and application — secondary
   prose fields that previously had no length cap. Signature
   changes to (entity.EntryOpts, error); the two call sites in
   route/tool/tool.go propagate the error to the MCP client via
   InputTooLong, naming the offending field.

Spec: specs/sanitize-hardening-followup.md
@CoderMungan
Copy link
Copy Markdown
Member Author

It’s been great working with you and being part of this project, Jose. Looking forward to the new features... @josealekhine

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.

MCP-COV: MCP Test Coverage MCP-SAN: MCP Server Input Sanitization

2 participants