From d43498154edb3b7156bece78b7c34880775a3f78 Mon Sep 17 00:00:00 2001 From: milan Date: Thu, 14 May 2026 17:39:10 +0200 Subject: [PATCH] mcp_server_collection now also a library own_assist now bundles the server collection by default --- .gitignore | 2 +- Cargo.lock | 535 ++++++++++++++++++++- Cargo.toml | 10 +- common/Cargo.toml | 5 +- common/src/exit_error.rs | 2 +- common/src/lib.rs | 2 + common/src/tracing_init.rs | 12 + mcp_server_collection/Cargo.lock | 4 +- mcp_server_collection/Cargo.toml | 1 - mcp_server_collection/src/caldav/client.rs | 2 +- mcp_server_collection/src/config.rs | 16 +- mcp_server_collection/src/datetime.rs | 3 +- mcp_server_collection/src/lib.rs | 95 ++++ mcp_server_collection/src/main.rs | 108 +---- own_mcp/src/audio/client.rs | 2 +- own_mcp/src/audio/recording.rs | 12 +- own_mcp/src/mcp/chat.rs | 19 +- own_mcp/src/mcp/translation.rs | 2 +- src/main.rs | 27 +- 19 files changed, 716 insertions(+), 143 deletions(-) create mode 100644 common/src/tracing_init.rs create mode 100644 mcp_server_collection/src/lib.rs diff --git a/.gitignore b/.gitignore index 11d96b0..279b55b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ /target */target assist.toml -mcp_server_collection/server.toml +server.toml temporary_audio src/human_interface/.AUTH_HEADER \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index a4bbf67..ae43273 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "alsa" version = "0.11.0" @@ -104,6 +110,17 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -171,6 +188,58 @@ dependencies = [ "fs_extra", ] +[[package]] +name = "axum" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" +dependencies = [ + "axum-core", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "base64" version = "0.22.1" @@ -280,6 +349,16 @@ dependencies = [ "windows-link", ] +[[package]] +name = "chrono-tz" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3" +dependencies = [ + "chrono", + "phf", +] + [[package]] name = "clap" version = "4.6.0" @@ -345,6 +424,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "console" version = "0.16.3" @@ -445,6 +533,30 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + [[package]] name = "crypto-common" version = "0.1.7" @@ -495,6 +607,15 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", +] + [[package]] name = "dialoguer" version = "0.12.0" @@ -538,6 +659,38 @@ dependencies = [ "syn", ] +[[package]] +name = "domain" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7ff15f82df7d5086fb15dfc1c1e96598a6ded9829840a9bcfa1fa3ccd8d01d" +dependencies = [ + "bumpalo", + "bytes", + "domain-macros", + "futures-util", + "hashbrown 0.14.5", + "log", + "moka", + "octseq", + "rand 0.8.5", + "smallvec", + "time", + "tokio", + "tracing", +] + +[[package]] +name = "domain-macros" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d1a6796ad411f6812d691955066ad27450196bfb181bb91b66a643cc3e8f5b7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "dunce" version = "1.0.5" @@ -604,6 +757,27 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "extended" version = "0.1.0" @@ -822,6 +996,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "allocator-api2", +] + [[package]] name = "hashbrown" version = "0.15.5" @@ -888,6 +1071,12 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + [[package]] name = "hyper" version = "1.9.0" @@ -902,6 +1091,7 @@ dependencies = [ "http", "http-body", "httparse", + "httpdate", "itoa", "pin-project-lite", "smallvec", @@ -918,7 +1108,9 @@ dependencies = [ "http", "hyper", "hyper-util", + "log", "rustls", + "rustls-native-certs", "rustls-pki-types", "tokio", "tokio-rustls", @@ -990,6 +1182,20 @@ dependencies = [ "cc", ] +[[package]] +name = "icalendar" +version = "0.17.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "264fe856964b7a84076dec2d8ea29fce7c9b422968c9a2f404d4aa3771ae2179" +dependencies = [ + "chrono", + "chrono-tz", + "iso8601", + "nom", + "nom-language", + "uuid", +] + [[package]] name = "icu_collections" version = "2.2.0" @@ -1152,6 +1358,15 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +[[package]] +name = "iso8601" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1082f0c48f143442a1ac6122f67e360ceee130b967af4d50996e5154a45df46" +dependencies = [ + "nom", +] + [[package]] name = "itoa" version = "1.0.18" @@ -1266,6 +1481,23 @@ version = "0.2.184" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" +[[package]] +name = "libdav" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9992f07580da9541219ae9b94ac67de3b832953a8ca63855b4be5f44c5076ba8" +dependencies = [ + "domain", + "http", + "http-body-util", + "hyper", + "log", + "roxmltree", + "thiserror 2.0.18", + "tokio", + "tower-service", +] + [[package]] name = "libm" version = "0.2.16" @@ -1284,6 +1516,15 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.29" @@ -1305,6 +1546,45 @@ dependencies = [ "libc", ] +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "mcp_server_collection" +version = "0.2.1" +dependencies = [ + "axum", + "chrono", + "http", + "hyper-rustls", + "hyper-util", + "icalendar", + "libdav", + "own_assist_common", + "rmcp", + "serde", + "thiserror 2.0.18", + "tokio", + "tokio-util", + "toml", + "tower-http", + "tracing", + "url", + "uuid", +] + [[package]] name = "memchr" version = "2.8.0" @@ -1338,6 +1618,26 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "moka" +version = "0.12.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046" +dependencies = [ + "async-lock", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "equivalent", + "event-listener", + "futures-util", + "parking_lot", + "portable-atomic", + "smallvec", + "tagptr", + "uuid", +] + [[package]] name = "native-tls" version = "0.2.18" @@ -1396,6 +1696,33 @@ dependencies = [ "libc", ] +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "nom-language" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2de2bc5b451bfedaef92c90b8939a8fff5770bdcc1fafd6239d086aab8fa6b29" +dependencies = [ + "nom", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -1406,6 +1733,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" + [[package]] name = "num-derive" version = "0.4.2" @@ -1577,6 +1910,16 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "octseq" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126c3ca37c9c44cec575247f43a3e4374d8927684f129d2beeb0d2cef262fe12" +dependencies = [ + "bytes", + "smallvec", +] + [[package]] name = "ollama-rs" version = "0.3.4" @@ -1665,16 +2008,16 @@ dependencies = [ [[package]] name = "own_assist" -version = "0.2.0" +version = "0.3.0" dependencies = [ "base64", "clap", "console", "cpal", "dialoguer", - "env_logger", "indicatif", "log", + "mcp_server_collection", "ollama-rs", "own_assist_common", "own_mcp", @@ -1688,12 +2031,13 @@ dependencies = [ [[package]] name = "own_assist_common" -version = "0.2.0" +version = "0.3.0" dependencies = [ "log", "serde", "thiserror 2.0.18", "toml", + "tracing-subscriber", ] [[package]] @@ -1715,6 +2059,35 @@ dependencies = [ "url", ] +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + [[package]] name = "pastey" version = "0.2.1" @@ -1727,6 +2100,24 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "phf" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_shared" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.17" @@ -1763,6 +2154,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -1977,6 +2374,15 @@ dependencies = [ "rand 0.10.0", ] +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.11.0", +] + [[package]] name = "ref-cast" version = "1.0.25" @@ -2129,13 +2535,17 @@ checksum = "2231b2c085b371c01bc90c0e6c1cab8834711b6394533375bdbf870b0166d419" dependencies = [ "async-trait", "base64", + "bytes", "chrono", "futures", "http", + "http-body", + "http-body-util", "oauth2", "pastey", "pin-project-lite", "process-wrap", + "rand 0.10.0", "reqwest 0.13.2", "rmcp-macros", "schemars", @@ -2146,8 +2556,10 @@ dependencies = [ "tokio", "tokio-stream", "tokio-util", + "tower-service", "tracing", "url", + "uuid", ] [[package]] @@ -2179,6 +2591,15 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "roxmltree" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1964b10c76125c36f8afe190065a4bf9a87bf324842c05701330bba9f1cacbb" +dependencies = [ + "memchr", +] + [[package]] name = "rtrb" version = "0.3.3" @@ -2211,6 +2632,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ "aws-lc-rs", + "log", "once_cell", "rustls-pki-types", "rustls-webpki", @@ -2335,6 +2757,12 @@ dependencies = [ "syn", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "security-framework" version = "3.7.0" @@ -2462,6 +2890,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shell-words" version = "1.1.1" @@ -2484,6 +2921,12 @@ dependencies = [ "libc", ] +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + [[package]] name = "slab" version = "0.4.12" @@ -2742,6 +3185,12 @@ dependencies = [ "libc", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "tempfile" version = "3.27.0" @@ -2795,6 +3244,34 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + [[package]] name = "tinystr" version = "0.8.3" @@ -2829,6 +3306,7 @@ dependencies = [ "bytes", "libc", "mio", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -2955,6 +3433,7 @@ dependencies = [ "tokio", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -2963,12 +3442,14 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ + "base64", "bitflags 2.11.0", "bytes", "futures-util", "http", "http-body", "iri-string", + "mime", "pin-project-lite", "tower", "tower-layer", @@ -2993,6 +3474,7 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -3016,6 +3498,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] @@ -3091,6 +3603,23 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +dependencies = [ + "getrandom 0.4.2", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/Cargo.toml b/Cargo.toml index c2de63f..5465a7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "own_assist" -version = "0.2.0" +version = "0.3.0" edition = "2024" [dependencies] @@ -8,11 +8,11 @@ ollama-rs = { version = "0.3.4", features = ["macros", "headers"] } tokio = { version = "1.50.0", features = ["rt", "rt-multi-thread", "macros", "io-std"] } rmcp = { version = "1.3.0", features = ["client"] } log = { version = "0.4.29" } -env_logger = "0.11.10" serde = { version = "1.0.228", features = ["derive"] } url = "2.5.8" own_mcp = { path = "own_mcp" } own_assist_common = { path = "common" } +mcp_server_collection = { path = "mcp_server_collection", optional = true} thiserror = "2.0.18" dialoguer = "0.12.0" indicatif = "0.18.4" @@ -20,4 +20,8 @@ console = "0.16.3" clap = { version = "4.6.0", features = ["derive"] } base64 = "0.22.1" cpal = "0.17.3" -rodio = "0.22.2" \ No newline at end of file +rodio = "0.22.2" + +[features] +default = ["built-in-mcp-collection"] +built-in-mcp-collection = ["dep:mcp_server_collection"] \ No newline at end of file diff --git a/common/Cargo.toml b/common/Cargo.toml index 5b7cf23..1746830 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -1,10 +1,11 @@ [package] name = "own_assist_common" -version = "0.2.0" +version = "0.3.0" edition = "2024" [dependencies] thiserror = "2.0.18" toml = "1.1.2" serde = "1.0.228" -log = "0.4.29" \ No newline at end of file +log = "0.4.29" +tracing-subscriber = { version = "0.3.23", features = ["env-filter"]} \ No newline at end of file diff --git a/common/src/exit_error.rs b/common/src/exit_error.rs index 84cecb1..b241831 100644 --- a/common/src/exit_error.rs +++ b/common/src/exit_error.rs @@ -2,7 +2,7 @@ use std::fmt::Display; pub fn exit_with_error_message(error: impl Display, message: impl Display) { log::error!("{message}: {error}"); - eprintln!("{}", message); // makes sure that message is printed even if logging is deactivated + eprintln!("{message}: {error}"); // makes sure that message is printed even if logging is deactivated std::process::exit(1); } diff --git a/common/src/lib.rs b/common/src/lib.rs index 246641e..848825e 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,5 +1,7 @@ pub mod config_loader; mod exit_error; +mod tracing_init; pub use config_loader::config_from_file; pub use exit_error::exit_with_error_message; +pub use tracing_init::init_tracing_subscriber; diff --git a/common/src/tracing_init.rs b/common/src/tracing_init.rs new file mode 100644 index 0000000..756693a --- /dev/null +++ b/common/src/tracing_init.rs @@ -0,0 +1,12 @@ +use tracing_subscriber::layer::SubscriberExt; +use tracing_subscriber::util::SubscriberInitExt; + +pub fn init_tracing_subscriber() { + tracing_subscriber::registry() + .with( + tracing_subscriber::EnvFilter::try_from_default_env() + .unwrap_or_else(|_| "info".to_string().into()), + ) + .with(tracing_subscriber::fmt::layer()) + .init(); +} diff --git a/mcp_server_collection/Cargo.lock b/mcp_server_collection/Cargo.lock index 981b8d1..3450ca2 100644 --- a/mcp_server_collection/Cargo.lock +++ b/mcp_server_collection/Cargo.lock @@ -995,7 +995,6 @@ dependencies = [ "toml", "tower-http", "tracing", - "tracing-subscriber", "url", "uuid", ] @@ -1109,12 +1108,13 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "own_assist_common" -version = "0.2.0" +version = "0.3.0" dependencies = [ "log", "serde", "thiserror", "toml", + "tracing-subscriber", ] [[package]] diff --git a/mcp_server_collection/Cargo.toml b/mcp_server_collection/Cargo.toml index 846a835..be3da81 100644 --- a/mcp_server_collection/Cargo.toml +++ b/mcp_server_collection/Cargo.toml @@ -12,7 +12,6 @@ tokio = { version = "1.51.0", features = ["full"] } own_assist_common = { path = "../common" } tokio-util = "0.7.18" tracing = "0.1.44" -tracing-subscriber = { version = "0.3.23", features = ["env-filter"] } url = { version = "2.5.8", features = ["serde"] } uuid = { version = "1.23.0", features = ["v4"], optional = true } tower-http = { version = "0.6.8", features = ["auth"], optional = true } diff --git a/mcp_server_collection/src/caldav/client.rs b/mcp_server_collection/src/caldav/client.rs index ba93795..442fd82 100644 --- a/mcp_server_collection/src/caldav/client.rs +++ b/mcp_server_collection/src/caldav/client.rs @@ -11,8 +11,8 @@ use rmcp::ErrorData; use rmcp::model::ErrorCode; use thiserror::Error; use tower_http::auth::AddAuthorization; -use tracing::event; use tracing::Level; +use tracing::event; use uuid::Uuid; pub(crate) type AuthorizedCaldavClient = diff --git a/mcp_server_collection/src/config.rs b/mcp_server_collection/src/config.rs index 26aadc2..f34f37e 100644 --- a/mcp_server_collection/src/config.rs +++ b/mcp_server_collection/src/config.rs @@ -5,18 +5,18 @@ use serde::{Deserialize, Serialize}; use toml::map::Map; #[derive(Debug, Deserialize, Serialize)] -pub(crate) struct Config { +pub struct Config { #[serde(rename = "bind-address")] - pub(crate) bind_address: Option, - pub(crate) servers: Vec, + pub bind_address: Option, + pub servers: Vec, } #[derive(Debug, Clone, Deserialize, Serialize)] -pub(crate) struct ServerConfig { - pub(crate) path: String, - pub(crate) r#type: McpServiceType, - #[serde(rename = "additional-properties")] - pub(crate) additional_properties: Map, +pub struct ServerConfig { + pub path: String, + pub r#type: McpServiceType, + #[serde(rename = "additional-properties", default = "Map::new")] + pub additional_properties: Map, } impl Config { diff --git a/mcp_server_collection/src/datetime.rs b/mcp_server_collection/src/datetime.rs index ebb0453..3aeebd2 100644 --- a/mcp_server_collection/src/datetime.rs +++ b/mcp_server_collection/src/datetime.rs @@ -62,7 +62,8 @@ impl DateTimeHandler { Fri => "Friday", Sat => "Saturday", Sun => "Sunday", - }.to_string() + } + .to_string() } } diff --git a/mcp_server_collection/src/lib.rs b/mcp_server_collection/src/lib.rs new file mode 100644 index 0000000..c03d478 --- /dev/null +++ b/mcp_server_collection/src/lib.rs @@ -0,0 +1,95 @@ +pub mod config; +#[cfg(feature = "datetime")] +pub mod datetime; + +#[cfg(feature = "caldav")] +pub mod caldav; +mod server_handler; + +#[cfg(feature = "caldav")] +use crate::caldav::CalDavHandler; +use crate::config::{Config, ServerConfig}; +#[cfg(feature = "datetime")] +use crate::datetime::DateTimeHandler; +use crate::server_handler::{McpServerHandler, McpServerHandlerError}; +use axum::Router; +use axum::response::Json; +use own_assist_common::exit_msg; +use serde::{Deserialize, Serialize}; +use tracing::{Level, event}; + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[non_exhaustive] +pub enum McpServiceType { + #[cfg(feature = "datetime")] + DateTime, + #[cfg(feature = "caldav")] + CalDav, +} + +pub(crate) async fn mcp_router( + server_configs: &Vec, +) -> Result { + let mut router = Router::new(); + + for config in server_configs { + router = match config.r#type { + #[cfg(feature = "datetime")] + McpServiceType::DateTime => router.route_service( + config.path.as_str(), + DateTimeHandler::mcp_service(config.additional_properties.clone()).await?, + ), + #[cfg(feature = "caldav")] + McpServiceType::CalDav => router.route_service( + config.path.as_str(), + CalDavHandler::mcp_service(config.additional_properties.clone()).await?, + ), + } + } + + Ok(router) +} + +fn bind_address_format(url: url::Url) -> String { + format!( + "{}:{}", + url.host_str().expect("No host specified"), + url.port().unwrap_or(8000) + ) +} + +pub async fn serve(config: Config) { + let routes = Json( + config + .servers + .clone() + .iter() + .map(|server| server.path.clone()) + .collect::>(), + ); + + let router = mcp_router(&config.servers) + .await + .inspect_err(exit_msg!("Error handling server: {e}")) + .unwrap() + .route("/", axum::routing::get(|| async { routes })); + + let bind_address = config + .bind_address + .unwrap_or(url::Url::parse("http://localhost:8000").unwrap()); + event!(Level::INFO, "binding address at {bind_address}"); + + let tcp_listener = tokio::net::TcpListener::bind(bind_address_format(bind_address)) + .await + .inspect_err(exit_msg!("Error bind tcp listener: {e:#?}")) + .unwrap(); + + let ct = tokio_util::sync::CancellationToken::new(); + + let _ = axum::serve(tcp_listener, router) + .with_graceful_shutdown(async move { + tokio::signal::ctrl_c().await.unwrap(); + ct.cancel(); + }) + .await; +} diff --git a/mcp_server_collection/src/main.rs b/mcp_server_collection/src/main.rs index fbb8885..a4cc5da 100644 --- a/mcp_server_collection/src/main.rs +++ b/mcp_server_collection/src/main.rs @@ -1,111 +1,15 @@ -mod config; -#[cfg(feature = "datetime")] -pub mod datetime; - -#[cfg(feature = "caldav")] -pub mod caldav; -mod server_handler; - -#[cfg(feature = "caldav")] -use crate::caldav::CalDavHandler; -use crate::config::{Config, ServerConfig}; -#[cfg(feature = "datetime")] -use crate::datetime::DateTimeHandler; -use crate::server_handler::{McpServerHandler, McpServerHandlerError}; -use axum::Router; -use axum::response::Json; -use serde::{Deserialize, Serialize}; +use mcp_server_collection::config::Config; +use mcp_server_collection::serve; +use own_assist_common::{exit_msg, init_tracing_subscriber}; use tokio::main; -use tracing::{event, Level}; -use tracing_subscriber::layer::SubscriberExt; -use tracing_subscriber::util::SubscriberInitExt; -use own_assist_common::exit_msg; - -#[derive(Debug, Clone, Deserialize, Serialize)] -#[non_exhaustive] -pub enum McpServiceType { - #[cfg(feature = "datetime")] - DateTime, - #[cfg(feature = "caldav")] - CalDav, -} - -pub(crate) async fn mcp_router( - server_configs: &Vec, -) -> Result { - let mut router = Router::new(); - - for config in server_configs { - router = match config.r#type { - #[cfg(feature = "datetime")] - McpServiceType::DateTime => router.route_service( - config.path.as_str(), - DateTimeHandler::mcp_service(config.additional_properties.clone()).await?, - ), - #[cfg(feature = "caldav")] - McpServiceType::CalDav => router.route_service( - config.path.as_str(), - CalDavHandler::mcp_service(config.additional_properties.clone()).await?, - ), - } - } - - Ok(router) -} - -fn bind_address_format(url: url::Url) -> String { - format!( - "{}:{}", - url.host_str().expect("No host specified"), - url.port().unwrap_or(8000) - ) -} #[main] async fn main() { - tracing_subscriber::registry() - .with( - tracing_subscriber::EnvFilter::try_from_default_env() - .unwrap_or_else(|_| "debug".to_string().into()), - ) - .with(tracing_subscriber::fmt::layer()) - .init(); + init_tracing_subscriber(); let config = Config::from_file() - .inspect_err(exit_msg!("Error loading config: {e}")) + .inspect_err(exit_msg!("Error loading config")) .unwrap(); - let routes = Json( - config - .servers - .clone() - .iter() - .map(|server| server.path.clone()) - .collect::>(), - ); - - let router = mcp_router(&config.servers) - .await - .inspect_err(exit_msg!("Error handling server: {e}")) - .unwrap() - .route("/", axum::routing::get(|| async { routes })); - - let bind_address = config - .bind_address - .unwrap_or(url::Url::parse("http://localhost:8000").unwrap()); - event!(Level::INFO,"binding address at {bind_address}"); - - let tcp_listener = tokio::net::TcpListener::bind(bind_address_format(bind_address)) - .await - .inspect_err(exit_msg!("Error bind tcp listener: {e:#?}")) - .unwrap(); - - let ct = tokio_util::sync::CancellationToken::new(); - - let _ = axum::serve(tcp_listener, router) - .with_graceful_shutdown(async move { - tokio::signal::ctrl_c().await.unwrap(); - ct.cancel(); - }) - .await; + serve(config).await; } diff --git a/own_mcp/src/audio/client.rs b/own_mcp/src/audio/client.rs index b41c301..e661f1e 100644 --- a/own_mcp/src/audio/client.rs +++ b/own_mcp/src/audio/client.rs @@ -43,7 +43,7 @@ impl AudioClient { fn get(&self, url: Url) -> reqwest::RequestBuilder { self.client.get(url).header( "Authorization", - self.authorization.clone().unwrap_or(String::new()), + self.authorization.clone().unwrap_or_default(), ) } } diff --git a/own_mcp/src/audio/recording.rs b/own_mcp/src/audio/recording.rs index afb3bb8..a4e6684 100644 --- a/own_mcp/src/audio/recording.rs +++ b/own_mcp/src/audio/recording.rs @@ -108,11 +108,11 @@ fn start_recording_blocking_with_parameters( loop { thread::sleep(Duration::from_millis(100)); - if let Ok(guard) = should_stop.lock() { - if *guard { - debug!("Stopping recording gracefully"); - break; - } + if let Ok(guard) = should_stop.lock() + && *guard + { + debug!("Stopping recording gracefully"); + break; } } @@ -173,7 +173,7 @@ pub fn stop_and_take_data( .ok_or(RecordingError::RecordingAlreadyStopped)?; let samples = handler.samples.clone(); - let spec = handler.spec.clone(); + let spec = handler.spec; handler.stop_recording()?; diff --git a/own_mcp/src/mcp/chat.rs b/own_mcp/src/mcp/chat.rs index dee3345..9bf57e1 100644 --- a/own_mcp/src/mcp/chat.rs +++ b/own_mcp/src/mcp/chat.rs @@ -8,6 +8,7 @@ use rmcp::ServiceError; use rmcp::model::{CallToolRequestParams, CallToolResult}; use serde::Deserialize; use std::collections::HashMap; +use ollama_rs::generation::completion::request::GenerationRequest; use thiserror::Error; #[derive(Debug, Copy, Clone, Default, Deserialize, PartialEq)] @@ -113,6 +114,13 @@ impl AgentChat { servers.insert(server.name.clone(), server); } + // lets the ollama server load the model + let ollama_client_clone = ollama_client.clone(); + let model_clone = model.clone(); + tokio::spawn(async move { + let _ = ollama_client_clone.generate(GenerationRequest::new(model_clone, "")).await; + }); + Ok(Self { ollama_client, model, @@ -124,8 +132,7 @@ impl AgentChat { pub fn get_all_tools(&self) -> impl Iterator { self.mcp_servers .values() - .map(|server| server.translated_tools.iter()) - .flatten() + .flat_map(|server| server.translated_tools.iter()) } /// @@ -300,10 +307,10 @@ impl AgentChat { let mcp_server_data = self .get_mcp_server_by_name(mcp_server_name.clone()) .ok_or(ChatError::ServiceNotFoundError(mcp_server_name.clone()))?; - let restricted_tool = - AgentChat::get_tool(&mcp_server_data, full_unparsed_tool_name.clone()).ok_or( - ChatError::ToolNotFoundError(full_unparsed_tool_name.clone()), - )?; + let restricted_tool = AgentChat::get_tool(mcp_server_data, full_unparsed_tool_name.clone()) + .ok_or(ChatError::ToolNotFoundError( + full_unparsed_tool_name.clone(), + ))?; match restricted_tool.permission { ToolPermission::Allowed => { diff --git a/own_mcp/src/mcp/translation.rs b/own_mcp/src/mcp/translation.rs index a9d2b57..82560fa 100644 --- a/own_mcp/src/mcp/translation.rs +++ b/own_mcp/src/mcp/translation.rs @@ -12,7 +12,7 @@ pub(in crate::mcp) async fn get_server_tool_info( .list_all_tools() .await? .iter() - .map(|mcp_tool| tool_info_from_mcp_tool(&mcp_tool, server_name)) + .map(|mcp_tool| tool_info_from_mcp_tool(mcp_tool, server_name)) .collect::>(); Ok(tool_info) diff --git a/src/main.rs b/src/main.rs index 810f16f..68562d8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,8 +10,10 @@ use crate::model::create_model_from_config; use base64::Engine; use clap::Parser; use cpal::traits::HostTrait; -use own_assist_common::exit_msg; +use own_assist_common::config_loader::ConfigLoadingError; +use own_assist_common::{exit_msg, init_tracing_subscriber}; use own_mcp::AgentChat; +use tokio::task::JoinHandle; /// partial mcp client with cli and voice interaction #[derive(Parser, Debug)] @@ -64,6 +66,15 @@ async fn chat_loop(mut human_interface: impl HumanInterface, mut agent_chat: Age } } +#[cfg(feature = "built-in-mcp-collection")] +fn launch_mcp_server() -> Result, ConfigLoadingError> { + let config = mcp_server_collection::config::Config::from_file()?; + + let handle = tokio::task::spawn(mcp_server_collection::serve(config)); + + Ok(handle) +} + #[tokio::main] async fn main() { let args = Args::parse(); @@ -72,10 +83,15 @@ async fn main() { return; } - env_logger::init(); + init_tracing_subscriber(); + + #[cfg(feature = "built-in-mcp-collection")] + let mcp_server_task = launch_mcp_server() + .inspect_err(exit_msg!("error loading server.toml")) + .unwrap(); let config = Config::from_file() - .inspect_err(exit_msg!("error loading assist.toml: {}")) + .inspect_err(exit_msg!("error loading assist.toml")) .unwrap(); let ollama = config.ollama_instance(); @@ -100,7 +116,7 @@ async fn main() { .unwrap(); config.set_tool_permissions(&mut agent_chat).await.unwrap(); - log::info!( + log::debug!( "all tools: {:#?}", agent_chat.get_all_tools().collect::>() ); @@ -131,4 +147,7 @@ async fn main() { }; } }; + + #[cfg(feature = "built-in-mcp-collection")] + mcp_server_task.await.unwrap(); }