//! Tool descriptions (each with a code-mode example) and MCP output schemas //! shared by the read-only and read-write kcp servers. use std::sync::Arc; use rmcp::model::JsonObject; use serde_json::{json, Value}; pub const LIST_KCPS: &str = "Discover running socialweb-computer kcp servers. Other tools use the only running kcp when `kcp` is omitted.\nExample: [k[\"id\"] for k in (await list_kcps())[\"kcps\"] if k[\"running\"]]"; pub const LIST_WORKSPACES: &str = "List the workspace tree of one kcp.\nExample: [w[\"path\"] for w in (await list_workspaces())[\"workspaces\"]]"; pub const GET_API_RESOURCES: &str = "List the API resources served in one workspace.\nExample: [r[\"kind\"] for r in (await get_api_resources(workspace=\"root:app\"))[\"resources\"] if r[\"api_version\"].startswith(\"socialweb.computer/\")]"; pub const LIST_OBJECTS: &str = "List objects of one resource in a workspace (kubectl get -o json).\nExample: names(await list_objects(workspace=\"root:app\", resource=\"configmaps\", all_namespaces=True))"; pub const GET_OBJECT: &str = "Get one object (kubectl get -o json).\nExample: dig(await get_object(workspace=\"root:app\", resource=\"configmaps\", name=\"x\", namespace=\"default\"), \"data\")"; pub const GET_LOGS: &str = "Read pod logs. Returns plain text.\nExample: (await get_logs(workspace=\"root:app\", pod=\"web-1\", tail_lines=50)).splitlines()[-5:]"; pub const GET_EVENTS: &str = "List events in a workspace (kubectl get events -o json).\nExample: count_by(await get_events(workspace=\"root:app\"), \"type\")"; pub const READONLY_CREDENTIALS: &str = "Ensure the read-only ServiceAccount, ClusterRole, and ClusterRoleBinding exist, then mint a short-lived token for one workspace. All other read tools use the minted token. Reports the token kubeconfig path and lifetime, never the token.\nExample: (await readonly_credentials(workspace=\"root:app\"))[\"token_expires_in_seconds\"]"; pub const APPLY_OBJECT: &str = "Server-side apply one Kubernetes object to a workspace. Mutates the cluster unless dry_run is set.\nExample: await apply_object(workspace=\"root:app\", manifest={\"apiVersion\": \"v1\", \"kind\": \"ConfigMap\", \"metadata\": {\"name\": \"x\", \"namespace\": \"default\"}, \"data\": {\"k\": \"v\"}})"; pub const DELETE_OBJECT: &str = "Delete one object from a workspace. Mutates the cluster. Returns the deleted name as text.\nExample: await delete_object(workspace=\"root:app\", resource=\"configmaps\", name=\"x\", namespace=\"default\")"; pub const PATCH_OBJECT: &str = "Patch one object in a workspace (merge patch by default). Mutates the cluster.\nExample: await patch_object(workspace=\"root:app\", resource=\"configmaps\", name=\"x\", namespace=\"default\", patch={\"data\": {\"k\": \"v2\"}})"; pub const SCALE_OBJECT: &str = "Scale one object in a workspace. Mutates the cluster.\nExample: await scale_object(workspace=\"root:app\", resource=\"deployments\", name=\"web\", namespace=\"default\", replicas=2)"; fn schema(value: Value) -> Arc { match value { Value::Object(object) => Arc::new(object), _ => unreachable!("schemas are objects"), } } fn string() -> Value { json!({"type": "string"}) } fn kube_object_value() -> Value { json!({ "type": "object", "properties": { "apiVersion": string(), "kind": string(), "metadata": { "type": "object", "properties": { "name": string(), "namespace": string(), "labels": {"type": "object"}, "annotations": {"type": "object"}, "uid": string(), "resourceVersion": string(), "creationTimestamp": string(), }, }, "spec": {"type": "object"}, "status": {"type": "object"}, "data": {"type": "object"}, }, }) } /// One Kubernetes object. pub fn kube_object() -> Arc { schema(kube_object_value()) } /// A Kubernetes `List`. pub fn kube_list() -> Arc { schema(json!({ "type": "object", "properties": { "apiVersion": string(), "kind": string(), "items": {"type": "array", "items": kube_object_value()}, }, })) } /// A list of core/v1 Events. pub fn event_list() -> Arc { schema(json!({ "type": "object", "properties": { "items": {"type": "array", "items": { "type": "object", "properties": { "type": string(), "reason": string(), "message": string(), "count": {"type": "integer"}, "lastTimestamp": string(), "involvedObject": {"type": "object", "properties": { "kind": string(), "name": string(), "namespace": string(), }}, }, }}, }, })) } pub fn kcp_report() -> Arc { schema(json!({ "type": "object", "properties": { "kcps": {"type": "array", "items": { "type": "object", "properties": { "id": string(), "host": string(), "kubeconfig": string(), "server": string(), "workspace": string(), "context": string(), "running": {"type": "boolean"}, "error": {"type": ["string", "null"]}, }, "additionalProperties": false, }}, "errors": {"type": "array", "items": string()}, }, "additionalProperties": false, })) } pub fn workspaces() -> Arc { schema(json!({ "type": "object", "properties": { "workspaces": {"type": "array", "items": { "type": "object", "properties": { "name": string(), "path": string(), "url": string(), "phase": string(), "kind": string(), }, "additionalProperties": false, }}, }, "additionalProperties": false, })) } pub fn api_resources() -> Arc { let strings = json!({"type": "array", "items": string()}); schema(json!({ "type": "object", "properties": { "resources": {"type": "array", "items": { "type": "object", "properties": { "name": string(), "short_names": strings, "api_version": string(), "namespaced": {"type": "boolean"}, "kind": string(), "verbs": strings, "categories": strings, }, "additionalProperties": false, }}, }, "additionalProperties": false, })) } pub fn credential() -> Arc { schema(json!({ "type": "object", "properties": { "kcp": string(), "host": string(), "workspace": string(), "token_kubeconfig": string(), "token_expires_in_seconds": {"type": "integer"}, "note": string(), }, "additionalProperties": false, })) }