Skip to content

Commit 55e959a

Browse files
author
Test User
committed
Merge remote-tracking branch 'gitea/main'
2 parents e964ea8 + 4a8ce5c commit 55e959a

10 files changed

Lines changed: 1563 additions & 3 deletions

File tree

Cargo.lock

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
[package]
2+
name = "terraphim_mcp_search"
3+
# Independent versioning — fresh crate, semver 0.x as we iterate.
4+
# Bump to 1.x once the API stabilises (after Step 3-4 of issue terraphim-agents#64).
5+
version = "0.1.0"
6+
edition.workspace = true
7+
rust-version.workspace = true
8+
authors = ["Terraphim Team <team@terraphim.ai>"]
9+
description = "MCP tool index and discovery using terraphim_automata (Aho-Corasick pattern matching)"
10+
documentation = "https://terraphim.ai"
11+
homepage = "https://terraphim.ai"
12+
repository = "https://github.com/terraphim/terraphim-ai"
13+
keywords = ["mcp", "model-context-protocol", "tool-discovery", "aho-corasick", "search"]
14+
license = "Apache-2.0"
15+
readme = "README.md"
16+
17+
[dependencies]
18+
# Use the same terraphim_types / terraphim_automata versions as the rest of
19+
# the terraphim-ai workspace (1.20.4 from crates.io). Mixing registries
20+
# (e.g. terraphim-registry 1.20.2 here, crates.io 1.20.4 in the workspace)
21+
# causes Cargo to treat them as separate crates, leading to type-mismatch
22+
# errors when crossing crate boundaries.
23+
terraphim_automata = { version = "1.20.4" }
24+
terraphim_types = { version = "1.20.4" }
25+
serde = { workspace = true }
26+
serde_json = { workspace = true }
27+
28+
[dev-dependencies]
29+
tempfile = { workspace = true }
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# terraphim_mcp_search
2+
3+
MCP (Model Context Protocol) tool and Terraphim skill indexing & discovery,
4+
using `terraphim_automata`'s Aho-Corasick pattern matching for sub-100-entry
5+
searches under 70ms.
6+
7+
## What this crate gives you
8+
9+
| Item | When to use |
10+
|------|-------------|
11+
| [`McpToolIndex`] | You want a persistent, mutable, large-corpus tool index with save/load. |
12+
| [`mcp_search_tools`] | You have a slice of tools and want a one-shot search without managing state. |
13+
| [`SkillEntry`] + [`mcp_search_skills`] | You want to search Terraphim skills (TinyClaw JSON, etc.) with the same engine. |
14+
15+
## Why this crate exists
16+
17+
Extracted from `terraphim_agent::mcp_tool_index` (sibling `terraphim-agents`
18+
polyrepo, version 1.20.x) on **2026-06-28**, as part of the Mega-MCP / Tool
19+
Search adaptation plan for terraphim-ai. `mcp_search_tools` and
20+
`mcp_search_skills` were added the same day as the first consumers of the
21+
extracted index.
22+
23+
The extraction of `McpToolIndex` is **source-verbatim** to preserve the
24+
existing API contract and all 9 unit tests + 7 doctests unchanged.
25+
26+
The new search helpers are stateless conveniences over `McpToolIndex`
27+
they build an ephemeral index per call. For repeated searches over a stable
28+
corpus, build a `McpToolIndex` directly.
29+
30+
## Status
31+
32+
- **Here in `terraphim-ai`:** functional, tested, clippy-clean, ready for new
33+
consumers in this workspace.
34+
- **In `terraphim_agent` (sibling repo):** the original `mcp_tool_index` module
35+
is **still present and unchanged** — see Gitea issue
36+
[`terraphim-agents#64`](https://git.terraphim.cloud/terraphim/terraphim-agents/issues/64)
37+
for the dependency-swap migration plan.
38+
39+
## Usage
40+
41+
```rust
42+
use terraphim_mcp_search::{
43+
McpToolIndex, mcp_search_tools, mcp_search_skills, SkillEntry,
44+
};
45+
use terraphim_types::McpToolEntry;
46+
use std::path::PathBuf;
47+
48+
// State-managed: persistent, mutable index
49+
let mut index = McpToolIndex::new(PathBuf::from("/tmp/mcp-tools.json"));
50+
index.add_tool(McpToolEntry::new("search_files", "Search files", "filesystem"));
51+
index.add_tool(McpToolEntry::new("read_file", "Read file contents", "filesystem"));
52+
let hits = index.search("search");
53+
// hits[0].name == "search_files"
54+
55+
// Stateless: one-shot slice search
56+
let tools = index.tools().to_vec();
57+
let hits = mcp_search_tools("search", &tools);
58+
// hits is Vec<McpToolEntry> (owned)
59+
60+
// Skill search via the same engine
61+
let skills = vec![
62+
SkillEntry::new("code-review", "Automated code review")
63+
.with_tags(vec!["review".into()]),
64+
SkillEntry::new("deploy", "Deploy to staging"),
65+
];
66+
let skill_hits = mcp_search_skills("review", &skills);
67+
// skill_hits[0].name == "code-review"
68+
```
69+
70+
## Performance NFR
71+
72+
- **Search latency**: < 70 ms for 100 tools (`McpToolIndex::test_discovery_latency_benchmark`,
73+
release-mode only).
74+
- **Stateless helpers**: ephemeral index in `/tmp/terraphim-mcp-search-ephemeral.json`,
75+
never persisted.
76+
- **Memory**: proportional to corpus size.
77+
78+
## Migration plan (the "C" of "A/B/C")
79+
80+
| Step | Where | Who | Status |
81+
|------|-------|-----|--------|
82+
| 1. Create standalone crate | `terraphim-ai` workspace | done 2026-06-28 ||
83+
| 2. Add stateless search helpers | `terraphim-ai` workspace | done 2026-06-28 ||
84+
| 3. File Gitea issue in `terraphim-agents` | `terraphim-agents` repo | done 2026-06-28 ||
85+
| 4. Update `terraphim_agent` Cargo.toml to depend on `terraphim_mcp_search` | `terraphim-agents` polyrepo | TBD ||
86+
| 5. Re-export `terraphim_agent::mcp_tool_index` as a deprecation shim pointing at this crate | `terraphim-agents` polyrepo | TBD ||
87+
| 6. Eventually remove the legacy module | `terraphim-agents` polyrepo | TBD ||
88+
89+
Steps 4-6 belong in the `terraphim-agents` polyrepo — **do not** execute them
90+
from this workspace. They're out of scope per the surgeon pre-cut check.
91+
92+
## Dependencies
93+
94+
- `terraphim_automata = "1.20.2"` (from terraphim registry)
95+
- `terraphim_types = "1.20.2"` (from terraphim registry, for `McpToolEntry`)
96+
- `serde`, `serde_json`, `tempfile` (dev)
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//! # terraphim_mcp_search
2+
//!
3+
//! MCP (Model Context Protocol) tool indexing and search.
4+
//!
5+
//! Provides [`McpToolIndex`] for fast discovery of MCP tools across configured
6+
//! servers, using `terraphim_automata`'s Aho-Corasick pattern matching.
7+
//!
8+
//! ## What this crate gives you
9+
//!
10+
//! | Item | When to use |
11+
//! |------|-------------|
12+
//! | [`McpToolIndex`] | You want a persistent, mutable, large-corpus tool index with save/load. |
13+
//! | [`mcp_search_tools`] | You have a slice of tools and want a one-shot search without managing state. |
14+
//! | [`SkillEntry`] + [`mcp_search_skills`] | You want to search Terraphim skills (TinyClaw JSON, etc.) with the same engine. |
15+
//!
16+
//! ## Origin and migration plan
17+
//!
18+
//! This crate was extracted from `terraphim_agent::mcp_tool_index` (in the
19+
//! sibling `terraphim-agents` polyrepo, version 1.20.x) on 2026-06-28. The
20+
//! source is verbatim so that:
21+
//!
22+
//! - The `McpToolIndex` API is identical to the legacy one.
23+
//! - Search semantics (per-keyword Aho-Corasick matching over
24+
//! `name + description + tags`) match the existing tests.
25+
//! - Performance NFR is preserved: search completes in **< 70 ms for 100 tools**.
26+
//!
27+
//! Once `terraphim_agent` switches to depending on this crate (tracked in
28+
//! Gitea issue [terraphim-agents#64](https://git.terraphim.cloud/terraphim/terraphim-agents/issues/64)),
29+
//! `terraphim_agent::mcp_tool_index` will become a deprecated re-export shim
30+
//! and eventually be removed.
31+
//!
32+
//! ## Example
33+
//!
34+
//! ```
35+
//! use terraphim_mcp_search::{McpToolIndex, mcp_search_tools, mcp_search_skills, SkillEntry};
36+
//! use terraphim_types::McpToolEntry;
37+
//! use std::path::PathBuf;
38+
//!
39+
//! let mut index = McpToolIndex::new(PathBuf::from("/tmp/mcp-tools.json"));
40+
//! index.add_tool(McpToolEntry::new("search_files", "Search files", "filesystem"));
41+
//! index.add_tool(McpToolEntry::new("read_file", "Read file contents", "filesystem"));
42+
//!
43+
//! let results = index.search("search");
44+
//! assert_eq!(results.len(), 1);
45+
//! assert_eq!(results[0].name, "search_files");
46+
//!
47+
//! // One-shot search helper
48+
//! let hits = mcp_search_tools("search", &index.tools().iter().cloned().collect::<Vec<_>>());
49+
//! assert_eq!(hits.len(), 1);
50+
//!
51+
//! // Skill search (separate corpus, same engine)
52+
//! let skills = vec![
53+
//! SkillEntry::new("code-review", "Automated code review").with_tags(vec!["review".into()]),
54+
//! ];
55+
//! let skill_hits = mcp_search_skills("review", &skills);
56+
//! assert_eq!(skill_hits.len(), 1);
57+
//! ```
58+
59+
pub mod mcp_tool_index;
60+
pub mod search;
61+
62+
pub use mcp_tool_index::McpToolIndex;
63+
pub use search::{mcp_search_skills, mcp_search_tools, SkillEntry};

0 commit comments

Comments
 (0)