1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
//! 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<JsonObject> {
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<JsonObject> {
schema(kube_object_value())
}
/// A Kubernetes `List`.
pub fn kube_list() -> Arc<JsonObject> {
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<JsonObject> {
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<JsonObject> {
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<JsonObject> {
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<JsonObject> {
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<JsonObject> {
schema(json!({
"type": "object",
"properties": {
"kcp": string(),
"host": string(),
"workspace": string(),
"token_kubeconfig": string(),
"token_expires_in_seconds": {"type": "integer"},
"note": string(),
},
"additionalProperties": false,
}))
}