Skip to content

feat: add @arvoretech/await-until-mcp server#14

Merged
Joao208 merged 8 commits into
mainfrom
joaobarros-/-await-until-mcp
Mar 10, 2026
Merged

feat: add @arvoretech/await-until-mcp server#14
Joao208 merged 8 commits into
mainfrom
joaobarros-/-await-until-mcp

Conversation

@Joao208

@Joao208 Joao208 commented Mar 10, 2026

Copy link
Copy Markdown
Contributor

Descricao

Novo MCP server @arvoretech/await-until-mcp que fornece primitivas de polling/waiting. Quatro tools:

  • await_until_command: executa um comando shell repetidamente até o output bater com uma condição
  • await_until_url: faz polling de endpoints HTTP até retornar status/body esperado
  • await_until_file: monitora o filesystem até um arquivo existir, sumir, ou conter conteúdo
  • await_until_mcp: chama tools de outros MCP servers configurados no mcp.json (auto-detecta Kiro, Cursor, Claude Desktop, com suporte a upstreams do mcp-proxy)

Todos suportam interval_seconds, timeout_seconds, e condições de match configuráveis (contains, regex, equals, etc).

Etiquetas (Labels)

  • Nova Funcionalidade
  • Correcao de Bug
  • Estrutura
  • Testes
  • Outros

Historia Relacionada

N/A

Motivacao e Contexto

Agentes precisam esperar condições assíncronas (serviços subindo, deploys completando, dados aparecendo no banco, flags sendo habilitadas). Esse MCP server resolve isso com polling nativo, sem depender do agente manter o loop manualmente.

Como Isso Foi Testado?

  • Testes Unitarios
  • Testes de Integracao
  • Testes e2e (playwright)
  • Testes de Aceitacao (QA)
  • Testes de Performance
  • Outros (quais?)
    • Testado manualmente via Kiro: await_until_command (echo), await_until_url (httpbin), await_until_file (package.json), await_until_mcp (npm-registry via mcp-proxy, agent-teams-lead direto, team-memory com env vars)
  • Nenhum (por que?)

Analise de Risco e Impacto

  • Baixo
  • Alto

Capturas de Tela ou Auxilios Visuais (se apropriado)

N/A

Summary by CodeRabbit

  • New Features

    • Introduced await-until-mcp — a CLI/tool to wait for conditions (commands, HTTP endpoints, files, or MCP tools) with configurable intervals and timeouts; includes a runnable server and CLI entry.
  • Documentation

    • Added comprehensive await-until-mcp docs with examples and configuration guidance.
    • Registered the package in the root README, added install instructions, and added a Claude Desktop config entry.
    • Minor README formatting tweaks across several packages.
  • Chores

    • Updated dependency version constraints across multiple packages.

Joao208 added 2 commits March 10, 2026 10:41
Polling/waiting primitives for MCP. Four tools:
- await_until_command: poll shell commands
- await_until_url: poll HTTP endpoints
- await_until_file: poll filesystem
- await_until_mcp: poll other MCP servers (auto-discovers from mcp.json, supports mcp-proxy upstreams)
@coderabbitai

coderabbitai Bot commented Mar 10, 2026

Copy link
Copy Markdown

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Adds a new package "@arvoretech/await-until-mcp" providing an MCP server and CLI that poll commands, URLs, files, or other MCP tools until match criteria; includes TypeScript sources, schemas, MCP client helpers, tooling configs, package manifest, and documentation. Also bumps @modelcontextprotocol/sdk across many packages and minor README formatting edits.

Changes

Cohort / File(s) Summary
New await-until package
packages/await-until/package.json, packages/await-until/tsconfig.json, packages/await-until/eslint.config.js, packages/await-until/README.md
Adds package manifest, TypeScript and ESLint configs, and user documentation for the new await-until MCP package.
Server & CLI
packages/await-until/src/server.ts, packages/await-until/src/cli.ts, packages/await-until/src/index.ts
Implements AwaitUntilMCPServer (tool registrations, lifecycle, graceful shutdown) and CLI entrypoint; exports public API surface.
Polling utilities
packages/await-until/src/pollers.ts
Adds pollCommand, pollUrl, pollFile, pollMcp with timeout/interval loops, matching logic, and uniform PollResult shape.
MCP client helpers
packages/await-until/src/mcp-client.ts
Adds findMcpConfig, getServerConfig, callMcpTool to discover/resolve mcp.json, expand envs, and invoke tools via stdio transport with result formatting and safe cleanup.
Types & schemas
packages/await-until/src/types.ts
Adds zod validation schemas and TypeScript types/interfaces for await modalities, MCP config shapes, and PollResult.
Exports
packages/await-until/src/index.ts
Re-exports server, types, pollers, and mcp-client functions as the package public API.
Root README update
README.md
Registers new public package await-until-mcp and adds install/Claude Desktop config sample.
Dependency bumps (multiple packages)
packages/*/package.json (many: aws-secrets-manager, clickhouse, datadog, google-chat, launchdarkly, mcp-proxy, meet-transcriptions, memory, mysql, npm-registry, postgresql, runtime-lens, sendgrid, tempmail, agent-teams-*, etc.)
Updates @modelcontextprotocol/sdk version range from ^1.0.0 to ~1.22.0 across many package manifests (manifest-only changes).
Minor README formatting
packages/mysql/README.md, packages/npm-registry/README.md, packages/postgresql/README.md, packages/tempmail/README.md
Cosmetic bullet/feature-list formatting changes (no behavior changes).

Sequence Diagram

sequenceDiagram
    participant Client as External Client
    participant Server as AwaitUntilMCPServer
    participant Poller as Polling Module
    participant Resource as External Resource / MCP

    Client->>Server: callTool(toolName, params)
    Server->>Poller: dispatch to pollCommand/pollUrl/pollFile/pollMcp
    loop until matched or timeout
        Poller->>Resource: perform check (run cmd / fetch URL / read file / call MCP)
        Resource-->>Poller: return output/status
        Poller->>Poller: evaluate match condition
    end
    Poller-->>Server: return PollResult (success/attempts/elapsed/last_output)
    Server-->>Client: formatted tool response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐇 I nibble on logs and patiently wait,
I ping, I read, I run — I never mind the time,
Commands, URLs, files, or another MCP gate,
I hop, match, and return the result sublime.
Hooray for the server — small, steady, and kind!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately describes the main change: adding a new MCP server package @arvoretech/await-until-mcp with polling utilities.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch joaobarros-/-await-until-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: 4

🧹 Nitpick comments (6)
packages/await-until/eslint.config.js (1)

45-45: no-undef conflicts with TypeScript.

With TypeScript, no-undef is redundant and can cause false positives for type-only imports and TypeScript-specific syntax. The TypeScript compiler already handles undefined variable detection.

Consider disabling it or using @typescript-eslint/no-undef if available.

♻️ Disable no-undef for TypeScript
     "no-console": "off",
-    "no-undef": "error",
+    "no-undef": "off",
   },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/await-until/eslint.config.js` at line 45, The "no-undef" ESLint rule
is conflicting with TypeScript; update the ESLint config to remove or disable
"no-undef" and instead rely on TypeScript's checking (or replace it with the
TypeScript-aware rule "@typescript-eslint/no-undef" if that plugin is used).
Locate the rule entry "no-undef": "error" in the eslint.config.js and either
delete it or set it to "off", or enable "@typescript-eslint/no-undef" in rules
and ensure "@typescript-eslint" is in the plugins/extends so the
TypeScript-aware rule is used.
packages/await-until/tsconfig.json (2)

5-5: Consider aligning moduleResolution with root config.

The root tsconfig.json uses "moduleResolution": "bundler" which is the recommended setting for modern ESM projects. This package uses "Node", which is inconsistent.

While "Node" works (and matches packages/meet-transcriptions), consider aligning with the root config or packages/mcp-proxy which uses "Bundler" for consistency across CLI packages.

♻️ Optional: align with root config
-    "moduleResolution": "Node",
+    "moduleResolution": "Bundler",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/await-until/tsconfig.json` at line 5, The package's tsconfig
currently sets "moduleResolution": "Node"; change the tsconfig's
moduleResolution value to match the root config ("bundler") for consistent ESM
handling — update the "moduleResolution" property in the package tsconfig
(referencing the moduleResolution key) to "bundler" so it aligns with the root
and other CLI packages that use bundler/Bundler.

2-19: Missing declaration and declarationMap options.

Other packages in this monorepo (e.g., mcp-proxy, aws-secrets-manager) include declaration: true and declarationMap: true to generate .d.ts files for TypeScript consumers. If this package is intended to be imported programmatically, consider adding these options.

♻️ Optional: add declaration generation
     "noFallthroughCasesInSwitch": true,
     "moduleDetection": "force",
-    "skipLibCheck": true
+    "skipLibCheck": true,
+    "declaration": true,
+    "declarationMap": true,
+    "forceConsistentCasingInFileNames": true,
+    "resolveJsonModule": true
   },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/await-until/tsconfig.json` around lines 2 - 19, Add TypeScript
declaration generation to the compiler options by setting "declaration": true
and "declarationMap": true inside the existing "compilerOptions" block
(alongside "outDir" and "rootDir") so the build emits .d.ts files for consumers;
ensure these keys are added at the same level as "target"/"module" and keep
"outDir" intact so declarations land alongside compiled output.
packages/await-until/src/server.ts (1)

51-59: Consider extracting pattern validation to a shared helper.

The pattern-required validation is repeated across three tools (lines 51-59, 90-97, 114-121). A small helper would reduce duplication:

function validatePatternRequired(match: string, pattern?: string): string | null {
  const needsPattern = ["contains", "not_contains", "equals", "not_equals", "regex"];
  if (needsPattern.includes(match) && !pattern) {
    return `Error: 'pattern' is required when match is '${match}'`;
  }
  return null;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/await-until/src/server.ts` around lines 51 - 59, Extract the
repeated pattern-required check into a shared helper (e.g.,
validatePatternRequired(match: string, pattern?: string): string | null) and
replace the three inline checks that examine validated.match and
validated.pattern with calls to this helper; update the callers to return the
helper's error string (wrapped into the existing content/isError response) when
non-null. Ensure the helper contains the same match set
["contains","not_contains","equals","not_equals","regex"] and is imported/placed
so functions handling the three tools can call it, preserving existing response
shape where the error message is used.
packages/await-until/src/pollers.ts (2)

229-234: Empty conditional in catch block is confusing.

The if statement checks match types but does nothing. If this is intentional (continue polling when file access fails for these match types), simplify by removing the conditional entirely.

♻️ Proposed simplification
     } catch (err) {
       lastOutput = err instanceof Error ? err.message : String(err);
-      if (params.match === "exists" || params.match === "contains" || params.match === "regex" || params.match === "not_empty") {
-        // noop
-      }
+      // File access failed; continue polling for exists/contains/regex/not_empty
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/await-until/src/pollers.ts` around lines 229 - 234, The catch block
assigns lastOutput but contains an empty if checking params.match
("exists"/"contains"/"regex"/"not_empty"); remove that no-op conditional in the
catch to simplify the logic in pollers.ts (leave the lastOutput assignment
as-is) or, if the empty branch is intentional, replace it with a short
clarifying comment referencing params.match to explain why we continue polling
on file access errors; locate this logic around the catch that sets lastOutput
and update accordingly.

278-298: Each poll iteration spawns a new MCP child process.

callMcpTool creates a new StdioClientTransport and spawns a child process on every iteration. For long-running polls with short intervals, this could be resource-intensive.

Consider reusing the client connection across iterations or documenting this behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/await-until/src/pollers.ts` around lines 278 - 298, The loop
currently calls callMcpTool each iteration which constructs a new
StdioClientTransport and spawns a child process, causing heavy resource use for
long polls; change pollers.ts to create and reuse a single client/transport
outside the while loop (e.g., instantiate the StdioClientTransport or a
persistent client once before the loop that callMcpTool can accept or the loop
can call directly), use that client for each iteration, handle transient errors
by attempting to reinitialize the client if it fails, and ensure the
transport/client is properly closed or disposed after success, timeout, or
unrecoverable error; reference callMcpTool and StdioClientTransport for where to
move initialization, reuse, reinit-on-error, and cleanup logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/await-until/eslint.config.js`:
- Line 29: Remove the mistaken runtime global entry "Record" from the eslint
config's globals object (the "globals" map in eslint.config.js) because Record
is a TypeScript compile-time utility type, not a runtime value; simply delete
the Record: "readonly" line from the globals list (no replacement needed) so
ESLint no longer treats Record as a global identifier.

In `@packages/await-until/README.md`:
- Around line 246-254: The Development section in README.md lists a non-existent
`pnpm test` command which breaks CI; either remove the `pnpm test` line from the
command sequence in the Development section or add test files and a test script
(e.g., implement a test runner and package.json "test" script) so `pnpm test`
works; update the README's command block accordingly to reflect the chosen
approach (remove the `pnpm test` line if not adding tests, or keep it and add
the tests + package.json "test" script).

In `@packages/await-until/src/index.ts`:
- Around line 5-17: The module runs side-effectful startup code at import time
(creating AwaitUntilMCPServer, calling server.setupGracefulShutdown() and await
server.start()), which should be moved out of the library entrypoint; extract
that block into a new CLI entry file (e.g., cli.ts) that imports
AwaitUntilMCPServer and runs the try/catch startup logic, keep src/index.ts to
only export library symbols (AwaitUntilMCPServer export can remain if desired
but remove startup calls), and update package.json "bin" to point to the new CLI
so imports like pollCommand, pollUrl, pollFile, pollMcp, findMcpConfig,
getServerConfig, callMcpTool are safe to import without starting the server.

In `@packages/await-until/src/pollers.ts`:
- Line 52: The code currently hardcodes "/bin/bash" for the shell option (see
the "shell: shell ?? \"/bin/bash\"" expression); replace that with a
platform-aware default such as using process.env.SHELL when present and falling
back to process.platform === "win32" ? "cmd.exe" (or "powershell.exe" if you
prefer) : "/bin/bash", i.e. change the default expression to something like
shell ?? process.env.SHELL ?? (process.platform === "win32" ? "cmd.exe" :
"/bin/bash"); ensure this change is applied where the shell option is set
(pollers.ts) and add a short comment noting Windows vs POSIX defaults.

---

Nitpick comments:
In `@packages/await-until/eslint.config.js`:
- Line 45: The "no-undef" ESLint rule is conflicting with TypeScript; update the
ESLint config to remove or disable "no-undef" and instead rely on TypeScript's
checking (or replace it with the TypeScript-aware rule
"@typescript-eslint/no-undef" if that plugin is used). Locate the rule entry
"no-undef": "error" in the eslint.config.js and either delete it or set it to
"off", or enable "@typescript-eslint/no-undef" in rules and ensure
"@typescript-eslint" is in the plugins/extends so the TypeScript-aware rule is
used.

In `@packages/await-until/src/pollers.ts`:
- Around line 229-234: The catch block assigns lastOutput but contains an empty
if checking params.match ("exists"/"contains"/"regex"/"not_empty"); remove that
no-op conditional in the catch to simplify the logic in pollers.ts (leave the
lastOutput assignment as-is) or, if the empty branch is intentional, replace it
with a short clarifying comment referencing params.match to explain why we
continue polling on file access errors; locate this logic around the catch that
sets lastOutput and update accordingly.
- Around line 278-298: The loop currently calls callMcpTool each iteration which
constructs a new StdioClientTransport and spawns a child process, causing heavy
resource use for long polls; change pollers.ts to create and reuse a single
client/transport outside the while loop (e.g., instantiate the
StdioClientTransport or a persistent client once before the loop that
callMcpTool can accept or the loop can call directly), use that client for each
iteration, handle transient errors by attempting to reinitialize the client if
it fails, and ensure the transport/client is properly closed or disposed after
success, timeout, or unrecoverable error; reference callMcpTool and
StdioClientTransport for where to move initialization, reuse, reinit-on-error,
and cleanup logic.

In `@packages/await-until/src/server.ts`:
- Around line 51-59: Extract the repeated pattern-required check into a shared
helper (e.g., validatePatternRequired(match: string, pattern?: string): string |
null) and replace the three inline checks that examine validated.match and
validated.pattern with calls to this helper; update the callers to return the
helper's error string (wrapped into the existing content/isError response) when
non-null. Ensure the helper contains the same match set
["contains","not_contains","equals","not_equals","regex"] and is imported/placed
so functions handling the three tools can call it, preserving existing response
shape where the error message is used.

In `@packages/await-until/tsconfig.json`:
- Line 5: The package's tsconfig currently sets "moduleResolution": "Node";
change the tsconfig's moduleResolution value to match the root config
("bundler") for consistent ESM handling — update the "moduleResolution" property
in the package tsconfig (referencing the moduleResolution key) to "bundler" so
it aligns with the root and other CLI packages that use bundler/Bundler.
- Around line 2-19: Add TypeScript declaration generation to the compiler
options by setting "declaration": true and "declarationMap": true inside the
existing "compilerOptions" block (alongside "outDir" and "rootDir") so the build
emits .d.ts files for consumers; ensure these keys are added at the same level
as "target"/"module" and keep "outDir" intact so declarations land alongside
compiled output.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f3f8f927-0757-439b-965e-2eabc9ffbc6b

📥 Commits

Reviewing files that changed from the base of the PR and between f439ce5 and 23989d1.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (14)
  • README.md
  • packages/await-until/README.md
  • packages/await-until/eslint.config.js
  • packages/await-until/package.json
  • packages/await-until/src/index.ts
  • packages/await-until/src/mcp-client.ts
  • packages/await-until/src/pollers.ts
  • packages/await-until/src/server.ts
  • packages/await-until/src/types.ts
  • packages/await-until/tsconfig.json
  • packages/mysql/README.md
  • packages/npm-registry/README.md
  • packages/postgresql/README.md
  • packages/tempmail/README.md

Comment thread packages/await-until/eslint.config.js Outdated
Comment thread packages/await-until/README.md
Comment thread packages/await-until/src/index.ts Outdated
Comment thread packages/await-until/src/pollers.ts Outdated

@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

🧹 Nitpick comments (1)
packages/await-until/package.json (1)

17-18: Consider adding unit tests before release.

The --passWithNoTests flag indicates no tests exist yet. While manual testing was performed per the PR description, adding automated tests for the polling logic (especially edge cases like timeouts, regex matching, and error handling) would improve reliability and prevent regressions.

This can be deferred if the package is intended for internal use initially.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/await-until/package.json` around lines 17 - 18, The package
currently ships test scripts with --passWithNoTests but lacks unit tests; add
automated Vitest specs for the polling logic (create tests in a __tests__ or
tests folder) covering key functions such as the module's
waitUntil/awaitUntil/pollUntil entrypoints: write cases for immediate success,
timeout behavior, regex matching, thrown errors from the predicate, and
cancellation/retry behavior; update package.json test/test:cov scripts to remove
--passWithNoTests once tests exist and ensure tests import the polling functions
directly to assert timing, returned values, and that errors/timeouts are raised
as expected.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/await-until/package.json`:
- Around line 39-42: Update the `@modelcontextprotocol/sdk` dependency entry in
packages/await-until/package.json to a known published version (e.g., replace
"^1.0.0" with a tested release like "^1.26.0" or another specific compatible
version) so npm can resolve the package; edit the "dependencies" block where
"@modelcontextprotocol/sdk" is declared to point to the chosen valid version and
run an install to verify resolution.

---

Nitpick comments:
In `@packages/await-until/package.json`:
- Around line 17-18: The package currently ships test scripts with
--passWithNoTests but lacks unit tests; add automated Vitest specs for the
polling logic (create tests in a __tests__ or tests folder) covering key
functions such as the module's waitUntil/awaitUntil/pollUntil entrypoints: write
cases for immediate success, timeout behavior, regex matching, thrown errors
from the predicate, and cancellation/retry behavior; update package.json
test/test:cov scripts to remove --passWithNoTests once tests exist and ensure
tests import the polling functions directly to assert timing, returned values,
and that errors/timeouts are raised as expected.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bed1cea1-af67-4d7c-942e-6d66250833d2

📥 Commits

Reviewing files that changed from the base of the PR and between 23989d1 and 7c2629e.

📒 Files selected for processing (1)
  • packages/await-until/package.json

Comment thread packages/await-until/package.json
Joao208 added 5 commits March 10, 2026 11:04
- Remove Record from eslint globals (TS type, not runtime)
- Split CLI from library exports (no side-effects on import)
- Cross-platform shell default (win32 support)
- Remove pnpm test from README dev section
SDK 1.23+ requires zod ^3.25 (Zod 4 mini) which causes type
incompatibilities with ZodOptional/ZodDefault in registerTool.
Pin to 1.22.0 which works with zod ^3.22.4.
@Joao208 Joao208 merged commit fe844be into main Mar 10, 2026
4 of 5 checks passed
@Joao208 Joao208 deleted the joaobarros-/-await-until-mcp branch March 10, 2026 15:06
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