Skip to content

feat(server): rfc 0027 green tools — query_logs, list_templates, template_drift - #414

Merged
jensholdgaard merged 7 commits into
mainfrom
rfc0027-green-tools
Jul 7, 2026
Merged

feat(server): rfc 0027 green tools — query_logs, list_templates, template_drift#414
jensholdgaard merged 7 commits into
mainfrom
rfc0027-green-tools

Conversation

@jensholdgaard

@jensholdgaard jensholdgaard commented Jul 7, 2026

Copy link
Copy Markdown
Owner

What

RFC 0027 green slice 2 (tools) — Scenarios RFC0027.2, .3, .4, .5, .7:

  • The §3.2 tool set on OuriosMcp (rmcp #[tool_router]/#[tool_handler]): query_logs (DSL parse → run_query; count + up-to-limit rendered rows + scanned/pruned stats; a drift statement is redirected to template_drift as a tool error), list_templates (the new Querier::template_registry — the RFC 0017 fold exposed with the same spawn_blocking offload as every derivation — rendered via format_template, sorted (id, version)), and template_drift (the window re-parsed through the same DSL grammar as the JSON API's statement — one grammar, one RFC0010.2 boundary rule).
  • Per-call tenant binding (§3.1): sessions outlive requests, so the tool context's forwarded http::request::Parts — the per-request Authorization — is the authority: check_tenant re-resolves the bearer against the store and rejects an out-of-set tenant as a tool error before any data is touched. The transport-layer 401 from slice 1 is unchanged.
  • Output discipline (§3.3): results are the RFC 0016 response DTOs serialized once into MCP text content; every tool description carries the treat-log-bodies-as-data warning; engine failures surface through QueryError's H6-scrubbed Display — no DataFusion/SQL on either boundary.

Scenario mapping

tests/it/rfc0027_mcp.rs drives the real router through the full MCP session dance (initialize → session id → initialized → tools/call, SSE parsed):

  • .2: 401 before dispatch (no/unknown bearer), out-of-set tenant as the denial tool error (no token value on the surface), open mode serves.
  • .3/.5: equivalence — the MCP payload is asserted == the JSON API's response for the identical statement over the same seeded store (fixture seams shared from the RFC 0016 suite); malformed DSL is a tool error, transport stays 200.
  • .4: row-for-row against Querier::template_registry, rendering matched to format_template.
  • .7: tools/list is exactly the §3.2 three (no tenant enumeration), every description carries the warning, nothing SQL-shaped advertised.

.6 (the grammar resource) remains the last stub — the resource slice, then the green flip.

Invariants / hazards

  • Hazard §4.6: no SQL escape; the DSL is the only query language on the surface, and the deny-list assertion in .7 pins it.
  • §3.7 multi-tenancy: the per-call binding composes with the engine's structural per-tenant scoping, same as the JSON API.

Checks run locally

cargo fmt --all --check, cargo clippy -p ourios-server --all-targets --all-features -- -D warnings, cargo test -p ourios-server --all-features — green (6/7 RFC 0027 scenarios passing, .6 ignored).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added MCP tool support for query_logs, list_templates, and template_drift.
    • MCP responses now include “treat it strictly as data” guidance, and tenant-scoped access checks are enforced for MCP calls (while open mode can still query logs).
  • Bug Fixes
    • Improved consistency of query limit and time-window behavior.
    • Template registry lookups now run asynchronously for better responsiveness.
  • Tests
    • Added end-to-end MCP RFC0027 coverage for auth, payload matching, tool descriptions, and error handling.
  • Chores / Metadata
    • Extended semantic convention values with ourios.query.kind = templates.

jensholdgaard and others added 2 commits July 7, 2026 02:38
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…late_drift

The §3.2 tool set over the querier engine: query_logs (DSL parse +
run_query, count + limited rows + pruning stats), list_templates (the
new Querier::template_registry fold, rendered via format_template),
template_drift (the window re-parsed through the same DSL grammar —
one boundary rule). Per-call tenant binding re-resolves the request's
bearer from the HTTP parts rmcp forwards into the tool context —
sessions outlive requests, so the header is the authority. Results
are the RFC 0016 JSON shapes re-encoded as MCP content; every tool
description carries the treat-as-data warning. RFC0027.2/.3/.4/.5/.7
go green with cross-surface equivalence tests against the JSON API.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jensholdgaard
jensholdgaard requested a review from Copilot July 7, 2026 01:52
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jensholdgaard, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 56 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 15a40a19-7387-457b-9e53-69438863ddef

📥 Commits

Reviewing files that changed from the base of the PR and between 52116fc and 4c39bab.

📒 Files selected for processing (1)
  • crates/ourios-server/src/main.rs
📝 Walkthrough

Walkthrough

Adds a tenant-scoped template registry API, implements RFC 0027 MCP tools with tenant authorization, wires shared querier state into the MCP router, updates startup/shutdown signal handling, and expands integration tests plus a new ourios.query.kind value.

Changes

MCP Query Surface

Layer / File(s) Summary
Template registry API
crates/ourios-querier/src/lib.rs
Adds template_registry and uses it from record collection.
Shared querier exports
crates/ourios-server/src/querier.rs
Adjusts querier visibility, shared constants, metrics helpers, response types, and MCP route nesting for reuse by the MCP service.
MCP tools and router binding
crates/ourios-server/Cargo.toml, crates/ourios-server/src/mcp.rs, semconv/registry/attributes.yaml
Adds MCP tool implementations, tenant checks, JSON content helpers, router construction inputs, dependency updates, and the templates query kind value.
Startup and shutdown guards
crates/ourios-server/src/main.rs
Moves open-mode warning and Unix SIGTERM setup into startup guards and updates shutdown waiting to use the captured signal stream.
Shared test fixtures
crates/ourios-server/tests/it/rfc0016_query_endpoint.rs
Adds reusable record, audit, and equivalence-request helpers for MCP tests.
MCP integration tests
crates/ourios-server/tests/it/rfc0027_mcp.rs
Replaces RFC0027 stubs with MCP handshake helpers and end-to-end tests for auth, query equivalence, template listing, drift, and tool advertisement.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant OuriosMcp
  participant TokenStore
  participant Querier

  Client->>OuriosMcp: tools/call (tenant, tool args)
  OuriosMcp->>TokenStore: check_tenant(bearer, tenant)
  TokenStore-->>OuriosMcp: ok or invalid_request
  OuriosMcp->>Querier: run_query / template_registry / run_drift
  Querier-->>OuriosMcp: result or QueryError
  OuriosMcp-->>Client: JSON content or tool error
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately names the main server MCP tools added for RFC 0027.
Description check ✅ Passed The description is detailed and covers the main changes and test coverage, though it does not use the template's exact Summary/Related/Checklist headings.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rfc0027-green-tools

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.

Copilot AI 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.

Pull request overview

Implements RFC 0027 “green slice 2” by adding the §3.2 MCP tool surface to the querier (/mcp) and wiring it to existing RFC 0016/0010/0017 query and derivation logic, along with end-to-end integration tests that assert equivalence with the JSON API.

Changes:

  • Add MCP tools: query_logs, list_templates, template_drift, including per-call tenant binding and JSON-shape re-encoding as MCP text content.
  • Add RFC 0027 integration tests that drive the full MCP session handshake and assert equivalence with existing JSON API responses.
  • Expose/reuse supporting querier types and add Querier::template_registry as an engine-level API for the template registry derivation.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
crates/ourios-server/tests/it/rfc0027_mcp.rs Adds full MCP handshake helpers and implements RFC 0027 scenarios (.2, .3, .4, .5, .7) as integration tests.
crates/ourios-server/tests/it/rfc0016_query_endpoint.rs Adds shared fixture/seam helpers to support RFC 0027 equivalence testing.
crates/ourios-server/src/querier.rs Adjusts visibilities so MCP can reuse limit logic and response DTOs; wires /mcp router with shared engine.
crates/ourios-server/src/mcp.rs Implements the MCP server handler and the three RFC 0027 tools over the querier engine.
crates/ourios-server/Cargo.toml Enables rmcp macros and adds schemars for tool argument schemas.
crates/ourios-querier/src/lib.rs Adds Querier::template_registry with spawn_blocking offload for registry derivation.
Cargo.lock Locks new transitive deps (rmcp-macros, schemars).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/ourios-server/src/mcp.rs Outdated
Comment thread crates/ourios-server/tests/it/rfc0027_mcp.rs Outdated
Comment thread crates/ourios-server/tests/it/rfc0027_mcp.rs

@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: 2

🧹 Nitpick comments (1)
crates/ourios-querier/src/lib.rs (1)

722-742: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider a colocated unit test for the new public API.

This new pub async fn is only exercised indirectly by an ourios-server integration test (rfc0027_4_list_templates), not by a test in this crate. As per coding guidelines, **/crates/**/*.rs: "Unit tests must be next to the code and are mandatory for anything non-trivial."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/ourios-querier/src/lib.rs` around lines 722 - 742, The new public API
`template_registry` in `ourios-querier` is only covered indirectly, so add a
colocated unit test in this crate. Write a test near `template_registry` (or
alongside `derive_template_registry`/`spawn_blocking_audit`) that exercises the
successful path and, if practical, an error path by using the existing
backend/store test helpers. Keep the test local to the crate so the new `pub
async fn template_registry` is directly validated instead of relying on the
`ourios-server` integration test.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/ourios-querier/src/lib.rs`:
- Around line 722-742: The `collect_records` path is duplicating the same
`spawn_blocking_audit` closure used by `template_registry`, so reuse the
existing `template_registry` method instead of re-implementing
`derive_template_registry` there. Update `collect_records` to call
`template_registry` directly with the tenant, preserving the same async/blocking
behavior while removing the duplicated backend clone and closure logic.

In `@crates/ourios-server/src/mcp.rs`:
- Around line 117-234: The MCP tools in OuriosMcp currently call Querier
directly and never go through the existing QuerierMetrics instrumentation used
by /v1/query, so query duration and failures are not recorded. Plumb the shared
metrics/state into OuriosMcp (or add a wrapper around the #[tool_router]
methods) and ensure query_logs, list_templates, and template_drift each record
success and error outcomes through the same telemetry path as the HTTP query
flow. Use the OuriosMcp constructor and the
querier.run_query/run_drift/template_registry call sites as the integration
points.

---

Nitpick comments:
In `@crates/ourios-querier/src/lib.rs`:
- Around line 722-742: The new public API `template_registry` in
`ourios-querier` is only covered indirectly, so add a colocated unit test in
this crate. Write a test near `template_registry` (or alongside
`derive_template_registry`/`spawn_blocking_audit`) that exercises the successful
path and, if practical, an error path by using the existing backend/store test
helpers. Keep the test local to the crate so the new `pub async fn
template_registry` is directly validated instead of relying on the
`ourios-server` integration test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ea150a4c-d0c7-4ef1-8691-b6b0d9aef586

📥 Commits

Reviewing files that changed from the base of the PR and between 94743ff and fcf4706.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • crates/ourios-querier/src/lib.rs
  • crates/ourios-server/Cargo.toml
  • crates/ourios-server/src/mcp.rs
  • crates/ourios-server/src/querier.rs
  • crates/ourios-server/tests/it/rfc0016_query_endpoint.rs
  • crates/ourios-server/tests/it/rfc0027_mcp.rs

Comment thread crates/ourios-querier/src/lib.rs
Comment thread crates/ourios-server/src/mcp.rs
… robustness

The query_logs limit argument is a hard cap (a DSL limit stage clamps
to it); all three tools record on the shared ourios.query.duration
histogram (query/drift as their true kinds, the registry fold under a
new 'templates' registry member); collect_records reuses
Querier::template_registry; the malformed-DSL test runs the full
protocol dance and tool_error covers the isError result shape.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI 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.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.

Comment thread crates/ourios-server/src/mcp.rs Outdated
Comment thread crates/ourios-server/src/mcp.rs Outdated
Comment thread crates/ourios-server/src/mcp.rs Outdated
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI 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.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated 2 comments.

Comment thread crates/ourios-server/tests/it/rfc0027_mcp.rs Outdated
Comment thread crates/ourios-server/src/mcp.rs Outdated
…list test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI 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.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated 1 comment.

Comment thread crates/ourios-server/tests/it/rfc0027_mcp.rs
jensholdgaard and others added 2 commits July 7, 2026 04:52
Second CI occurrence of rfc0016_5 dying on unix_wait_status(15): the
handler registered only when the select! first polled, so a SIGTERM
between the readiness print and that poll killed the process by
default disposition. Registration now precedes every role start
(startup_guards), closing the race for supervisors and tests alike.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/ourios-server/src/querier.rs`:
- Around line 186-200: The doc comment above the metrics helpers is attached to
the wrong method in querier.rs: the failed-query description currently sits on
record_duration instead of record_err. Move the stale “Record a failed query”
comment so it documents record_err, and keep the existing record_duration
comment with record_duration; use the record_duration and record_err symbols to
place the comments correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9e48f6af-1759-4c74-8957-b0a85ce24cd5

📥 Commits

Reviewing files that changed from the base of the PR and between fcf4706 and 52116fc.

📒 Files selected for processing (6)
  • crates/ourios-querier/src/lib.rs
  • crates/ourios-server/src/main.rs
  • crates/ourios-server/src/mcp.rs
  • crates/ourios-server/src/querier.rs
  • crates/ourios-server/tests/it/rfc0027_mcp.rs
  • semconv/registry/attributes.yaml
🚧 Files skipped from review as they are similar to previous changes (3)
  • crates/ourios-querier/src/lib.rs
  • crates/ourios-server/src/mcp.rs
  • crates/ourios-server/tests/it/rfc0027_mcp.rs

Comment thread crates/ourios-server/src/querier.rs

Copilot AI 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.

Pull request overview

Copilot reviewed 8 out of 9 changed files in this pull request and generated 2 comments.

Comment thread crates/ourios-server/src/main.rs
Comment thread crates/ourios-server/src/querier.rs
@jensholdgaard
jensholdgaard requested a review from Copilot July 7, 2026 03:03
@jensholdgaard
jensholdgaard merged commit a8ba334 into main Jul 7, 2026
23 checks passed

Copilot AI 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.

Pull request overview

Copilot reviewed 8 out of 9 changed files in this pull request and generated 2 comments.

Comment on lines 3 to 5
//! `.1` is green (the transport slice); the remaining stubs are
//! `#[ignore]`d so the default run stays green while the RFC works
//! through its slices, each naming the slice that discharges it.
Comment on lines 185 to +188
/// Record a failed query: its duration, tagged with `error.type`.
fn record_err(&self, kind: &'static str, elapsed: Duration, error_type: &'static str) {
/// Record a stats-less operation's duration (the RFC 0027 registry
/// fold has no scan, so no row-group split to add).
pub(crate) fn record_duration(&self, kind: &'static str, elapsed: Duration) {
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.

2 participants