1use serde_json::Value;
4
5use crate::api::AuthyClient;
6
7pub fn tool_definitions() -> Vec<Value> {
9 vec![
10 serde_json::json!({
11 "name": "get_secret",
12 "description": "Retrieve a secret value from the vault",
13 "inputSchema": {
14 "type": "object",
15 "properties": {
16 "name": { "type": "string", "description": "Secret name" }
17 },
18 "required": ["name"]
19 }
20 }),
21 serde_json::json!({
22 "name": "list_secrets",
23 "description": "List all secret names, optionally filtered by a policy scope",
24 "inputSchema": {
25 "type": "object",
26 "properties": {
27 "scope": { "type": "string", "description": "Policy scope to filter by (optional)" }
28 }
29 }
30 }),
31 serde_json::json!({
32 "name": "store_secret",
33 "description": "Store a secret in the vault",
34 "inputSchema": {
35 "type": "object",
36 "properties": {
37 "name": { "type": "string", "description": "Secret name" },
38 "value": { "type": "string", "description": "Secret value" },
39 "force": { "type": "boolean", "description": "Overwrite if exists (default: false)" }
40 },
41 "required": ["name", "value"]
42 }
43 }),
44 serde_json::json!({
45 "name": "remove_secret",
46 "description": "Remove a secret from the vault",
47 "inputSchema": {
48 "type": "object",
49 "properties": {
50 "name": { "type": "string", "description": "Secret name" }
51 },
52 "required": ["name"]
53 }
54 }),
55 serde_json::json!({
56 "name": "test_policy",
57 "description": "Test whether a policy allows access to a secret name",
58 "inputSchema": {
59 "type": "object",
60 "properties": {
61 "scope": { "type": "string", "description": "Policy/scope name" },
62 "secret_name": { "type": "string", "description": "Secret name to test" }
63 },
64 "required": ["scope", "secret_name"]
65 }
66 }),
67 ]
68}
69
70pub fn dispatch(client: &AuthyClient, tool_name: &str, args: &Value) -> Value {
72 match tool_name {
73 "get_secret" => handle_get_secret(client, args),
74 "list_secrets" => handle_list_secrets(client, args),
75 "store_secret" => handle_store_secret(client, args),
76 "remove_secret" => handle_remove_secret(client, args),
77 "test_policy" => handle_test_policy(client, args),
78 _ => error_result(&format!("Unknown tool: {}", tool_name)),
79 }
80}
81
82pub fn error_result(msg: &str) -> Value {
84 serde_json::json!({
85 "content": [{ "type": "text", "text": msg }],
86 "isError": true
87 })
88}
89
90fn text_result(text: &str) -> Value {
92 serde_json::json!({
93 "content": [{ "type": "text", "text": text }]
94 })
95}
96
97fn handle_get_secret(client: &AuthyClient, args: &Value) -> Value {
98 let name = match args.get("name").and_then(|v| v.as_str()) {
99 Some(n) => n,
100 None => return error_result("Missing required parameter: name"),
101 };
102
103 match client.get_or_err(name) {
104 Ok(value) => text_result(&value),
105 Err(e) => error_result(&e.to_string()),
106 }
107}
108
109fn handle_list_secrets(client: &AuthyClient, args: &Value) -> Value {
110 let scope = args.get("scope").and_then(|v| v.as_str());
111
112 match client.list(scope) {
113 Ok(names) => {
114 let json = serde_json::to_string(&names).unwrap_or_else(|_| "[]".to_string());
115 text_result(&json)
116 }
117 Err(e) => error_result(&e.to_string()),
118 }
119}
120
121fn handle_store_secret(client: &AuthyClient, args: &Value) -> Value {
122 let name = match args.get("name").and_then(|v| v.as_str()) {
123 Some(n) => n,
124 None => return error_result("Missing required parameter: name"),
125 };
126 let value = match args.get("value").and_then(|v| v.as_str()) {
127 Some(v) => v,
128 None => return error_result("Missing required parameter: value"),
129 };
130 let force = args.get("force").and_then(|v| v.as_bool()).unwrap_or(false);
131
132 match client.store(name, value, force) {
133 Ok(()) => text_result(&format!("Stored secret '{}'", name)),
134 Err(e) => error_result(&e.to_string()),
135 }
136}
137
138fn handle_remove_secret(client: &AuthyClient, args: &Value) -> Value {
139 let name = match args.get("name").and_then(|v| v.as_str()) {
140 Some(n) => n,
141 None => return error_result("Missing required parameter: name"),
142 };
143
144 match client.remove(name) {
145 Ok(true) => text_result(&format!("Removed secret '{}'", name)),
146 Ok(false) => text_result(&format!("Secret '{}' not found", name)),
147 Err(e) => error_result(&e.to_string()),
148 }
149}
150
151fn handle_test_policy(client: &AuthyClient, args: &Value) -> Value {
152 let scope = match args.get("scope").and_then(|v| v.as_str()) {
153 Some(s) => s,
154 None => return error_result("Missing required parameter: scope"),
155 };
156 let secret_name = match args.get("secret_name").and_then(|v| v.as_str()) {
157 Some(n) => n,
158 None => return error_result("Missing required parameter: secret_name"),
159 };
160
161 match client.test_policy(scope, secret_name) {
162 Ok(true) => text_result(&format!(
163 "allowed: scope '{}' can read '{}'",
164 scope, secret_name
165 )),
166 Ok(false) => text_result(&format!(
167 "denied: scope '{}' cannot read '{}'",
168 scope, secret_name
169 )),
170 Err(e) => error_result(&e.to_string()),
171 }
172}