You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Extract the generic parts of rtemplate-contracts into a reusable public contracts-core style crate for Rust MCP servers, while keeping rmcp-template's concrete service/action/config material in template-local crates.
This is the lowest-level shared contract issue. It should land before higher-level gateway/server/runtime extraction (#69), facade-builder composition (#70), crates.io publishing infrastructure (#71), release-please automation (#72), Code Mode (#74), auth (#75), traces (#76), and OpenAPI generation (#77) start depending on a shared vocabulary.
Current repo evidence
crates/rtemplate-contracts/src/lib.rs currently exports actions, config, env_registry, errors, and token_limit from one crate.
actions.rs mixes generic contract types (ActionTransport, ActionCost, ParamSpec, CliSpec, ActionSpec) with template-specific constants and behavior (READ_SCOPE = "example:read", ExampleAction, ACTION_SPECS, example remediation text, destructive confirmation policy).
config.rs is template/runtime specific: .example, RTEMPLATE_*, McpConfig, AuthConfig, home-directory discovery, dotenv loading, and TOML parsing do not belong in consumers that only need action/error contracts.
config.rs::load_dotenv() currently calls std::process::exit(1) on a symlinked .env; that may be fine for a binary startup path, but not for a public library dependency.
errors.rs contains reusable structured tool error concepts (ServiceErrorKind, ToolError, REST/MCP payload conversion), but currently imports actions::ActionValidationError and action_names(), coupling generic errors back to template actions.
token_limit.rs contains reusable response budget constants/helpers, but its MCP pagination behavior is actually enforced in the MCP adapter; keep the core crate narrowly about budgets/helpers unless paging types are explicitly extracted.
Create a new shared platform crate, tentatively rmcp-contracts-core, and leave rtemplate-contracts as the template/service-specific crate that depends on it.
Do not move template config, auth config, dotenv loading, home-directory discovery, concrete scopes, ExampleAction, ACTION_SPECS, REST help text, plugin env mappings, or generated-service examples into the core crate.
Proposed core surface
action module:
ActionTransport, ActionCost, ParamSpec, CliFlagSpec, CliSpec, ActionSpec or owned/string-backed equivalents if the public API should not require 'static slices.
Generic action-name utilities that operate on caller-provided specs, not global ACTION_SPECS.
Generic validation primitives such as missing action, unknown action, missing field, wrong type, and transport-unavailable errors with caller-provided available action names.
error module:
Stable ToolError / ServiceErrorKind envelope with schema versioning, retryability, remediation, optional field / bad_value / expected_pattern / reason_kind.
Conversion helpers that accept tool/action names as parameters and do not import template action globals.
budget module:
MAX_RESPONSE_BYTES style default budget and plain text truncation helper, with the actual MCP paging cache remaining in the MCP/server crate unless separately extracted.
Optional env module only if it stays neutral:
Env-key descriptors and metadata, not RTEMPLATE_* loading or filesystem side effects.
Move generic action metadata types and tests from rtemplate-contracts/src/actions.rs into the new crate.
Refactor rtemplate-contracts::actions to define READ_SCOPE, WRITE_SCOPE, DENY_SCOPE, ExampleAction, ACTION_SPECS, scope satisfaction, destructive confirmation, and template-specific validation/remediation on top of core types.
Move ToolError / ServiceErrorKind into core, then make from_action_validation a template-local adapter or a generic function that accepts an ActionCatalog/available-action list.
Move budget constants/helpers only after confirming no MCP paging cache/state leaks into the core dependency graph.
Leave Config, McpConfig, AuthConfig, ExampleConfig, default_data_dir, load_dotenv, and env_registry in rtemplate-contracts or split them into a separate template config crate later. Remove public-library process::exit from any shared crate path; return a typed error and let binaries decide whether to exit.
Update direct imports in rtemplate-mcp, rtemplate-cli, rtemplate-api, rtemplate-service, and tests only after rtemplate-contracts re-exports or wraps the new core types.
Add a consumer fixture crate/test that depends on rmcp-contracts-core without rtemplate-contracts, dirs, dotenvy, toml, auth, runtime, MCP transport, or template config.
Do not change the one-tool action-dispatch template shape.
Do not force schema generation into this crate yet. The current MCP schema builder can continue to live in rtemplate-mcp; Implement rmcp-openapi support for generated servers #77 may add OpenAPI-derived schema sidecars later.
Risks / clarifications
ActionSpec currently uses &'static str and slices, which is convenient for generated constants but awkward for runtime/imported catalogs. Decide before extraction whether core exposes borrowed static specs, owned specs, or both.
Error helpers currently depend on action_names() for remediation. Core must not know template action globals.
ServiceErrorKind::retryable() currently marks validation retryable; validate whether that is intentional before freezing it publicly.
Moving token_limit without response paging may imply stronger guarantees than the core crate can enforce. Keep wording/API explicit.
Extracting config at the same time would drag in filesystem/env side effects and should be deferred.
Validation approach
cargo fmt --all --check
cargo check --workspace --all-features
cargo test -p rmcp-contracts-core
cargo test -p rtemplate-contracts
Focused integration tests that call ExampleAction::from_mcp_args, ExampleAction::from_rest, required_scope_for_action, and ToolError::to_mcp_payload through the existing template crate.
Consumer fixture check proving rmcp-contracts-core compiles independently with minimal dependencies.
cargo tree -p rmcp-contracts-core to confirm it does not pull dirs, dotenvy, toml, auth, gateway, runtime, CLI, or MCP transport crates.
Goal
Extract the generic parts of
rtemplate-contractsinto a reusable publiccontracts-corestyle crate for Rust MCP servers, while keeping rmcp-template's concrete service/action/config material in template-local crates.This is the lowest-level shared contract issue. It should land before higher-level gateway/server/runtime extraction (#69), facade-builder composition (#70), crates.io publishing infrastructure (#71), release-please automation (#72), Code Mode (#74), auth (#75), traces (#76), and OpenAPI generation (#77) start depending on a shared vocabulary.
Current repo evidence
crates/rtemplate-contracts/src/lib.rscurrently exportsactions,config,env_registry,errors, andtoken_limitfrom one crate.actions.rsmixes generic contract types (ActionTransport,ActionCost,ParamSpec,CliSpec,ActionSpec) with template-specific constants and behavior (READ_SCOPE = "example:read",ExampleAction,ACTION_SPECS, example remediation text, destructive confirmation policy).config.rsis template/runtime specific:.example,RTEMPLATE_*,McpConfig,AuthConfig, home-directory discovery, dotenv loading, and TOML parsing do not belong in consumers that only need action/error contracts.config.rs::load_dotenv()currently callsstd::process::exit(1)on a symlinked.env; that may be fine for a binary startup path, but not for a public library dependency.errors.rscontains reusable structured tool error concepts (ServiceErrorKind,ToolError, REST/MCP payload conversion), but currently importsactions::ActionValidationErrorandaction_names(), coupling generic errors back to template actions.token_limit.rscontains reusable response budget constants/helpers, but its MCP pagination behavior is actually enforced in the MCP adapter; keep the core crate narrowly about budgets/helpers unless paging types are explicitly extracted.release/components.tomlcurrently has onetemplatecomponent, so public crate release metadata needs Add crates.io publishing infrastructure for public reusable crates #71 before publishing.Architecture decision
Create a new shared platform crate, tentatively
rmcp-contracts-core, and leavertemplate-contractsas the template/service-specific crate that depends on it.Dependency direction:
Do not move template config, auth config, dotenv loading, home-directory discovery, concrete scopes,
ExampleAction,ACTION_SPECS, REST help text, plugin env mappings, or generated-service examples into the core crate.Proposed core surface
actionmodule:ActionTransport,ActionCost,ParamSpec,CliFlagSpec,CliSpec,ActionSpecor owned/string-backed equivalents if the public API should not require'staticslices.ACTION_SPECS.errormodule:ToolError/ServiceErrorKindenvelope with schema versioning, retryability, remediation, optionalfield/bad_value/expected_pattern/reason_kind.budgetmodule:MAX_RESPONSE_BYTESstyle default budget and plain text truncation helper, with the actual MCP paging cache remaining in the MCP/server crate unless separately extracted.envmodule only if it stays neutral:RTEMPLATE_*loading or filesystem side effects.Implementation sequence
crates/rmcp-contracts-coreto the workspace with minimal dependencies andpublish = falseuntil Add crates.io publishing infrastructure for public reusable crates #71 is ready.rtemplate-contracts/src/actions.rsinto the new crate.rtemplate-contracts::actionsto defineREAD_SCOPE,WRITE_SCOPE,DENY_SCOPE,ExampleAction,ACTION_SPECS, scope satisfaction, destructive confirmation, and template-specific validation/remediation on top of core types.ToolError/ServiceErrorKindinto core, then makefrom_action_validationa template-local adapter or a generic function that accepts anActionCatalog/available-action list.Config,McpConfig,AuthConfig,ExampleConfig,default_data_dir,load_dotenv, andenv_registryinrtemplate-contractsor split them into a separate template config crate later. Remove public-libraryprocess::exitfrom any shared crate path; return a typed error and let binaries decide whether to exit.rtemplate-mcp,rtemplate-cli,rtemplate-api,rtemplate-service, and tests only afterrtemplate-contractsre-exports or wraps the new core types.rmcp-contracts-corewithoutrtemplate-contracts,dirs,dotenvy,toml, auth, runtime, MCP transport, or template config.Likely files/modules touched
crates/rmcp-contracts-core/Cargo.tomlcrates/rmcp-contracts-core/src/lib.rscrates/rmcp-contracts-core/src/action.rscrates/rmcp-contracts-core/src/error.rscrates/rmcp-contracts-core/src/budget.rsCargo.tomlworkspace memberscrates/rtemplate-contracts/Cargo.tomlcrates/rtemplate-contracts/src/lib.rscrates/rtemplate-contracts/src/actions.rscrates/rtemplate-contracts/src/errors.rscrates/rtemplate-contracts/src/token_limit.rsif budget helpers move or re-exportcrates/rtemplate-mcp/src/schemas.rs,crates/rtemplate-mcp/src/rmcp_server.rs,crates/rtemplate-mcp/src/tools.rs,crates/rtemplate-cli/src/lib.rs,crates/rtemplate-api/src/api.rs,crates/rtemplate-service/src/lib.rsNon-goals
rtemplate-mcp; Implement rmcp-openapi support for generated servers #77 may add OpenAPI-derived schema sidecars later.Risks / clarifications
ActionSpeccurrently uses&'static strand slices, which is convenient for generated constants but awkward for runtime/imported catalogs. Decide before extraction whether core exposes borrowed static specs, owned specs, or both.action_names()for remediation. Core must not know template action globals.ServiceErrorKind::retryable()currently marks validation retryable; validate whether that is intentional before freezing it publicly.token_limitwithout response paging may imply stronger guarantees than the core crate can enforce. Keep wording/API explicit.Validation approach
cargo fmt --all --checkcargo check --workspace --all-featurescargo test -p rmcp-contracts-corecargo test -p rtemplate-contractsExampleAction::from_mcp_args,ExampleAction::from_rest,required_scope_for_action, andToolError::to_mcp_payloadthrough the existing template crate.rmcp-contracts-corecompiles independently with minimal dependencies.cargo tree -p rmcp-contracts-coreto confirm it does not pulldirs,dotenvy,toml, auth, gateway, runtime, CLI, or MCP transport crates.cargo xtask check-version-syncafter Add crates.io publishing infrastructure for public reusable crates #71 adds release metadata or if tracked version files change.Relationship to related issues
_metahelpers must respect the same response-budget/error envelope boundaries.ActionSpec-compatible metadata after the core action vocabulary exists.Acceptance criteria
rtemplate-contractskeeps template-specific action tables, scopes, config, env loading, and service naming.dirs,dotenvy,toml, auth, gateway, runtime, CLI, or MCP transport dependencies.std::process::exit.rtemplate-contractswrappers or re-exports.Sources
/home/jmagar/workspace/rmcp-template/Cargo.toml:8— current workspace crate list./home/jmagar/workspace/rmcp-template/crates/rtemplate-contracts/Cargo.toml:1— current contracts crate metadata/dependencies andpublish = false./home/jmagar/workspace/rmcp-template/crates/rtemplate-contracts/src/lib.rs:1— current exported modules./home/jmagar/workspace/rmcp-template/crates/rtemplate-contracts/src/actions.rs:93— template-specific scopes./home/jmagar/workspace/rmcp-template/crates/rtemplate-contracts/src/actions.rs:106— reusable action metadata types begin./home/jmagar/workspace/rmcp-template/crates/rtemplate-contracts/src/actions.rs:213— template-specific concrete action table./home/jmagar/workspace/rmcp-template/crates/rtemplate-contracts/src/config.rs:12— template-specific service home/defaults./home/jmagar/workspace/rmcp-template/crates/rtemplate-contracts/src/config.rs:232— dotenv loader with binary-style exit behavior./home/jmagar/workspace/rmcp-template/crates/rtemplate-contracts/src/errors.rs:49— stable structured tool error envelope./home/jmagar/workspace/rmcp-template/crates/rtemplate-contracts/src/token_limit.rs:41— response-size budget helper./home/jmagar/workspace/rmcp-template/release/components.toml:3— current single release component.