Skip to main content

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}