tmux_mcp/model.rs
1use rmcp::schemars;
2use serde::Deserialize;
3
4use crate::schema::{
5 OptionScopeSchema, ResizeDirectionSchema, SelectPaneDirectionSchema,
6 SelectWindowDirectionSchema,
7};
8
9/// Arguments naming one session.
10#[derive(Debug, Deserialize, schemars::JsonSchema)]
11#[serde(deny_unknown_fields)]
12pub struct SessionArgs {
13 /// The session, by `$`-prefixed id as `list_sessions` reports it, or by
14 /// name.
15 pub session: String,
16}
17
18/// Arguments for creating a session.
19#[derive(Debug, Deserialize, schemars::JsonSchema)]
20#[serde(deny_unknown_fields)]
21pub struct CreateSessionArgs {
22 /// The name for the new session. It must not already exist.
23 pub name: String,
24 /// The first window's working directory. Omit for the directory this MCP
25 /// server started in.
26 pub start_directory: Option<String>,
27}
28
29/// Arguments naming one pane.
30#[derive(Debug, Deserialize, schemars::JsonSchema)]
31#[serde(deny_unknown_fields)]
32pub struct PaneArgs {
33 /// The `%`-prefixed pane id, as `list_panes` reports it.
34 pub pane: String,
35}
36
37/// Arguments naming one window.
38#[derive(Debug, Deserialize, schemars::JsonSchema)]
39#[serde(deny_unknown_fields)]
40pub struct WindowArgs {
41 /// The `@`-prefixed window id, as `list_windows` reports it.
42 pub window: String,
43}
44
45/// Arguments for moving focus between panes.
46#[derive(Debug, Deserialize, schemars::JsonSchema)]
47#[serde(deny_unknown_fields)]
48pub struct SelectPaneArgs {
49 /// The `%`-prefixed pane to select, or to move relative to.
50 pub pane: String,
51 /// Move relative to that pane instead of selecting it.
52 ///
53 /// `up`, `down`, `left`, and `right` follow the layout, so `up` selects
54 /// whatever pane is drawn above. `last` returns to the previously active
55 /// pane, and `next` and `previous` step through the window's panes in
56 /// order. Omit to select the named pane itself.
57 #[schemars(with = "Option<SelectPaneDirectionSchema>")]
58 pub direction: Option<String>,
59}
60
61/// Arguments for running a command and waiting for it.
62#[derive(Debug, Deserialize, schemars::JsonSchema)]
63#[serde(deny_unknown_fields)]
64pub struct RunCommandArgs {
65 /// The `%`-prefixed pane to run in.
66 pub pane: String,
67 /// The command for the pane's trusted POSIX-compatible shell.
68 ///
69 /// Shell reserved words and special builtins must retain their standard
70 /// meanings. The command runs inside a subshell, so several lines are fine
71 /// and a bare `exit` does not end the pane's own shell. Invalid syntax is
72 /// contained and completes with the shell's nonzero status. Valid inherited
73 /// Bash and zsh `ERR` and `DEBUG` traps remain visible to the command while
74 /// the pane's parent-shell traps and options remain unchanged.
75 pub command: String,
76 /// How long to allow, in seconds. Defaults to 30, capped at 600.
77 pub seconds: Option<u64>,
78 /// Whether to keep the command out of the shell's history.
79 #[serde(default)]
80 pub suppress_history: bool,
81}
82
83/// Arguments for reading a tmux environment.
84#[derive(Debug, Deserialize, schemars::JsonSchema)]
85#[serde(deny_unknown_fields)]
86pub struct ShowEnvironmentArgs {
87 /// The session whose environment to read, by `$`-prefixed id or name.
88 ///
89 /// Omit for the server's own.
90 pub session: Option<String>,
91}
92
93/// Arguments for reading the hooks set at a scope.
94#[derive(Debug, Deserialize, schemars::JsonSchema)]
95#[serde(deny_unknown_fields)]
96pub struct ShowHooksArgs {
97 /// The session whose hooks to read, by `$`-prefixed id or name. Omit for
98 /// the server's own.
99 pub session: Option<String>,
100}
101
102/// Arguments for arranging a window's panes.
103#[derive(Debug, Deserialize, schemars::JsonSchema)]
104#[serde(deny_unknown_fields)]
105pub struct SelectLayoutArgs {
106 /// The `@`-prefixed window to arrange.
107 pub window: String,
108 /// A saved tmux layout, or a named layout and its unique abbreviation.
109 ///
110 /// The names are `even-horizontal`, `even-vertical`, `main-horizontal`,
111 /// `main-vertical` and `tiled`. The running daemon determines which names
112 /// and abbreviations are supported; mirrored main layouts require tmux 3.5.
113 pub layout: String,
114}
115
116/// Arguments for putting text into a pane without typing it.
117#[derive(Debug, Deserialize, schemars::JsonSchema)]
118#[serde(deny_unknown_fields)]
119pub struct PasteTextArgs {
120 /// The `%`-prefixed pane to paste into.
121 pub pane: String,
122 /// The text to deliver.
123 pub text: String,
124 /// Whether to append Enter to the same paste block.
125 #[serde(default)]
126 pub enter: bool,
127}
128
129/// Arguments for waiting until a pane says something.
130#[derive(Debug, Deserialize, schemars::JsonSchema)]
131#[serde(deny_unknown_fields)]
132pub struct WaitForTextArgs {
133 /// The `%`-prefixed pane to watch.
134 pub pane: String,
135 /// Text that ends the wait successfully. Omit to wait for any output.
136 #[schemars(length(max = 32))]
137 pub patterns: Option<Vec<String>>,
138 /// Text that ends the wait as a failure, reported as `stopped`. Omit for
139 /// none.
140 ///
141 /// Give the failure markers you already know — `error:`, `Traceback` — and
142 /// a failed run returns at once instead of at the deadline.
143 #[schemars(length(max = 32))]
144 pub stop: Option<Vec<String>>,
145 /// Read both lists as regular expressions rather than literal text.
146 #[serde(default)]
147 pub regex: bool,
148 /// Match case. Off by default.
149 #[serde(default)]
150 pub match_case: bool,
151 /// How long to wait, in seconds. Defaults to 30, capped at 600.
152 pub seconds: Option<u64>,
153}
154
155/// Arguments for reading what a pane wrote since last time.
156#[derive(Debug, Deserialize, schemars::JsonSchema)]
157#[serde(deny_unknown_fields)]
158pub struct CaptureSinceArgs {
159 /// The `%`-prefixed pane to read.
160 pub pane: String,
161 /// The cursor from the previous call. Omit to start watching.
162 pub cursor: Option<String>,
163}
164
165/// Arguments for moving focus between windows.
166#[derive(Debug, Deserialize, schemars::JsonSchema)]
167#[serde(deny_unknown_fields)]
168pub struct SelectWindowArgs {
169 /// The `@`-prefixed window to select, or to move relative to.
170 pub window: String,
171 /// Move relative to that window instead of selecting it.
172 ///
173 /// `next` and `previous` step through the session in index order, and
174 /// `last` returns to the previously active window. Omit to select the
175 /// named window itself.
176 #[schemars(with = "Option<SelectWindowDirectionSchema>")]
177 pub direction: Option<String>,
178}
179
180/// Arguments for searching what panes are showing.
181#[derive(Debug, Deserialize, schemars::JsonSchema)]
182#[serde(deny_unknown_fields)]
183pub struct SearchPanesArgs {
184 /// The text to look for.
185 #[schemars(length(max = 4096))]
186 pub pattern: String,
187 /// Read the pattern as a regular expression rather than literal text.
188 #[serde(default)]
189 pub regex: bool,
190 /// Match case. Off by default.
191 #[serde(default)]
192 pub match_case: bool,
193 /// Search scrollback as well as the visible screen.
194 #[serde(default)]
195 pub history: bool,
196 /// Only search panes in this session, by `$`-prefixed id or name. Omit
197 /// for every session.
198 pub session: Option<String>,
199 /// Only search panes in this window, by `@`-prefixed id. Omit for every
200 /// window.
201 pub window: Option<String>,
202}
203
204/// Arguments for reading a tmux option.
205#[derive(Debug, Deserialize, schemars::JsonSchema)]
206#[serde(deny_unknown_fields)]
207pub struct OptionArgs {
208 /// The option name, such as `history-limit` or a user option like `@theme`.
209 pub name: String,
210 /// Which tmux object the option belongs to.
211 ///
212 /// One of `server`, `global-session`, `global-window`, `session`,
213 /// `window`, or `pane`. Defaults to `global-session`, which is what
214 /// setting an option without a target means in tmux.
215 #[schemars(with = "Option<OptionScopeSchema>")]
216 pub scope: Option<String>,
217 /// The `$`, `@` or `%`-prefixed id, for the scopes that need one. Omit
218 /// for the others.
219 pub target: Option<String>,
220}
221
222/// Arguments for reading a pane's whole state.
223#[derive(Debug, Deserialize, schemars::JsonSchema)]
224#[serde(deny_unknown_fields)]
225pub struct SnapshotArgs {
226 /// The `%`-prefixed pane id.
227 pub pane: String,
228 /// The most content lines to return, oldest dropped first.
229 ///
230 /// Defaults to the whole visible screen. The end of a pane is what says
231 /// what just happened, so a limit keeps the end.
232 pub max_lines: Option<usize>,
233 /// Include scrollback rather than only the visible screen.
234 #[serde(default)]
235 pub history: bool,
236}
237
238/// Arguments naming a `wait-for` channel.
239#[derive(Debug, Deserialize, schemars::JsonSchema)]
240#[serde(deny_unknown_fields)]
241pub struct ChannelArgs {
242 /// The channel name, which is any string both sides agree on.
243 pub channel: String,
244 /// How long to wait, in seconds. Defaults to 30, capped at 600.
245 pub seconds: Option<u64>,
246}
247
248/// Arguments for resizing a pane.
249#[derive(Debug, Deserialize, schemars::JsonSchema)]
250#[serde(deny_unknown_fields)]
251pub struct ResizePaneArgs {
252 /// The `%`-prefixed pane id.
253 pub pane: String,
254 /// Which edge to move: `up`, `down`, `left`, or `right`.
255 #[schemars(with = "ResizeDirectionSchema")]
256 pub direction: String,
257 /// How many rows or columns to move it by.
258 pub cells: u32,
259}
260
261/// Arguments for reading a pane.
262#[derive(Debug, Deserialize, schemars::JsonSchema)]
263#[serde(deny_unknown_fields)]
264pub struct CapturePaneArgs {
265 /// The `%`-prefixed pane id.
266 pub pane: String,
267 /// Read the whole history rather than the visible screen.
268 #[serde(default)]
269 pub history: bool,
270 /// Return only the last command's output, when the shell marks its
271 /// prompts.
272 ///
273 /// Answers far less than the history, because it starts where the last
274 /// command's output began. When the pane's shell does not mark its
275 /// prompts -- fish does, bash and zsh do not -- this reports
276 /// `marks: "absent"` and returns the visible screen instead.
277 #[serde(default)]
278 pub last_command: bool,
279 /// Start at this line. Zero is the top of the screen, negative is
280 /// scrollback. Omit for the top of the screen, or of the scrollback with
281 /// `history`.
282 pub start: Option<i32>,
283 /// End at this line. Omit for the bottom of the screen.
284 pub end: Option<i32>,
285}
286
287/// Arguments for sending input to a pane.
288#[derive(Debug, Deserialize, schemars::JsonSchema)]
289#[serde(deny_unknown_fields)]
290pub struct SendKeysArgs {
291 /// The `%`-prefixed pane id.
292 pub pane: String,
293 /// Text typed literally into the pane. Key names are not interpreted. Omit
294 /// to type none.
295 pub text: Option<String>,
296 /// tmux key names to press, in order, after any text.
297 ///
298 /// These are interpreted rather than typed, which is the only way to send
299 /// a key that has no character: `C-c` to interrupt, `Escape`, `Up`,
300 /// `C-d`. Sending `C-c` as `text` would type those three characters.
301 /// Omit to press none.
302 pub keys: Option<Vec<String>>,
303 /// Whether to press Enter afterwards.
304 #[serde(default)]
305 pub enter: bool,
306}