Skip to content
IsoKron

Research / Public audit in Write correctness

GitHub MCP server v2.1.0: concurrent issue-field updates can silently lose changes

By IsoKron Research. Published . 23 minute read. AI-assisted.

Protocol
MCP 2025-11-25 (negotiated), stdio
Software
github/github-mcp-server v2.1.0 (commit 4bcdcdf8, Docker image pinned by digest); retests also on main at 99d6d650
Client
Claude Code 2.1.241 with Claude Opus and Claude Sonnet, MCP tools only; scripted JSON-RPC probes

Self-funded research by IsoKron, conducted and written with AI assistance. Not commissioned or endorsed by GitHub; IsoKron is not affiliated with GitHub. IsoKron sells MCP server audits and maintains the tools used here.

We gave Claude agents write access to a GitHub organization through GitHub's official MCP server, version 2.1.0, pinned by image digest, and had them do routine development work: fix a bug and merge the pull request, review a pull request, triage issues, rename code across files. Everything ran in a throwaway organization with one private repository of fake data, using tokens that could reach nothing else.

The most serious finding concerns concurrent issue_write calls that update different organization issue fields on the same issue, run from two separate server processes. One of the two changes was lost in 19 of 30 concurrent pairs (63%); both calls returned success. GitHub's per-field update, run as a control in the same sessions, lost 0 of 28 pairs.

In total: 78 agent runs over 7 tasks, including the 24 benchmark runs, and 683 writes in probes, developer runs, refuter checks and retests; the 683 does not include writes made by the benchmark runs. The audit produced 17 findings and 3 further observations: 13 findings are newly reported upstream in 11 new issues, and 4 were already covered by earlier upstream reports. In a before/after benchmark, an IsoKron experimental build used 26% fewer MCP tool calls and 18% fewer turns per round of four jobs, mostly because of two new batch-read tools. Both builds passed 12 of 12 runs, so that benchmark does not measure the correctness fixes; the evidence for those is the lost-update test.

Setup and boundary

Everything ran against one private repository of fake data in an organization IsoKron owns; no other users' data was touched.

ItemRead-only phaseWrite phase and benchmark
Serverv2.1.0 (commit 4bcdcdf8), Docker image pinned by digest, run locally over stdio with --read-only; profiles of 9, 27 and 57 toolsv2.1.0, write-enabled; toolsets repos, issues, pull_requests, context
TokenFine-grained, audit repository only, read-onlyFine-grained, audit repository only; Contents, Issues and Pull requests read/write; 7-day expiry
AgentsClaude Sonnet via Claude Code, MCP tools onlyClaude Opus "developer" runs, scripted JSON-RPC probes with no model in the loop, clean-context Sonnet refuters
Writes0683 in probes, developer runs, refuter checks and retests (benchmark runs not included); no rate limits hit
CaptureEvery JSON-RPC message logged; tokens and signed URLs redactedSame

Out of scope: prompt injection, load testing against live GitHub, a second (non-collaborator) account, and other users' repositories. The boundary is deliberately narrow so that every result traces to one repository, one token and one server build.

Headline finding: concurrent issue-field updates silently revert (GH-01)

Two agents set different organization issue fields on the same issue at the same time through issue_write, each through its own server process. One change was lost in about two of every three pairs and both calls returned success; GitHub's per-field update lost none.

RunWho ran itLost via issue_writeLost via GitHub per-field mutation
1finder10 of 110 of 11
2finder, fresh issue5 of 110 of 11
3separate-model refuter, own code4 of 80 of 6
Total19 of 300 of 28
  • Fields used: Priority (single select) and Target date, written from two separate server processes, read back through GraphQL. Both calls returned success in every pair, and in all 15 lost pairs of runs 1 and 2 the lost field went back to its exact earlier value.
  • Cause (v2.1.0, pkg/github/issues.go): fetchExistingIssueFieldValues reads all values (lines 406–465), mergeIssueFieldValues (471) merges in the requested change, and the full set is sent back by REST PATCH (3478, patchIssue 3628). REST PATCH set semantics are standard API behaviour; the issue is that the tool performs a read-merge-write with no version check, so two agents' independent changes overwrite each other. There is no lock or retry, and no concurrency caveat is documented.
  • The same code path requests only the first 25 field values and does not paginate; by code inspection, values beyond that would be omitted from the replacement set. We did not exercise this case separately.
  • Exposure: in the code since v1.1.0 (2026-05-27), described then as insiders-only; in v2.1.0 over stdio, issue_write exposes issue fields with no feature flag. The behaviour is unchanged on the main branch (commit 99d6d650).
  • An alternative path exists: the feature-flagged set_issue_fields tool uses the per-field mutation that lost 0 of 28 pairs in the control.
  • Upstream: issue 3751, with a proposed fix now submitted as pull request 3781: send only the changed fields through GitHub's per-field endpoints. In our test of that approach, a patched build lost 0 of 12 concurrent pairs and 0 of 3 clear-versus-set pairs, while v2.1.0 lost 2 of 6 in the same session.

For teams planning to let agents work in their organization, this is the finding that matters most. Issue fields hold priority, effort and dates, the data planning runs on. Two agents grooming a backlog at the same time is routine, and nothing reports the loss: the call returns success and the field reverts to its earlier value.

Other write-path findings

The other write-path defects share one pattern: what the tool reports does not match what happened in the repository.

  • Deletes (GH-02, GH-03): delete_file takes no sha, so it deletes content another writer changed after the caller's read, and a folder path deletes every file under it. Both calls report success.
  • Partial writes (GH-04, GH-05): when push_files creates a new branch and the push then fails, the new branch stays behind at the default branch's head. PR creation or editing can succeed, then return an error if the reviewer request fails. On creation the new PR number and URL are lost; on update the edit stays applied although the call reports an error.
  • No-op writes (GH-06): issue_write skips an empty title or body, and write tools drop unknown or misspelt parameters; the call returns success with nothing changed.

Findings register

The register lists 17 findings: 13 newly reported in 11 new issues, filed on 2026-11-08 and 2026-11-09, and 4 covered by existing upstream reports (we added reproductions to two of those threads). Three further observations were not filed and follow the register; 1 refuted claim is excluded.

IDFindingWhere the cause isTypeStatusUpstream
GH-01issue_write rewrites every issue-field value to change one; concurrent updates to different fields revert each other (19 of 30 pairs lost)MCP serverreliabilityFiledissue 3751; fix in pull request 3781
GH-02delete_file has no version check; it deletes content written after the caller's readMCP serverreliabilityFiledissue 3757
GH-03delete_file on a folder path deletes the whole folder and reports successMCP serverhardeningFiledissue 3757
GH-04When push_files creates a new branch and the push then fails, the new branch is left behind at the default branch's headMCP serverreliabilityFiledissue 3755; community fix PR 3778
GH-05PR creation or editing can succeed, then return an error if the reviewer request fails (reviewer is the PR author or not a collaborator). On creation the new PR number and URL are lost; on update the edit stays applied although the call reports an errorMCP serverreliabilityFiledissue 3756; community fix PR 3784
GH-06Silent no-op updates: issue_write skips an empty title or body, and misspelt or unknown parameters are dropped; success is returnedMCP serverreliabilityFiledissue 3759
GH-07update_issue_labels replaces labels but is annotated destructiveHint: false. destructiveHint is an MCP annotation clients use for confirmation prompts, not an enforcement control (feature-flagged tool)MCP annotationshardeningFiledissue 3760; spec question raised with the Tool Annotations Interest Group
GH-08GITHUB_READ_ONLY and GITHUB_LOCKDOWN_MODE are parsed with Go's strconv.ParseBool, so only 1, t, T, true, True or TRUE turn the mode on; yes, on, enabled or a typo leave the mode off, shown only as readOnly=false in the INFO startup log line. The --read-only flag rejects such valuesMCP server confighardeningFiledissue 3747; community fix PR 3750
GH-09Directory listings put tokenised private-repo download URLs into model contextGitHub REST response, passed on by the MCP serverhardeningFiledissue 3748
GH-10Config typos handled inconsistently: unknown tool is fatal, unknown toolset starts with 0 tools, misspelt --exclude-tools and --features entries are silentMCP serverusabilityFiledissue 3761; community fix PR 3771
GH-11Protocol-gated tools are listed by the client's requested protocol version, not the negotiated one (delete_repository listed in a 2025-11-25 session). Low impact: by code reading, deletion still requires confirmation through elicitationMCP serverdefectFiledissue 3763
GH-12Advertised page bounds not enforced on four tools: page = -1 is forwarded; page = 2^53 is forwarded and GitHub answers with an opaque HTTP 500MCP serverdefectFiledissue 3762; community fix PR 3785
GH-13page = -2^63 passes the range check and returns a raw Go decode error with internal type namesMCP servercosmeticFiledissue 3762
GH-14Labels can only be replaced; read-then-replace loses a concurrent addMCP serverreliabilityAlready reportedissue 3473, issue 2724; our reproduction
GH-15push_files has no head check; a stale push reverts a same-path changeMCP serverreliabilityAlready reportedissue 3473; our reproduction
GH-16push_files silently creates a missing branch from mainMCP serverhardeningAlready reportedissue 3473
GH-17README says the environment variable overrides --toolsets; the flag winsREADMEdocsAlready reportedissue 3578; fix PR 3585

Upstream statuses checked 2026-11-09. Filed means IsoKron opened the upstream issue; Already reported means an earlier upstream issue covers the finding. GitHub-side behaviours noted but not counted: an unknown label name creates a new label; NUL bytes are stripped from issue titles and bodies; some passed-through errors (GitRPC::BadObjectState) give no remedy.

Upstream status, 9 November 2026

  • All 11 issues are open. GitHub has labelled issue 3747 as a bug and issue 3748 as an enhancement.
  • IsoKron's own fix for GH-01 is open as pull request 3781: it sends only the changed issue fields through GitHub's per-field endpoints. It is awaiting maintainer review and is not merged.
  • Five fixes have come from other contributors: PR 3750 for the read-only parsing in issue 3747, PR 3771 for the silent --exclude-tools and --features typos in issue 3761, PR 3778 for the leftover branch in issue 3755, PR 3784 for the lost pull request details in issue 3756, and PR 3785 for the page bounds in issue 3762. All five are open; none is merged.
  • The annotation finding raises a question for the MCP specification as well as for this server: when may a tool that replaces existing values declare destructiveHint: false? We shared the annotation results with the MCP Tool Annotations Interest Group in issue 10.
  • The latest release is still v2.1.0, and the code behind GH-01 is unchanged on main.

We update this section as upstream moves.

Other observations

  • Not filed: API-level behaviour. issue_write and add_issue_comment send no idempotency key, so a retry after a lost response creates a duplicate issue or comment. This is GitHub API behaviour; the MCP server adds no protection of its own.
  • Not filed: unconfirmed, source code only. Projects items for pull requests carry merged_at but no merged field, and the test fixture hard-codes merged: true. Not reproduced live.
  • Not filed: integers above 2^53 lose precision (refuter-narrowed). An integer parameter of 2^53+1 was rounded on the way through the server (pkg/github/params.go, lines 68–93); the refuter narrowed this to low impact. Related SDK report: go-sdk issue 1201.

Ease of use: missing one-step operations

The agents completed every job, but several common steps took up to 13 calls where one or two would do.

GapWhat the agents did insteadCalls on v2.1.0With a one-step tool
A review with body, verdict and line commentsCreate a pending review, add each comment, submitN+2 (5 with 3 comments)1; GitHub's REST API already takes all of it in one call
No whole-repo file list or multi-file readCrawl folders one by one with get_file_contents12–131–2
No add-label or remove-label toolRead the labels, write back the full set2, and lossy (GH-14)1
Write tools return an internal ID, not the issue or PR numberRead the object back and parse its URL1 extra read0
Review-comment read and reply use different ID typesExtra read and URL parsing1 extra read0
create_branch cannot start from a commit SHAPass the SHA as a branch name, which fails1 failed call per attempt1
No milestone create, no compare; blame only behind the file_blame feature flagStep blocked or worked around——
  • Tool choice: for labels and assignees, agents first tried get_label and list_repository_collaborators; the call that worked was ui_get, described as "UI data for MCP Apps".
  • push_files: a mistyped branch is created silently (GH-16, confirmed by probes); in the source, files are always written as non-executable, and deletes and renames are not possible.
  • Error quality: apart from GitHub's rejection of a review requesting changes on the agent's own pull request, the failures were GitHub errors passed through without a remedy.

Reviews are the first fix: a complete review is one REST call and five MCP calls, and every extra call is another point where an agent can go off course. Returning issue and pull request numbers from write calls is the second: without them, an agent that creates an issue has to look it up again before it can refer to it.

Developer runs: calls and cost per job

Most of the observations above come from 8 developer runs: the four write-phase jobs, run twice each on v2.1.0 by Claude Opus (claude-opus-5) in Claude Code 2.1.241, with MCP tools only. They took 17–33 MCP tool calls and about $0.77–$1.37 per run. These 8 runs are separate from the 24 benchmark runs below and are not part of the benchmark table.

JobRunMCP tool callsTurnsFailed callsCost
Bug fix → PR → merge129340$1.20
Bug fix → PR → merge224290$1.07
PR review with inline comments119221$0.87
PR review with inline comments217201$0.77
Triage 10 issues133390$1.37
Triage 10 issues231370$1.28
Rename a function across code, tests and docs, one commit125290$0.85
Rename a function across code, tests and docs, one commit224280$0.78
All 8 runs2022$8.19
  • Cost is Claude Code's reported API-equivalent figure for the run, not an invoice.
  • Tool calls are MCP calls to the server. Claude Code's own tool-search calls (2–5 per run) are not counted.
  • All 8 runs reached the required end state. The one failed call in each review run is GitHub rejecting a review that requests changes on the agent's own pull request; both runs then submitted the review as a comment. In triage there was no milestone and no tool to create one, so both runs reported that step as blocked.
  • The four jobs of a round ran in parallel on the same repository, each on its own branches; the second round followed the first.

What held up

Most of what we tested held. The single-file write path handles versions correctly and the read-only flag fails closed; most findings sit in the newer multi-step write paths.

  • Different-field edits outside issue fields don't collide: issue body vs labels 11 of 11, PR title vs body 11 of 11, granular title vs labels 5 of 5.
  • Single-file writes are safe: create_or_update_file rejects a stale version.
  • Concurrent multi-file pushes to one branch: the second push fails rather than silently losing a commit, and a failed push to an existing branch leaves nothing behind.
  • No boolean coercion: the string "false" is rejected as a boolean rather than read as true.
  • The read-only flag fails closed: --read-only=yes exits with an error. Only the environment-variable form fails open (GH-08).
  • Default catalog size: about 10.7K model-visible tokens for the 46 tools in the default toolsets (cl100k estimate).
  • Canary check: the planted test marker did not appear in captured tool-call arguments or final responses. Captured: every JSON-RPC message between client and server, and each run's Claude Code event stream including the final answer. In the benchmark, agents read the file holding the marker in 6 of 12 runs per build.

Benchmark: what fixing the friction changes

An IsoKron experimental build of v2.1.0, carrying a combined set of write-path fixes and usability changes, used 26% fewer MCP tool calls and 18% fewer turns per round of four jobs than v2.1.0, with failed calls down from 3 to 1 per round. All 24 runs passed.

Most of the 26% comes from two new batch-read tools, a whole-repo file list and a multi-file read, not from the write-path fixes. Across the three runs of each job, get_file_contents calls fell from 40 to 8 in the rename job, 34 to 14 in the bug fix and 32 to 0 in triage: 84 fewer calls. Total calls over all 12 runs per build fell from 321 to 244: 77 fewer, net of 21 calls to the two new tools.

This benchmark does not measure the correctness fixes. Both builds pass 12 of 12 runs, each run is one agent working alone, and the changed write behaviours (push_files without silent branch creation, delete_file refusing folders, an error on no-op updates) were never triggered in the experimental build's runs. The evidence for the write-path fixes is the lost-update test under GH-01: 19 of 30 concurrent pairs lost a change on v2.1.0 against 0 of 28 through GitHub's per-field API, and the patched build lost 0 of 12. Results here measure the combined set of changes, not each change individually. For why we count calls and turns rather than tokens, see why MCP tool design matters.

Method: the four write-phase jobs, run 3 times each on v2.1.0 and 3 times each on the experimental build, by Claude Opus (claude-opus-5) in Claude Code 2.1.241 with MCP tools only. The run and grading scripts were hashed, and the hashes checked, before the first run. File timestamps show that the analysis script, which only post-processes the captured results, and the hash list itself were last written about two minutes after the first run began. The published hash (sha256 a08ebac0…) is of that final list, and it was checked at the start of the second phase. The repository was reset to the same state before every run, and only the server image changed between phases.

The experimental build adds write results that return the issue or PR number and URL; a one-call review with inline comments; consistent review-comment IDs; add-label and remove-label tools; per-field issue-field writes (the GH-01 fix); a whole-repo file list and multi-file read; create_branch from a SHA; a version check on delete_file and no folder deletes; push_files without silent branch creation or orphan branches; and an error on no-op updates.

Definitions used in the table:

  • Tool call: one MCP tool invocation.
  • Turn: one model response cycle.
  • Failed call: an MCP call that returned an error.
  • Passing run: the job's end state met its acceptance checks.

All 24 runs passed although some individual calls failed. Pass or fail is judged on the end state only, so a run passes when the agent works around a failed call, for example by resending a review that GitHub rejected as a comment.

Values are medians over 3 runs, with [min–max]. Bold marks non-overlapping observed ranges; with three runs per build this is descriptive, not a significance test. The per-round row sums one complete run of all four jobs and reports the median over the 3 rounds; it is not the sum of the per-job medians.

JobMCP tool calls, v2.1.0 → experimentalTurns, v2.1.0 → experimentalFailed calls, v2.1.0 → experimental
Bug fix → PR → merge30 [27–30] → 25 [21–25] (−17%)37 [34–38] → 32 [32–34]1 [1–1] → 0 [0–0]
PR review with 3 inline comments21 [19–22] → 17 [15–20]25 [25–27] → 24 [21–30]2 [2–2] → 1 [1–2]
Triage 10 issues35 [33–35] → 25 [25–28] (−29%)43 [40–46] → 35 [34–36] (−19%)0 → 0
Rename across 3 files, one commit22 [22–25] → 14 [11–18] (−36%)27 [27–32] → 21 [20–23] (−22%)0 → 0
Per round of all four jobs109 [101–111] → 81 [81–82] (−26%)137 [126–138] → 113 [111–118] (−18%)3 [3–3] → 1 [1–2]
  • Where the calls went: the whole-repo file list and multi-file read replaced folder-by-folder crawls. Across the three runs of each job, get_file_contents calls fell from 40 to 8 in the rename job, 34 to 14 in the bug fix and 32 to 0 in triage. That is 84 of the calls saved, against a net fall of 77 in total calls.
  • Reviews: the one-call review cut write tool calls in the review job from 11 to 6 per run (−45%); a review with 3 inline comments went from 5 calls to 1.
  • Error rate: 9 of 321 tool calls failed on v2.1.0 (2.8%) and 4 of 244 on the experimental build (1.6%). On v2.1.0, the bug-fix runs hit a missing path while crawling, and all 3 review runs failed create_branch with a SHA. The remaining failures in both builds are GitHub rejecting a review that requests changes on the agent's own pull request; the experimental build returns that rejection at the create step instead of the submit step.
  • Read-only baseline: in 27 read-only runs across tool profiles of 9, 27 and 57 tools, every run found the expected facts with 0 tool errors; 18 more runs with every tool definition loaded up front also had 0 tool errors.

Limitations

  • Three runs per job per build. Non-overlapping ranges at that size are a coarse screen, not a significance test, and an overlap does not show there is no effect.
  • Tokens, cost and wall time are not distinguishable between the builds at three runs: the ranges overlap for every job and per round (cost per round $3.93 [$3.85–$4.26] on v2.1.0, $3.77 [$3.44–$4.14] on the experimental build).
  • The two phases ran back to back, about 20 minutes apart, not interleaved. Any drift over time in API latency or model serving lands in the difference between builds.
  • Another process made small writes in the same repository during the second phase. The run guard did not flag them, but they shared the repository.
  • Failed-call counts are not strictly like-for-like. The experimental build turns some silent misbehaviour into errors, and its one-call review moves GitHub's rejection from the submit step to the create step.
  • One job's prompt asks for something v2.1.0 cannot do: the review job says to put a commit SHA on a new branch, and v2.1.0's create_branch takes only a branch name. The experimental build adds create_branch from a SHA, so that job favours it by construction.
  • One model (claude-opus-5), one Claude Code version and one prompt per job. Other models may use the new tools differently, or not at all.
  • The experimental catalog is larger by four tools (next section). That fixed overhead partly offsets the per-call savings and would weigh more on short tasks.

Catalog size

With the default toolsets, the experimental build lists four more tools than v2.1.0 (50 against 46), and its catalog is 984 tokens larger: 11,716 against 10,732 model-visible tokens, which is +9% on the v2.1.0 base. With the four toolsets used in the benchmark, the same 984 tokens are +9.6% on a base of 10,215. For reference, all 91 v2.1.0 tools are about 23.4K tokens; icons make up 56% of the full tools/list bytes. Token figures use cl100k as a common baseline; cl100k is not Claude's tokenizer, and the figures are estimates of definition size. How much of the catalog reaches the model depends on the client: in these runs Claude Code loaded definitions on demand through its tool search, while a client that loads every definition up front puts the whole catalog in context on every turn.

Rebuild the experimental server

The experimental build is public at isokron-ai/github-mcp-writepath-experiment: the unmodified v2.1.0 tag, the changes as separate commits and as a patch series that applies to a clean v2.1.0 checkout, the tests added for each change, and the results above. The benchmark harness is not public yet, so this section covers rebuilding the server, not re-running our benchmark. To compare the builds yourself, build both versions from source, point the same MCP client at each, run the same job, and compare tool calls, turns and failed calls. The figures above measure the combined set of changes, not each change on its own.

The build is a research experiment, not an official GitHub release and not maintained against later versions; use the official server for real work and run the experiment only with a short-lived token in a test organization. The benchmark harness itself is tied to our private test repository and will be published separately in a general form. If your results differ from ours, open an issue on the repository with the job, model, client version and counts. Fixes that prove useful are being offered upstream as small, separate pull requests, starting with the GH-01 fix in pull request 3781.

What this means for teams adopting the GitHub MCP server

Four practices follow from the findings for teams running v2.1.0.

  • Don't let agents update organization issue fields concurrently through issue_write until issue 3751 is fixed. Use the per-field path (the feature-flagged set_issue_fields tool) or serialize the updates.
  • Verify read-only mode: start the server with --read-only, or set GITHUB_READ_ONLY to 1 or true, then confirm that write tools such as issue_write are absent from tools/list.
  • Check end state after multi-step writes. An error response does not mean nothing was written: PR create and update (GH-05) and push_files (GH-04) can leave changes behind.
  • Prefer single-file writes with a sha (create_or_update_file) for safety-critical edits: it rejects a stale version, while push_files and delete_file have no version check.

How findings were checked

Every candidate finding goes to a refuter on a different model, in a clean context, which confirms, narrows or rejects it against the reproduction and the source.

  1. Static sweep of all 91 tool definitions served under the negotiated protocol version (2025-11-25): schemas, annotations and catalog weight. A client that requests protocol 2026-07-28 with form elicitation is shown 92 tools, because delete_repository is added (GH-11).
  2. Agent runs with the run and grading scripts hashed before measuring (the benchmark section gives the exact timing for that harness), and every JSON-RPC message logged.
  3. Write-side probes: scripted JSON-RPC with no model in the loop, plus Claude Opus developer runs.
  4. Refuters on a different model (Sonnet), each with a clean context and its own code, confirmed, narrowed or refuted every write-side claim.
  5. Duplicate search against existing upstream issues before filing.
  6. Retest before filing: the findings in the eight issues filed from 3755 to 3763 were re-run on both v2.1.0 and the main-branch nightly build (commit 99d6d650), and all reproduced on both; GH-01, GH-08 and GH-09 were re-checked live before they were filed.

Refuter results for the write side: of 14 claims, 7 were confirmed as stated, 6 were narrowed to the conditions under which they hold, and 1 was refuted: search_code returning nothing on a private repo is GitHub's indexing, and REST returns the same. The refuted claim is excluded from the findings register. 3 of the 14 overlap existing upstream reports.

Defects found in our own instrumentation during the engagement were corrected and the affected figures re-checked; none changed the findings reported here.

What the checking caught before anything went out:

  • The labels problem first looked like a coin-flip race. The refuter showed that truly simultaneous adds lose about 1 in 5, and that the reliable loss is an agent reading labels and writing the full set back; the finding is stated that way.
  • A draft of one issue said the server strips two URL fields from directory listings. A recheck showed it does not, and the issue was corrected before filing.
  • The README finding (GH-17) turned out to be already reported upstream, with a fix PR, so it was not filed again.

About this research

IsoKron performs fixed-price MCP server audits with the same method: real agent tasks against a pinned build, write-side probes, separate-model refutation, upstream filing and a before/after benchmark. Details: MCP server audits.

Get new research by email

New MCP audits and research, about twice a month, plus occasional IsoKron service news. Unsubscribe anytime.

Sent with Kit. See our privacy page.