Skip to content

MCP server: expose Rivet tools, resources, and prompts via Model Context Protocol #98

@avrabe

Description

@avrabe

Context

The AI agent ecosystem is converging on Model Context Protocol (MCP) as the standard for tool integration. Claude Code, Cursor, Goose, Kiro, and OpenCode all support MCP natively. Currently agents interact with Rivet via CLI (rivet validate --format json, rivet list --format json, etc.) which requires shell-out + JSON parsing. An MCP server would give agents typed, validated, direct access to the artifact graph.

This pairs with issue #93 (spec-driven development) — the Guide API from Phase 4 is the ideal surface to expose over MCP. It also pairs with #22 (rowan + salsa) — incremental validation via salsa makes real-time MCP resource subscriptions efficient.

Strategic value: Rivet becomes a first-class tool in any MCP-capable agent's toolbox, not just a CLI to shell out to. Agents can query traceability, validate changes, create artifacts, and check coverage without parsing text output.

Prior art

  • rmcp — Official Rust SDK for MCP (v0.16+). Provides #[tool] macro, ServerHandler trait, ToolRouter, stdio/SSE/streamable-HTTP transports.
  • codeprism-mcp-server — Rust MCP server for code analysis (reference for tool design patterns).
  • Rivet already has axum for the dashboard (rivet serve) — streamable HTTP transport can share the same server.

Design

New command

# Standalone MCP server over stdio (for Claude Code, Cursor, etc.)
rivet mcp

# MCP over streamable HTTP (for web-based agents, can co-host with dashboard)
rivet mcp --transport http --port 3001

# Combined: dashboard + MCP on same server
rivet serve --mcp

Crate structure

Add MCP support to rivet-cli (where serve already lives), with a new module rivet-cli/src/mcp/. Depends on:

[dependencies]
rmcp = { version = "0.16", features = ["server", "transport-io", "transport-streamable-http-server", "macros"] }
schemars = "0.8"  # Already used for JSON schema generation in --format json

Tools (agent-callable functions)

These map to existing CLI commands, exposing them as MCP tools with typed parameters:

Tool Parameters Returns Maps to
rivet_validate baseline?: string, format?: "summary"|"full" Diagnostics array (level, artifact_id, message, rule) rivet validate --format json
rivet_list type?: string, status?: string, search?: string, limit?: number Artifact array (id, title, type, status, links) rivet list --format json
rivet_get id: string Full artifact (all fields, links, backlinks) rivet get --format json (from #93 Phase 3)
rivet_add type: string, title: string, fields?: object, links?: [{type, target}] Created artifact ID rivet add
rivet_link source: string, link_type: string, target: string Success/failure rivet link
rivet_modify id: string, fields: object Updated artifact rivet modify
rivet_coverage type?: string Coverage percentages per type + gap list rivet coverage --format json
rivet_impact since?: string Changed artifacts + affected downstream rivet impact --format json
rivet_stats Artifact counts by type rivet stats --format json
rivet_schema_info schema?: string Types, link types, rules for a schema rivet schema show --format json
rivet_guide scope?: string Guide report (schema guidance + project health) rivet guide (from #93 Phase 4)
rivet_spec_status spec_id: string Spec completion: requirements, design, tasks, tests coverage New — builds on SDD schema

Resources (agent-readable data)

MCP resources let agents read artifact data directly without calling tools:

Resource URI Description MIME type
rivet://artifacts/{id} Single artifact as YAML text/yaml
rivet://schemas/{name} Schema definition text/yaml
rivet://coverage Full coverage matrix application/json
rivet://diagnostics Current validation diagnostics application/json
rivet://agents-md Generated AGENTS.md content text/markdown
rivet://graph/{id} Subgraph reachable from artifact application/json

Resource templates (dynamic):

  • rivet://artifacts?type={type} — all artifacts of a type
  • rivet://artifacts?status={status} — all artifacts with status

Prompts (stored prompts for agents)

Prompt Arguments Purpose
rivet_create_spec title, description Guides agent through creating a spec with requirements, design, tasks
rivet_fill_gaps type? Generates instructions to fill traceability coverage gaps
rivet_review_artifact id Reviews an artifact for completeness, link quality, field coverage

Implementation sketch

use rmcp::{ServerHandler, tool_handler, tool_router, tool};
use rmcp::model::{ServerInfo, ServerCapabilities, Implementation};
use schemars;

#[derive(Clone)]
pub struct RivetMcpServer {
    tool_router: ToolRouter<Self>,
    // Shared state: AppState from rivet-cli (store, schema_set, config)
    state: Arc<AppState>,
}

#[tool_router]
impl RivetMcpServer {
    pub fn new(state: Arc<AppState>) -> Self {
        Self { tool_router: Self::tool_router(), state }
    }
}

#[tool_handler]
impl ServerHandler for RivetMcpServer {
    fn get_info(&self) -> ServerInfo {
        ServerInfo {
            protocol_version: ProtocolVersion::V_2025_06_18,
            capabilities: ServerCapabilities::builder()
                .enable_tools()
                .enable_resources()
                .enable_prompts()
                .build(),
            server_info: Implementation {
                name: "rivet".into(),
                version: env!("CARGO_PKG_VERSION").into(),
            },
            instructions: Some(
                "Rivet is an SDLC traceability tool. Use tools to query, \
                 validate, and mutate lifecycle artifacts.".into()
            ),
        }
    }
}

// Example tool definition
#[derive(Debug, Deserialize, schemars::JsonSchema)]
pub struct ValidateParams {
    #[schemars(description = "Baseline version for scoped validation")]
    baseline: Option<String>,
    #[schemars(description = "Output detail level")]
    format: Option<String>,
}

#[tool(description = "Validate artifact traceability, link integrity, and schema rules")]
async fn rivet_validate(
    &self,
    Parameters(params): Parameters<ValidateParams>,
) -> Result<CallToolResult, McpError> {
    // Reuse existing validate logic from rivet-core
    let diagnostics = self.state.store.validate(&self.state.schema_set, ...)?;
    let json = serde_json::to_string_pretty(&diagnostics)?;
    Ok(CallToolResult::success(vec![Content::text(json)]))
}

Transport configuration for Claude Code

Users add to .claude/settings.json:

{
  "mcpServers": {
    "rivet": {
      "command": "rivet",
      "args": ["mcp"],
      "cwd": "/path/to/project"
    }
  }
}

Or for HTTP transport (shared with dashboard):

{
  "mcpServers": {
    "rivet": {
      "url": "http://localhost:3000/mcp"
    }
  }
}

Phases

Phase 1: Core tools over stdio

  • rivet mcp command with stdio transport
  • Tools: rivet_validate, rivet_list, rivet_get, rivet_stats, rivet_coverage
  • Basic error handling (McpError mapping from anyhow)
  • Test with Claude Code MCP integration

Phase 2: Mutation tools + resources

  • Tools: rivet_add, rivet_link, rivet_modify, rivet_impact
  • Resources: rivet://artifacts/{id}, rivet://schemas/{name}, rivet://diagnostics
  • Resource change notifications (when validation state changes)

Phase 3: HTTP transport + dashboard integration

  • Streamable HTTP transport on rivet serve --mcp
  • Share AppState between axum dashboard routes and MCP handler
  • SSE support for backwards compatibility

Phase 4: Prompts + guide integration

Dependencies

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions