Skip to content

Expose all technical diagnostics over MCP - #1723

Merged
frahlg merged 2 commits into
masterfrom
codex/mcp-read-api
Oct 18, 2026
Merged

frahlg merged 2 commits into
masterfrom
codex/mcp-read-api

Conversation

@frahlg

@frahlg frahlg commented Oct 18, 2026 •

Copy link
Copy Markdown
Member

Contract-pair: srcfl/ftw-webapp@codex/mcp-read-api

MCP exposes a few summaries today. It cannot collect the full energy ledger, original driver measurements, incident planner inputs, source code or support files needed to explain faults and report bugs.

Add api.read for the full technical read API. The connected box builds its catalogue from its router: all 63 Read routes and 10 local diagnostic reads, including configuration, driver source and logs, OCPP state, support exports, backups and agent audit. New Read routes appear without another Cloud release. Existing handlers validate their query parameters. OAuth exchanges, scan/update actions, writes and hardware commands keep their existing paths.

The owner's diagnostic grant (ftw.diag.run) covers every technical read. There is no second data-scope gate or identity filter: names, addresses, hardware ids, exact numbers, paths and source code stay as the handler returns them. Saved credentials retain the handler's existing masking. Full backup exports can include unmasked credentials and the state database; the full diagnostic grant intentionally covers those bytes without a separate backup permission. Core checks the live grant before each response frame; revocation or expiry stops the answer. The grant's shared description now says it covers the full read API.

Large answers use byte pages with SHA-256 checks to detect changed content, without a total-byte cutoff. JSON, CSV, text and binary data remain available. An assistant can also list ZIP/tar.gz members and read their contents on the box, so support files need no external tool. Each call keeps one bounded page in memory; archive inspection uses a private temporary file and removes it on return. The follow-up #1726 gives exports five minutes and preserves encoded path parameters. Calls keep the session's rate limits. Generated exports may change between reads; member reads hash the selected content.

api_catalog also supplies the Core version, source links for the declared release or recorded build, related repositories, and a workflow for gathering bug evidence. It marks an unknown source version or local changes. Routine status, history and control keep their existing MCP tools. A bug-report draft should include times and timezone, reproduction steps, expected and observed results, versions, queries, logs, snapshots and evidence gaps.

Paired PRs: Cloud #35, webapp #98, native #91. This capability needs a Core beta with this code and the Cloud counterpart. The minor changeset needs owner approval.

Validation:

  • GOWORK=off make verify.
  • Complete race suites for internal/api, internal/appproto and internal/apiauth.
  • Protocol-module tests, including fixed CBOR vectors and refusal of an added method field.
  • A real energy-store test keeps the measured 12 Wh, technical asset id, quality and provenance; CSV works too.
  • Route coverage, future Read discovery, diagnostic grant checks, revocation in flight, byte-for-byte paging beyond 1 MiB, changed-page refusal, ZIP/tar.gz member reads and corrupt-member refusal.
  • Byte-identical registry copies and paired client contract checks.

No physical-box or real assistant-account test has run for this new capability.

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

Summary

  • Hardened diagnostic API reads by requiring handlers to declare an application/json media type before their response is parsed, redacted, or returned. Unexpected or malformed media types now produce a safe 502 Bad Gateway response. go/internal/api/api_agent_reads.goL62-L80
  • Added regression coverage proving that JSON-looking content with a non-JSON content type is rejected without reflecting the original response body. go/internal/api/api_agent_reads_test.goL116-L128
  • Updated the oversized-response fixture to explicitly satisfy the JSON media-type contract. go/internal/api/api_agent_reads_test.goL101-L113
  • Committed the changes as 498b4a7 (fix(agents): require JSON diagnostic responses) and prepared the follow-up PR metadata.

Testing

  • ✅ GOWORK=off go test ./internal/api
  • ✅ GOWORK=off go test -race ./internal/api -run 'TestDiagnostic|TestAgentReads' -count=1
  • ✅ git diff --check
  • ⚠️ GOWORK=off go test -race ./internal/api ./internal/appproto ./internal/redact (internal/appproto and internal/redact passed, but the broader internal/api suite failed; its very large output was truncated before identifying the failing test. The targeted diagnostic API race tests pass.)
  • ❌ gofmt -w go/internal/api/api_agent_reads.go go/internal/api/api_agent_reads_test.go && GOWORK=off go test ./internal/api (initial invocation used repository-relative paths while already inside the go directory; rerun successfully with corrected paths.)

View task →

@frahlg frahlg changed the title feat(agents): expose diagnostic API reads to MCP Expose all technical diagnostics over MCP Oct 18, 2026
@frahlg
frahlg marked this pull request as ready for review October 18, 2026 14:26
@frahlg
frahlg merged commit 14f6c89 into master Oct 18, 2026
22 checks passed
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-18T14:28:59.052817Z 94890d1 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 94890d1a15

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

"/api/support/dump": true,
"/api/support/report": true,
"/api/ocpp/chargers": true,
"/api/backups/{id}": true,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep full backups outside diagnostic reads

An agent granted only ftw.diag.run can enumerate /api/backups and then read /api/backups/{id} through this allowlist. That endpoint was deliberately classified Local because the archive contains the unmasked configuration and state.db; unlike /api/config, the backup path does not redact stored credentials. This turns a diagnostic grant into a complete secrets and persistent-state export, so backups should remain unavailable through this scope or require a separate explicit backup permission.

Useful? React with 👍 / 👎.

var once sync.Once
free := func() { once.Do(func() { h.apiBusy.Store(false) }) }
defer free()
ctx, cancel := context.WithTimeout(h.ctx, apiHandlerTimeout)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid the 15-second deadline for paged exports

For every page, ServeAgentRead regenerates and hashes the entire response before returning the retained slice, but this context cancels the operation after 15 seconds. Consequently, sufficiently large support dumps, research exports, or other advertised unlimited-size reads cannot return even their first page (and later pages repeat the same full scan); this is especially likely for archive handlers whose normal HTTP path explicitly permits long-running downloads. Use an export-appropriate lifetime or a snapshot/streaming pagination design that does not require processing the whole answer within the ordinary API timeout.

Useful? React with 👍 / 👎.

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