| author | |
| committer | |
| log | 2547169c7c14c468d646a4529194116b1adfb1ee |
| tree | 4e5289d7272390afa2421cd922f79340795b93c6 |
| parent | 4e0a77820c14a4949c590a7beacb75a31502e9cf |
| signature | Signed by SSH key SHA256:52mNGHRsVFBDED9IAX5pe+LRWUefqTbxEReunq21QvU (~clover) |
4 files changed, 15 insertions(+), 7 deletions(-)
dashboard/src/observability.rs+4-3| ... | @@ -2,8 +2,9 @@ use crate::*; | ... | @@ -2,8 +2,9 @@ use crate::*; |
| 2 | use rmcp::{ | 2 | use rmcp::{ |
| 3 | ErrorData, RoleServer, ServerHandler, | 3 | ErrorData, RoleServer, ServerHandler, |
| 4 | model::{ | 4 | model::{ |
| 5 | CallToolRequestParams, CallToolResponse, CallToolResult, ContentBlock, ListToolsResult, | 5 | CacheScope, CallToolRequestParams, CallToolResponse, CallToolResult, ContentBlock, |
| 6 | PaginatedRequestParams, ServerCapabilities, ServerConfig, Tool, ToolAnnotations, | 6 | ListToolsResult, PaginatedRequestParams, ServerCapabilities, ServerConfig, Tool, |
| 7 | ToolAnnotations, | ||
| 7 | }, | 8 | }, |
| 8 | service::RequestContext, | 9 | service::RequestContext, |
| 9 | }; | 10 | }; |
| ... | @@ -27,7 +28,7 @@ impl ServerHandler for Observability { | ... | @@ -27,7 +28,7 @@ impl ServerHandler for Observability { |
| 27 | let mut properties = json!({"service":{"type":"string"},"q":{"type":"string"},"limit":{"type":"integer","minimum":1,"maximum":500}}); | 28 | let mut properties = json!({"service":{"type":"string"},"q":{"type":"string"},"limit":{"type":"integer","minimum":1,"maximum":500}}); |
| 28 | let required = if name=="get_trace" { properties=json!({"service":{"type":"string"},"trace_id":{"type":"string"}}); json!(["service","trace_id"]) } else {json!(["service"])}; | 29 | let required = if name=="get_trace" { properties=json!({"service":{"type":"string"},"trace_id":{"type":"string"}}); json!(["service","trace_id"]) } else {json!(["service"])}; |
| 29 | Tool::new(name, description, json!({"type":"object","properties":properties,"required":required,"additionalProperties":false}).as_object().unwrap().clone()).with_annotations(ToolAnnotations::new().read_only(true)) | 30 | Tool::new(name, description, json!({"type":"object","properties":properties,"required":required,"additionalProperties":false}).as_object().unwrap().clone()).with_annotations(ToolAnnotations::new().read_only(true)) |
| 30 | }).collect(), ..Default::default() }) | 31 | }).collect(), ttl_ms: Some(0), cache_scope: Some(CacheScope::Private), ..Default::default() }) |
| 31 | } | 32 | } |
| 32 | async fn call_tool( | 33 | async fn call_tool( |
| 33 | &self, | 34 | &self, |
dashboard/src/relay.rs+5-2| ... | @@ -5,8 +5,9 @@ use mcp::{delete, get, hash, list, put, secret}; | ... | @@ -5,8 +5,9 @@ use mcp::{delete, get, hash, list, put, secret}; |
| 5 | use rmcp::{ | 5 | use rmcp::{ |
| 6 | ErrorData, RoleServer, ServerHandler, | 6 | ErrorData, RoleServer, ServerHandler, |
| 7 | model::{ | 7 | model::{ |
| 8 | CallToolRequestParams, CallToolResponse, CallToolResult, ContentBlock, ListToolsResult, | 8 | CacheScope, CallToolRequestParams, CallToolResponse, CallToolResult, ContentBlock, |
| 9 | PaginatedRequestParams, ServerCapabilities, ServerConfig, Tool, ToolAnnotations, | 9 | ListToolsResult, PaginatedRequestParams, ServerCapabilities, ServerConfig, Tool, |
| 10 | ToolAnnotations, | ||
| 10 | }, | 11 | }, |
| 11 | service::RequestContext, | 12 | service::RequestContext, |
| 12 | }; | 13 | }; |
| ... | @@ -681,6 +682,8 @@ impl ServerHandler for Agents { | ... | @@ -681,6 +682,8 @@ impl ServerHandler for Agents { |
| 681 | }).collect(); | 682 | }).collect(); |
| 682 | Ok(ListToolsResult { | 683 | Ok(ListToolsResult { |
| 683 | tools, | 684 | tools, |
| 685 | ttl_ms: Some(0), | ||
| 686 | cache_scope: Some(CacheScope::Private), | ||
| 684 | ..Default::default() | 687 | ..Default::default() |
| 685 | }) | 688 | }) |
| 686 | } | 689 | } |
tools/dashboard-mcp-test.py+3-1| ... | @@ -133,7 +133,9 @@ def main(): | ... | @@ -133,7 +133,9 @@ def main(): |
| 133 | http("/oauth/token", "POST", form, form=True, status=400) | 133 | http("/oauth/token", "POST", form, form=True, status=400) |
| 134 | token = tokens["access_token"] | 134 | token = tokens["access_token"] |
| 135 | assert rpc(token, "initialize", {"protocolVersion": "2025-11-25", "capabilities": {}, "clientInfo": {"name": marker, "version": "1"}})["capabilities"]["tools"] == {} | 135 | assert rpc(token, "initialize", {"protocolVersion": "2025-11-25", "capabilities": {}, "clientInfo": {"name": marker, "version": "1"}})["capabilities"]["tools"] == {} |
| 136 | tools = rpc(token, "tools/list")["tools"] | 136 | listed = rpc(token, "tools/list") |
| 137 | assert listed["ttlMs"] == 0 and listed["cacheScope"] == "private", listed | ||
| 138 | tools = listed["tools"] | ||
| 137 | assert {tool["name"] for tool in tools} == {"get_logs", "get_traces", "get_trace"} | 139 | assert {tool["name"] for tool in tools} == {"get_logs", "get_traces", "get_trace"} |
| 138 | assert all(tool["annotations"]["readOnlyHint"] for tool in tools) | 140 | assert all(tool["annotations"]["readOnlyHint"] for tool in tools) |
| 139 | refused = rpc(token, "tools/call", {"name": "get_logs", "arguments": {"service": denied}}) | 141 | refused = rpc(token, "tools/call", {"name": "get_logs", "arguments": {"service": denied}}) |
tools/dashboard-relay-test.py+3-1| ... | @@ -252,7 +252,9 @@ def main(): | ... | @@ -252,7 +252,9 @@ def main(): |
| 252 | assert a1.machine == first["id"] and a2.machine == second["id"] | 252 | assert a1.machine == first["id"] and a2.machine == second["id"] |
| 253 | init = rpc(control["key"], "initialize", {"protocolVersion": "2025-11-25", "capabilities": {}, "clientInfo": {"name": marker, "version": "1"}}) | 253 | init = rpc(control["key"], "initialize", {"protocolVersion": "2025-11-25", "capabilities": {}, "clientInfo": {"name": marker, "version": "1"}}) |
| 254 | assert init["capabilities"]["tools"] == {} | 254 | assert init["capabilities"]["tools"] == {} |
| 255 | tools = rpc(control["key"], "tools/list")["tools"] | 255 | listed = rpc(control["key"], "tools/list") |
| 256 | assert listed["ttlMs"] == 0 and listed["cacheScope"] == "private", listed | ||
| 257 | tools = listed["tools"] | ||
| 256 | assert len(tools) == 7 | 258 | assert len(tools) == 7 |
| 257 | assert next(t for t in tools if t["name"] == "send_message")["annotations"]["readOnlyHint"] is False | 259 | assert next(t for t in tools if t["name"] == "send_message")["annotations"]["readOnlyHint"] is False |
| 258 | call(control["key"], "send_message", {"provider": "codex", "thread_id": str(uuid.uuid4()), "message": "ambiguous fixture"}, error=True) | 260 | call(control["key"], "send_message", {"provider": "codex", "thread_id": str(uuid.uuid4()), "message": "ambiguous fixture"}, error=True) |