Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .aether/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@
"${HOME}/.agents/rules",
"--rules-dir",
"${WORKSPACE}/.agents/rules"
],
"input": null
]
}
}
}
Expand Down
2 changes: 0 additions & 2 deletions .aether/skills/rust/error-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ use thiserror::Error;

#[derive(Debug, Error)]
pub enum AgentError {
#[error("MCP error: {0}")]
McpError(#[from] mcp_utils::client::McpError),
#[error("LLM error: {0}")]
LlmError(#[from] llm::LlmError),
#[error("IO error: {0}")]
Expand Down
16 changes: 8 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,21 +136,23 @@ Use `aether-agent-core` as a Rust library to build your own agent in ~25 lines.
mcp::mcp,
};
use llm::providers::anthropic::AnthropicProvider;
use aether_core::mcp::McpConfig;
use std::io::{self, Write};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. Create a provider (reads ANTHROPIC_API_KEY from env)
let llm = AnthropicProvider::new(None);

// 2. Spawn MCP tool servers from one or more mcp.json files
let mut mcp_runtime = mcp(".").from_json_files(&["mcp.json"])?.spawn().await?;
let snapshot = mcp_runtime.block_until_ready().await.ok_or("MCP bootstrap aborted")?;
// 2. Spawn MCP tool servers from an mcp.json file
let config = McpConfig::from_json_file("mcp.json")?;
let mcp = mcp(".").with_config(config)?.spawn()?;
mcp.ready().await;

// 3. Build and spawn the agent
let (tx, mut rx, _handle) = agent(llm)
.system_prompt(Prompt::file("AGENTS.md", "."))
.tools(mcp_runtime.handle().clone(), snapshot.tool_definitions())
.mcp(mcp)
.spawn()
.await?;

Expand Down
5 changes: 2 additions & 3 deletions crates/aether-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ name = "aether"
path = "src/main.rs"

[features]
testing = ["acp_utils/testing", "mcp_utils/testing"]
testing = ["acp_utils/testing", "mcp_utils/testing", "aether-core/testing"]

[dependencies]
aether-auth = { path = "../aether-auth", version = "0.1.17", features = ["keyring"] }
Expand All @@ -40,7 +40,7 @@ aether-project = { path = "../aether-project", version = "0.5.58" }
aether-telemetry = { path = "../aether-telemetry", version = "0.3.13" }
llm = { package = "aether-llm", path = "../llm", features = ["bedrock", "codex"], version = "0.9.13" }
mcp_utils = { package = "aether-mcp-utils", path = "../mcp-utils", version = "0.7.13" }
mcp-servers = { package = "aether-mcp-servers", path = "../mcp-servers", features = ["all"], version = "0.8.4" }
mcp-servers = { package = "aether-mcp-servers", path = "../mcp-servers", features = ["subagents"], version = "0.8.4" }
wisp = { package = "aether-wisp", path = "../wisp", version = "0.7.14" }
ratatui = { workspace = true }
acp_utils = { package = "aether-acp-utils", path = "../acp-utils", features = ["websocket"], version = "0.5.13" }
Expand All @@ -49,7 +49,6 @@ clankerdiff-core = { workspace = true }
clankerdiff-protocol = { workspace = true }
clankerdiff-server = { workspace = true }
aether-lspd = { path = "../aether-lspd", version = "0.3.3" }
rmcp = { workspace = true, features = ["client", "elicitation", "server", "transport-streamable-http-client-reqwest"] }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["rt", "rt-multi-thread", "macros", "sync", "io-util", "net", "fs", "time", "signal", "process"] }
tokio-tungstenite = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion crates/aether-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ The `mcp.json` file configures MCP tool servers:
- **coding** — Filesystem tools (read, write, bash, etc.) plus optional auto-read rules from configured `--rules-dir` paths
- **skills** — Slash commands and reusable prompts loaded from the configured `--dir` paths

Set `"deferTools": true` on a server to keep its schemas out of the model-visible tool definitions. Use `aether mcp --help` to discover deferred servers, then `aether mcp <server> --help` and `aether mcp <server> <tool> --help` to inspect tools and schemas. Invoke a tool with `--json '{...}'` or a JSON object on stdin. To partition tools, use `"deferTools": { "include": [...], "exclude": [...] }`; patterns are exact MCP-local names or trailing-`*` prefixes, and `exclude` wins.
Set `"deferTools": true` on a server to keep its schemas out of the model-visible tool definitions. Use `aether mcp --help` to discover deferred servers, then `aether mcp <server> --help` and `aether mcp <server> <tool> --help` to inspect tools and schemas. Invoke a tool with `--json '{...}'` or a JSON object on stdin. To partition tools, use `"deferTools": { "include": [...], "exclude": [...] }`; entries are exact MCP-local names, trailing-`*` prefixes, or annotation matchers such as `{ "readOnly": true }`, and `exclude` wins.

## Slash Commands

Expand Down
83 changes: 0 additions & 83 deletions crates/aether-cli/src/acp/fake_prompt_mcp.rs

This file was deleted.

3 changes: 0 additions & 3 deletions crates/aether-cli/src/acp/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
pub(crate) mod agent;
#[cfg(any(test, feature = "testing"))]
pub(crate) mod fake_prompt_mcp;
pub(crate) mod protocol;
pub mod server;
pub(crate) mod session;
pub(crate) mod state;
#[cfg(any(test, feature = "testing"))]
pub mod testing;

pub use protocol::map_mcp_prompt_to_available_command;
pub use session::hooks::{IdleHook, SessionHooks};

use crate::acp::state::{AcpState, AcpStateConfig};
Expand Down
19 changes: 7 additions & 12 deletions crates/aether-cli/src/acp/protocol/commands.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
use agent_client_protocol::schema::v2::{self as acp, AvailableCommandInput, TextCommandInput};
use rmcp::model::Prompt as McpPrompt;
use mcp_utils::gateway::ServerPrompt;

/// Converts an MCP Prompt to an ACP `AvailableCommand`
///
/// Strips the MCP namespace from the prompt name (e.g., "`coding__web`" -> "web")
/// and creates a slash command that clients can invoke.
pub fn map_mcp_prompt_to_available_command(prompt: &McpPrompt) -> acp::AvailableCommand {
let command_name = prompt.name.split("__").last().unwrap_or(prompt.name.as_ref()).to_string();
pub(crate) fn available_commands(prompts: &[ServerPrompt]) -> Vec<acp::AvailableCommand> {
prompts.iter().map(|listed| available_command(&listed.prompt)).collect()
}

fn available_command(prompt: &mcp_utils::model::Prompt) -> acp::AvailableCommand {
let hint = prompt
.arguments
.as_ref()
.and_then(|args| args.iter().find(|a| a.name.as_str() == "ARGUMENTS").and_then(|a| a.description.as_deref()))
.unwrap_or("optional arguments");

let input = Some(AvailableCommandInput::Text(TextCommandInput::new(hint)));

let description = prompt.description.clone().unwrap_or_else(|| "No description available".to_string());

acp::AvailableCommand::new(command_name, description).input(input)
acp::AvailableCommand::new(&prompt.name, description)
.input(Some(AvailableCommandInput::Text(TextCommandInput::new(hint))))
}
Loading
Loading