towow-mcp 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,923 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Towow MCP Server — canonical workflow adapter over /protocol APIs.
4
+ *
5
+ * Port of Python server.py — 30 tool definitions with identical names and parameters.
6
+ */
7
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
9
+ import { z } from "zod";
10
+ import { TowowClient, AuthError, APIError } from "./client.js";
11
+ import { getSessionToken, saveSessionToken, clearSessionToken, getAgentId, getDisplayName, saveAgent, clearAgent, } from "./config.js";
12
+ import { consumeSseStream, SSEError, SSEAuthError } from "./sse.js";
13
+ // ---------------------------------------------------------------------------
14
+ // Instructions (identical to Python version)
15
+ // ---------------------------------------------------------------------------
16
+ const _INSTRUCTIONS = `\
17
+ Towow (通爻) is an agent collaboration protocol. It connects agents who can help \
18
+ each other — not by searching, but by mutual discovery and structured negotiation.
19
+
20
+ ## Quick Start
21
+
22
+ If the user hasn't registered yet, help them get started:
23
+ 1. **Register**: \`towow_register\` with an invite code, email, password, name, and a profile.
24
+ 2. **Build a good profile**: The profile is how other agents discover you. Include:
25
+ - Who you are (role, background, key skills)
26
+ - What you're working on (current projects, goals)
27
+ - What you need help with (specific needs, collaboration interests)
28
+ - What you can offer others (expertise, resources, connections)
29
+ A 3-5 paragraph profile works best. Vague profiles get poor matches.
30
+ 3. **Discover collaborators**: Use \`towow_formulation_start\` to describe what you need, \
31
+ then \`towow_formulation_confirm\` to find matching agents.
32
+ 4. **Invite & negotiate**: Send invitations to promising matches with \`towow_invite\`, \
33
+ then start a negotiation run with \`towow_negotiate\`.
34
+
35
+ ## Typical Workflow
36
+
37
+ \`\`\`
38
+ Register/Login → Build Profile → Describe Need → Discover Matches
39
+ → Review Nominations → Invite → Negotiate → Get Results
40
+ \`\`\`
41
+
42
+ ### Formulation (Need Refinement)
43
+ When the user has a vague need, use \`towow_formulation_start\` to begin a structured \
44
+ conversation that refines it into a clear, matchable demand. The system will ask \
45
+ clarifying questions. Reply with \`towow_formulation_reply\` until the need is well-defined, \
46
+ then \`towow_formulation_confirm\` to trigger discovery.
47
+
48
+ ### Quick Discovery
49
+ For a clear, specific need, skip formulation and use \`towow_discover\` directly.
50
+
51
+ ### After Discovery
52
+ Results include nominations — agents who might be good collaborators. For each nomination:
53
+ - Review their profile and match reason
54
+ - If interested, create an invitation with \`towow_invite\`
55
+ - Once invitations are accepted, start negotiation with \`towow_negotiate\`
56
+
57
+ ### Negotiation
58
+ A negotiation run brings multiple agents together to co-create a plan. Each participant \
59
+ contributes their perspective. The system synthesizes all contributions into actionable \
60
+ deliverables. Check progress with \`towow_run_status\` and get results with \`towow_result\`.
61
+
62
+ ## Profile Standards
63
+
64
+ A good profile should include:
65
+ - **Identity**: Name, role, organization (if any)
66
+ - **Expertise**: What you know well, what you've built
67
+ - **Current focus**: What you're working on now
68
+ - **Needs**: What kind of help or collaboration you're looking for
69
+ - **Offerings**: What you can contribute to others
70
+
71
+ You can update the profile anytime with \`towow_update_profile\`.
72
+
73
+ ## BYOK (Bring Your Own Key)
74
+ Most features (formulation, discovery) require an LLM. You can bind your own API key:
75
+ 1. \`towow_byok_bind\` with your Anthropic API key
76
+ 2. \`towow_byok_status\` to check if it's active
77
+ 3. \`towow_byok_clear\` to remove it
78
+
79
+ Without BYOK, only pre-configured platform keys are used (if available).
80
+
81
+ ## Tips
82
+ - Use \`towow_agents\` to see all your agents and which one is selected.
83
+ - Each account can have multiple agents for different contexts.
84
+ - Use \`towow_agent_delete\` to clean up agents you no longer need.
85
+ - Use \`towow_refresh_token\` if your session is about to expire.
86
+ - Invitations expire — respond promptly with \`towow_invitation_respond\`.
87
+ - After a run completes, use \`towow_feedback\` to rate the experience.
88
+ - Use \`towow_get_formulation\` to check formulation state without sending a message.
89
+ - Use \`towow_get_discovery\` to re-read previous discovery results.
90
+ `;
91
+ // ---------------------------------------------------------------------------
92
+ // Server
93
+ // ---------------------------------------------------------------------------
94
+ const server = new McpServer({ name: "towow", version: "0.2.0" }, { instructions: _INSTRUCTIONS });
95
+ // ---------------------------------------------------------------------------
96
+ // Helpers
97
+ // ---------------------------------------------------------------------------
98
+ function getClient() {
99
+ return new TowowClient();
100
+ }
101
+ function requireAuth() {
102
+ if (!getSessionToken()) {
103
+ throw new ToolError("Not logged in. Call towow_login or towow_register first.");
104
+ }
105
+ }
106
+ function requireAgentId() {
107
+ const agentId = getAgentId();
108
+ if (!agentId) {
109
+ throw new ToolError("No current agent selected. Call towow_agents or towow_agent_select first.");
110
+ }
111
+ return agentId;
112
+ }
113
+ function toJson(payload) {
114
+ return JSON.stringify(payload);
115
+ }
116
+ function selectedAgentPayload() {
117
+ return {
118
+ agent_id: getAgentId(),
119
+ display_name: getDisplayName(),
120
+ };
121
+ }
122
+ function pickAgentPayload(agent) {
123
+ return {
124
+ agent_id: agent.agent_id,
125
+ display_name: agent.display_name,
126
+ visibility: agent.visibility,
127
+ scoped_tags: agent.scoped_tags ?? [],
128
+ };
129
+ }
130
+ // ToolError maps to Python's ToolError — returns isError content to the LLM.
131
+ class ToolError extends Error {
132
+ constructor(message) {
133
+ super(message);
134
+ this.name = "ToolError";
135
+ }
136
+ }
137
+ function ok(text) {
138
+ return { content: [{ type: "text", text }] };
139
+ }
140
+ function err(text) {
141
+ return { content: [{ type: "text", text }], isError: true };
142
+ }
143
+ function handleToolError(e) {
144
+ if (e instanceof ToolError)
145
+ return err(e.message);
146
+ if (e instanceof AuthError)
147
+ return err(e.message);
148
+ if (e instanceof APIError)
149
+ return err(`API error: ${e.detail}`);
150
+ if (e instanceof SSEError)
151
+ return err(`Formulation error: ${e.message}`);
152
+ if (e instanceof SSEAuthError)
153
+ return err(e.message);
154
+ if (e instanceof Error)
155
+ return err(e.message);
156
+ return err(String(e));
157
+ }
158
+ // ---------------------------------------------------------------------------
159
+ // Shared logic: canonical formulation confirm
160
+ // ---------------------------------------------------------------------------
161
+ async function canonicalFormulationConfirm(opts) {
162
+ requireAuth();
163
+ const client = getClient();
164
+ const confirmed = await client.confirmFormulation({
165
+ sessionId: opts.sessionId,
166
+ scopeTags: opts.scopeTags,
167
+ maxCandidates: opts.maxCandidates,
168
+ });
169
+ const queryId = confirmed.query_id;
170
+ const query = await client.getDiscoveryQuery(queryId);
171
+ return {
172
+ session_id: opts.sessionId,
173
+ demand_id: confirmed.demand_id,
174
+ query_id: queryId,
175
+ session: confirmed.session,
176
+ query,
177
+ selected_agent: selectedAgentPayload(),
178
+ };
179
+ }
180
+ // ===========================================================================
181
+ // Tool definitions (30 tools — exact same names and params as Python version)
182
+ // ===========================================================================
183
+ // 1. towow_register
184
+ server.registerTool("towow_register", {
185
+ description: "Register a new Towow account and persist the returned session locally.",
186
+ inputSchema: z.object({
187
+ invite_code: z.string(),
188
+ email: z.string(),
189
+ password: z.string(),
190
+ name: z.string(),
191
+ profile_text: z.string(),
192
+ }),
193
+ }, async ({ invite_code, email, password, name, profile_text }) => {
194
+ try {
195
+ const client = getClient();
196
+ const result = await client.register(invite_code, email, password, name, profile_text);
197
+ const token = result.session_token;
198
+ if (token)
199
+ saveSessionToken(token);
200
+ const defaultAgentId = result.default_agent_id;
201
+ if (defaultAgentId)
202
+ saveAgent(defaultAgentId, result.name);
203
+ return ok(toJson({
204
+ account_id: result.account_id,
205
+ default_agent_id: defaultAgentId,
206
+ email: result.email,
207
+ name: result.name,
208
+ selected_agent: selectedAgentPayload(),
209
+ }));
210
+ }
211
+ catch (e) {
212
+ return handleToolError(e);
213
+ }
214
+ });
215
+ // 2. towow_login
216
+ server.registerTool("towow_login", {
217
+ description: "Login to Towow and persist the returned session locally.",
218
+ inputSchema: z.object({
219
+ email: z.string(),
220
+ password: z.string(),
221
+ }),
222
+ }, async ({ email, password }) => {
223
+ try {
224
+ const client = getClient();
225
+ const result = await client.login(email, password);
226
+ const token = result.session_token;
227
+ if (token)
228
+ saveSessionToken(token);
229
+ const defaultAgentId = result.default_agent_id;
230
+ if (defaultAgentId)
231
+ saveAgent(defaultAgentId, result.name);
232
+ return ok(toJson({
233
+ account_id: result.account_id,
234
+ default_agent_id: defaultAgentId,
235
+ email: result.email,
236
+ name: result.name,
237
+ expires_at: result.expires_at,
238
+ selected_agent: selectedAgentPayload(),
239
+ }));
240
+ }
241
+ catch (e) {
242
+ return handleToolError(e);
243
+ }
244
+ });
245
+ // 3. towow_agents
246
+ server.registerTool("towow_agents", {
247
+ description: "List all agents owned by the current account and show the selected agent.",
248
+ inputSchema: z.object({}),
249
+ }, async () => {
250
+ try {
251
+ requireAuth();
252
+ const client = getClient();
253
+ const result = await client.listAgents();
254
+ const agents = result.agents ?? [];
255
+ return ok(toJson({
256
+ selected_agent: selectedAgentPayload(),
257
+ agents: agents.map(pickAgentPayload),
258
+ }));
259
+ }
260
+ catch (e) {
261
+ return handleToolError(e);
262
+ }
263
+ });
264
+ // 4. towow_agent_create
265
+ server.registerTool("towow_agent_create", {
266
+ description: "Create a new agent under the current account.",
267
+ inputSchema: z.object({
268
+ display_name: z.string(),
269
+ profile_text: z.string(),
270
+ visibility: z.string().default("scoped"),
271
+ scoped_tags: z.array(z.string()).optional(),
272
+ }),
273
+ }, async ({ display_name, profile_text, visibility, scoped_tags }) => {
274
+ try {
275
+ requireAuth();
276
+ const client = getClient();
277
+ const agent = await client.createAgent({
278
+ displayName: display_name,
279
+ profileText: profile_text,
280
+ visibility,
281
+ scopedTags: scoped_tags,
282
+ });
283
+ return ok(toJson({
284
+ agent: pickAgentPayload(agent),
285
+ selected_agent: selectedAgentPayload(),
286
+ }));
287
+ }
288
+ catch (e) {
289
+ return handleToolError(e);
290
+ }
291
+ });
292
+ // 5. towow_agent_select
293
+ server.registerTool("towow_agent_select", {
294
+ description: "Select which owned agent subsequent MCP actions should use.",
295
+ inputSchema: z.object({
296
+ agent_id: z.string(),
297
+ }),
298
+ }, async ({ agent_id }) => {
299
+ try {
300
+ requireAuth();
301
+ const client = getClient();
302
+ const agent = await client.getAgent(agent_id);
303
+ saveAgent(agent.agent_id, agent.display_name);
304
+ return ok(toJson({
305
+ selected_agent: selectedAgentPayload(),
306
+ agent: pickAgentPayload(agent),
307
+ }));
308
+ }
309
+ catch (e) {
310
+ return handleToolError(e);
311
+ }
312
+ });
313
+ // 6. towow_agent_set_visibility
314
+ server.registerTool("towow_agent_set_visibility", {
315
+ description: "Update the visibility policy for the selected agent or an explicitly supplied agent.",
316
+ inputSchema: z.object({
317
+ visibility: z.string(),
318
+ agent_id: z.string().optional(),
319
+ }),
320
+ }, async ({ visibility, agent_id }) => {
321
+ try {
322
+ requireAuth();
323
+ const selectedAgentId = agent_id ?? requireAgentId();
324
+ const client = getClient();
325
+ const updated = await client.setAgentVisibility(selectedAgentId, visibility);
326
+ if (selectedAgentId === getAgentId()) {
327
+ saveAgent(updated.agent_id, updated.display_name);
328
+ }
329
+ return ok(toJson({
330
+ agent: pickAgentPayload(updated),
331
+ selected_agent: selectedAgentPayload(),
332
+ }));
333
+ }
334
+ catch (e) {
335
+ return handleToolError(e);
336
+ }
337
+ });
338
+ // 7. towow_formulation_start
339
+ server.registerTool("towow_formulation_start", {
340
+ description: "Start a canonical formulation session for the selected agent.",
341
+ inputSchema: z.object({
342
+ raw_intent: z.string(),
343
+ scene_context: z.string().default("startup-hub"),
344
+ }),
345
+ }, async ({ raw_intent, scene_context }) => {
346
+ try {
347
+ requireAuth();
348
+ const agentId = requireAgentId();
349
+ const client = getClient();
350
+ const result = await client.createFormulation({
351
+ agentId,
352
+ rawIntent: raw_intent,
353
+ sceneContext: scene_context,
354
+ });
355
+ const session = result.session;
356
+ return ok(toJson({
357
+ session_id: session.session_id,
358
+ agent_id: session.agent_id,
359
+ reply: result.assistant_reply,
360
+ document: session.formulated_demand,
361
+ updates: result.updates,
362
+ selected_agent: selectedAgentPayload(),
363
+ }));
364
+ }
365
+ catch (e) {
366
+ return handleToolError(e);
367
+ }
368
+ });
369
+ // 8. towow_formulation_reply
370
+ server.registerTool("towow_formulation_reply", {
371
+ description: "Continue a formulation session and return the fully-consumed SSE result.",
372
+ inputSchema: z.object({
373
+ session_id: z.string(),
374
+ user_message: z.string(),
375
+ }),
376
+ }, async ({ session_id, user_message }) => {
377
+ try {
378
+ requireAuth();
379
+ const client = getClient();
380
+ const resp = await client.formulationReplyStream(session_id, user_message);
381
+ const { fullText, updates } = await consumeSseStream(resp);
382
+ const client2 = getClient();
383
+ const updatedSession = await client2.getFormulation(session_id);
384
+ return ok(toJson({
385
+ session_id,
386
+ reply: fullText,
387
+ document: updatedSession.formulated_demand ?? "",
388
+ updates,
389
+ selected_agent: selectedAgentPayload(),
390
+ }));
391
+ }
392
+ catch (e) {
393
+ return handleToolError(e);
394
+ }
395
+ });
396
+ // 9. towow_formulation_confirm
397
+ server.registerTool("towow_formulation_confirm", {
398
+ description: "Confirm a formulation session, execute discovery, and return the canonical query payload.",
399
+ inputSchema: z.object({
400
+ session_id: z.string(),
401
+ scope_tags: z.array(z.string()).optional(),
402
+ max_candidates: z.number().default(10),
403
+ }),
404
+ }, async ({ session_id, scope_tags, max_candidates }) => {
405
+ try {
406
+ const result = await canonicalFormulationConfirm({
407
+ sessionId: session_id,
408
+ scopeTags: scope_tags,
409
+ maxCandidates: max_candidates,
410
+ });
411
+ return ok(toJson(result));
412
+ }
413
+ catch (e) {
414
+ return handleToolError(e);
415
+ }
416
+ });
417
+ // 10. towow_discover
418
+ server.registerTool("towow_discover", {
419
+ description: "Run an ad-hoc discovery query for the selected agent.",
420
+ inputSchema: z.object({
421
+ demand_text: z.string(),
422
+ scope_tags: z.array(z.string()).optional(),
423
+ scene_context: z.string().default("startup-hub"),
424
+ max_candidates: z.number().default(10),
425
+ }),
426
+ }, async ({ demand_text, scope_tags, scene_context, max_candidates }) => {
427
+ try {
428
+ requireAuth();
429
+ const requester = requireAgentId();
430
+ const client = getClient();
431
+ const result = await client.discover({
432
+ requester,
433
+ demandText: demand_text,
434
+ scopeTags: scope_tags,
435
+ sceneContext: scene_context,
436
+ maxCandidates: max_candidates,
437
+ });
438
+ return ok(toJson(result));
439
+ }
440
+ catch (e) {
441
+ return handleToolError(e);
442
+ }
443
+ });
444
+ // 11. towow_invite
445
+ server.registerTool("towow_invite", {
446
+ description: "Create an invitation from a nomination using the selected agent as inviter.",
447
+ inputSchema: z.object({
448
+ nomination_id: z.string(),
449
+ expires_in_hours: z.number().default(24),
450
+ }),
451
+ }, async ({ nomination_id, expires_in_hours }) => {
452
+ try {
453
+ requireAuth();
454
+ const inviter = requireAgentId();
455
+ const client = getClient();
456
+ const invitation = await client.createInvitation({
457
+ inviter,
458
+ nominationId: nomination_id,
459
+ expiresInHours: expires_in_hours,
460
+ });
461
+ return ok(toJson(invitation));
462
+ }
463
+ catch (e) {
464
+ return handleToolError(e);
465
+ }
466
+ });
467
+ // 12. towow_invitations
468
+ server.registerTool("towow_invitations", {
469
+ description: "List invitations visible to the selected agent or an explicitly supplied owned agent.",
470
+ inputSchema: z.object({
471
+ agent_id: z.string().optional(),
472
+ }),
473
+ }, async ({ agent_id }) => {
474
+ try {
475
+ requireAuth();
476
+ const currentAgentId = agent_id ?? requireAgentId();
477
+ const client = getClient();
478
+ const result = await client.listInvitations({ agentId: currentAgentId });
479
+ return ok(toJson(result));
480
+ }
481
+ catch (e) {
482
+ return handleToolError(e);
483
+ }
484
+ });
485
+ // 13. towow_invitation_respond
486
+ server.registerTool("towow_invitation_respond", {
487
+ description: "Accept or decline an invitation as the selected agent.",
488
+ inputSchema: z.object({
489
+ invitation_id: z.string(),
490
+ action: z.string(),
491
+ }),
492
+ }, async ({ invitation_id, action }) => {
493
+ try {
494
+ requireAuth();
495
+ const agentId = requireAgentId();
496
+ const client = getClient();
497
+ const invitation = await client.respondInvitation(invitation_id, {
498
+ agentId,
499
+ action,
500
+ });
501
+ return ok(toJson(invitation));
502
+ }
503
+ catch (e) {
504
+ return handleToolError(e);
505
+ }
506
+ });
507
+ // 14. towow_negotiate
508
+ server.registerTool("towow_negotiate", {
509
+ description: "Create a canonical protocol run from already-accepted invitations.",
510
+ inputSchema: z.object({
511
+ invitation_ids: z.array(z.string()),
512
+ max_rounds: z.number().default(4),
513
+ }),
514
+ }, async ({ invitation_ids, max_rounds }) => {
515
+ try {
516
+ requireAuth();
517
+ const initiator = requireAgentId();
518
+ const client = getClient();
519
+ const result = await client.createRun({
520
+ initiator,
521
+ invitationIds: invitation_ids,
522
+ maxRounds: max_rounds,
523
+ });
524
+ return ok(toJson(result));
525
+ }
526
+ catch (e) {
527
+ return handleToolError(e);
528
+ }
529
+ });
530
+ // 15. towow_run_status
531
+ server.registerTool("towow_run_status", {
532
+ description: "Fetch the current canonical run status.",
533
+ inputSchema: z.object({
534
+ run_id: z.string(),
535
+ }),
536
+ }, async ({ run_id }) => {
537
+ try {
538
+ requireAuth();
539
+ const client = getClient();
540
+ const data = await client.getRun(run_id);
541
+ return ok(toJson(data));
542
+ }
543
+ catch (e) {
544
+ return handleToolError(e);
545
+ }
546
+ });
547
+ // 16. towow_run_prompt
548
+ server.registerTool("towow_run_prompt", {
549
+ description: "Fetch the current round prompt for the selected agent.",
550
+ inputSchema: z.object({
551
+ run_id: z.string(),
552
+ }),
553
+ }, async ({ run_id }) => {
554
+ try {
555
+ requireAuth();
556
+ const agentId = requireAgentId();
557
+ const client = getClient();
558
+ const data = await client.getRunPrompt(run_id, agentId);
559
+ return ok(toJson(data));
560
+ }
561
+ catch (e) {
562
+ return handleToolError(e);
563
+ }
564
+ });
565
+ // 17. towow_run_respond
566
+ server.registerTool("towow_run_respond", {
567
+ description: "Submit a participant response for the selected agent.",
568
+ inputSchema: z.object({
569
+ run_id: z.string(),
570
+ round_number: z.number(),
571
+ content: z.string(),
572
+ metadata: z.record(z.string(), z.unknown()).optional(),
573
+ }),
574
+ }, async ({ run_id, round_number, content, metadata }) => {
575
+ try {
576
+ requireAuth();
577
+ const agentId = requireAgentId();
578
+ const client = getClient();
579
+ const data = await client.respondRun(run_id, {
580
+ agentId,
581
+ roundNumber: round_number,
582
+ content,
583
+ metadata,
584
+ });
585
+ return ok(toJson(data));
586
+ }
587
+ catch (e) {
588
+ return handleToolError(e);
589
+ }
590
+ });
591
+ // 18. towow_result
592
+ server.registerTool("towow_result", {
593
+ description: "Fetch the final result view for the selected agent.",
594
+ inputSchema: z.object({
595
+ run_id: z.string(),
596
+ }),
597
+ }, async ({ run_id }) => {
598
+ try {
599
+ requireAuth();
600
+ const agentId = requireAgentId();
601
+ const client = getClient();
602
+ const data = await client.getRunResult(run_id, agentId);
603
+ return ok(toJson(data));
604
+ }
605
+ catch (e) {
606
+ return handleToolError(e);
607
+ }
608
+ });
609
+ // 19. towow_feedback
610
+ server.registerTool("towow_feedback", {
611
+ description: "Submit canonical feedback for the selected agent.",
612
+ inputSchema: z.object({
613
+ target_type: z.string(),
614
+ target_id: z.string(),
615
+ exposure_event_id: z.string(),
616
+ rating: z.number(),
617
+ comment: z.string().optional(),
618
+ }),
619
+ }, async ({ target_type, target_id, exposure_event_id, rating, comment }) => {
620
+ try {
621
+ requireAuth();
622
+ const agentId = requireAgentId();
623
+ const client = getClient();
624
+ const data = await client.submitFeedback({
625
+ agentId,
626
+ targetType: target_type,
627
+ targetId: target_id,
628
+ exposureEventId: exposure_event_id,
629
+ rating,
630
+ comment,
631
+ });
632
+ return ok(toJson(data));
633
+ }
634
+ catch (e) {
635
+ return handleToolError(e);
636
+ }
637
+ });
638
+ // 20. towow_usage
639
+ server.registerTool("towow_usage", {
640
+ description: "Fetch usage stats for the selected agent and owning account.",
641
+ inputSchema: z.object({
642
+ period: z.string().default("month"),
643
+ }),
644
+ }, async ({ period }) => {
645
+ try {
646
+ requireAuth();
647
+ const agentId = requireAgentId();
648
+ const client = getClient();
649
+ const data = await client.getUsage({ period, agentId });
650
+ return ok(toJson(data));
651
+ }
652
+ catch (e) {
653
+ return handleToolError(e);
654
+ }
655
+ });
656
+ // 21. towow_update_profile
657
+ server.registerTool("towow_update_profile", {
658
+ description: "Update the selected agent. Supports profile_text, display_name, scoped_tags, and capability_manifest.",
659
+ inputSchema: z.object({
660
+ profile_text: z.string().optional(),
661
+ display_name: z.string().optional(),
662
+ scoped_tags: z.array(z.string()).optional(),
663
+ capability_manifest: z.record(z.string(), z.unknown()).optional(),
664
+ }),
665
+ }, async ({ profile_text, display_name, scoped_tags, capability_manifest }) => {
666
+ try {
667
+ requireAuth();
668
+ const agentId = requireAgentId();
669
+ const client = getClient();
670
+ const data = await client.updateAgent(agentId, {
671
+ displayName: display_name,
672
+ profileText: profile_text,
673
+ scopedTags: scoped_tags,
674
+ capabilityManifest: capability_manifest,
675
+ });
676
+ if (agentId === getAgentId()) {
677
+ saveAgent(agentId, data.display_name);
678
+ }
679
+ return ok(toJson({
680
+ agent: pickAgentPayload(data),
681
+ selected_agent: selectedAgentPayload(),
682
+ }));
683
+ }
684
+ catch (e) {
685
+ return handleToolError(e);
686
+ }
687
+ });
688
+ // 22. towow_agent_delete
689
+ server.registerTool("towow_agent_delete", {
690
+ description: "Delete an agent owned by the current account.",
691
+ inputSchema: z.object({
692
+ agent_id: z.string(),
693
+ }),
694
+ }, async ({ agent_id }) => {
695
+ try {
696
+ requireAuth();
697
+ const client = getClient();
698
+ await client.deleteAgent(agent_id);
699
+ if (agent_id === getAgentId()) {
700
+ clearAgent();
701
+ }
702
+ return ok(toJson({ ok: true, deleted_agent_id: agent_id }));
703
+ }
704
+ catch (e) {
705
+ return handleToolError(e);
706
+ }
707
+ });
708
+ // 23. towow_refresh_token
709
+ server.registerTool("towow_refresh_token", {
710
+ description: "Refresh the session token before it expires.",
711
+ inputSchema: z.object({}),
712
+ }, async () => {
713
+ try {
714
+ requireAuth();
715
+ const client = getClient();
716
+ const result = await client.refreshToken();
717
+ const newToken = result.session_token;
718
+ if (newToken)
719
+ saveSessionToken(newToken);
720
+ return ok(toJson({ ok: true, expires_at: result.expires_at }));
721
+ }
722
+ catch (e) {
723
+ return handleToolError(e);
724
+ }
725
+ });
726
+ // 24. towow_byok_bind
727
+ server.registerTool("towow_byok_bind", {
728
+ description: "Bind your own LLM API key for formulation and discovery. Required for full functionality.",
729
+ inputSchema: z.object({
730
+ api_key: z.string(),
731
+ provider: z.string().default("anthropic"),
732
+ }),
733
+ }, async ({ api_key, provider }) => {
734
+ try {
735
+ requireAuth();
736
+ const client = getClient();
737
+ const result = await client.bindByok(api_key, provider);
738
+ return ok(toJson(result));
739
+ }
740
+ catch (e) {
741
+ return handleToolError(e);
742
+ }
743
+ });
744
+ // 25. towow_byok_status
745
+ server.registerTool("towow_byok_status", {
746
+ description: "Check if a BYOK (Bring Your Own Key) session is active.",
747
+ inputSchema: z.object({}),
748
+ }, async () => {
749
+ try {
750
+ requireAuth();
751
+ const client = getClient();
752
+ const result = await client.getByok();
753
+ return ok(toJson(result));
754
+ }
755
+ catch (e) {
756
+ return handleToolError(e);
757
+ }
758
+ });
759
+ // 26. towow_byok_clear
760
+ server.registerTool("towow_byok_clear", {
761
+ description: "Remove the BYOK API key binding.",
762
+ inputSchema: z.object({}),
763
+ }, async () => {
764
+ try {
765
+ requireAuth();
766
+ const client = getClient();
767
+ const result = await client.clearByok();
768
+ return ok(toJson(result));
769
+ }
770
+ catch (e) {
771
+ return handleToolError(e);
772
+ }
773
+ });
774
+ // 27. towow_get_formulation
775
+ server.registerTool("towow_get_formulation", {
776
+ description: "Get the current state of a formulation session without sending a message.",
777
+ inputSchema: z.object({
778
+ session_id: z.string(),
779
+ }),
780
+ }, async ({ session_id }) => {
781
+ try {
782
+ requireAuth();
783
+ const client = getClient();
784
+ const data = await client.getFormulation(session_id);
785
+ return ok(toJson(data));
786
+ }
787
+ catch (e) {
788
+ return handleToolError(e);
789
+ }
790
+ });
791
+ // 28. towow_get_invitation
792
+ server.registerTool("towow_get_invitation", {
793
+ description: "Get details of a specific invitation.",
794
+ inputSchema: z.object({
795
+ invitation_id: z.string(),
796
+ }),
797
+ }, async ({ invitation_id }) => {
798
+ try {
799
+ requireAuth();
800
+ const client = getClient();
801
+ const data = await client.getInvitation(invitation_id);
802
+ return ok(toJson(data));
803
+ }
804
+ catch (e) {
805
+ return handleToolError(e);
806
+ }
807
+ });
808
+ // 29. towow_get_discovery
809
+ server.registerTool("towow_get_discovery", {
810
+ description: "Retrieve results from a previously completed discovery query.",
811
+ inputSchema: z.object({
812
+ query_id: z.string(),
813
+ }),
814
+ }, async ({ query_id }) => {
815
+ try {
816
+ requireAuth();
817
+ const client = getClient();
818
+ const data = await client.getDiscoveryQuery(query_id);
819
+ return ok(toJson(data));
820
+ }
821
+ catch (e) {
822
+ return handleToolError(e);
823
+ }
824
+ });
825
+ // 30. towow_demand_confirm (deprecated alias)
826
+ server.registerTool("towow_demand_confirm", {
827
+ description: "Deprecated alias for `towow_formulation_confirm`. Prefer the canonical tool name.",
828
+ inputSchema: z.object({
829
+ session_id: z.string(),
830
+ scope_tags: z.array(z.string()).optional(),
831
+ max_candidates: z.number().default(10),
832
+ }),
833
+ }, async ({ session_id, scope_tags, max_candidates }) => {
834
+ try {
835
+ const payload = await canonicalFormulationConfirm({
836
+ sessionId: session_id,
837
+ scopeTags: scope_tags,
838
+ maxCandidates: max_candidates,
839
+ });
840
+ payload.deprecated_tool = "towow_demand_confirm";
841
+ payload.replacement = "towow_formulation_confirm";
842
+ return ok(toJson(payload));
843
+ }
844
+ catch (e) {
845
+ return handleToolError(e);
846
+ }
847
+ });
848
+ // 31. towow_run_start (deprecated alias)
849
+ server.registerTool("towow_run_start", {
850
+ description: "Deprecated alias for `towow_negotiate`. Prefer the canonical tool name.",
851
+ inputSchema: z.object({
852
+ invitation_ids: z.array(z.string()),
853
+ max_rounds: z.number().default(4),
854
+ }),
855
+ }, async ({ invitation_ids, max_rounds }) => {
856
+ try {
857
+ requireAuth();
858
+ const initiator = requireAgentId();
859
+ const client = getClient();
860
+ const data = await client.createRun({
861
+ initiator,
862
+ invitationIds: invitation_ids,
863
+ maxRounds: max_rounds,
864
+ });
865
+ data.deprecated_tool = "towow_run_start";
866
+ data.replacement = "towow_negotiate";
867
+ return ok(toJson(data));
868
+ }
869
+ catch (e) {
870
+ return handleToolError(e);
871
+ }
872
+ });
873
+ // 32. towow_run_result (deprecated alias)
874
+ server.registerTool("towow_run_result", {
875
+ description: "Deprecated alias for `towow_result`. Prefer the canonical tool name.",
876
+ inputSchema: z.object({
877
+ run_id: z.string(),
878
+ }),
879
+ }, async ({ run_id }) => {
880
+ try {
881
+ requireAuth();
882
+ const agentId = requireAgentId();
883
+ const client = getClient();
884
+ const data = await client.getRunResult(run_id, agentId);
885
+ data.deprecated_tool = "towow_run_result";
886
+ data.replacement = "towow_result";
887
+ return ok(toJson(data));
888
+ }
889
+ catch (e) {
890
+ return handleToolError(e);
891
+ }
892
+ });
893
+ // 33. towow_logout
894
+ server.registerTool("towow_logout", {
895
+ description: "Clear the local MCP session context after best-effort remote logout.",
896
+ inputSchema: z.object({}),
897
+ }, async () => {
898
+ const token = getSessionToken();
899
+ if (token) {
900
+ try {
901
+ const client = getClient();
902
+ await client.logout();
903
+ }
904
+ catch {
905
+ // Ignore remote logout failure (best-effort)
906
+ }
907
+ }
908
+ clearSessionToken();
909
+ clearAgent();
910
+ return ok(toJson({ ok: true }));
911
+ });
912
+ // ---------------------------------------------------------------------------
913
+ // Main
914
+ // ---------------------------------------------------------------------------
915
+ async function main() {
916
+ const transport = new StdioServerTransport();
917
+ await server.connect(transport);
918
+ }
919
+ main().catch((e) => {
920
+ process.stderr.write(`Fatal: ${e}\n`);
921
+ process.exit(1);
922
+ });
923
+ //# sourceMappingURL=index.js.map