Skip to content

fix: report registered MCP tool count - #504

Merged
mergify[bot] merged 3 commits into
mainfrom
fix/502-dynamic-tool-count
Jul 10, 2026
Merged

fix: report registered MCP tool count#504
mergify[bot] merged 3 commits into
mainfrom
fix/502-dynamic-tool-count

Conversation

@charliecreates

@charliecreates charliecreates Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • count successful tool and registerTool registrations dynamically
  • report the observed count on the mcp.tools.register span
  • cover direct registrations and internal tool delegation without double-counting

Testing

  • npx vitest run src/index.test.ts src/tools/annotations.test.ts
  • npm run check
  • npm run check:types
  • npx vitest run --exclude tests/integration/**
  • npm run build
  • npm run check:changeset

Resolves #502

✨ PR Description

Purpose: Replace hardcoded tool count with dynamic tracking to accurately report registered MCP tools during server initialization.

Main changes:

  • Implemented createToolCountingServer() proxy wrapper to track actual tool registrations via tool() and registerTool() calls
  • Refactored tools registration span to use dynamic count from proxy instead of hardcoded value of 6
  • Added comprehensive test coverage validating tool count accuracy in registration span attributes

Generated by LinearB AI and added by gitStream.
AI-generated content may contain inaccuracies. Please verify before using.
💡 Tip: You can customize your AI Description using Guidelines Learn how

@gitstream-cm gitstream-cm Bot left a comment

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.

✨ PR Review

LGTM

Generated by LinearB AI and added by gitStream.
AI-generated content may contain inaccuracies. Please verify before using.
💡 Tip: You can customize your AI Review using Guidelines Learn how

@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.59259% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.53%. Comparing base (fb00d27) to head (66d06e5).

Files with missing lines Patch % Lines
src/index.ts 92.59% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #504      +/-   ##
==========================================
- Coverage   90.55%   90.53%   -0.03%     
==========================================
  Files          24       24              
  Lines        1091     1109      +18     
  Branches      281      283       +2     
==========================================
+ Hits          988     1004      +16     
- Misses         45       46       +1     
- Partials       58       59       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mergify

mergify Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-07-10 10:31 UTC · Rule: default · triggered by rule Queue pull requests labeled 'queue'
  • 🚫 Left the queue2026-07-10 10:43 UTC · at 5bbc1f85eeeaea8a4594a3c1b79f087c6411aa7d

This pull request spent 12 minutes 2 seconds in the queue, with no time running CI.

Reason

Pull request #504 has been dequeued

Queue conditions are not satisfied:

  • -conflict [📌 queue requirement]

Hint

You should look at the reason for the failure and decide if the pull request needs to be fixed or if you want to requeue it.
If you do update this pull request, it will automatically be requeued once the queue conditions match again.
If you think this was a flaky issue instead, you can requeue the pull request, without updating it, by posting a @mergifyio queue comment.

Requeued — the merge queue status continues in this comment ↓.

@chrisdoc

Copy link
Copy Markdown
Owner

@Mergifyio refresh

@mergify

mergify Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

refresh

✅ Pull request refreshed

@mergify mergify Bot added dequeued and removed queued labels Jul 10, 2026
@charliecreates

charliecreates Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

The Rule: Queue pull requests labeled queue (queue) check was cancelled because this PR conflicts with main. I did not modify the branch: resolving merge conflicts or refreshing it from the base branch is outside this repair scope. Please resolve the conflicts; Mergify will requeue the PR automatically once its queue conditions are met.

— charlied/pr-check-repair

@mergify mergify Bot removed the dequeued label Jul 10, 2026
@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Unit Test Results

  1 files   22 suites   1s ⏱️
332 tests 332 ✅ 0 💤 0 ❌
333 runs  333 ✅ 0 💤 0 ❌

Results for commit 66d06e5.

♻️ This comment has been updated with latest results.

@gitstream-cm

gitstream-cm Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

🥷 Code experts: chrisdoc, CharlieHelps

chrisdoc, CharlieHelps have most 👩‍💻 activity in the files.
chrisdoc, CharlieHelps have most 🧠 knowledge in the files.

✨ Comment /gs review for LinearB AI review. Learn how to automate it here.

@mergify mergify Bot added the queued label Jul 10, 2026
@mergify

mergify Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-07-10 10:57 UTC · Rule: default · triggered by rule Queue pull requests labeled 'queue'
  • 🚫 Left the queue2026-07-10 11:02 UTC · at 660fa37d3c38a1fa8ea0c516fd985e413b0262be

This pull request spent 4 minutes 53 seconds in the queue, with no time running CI.

Reason

The pull request #504 has been manually updated

Requeued — the merge queue status continues in this comment ↓.

@charliecreates

Copy link
Copy Markdown
Contributor Author

The latest gitStream.cm check is failing even though its linked workflow run completed successfully (including every job step) on the current head. This indicates a gitStream/provider-side check-reporting problem, not a repository change I can safely repair.

Please inspect the gitStream integration or required-check configuration. I did not modify the branch.

— charlied/pr-check-repair

@mergify

mergify Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

This pull request spent 6 minutes 42 seconds in the queue, including 1 minute 17 seconds running CI.

Required conditions to merge
  • check-success = "Build and test (Node 24.x)"
  • check-success = "Build and test (Node 26.x)"

@gitstream-cm gitstream-cm Bot left a comment

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.

✨ PR Review

The PR correctly replaces the hardcoded tool count with a Proxy-based counting mechanism and includes a matching changeset. The implementation avoids double-counting through careful placement on the proxy boundary. One count-accuracy risk and a test correctness issue are worth addressing before merge.

2 issues detected:

🐞 Bug - Typing the interceptor with `Parameters` collapses all overloads to a single signature, which could silently miss new overloads added by SDK upgrades. 🛠️

Details: In the tool proxy handler, count += 1 executes after target.tool(...args) returns, so if the call throws the count is not incremented — that is intentional and correct. However, for the registerTool proxy the same pattern is used, and it is also correct. The real risk is in the tool handler: the spread type Parameters<McpServer["tool"]> covers only a single overload selected by TypeScript. If the SDK exposes tool as an overloaded function, the spread will only match one overload signature at compile time but will forward all runtime argument shapes to target.tool. If the SDK adds a new overload that the inferred Parameters<> does not cover, calls will silently pass through without being counted (TypeScript will error, but the runtime behavior depends on whether the SDK is updated before the types). This is low-risk today but fragile.

File: src/index.ts (92-96)

🛠️ A suggested code correction is included in the review comments.

🐞 Bug - Using `testDoubles.registerTool.mock.calls.length` as the expected value creates a circular assertion — it checks that the span received the same number that was recorded, not that the number is correct.

Details: The test at line 162-171 asserts that setAttribute was called with "mcp.tools.count" equal to testDoubles.registerTool.mock.calls.length. However, the counting proxy also increments its internal counter for every tool-proxy interception, not only for registerTool calls. The mock tool implementation calls this.registerTool(), which appends to testDoubles.registerTool.mock.calls — but those delegated calls are made on target (bypassing the proxy) and are counted by the proxy's tool handler, not its registerTool handler. If any register function uses server.tool() directly and the SDK mock is changed to NOT delegate, the two counts diverge and the assertion would silently accept an incorrect mcp.tools.count value. The assertion should instead check the exact expected count.

File: src/index.test.ts (165-170)

Generated by LinearB AI and added by gitStream.
AI-generated content may contain inaccuracies. Please verify before using.
💡 Tip: You can customize your AI Review using Guidelines Learn how

Comment thread src/index.ts
Comment on lines +92 to +96
return (...args: Parameters<McpServer["tool"]>) => {
const registeredTool = target.tool(...args);
count += 1;
return registeredTool;
};

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.

🐞 Bug - Count on Throw: Use Reflect.apply to forward all arguments unconditionally, keeping the count increment only on success:

if (property === "tool") {
  return (...args: unknown[]) => {
    const result = Reflect.apply(target.tool as (...a: unknown[]) => unknown, target, args);
    count += 1;
    return result;
  };
}
Suggested change
return (...args: Parameters<McpServer["tool"]>) => {
const registeredTool = target.tool(...args);
count += 1;
return registeredTool;
};
return (...args: unknown[]) => {
const result = Reflect.apply(target.tool as (...a: unknown[]) => unknown, target, args);
count += 1;
return result;
};
Is this review accurate? Use 👍 or 👎 to rate it

If you want to tell us more, use /gs feedback e.g. /gs feedback this review doesn't make sense, I disagree, and it keeps repeating over and over

mergify Bot added a commit that referenced this pull request Jul 10, 2026
mergify Bot added a commit that referenced this pull request Jul 10, 2026
@mergify
mergify Bot merged commit bae0ffb into main Jul 10, 2026
29 of 30 checks passed
@mergify
mergify Bot deleted the fix/502-dynamic-tool-count branch July 10, 2026 11:09
@mergify mergify Bot removed the queued label Jul 10, 2026
@github-actions github-actions Bot mentioned this pull request Jul 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: Correct hardcoded tool count in server build span

2 participants