| 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 | 2 | use rmcp::{ |
| 3 | 3 | ErrorData, RoleServer, ServerHandler, |
| 4 | 4 | model::{ |
| 5 | CallToolRequestParams, CallToolResponse, CallToolResult, ContentBlock, ListToolsResult, | |
| 6 | PaginatedRequestParams, ServerCapabilities, ServerConfig, Tool, ToolAnnotations, | |
| 5 | CacheScope, CallToolRequestParams, CallToolResponse, CallToolResult, ContentBlock, | |
| 6 | ListToolsResult, PaginatedRequestParams, ServerCapabilities, ServerConfig, Tool, | |
| 7 | ToolAnnotations, | |
| 7 | 8 | }, |
| 8 | 9 | service::RequestContext, |
| 9 | 10 | }; |
| ... | ... | @@ -27,7 +28,7 @@ impl ServerHandler for Observability { |
| 27 | 28 | let mut properties = json!({"service":{"type":"string"},"q":{"type":"string"},"limit":{"type":"integer","minimum":1,"maximum":500}}); |
| 28 | 29 | let required = if name=="get_trace" { properties=json!({"service":{"type":"string"},"trace_id":{"type":"string"}}); json!(["service","trace_id"]) } else {json!(["service"])}; |
| 29 | 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 | 33 | async fn call_tool( |
| 33 | 34 | &self, |
dashboard/src/relay.rs+5-2| ... | ... | @@ -5,8 +5,9 @@ use mcp::{delete, get, hash, list, put, secret}; |
| 5 | 5 | use rmcp::{ |
| 6 | 6 | ErrorData, RoleServer, ServerHandler, |
| 7 | 7 | model::{ |
| 8 | CallToolRequestParams, CallToolResponse, CallToolResult, ContentBlock, ListToolsResult, | |
| 9 | PaginatedRequestParams, ServerCapabilities, ServerConfig, Tool, ToolAnnotations, | |
| 8 | CacheScope, CallToolRequestParams, CallToolResponse, CallToolResult, ContentBlock, | |
| 9 | ListToolsResult, PaginatedRequestParams, ServerCapabilities, ServerConfig, Tool, | |
| 10 | ToolAnnotations, | |
| 10 | 11 | }, |
| 11 | 12 | service::RequestContext, |
| 12 | 13 | }; |
| ... | ... | @@ -681,6 +682,8 @@ impl ServerHandler for Agents { |
| 681 | 682 | }).collect(); |
| 682 | 683 | Ok(ListToolsResult { |
| 683 | 684 | tools, |
| 685 | ttl_ms: Some(0), | |
| 686 | cache_scope: Some(CacheScope::Private), | |
| 684 | 687 | ..Default::default() |
| 685 | 688 | }) |
| 686 | 689 | } |
tools/dashboard-mcp-test.py+3-1| ... | ... | @@ -133,7 +133,9 @@ def main(): |
| 133 | 133 | http("/oauth/token", "POST", form, form=True, status=400) |
| 134 | 134 | token = tokens["access_token"] |
| 135 | 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 | 139 | assert {tool["name"] for tool in tools} == {"get_logs", "get_traces", "get_trace"} |
| 138 | 140 | assert all(tool["annotations"]["readOnlyHint"] for tool in tools) |
| 139 | 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 | 252 | assert a1.machine == first["id"] and a2.machine == second["id"] |
| 253 | 253 | init = rpc(control["key"], "initialize", {"protocolVersion": "2025-11-25", "capabilities": {}, "clientInfo": {"name": marker, "version": "1"}}) |
| 254 | 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 | 258 | assert len(tools) == 7 |
| 257 | 259 | assert next(t for t in tools if t["name"] == "send_message")["annotations"]["readOnlyHint"] is False |
| 258 | 260 | call(control["key"], "send_message", {"provider": "codex", "thread_id": str(uuid.uuid4()), "message": "ambiguous fixture"}, error=True) |