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
180
181
182
183
184
use std::net::SocketAddr;
use clap::{Args, Subcommand};
use super::orchestrator::OrchestratorLocalArgs;
use super::serve::McpServeTransport;
#[derive(Debug, Args)]
pub(crate) struct McpArgs {
#[command(subcommand)]
pub command: McpCommand,
}
#[derive(Debug, Subcommand)]
pub(crate) enum McpCommand {
/// Expose a running orchestrator as an MCP server.
Serve(McpServeArgs),
/// Record, replay, verify, or simulate MCP servers for deterministic evals.
Mock(McpMockArgs),
/// Log in to a remote MCP server via OAuth.
Login(McpLoginArgs),
/// Remove a stored OAuth token.
Logout(McpServerRefArgs),
/// Show stored OAuth status for a server.
Status(McpServerRefArgs),
/// Print the default OAuth redirect URI.
RedirectUri,
/// List the canonical catalog of well-known MCP server presets.
Presets(McpPresetsArgs),
}
#[derive(Debug, Args)]
pub(crate) struct McpPresetsArgs {
/// Emit the catalog as a stable JSON envelope instead of a table.
#[arg(long)]
pub json: bool,
}
#[derive(Debug, Args)]
pub(crate) struct McpMockArgs {
#[command(subcommand)]
pub command: McpMockCommand,
}
#[derive(Debug, Subcommand)]
pub(crate) enum McpMockCommand {
/// Proxy a stdio MCP server and write a redacted JSON-RPC cassette.
Record(McpMockRecordArgs),
/// Serve a redacted cassette back as a credential-free stdio MCP server.
Replay(McpMockReplayArgs),
/// Diff a cassette against another cassette or a freshly probed stdio server.
Verify(McpMockVerifyArgs),
/// Serve a seeded stateful simulated world over stdio MCP.
World(McpMockWorldArgs),
/// Score one or more final world states against a world spec.
Eval(McpMockEvalArgs),
}
#[derive(Debug, Args)]
pub(crate) struct McpMockRecordArgs {
/// Path to write the redacted cassette JSON.
#[arg(long, value_name = "PATH")]
pub cassette: String,
/// Upstream stdio MCP server command. Pass after `--`.
#[arg(last = true, required = true)]
pub command: Vec<String>,
}
#[derive(Debug, Args)]
pub(crate) struct McpMockReplayArgs {
/// Cassette JSON produced by `harn mcp mock record`.
#[arg(long, value_name = "PATH")]
pub cassette: String,
}
#[derive(Debug, Args)]
pub(crate) struct McpMockVerifyArgs {
/// Recorded cassette to treat as the baseline.
#[arg(long, value_name = "PATH")]
pub cassette: String,
/// Candidate cassette to diff against the baseline.
#[arg(long, value_name = "PATH", conflicts_with = "command")]
pub candidate: Option<String>,
/// Write the structured verify report here. Defaults to stdout.
#[arg(long, value_name = "PATH")]
pub report: Option<String>,
/// Candidate stdio MCP server command. Pass after `--`.
#[arg(last = true)]
pub command: Vec<String>,
}
#[derive(Debug, Args)]
pub(crate) struct McpMockWorldArgs {
/// World spec JSON.
#[arg(long, value_name = "PATH")]
pub spec: String,
/// Write the final state JSON when stdin closes.
#[arg(long = "state-out", value_name = "PATH")]
pub state_out: Option<String>,
/// Write a world eval report against `goal_state` when stdin closes.
#[arg(long, value_name = "PATH")]
pub report: Option<String>,
}
#[derive(Debug, Args)]
pub(crate) struct McpMockEvalArgs {
/// World spec JSON containing `initial_state` and `goal_state`.
#[arg(long, value_name = "PATH")]
pub spec: String,
/// Final state JSON. Repeat to compute pass-rate and pass^k.
#[arg(long = "state", value_name = "PATH", required = true)]
pub states: Vec<String>,
/// Write the structured report here. Defaults to stdout.
#[arg(long, value_name = "PATH")]
pub report: Option<String>,
}
#[derive(Debug, Args)]
pub(crate) struct McpServeArgs {
#[command(flatten)]
pub local: OrchestratorLocalArgs,
/// Transport to expose for MCP clients.
#[arg(long, value_enum, default_value_t = McpServeTransport::Stdio)]
pub transport: McpServeTransport,
/// Socket address to bind when serving over HTTP.
#[arg(
long,
env = "HARN_MCP_SERVE_BIND",
default_value = "127.0.0.1:8765",
value_name = "ADDR"
)]
pub bind: SocketAddr,
/// Streamable HTTP endpoint path.
#[arg(long, default_value = "/mcp", value_name = "PATH")]
pub path: String,
/// Legacy SSE endpoint path for older MCP clients.
#[arg(long = "sse-path", default_value = "/sse", value_name = "PATH")]
pub sse_path: String,
/// Legacy SSE POST endpoint path for older MCP clients.
#[arg(
long = "messages-path",
default_value = "/messages",
value_name = "PATH"
)]
pub messages_path: String,
}
#[derive(Debug, Args)]
pub(crate) struct McpLoginArgs {
/// MCP server name from harn.toml or a direct URL.
pub target: Option<String>,
/// Explicit server URL for ad hoc login or status checks.
#[arg(long)]
pub url: Option<String>,
/// Explicit OAuth client ID.
#[arg(long = "client-id")]
pub client_id: Option<String>,
/// Explicit OAuth client secret.
#[arg(long = "client-secret")]
pub client_secret: Option<String>,
/// Requested OAuth scope string.
#[arg(long = "scope")]
pub scope: Option<String>,
/// OAuth redirect URI for the local callback listener.
#[arg(
long = "redirect-uri",
default_value = "http://127.0.0.1:9783/oauth/callback"
)]
pub redirect_uri: String,
}
#[derive(Debug, Args)]
pub(crate) struct McpServerRefArgs {
/// MCP server name from harn.toml or a direct URL.
pub target: Option<String>,
/// Explicit server URL for ad hoc login or status checks.
#[arg(long)]
pub url: Option<String>,
/// Emit machine-readable JSON instead of a human summary. With no
/// target, `mcp status` reports every configured MCP server; with a
/// target it reports that one server's OAuth status.
#[arg(long)]
pub json: bool,
}