wolfpack-mcp 1.0.52 → 1.0.53

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.
@@ -0,0 +1,124 @@
1
+ import { z } from 'zod';
2
+ function text(data) {
3
+ return JSON.stringify(data, null, 2);
4
+ }
5
+ // ─── Tool definitions ──────────────────────────────────────────────────────────
6
+ export const AGENT_SELF_TOOLS = [
7
+ {
8
+ name: 'get_self',
9
+ description: 'Get your own agent profile with full composed context: template system prompt, agent instructions, skills, LLM model, and assigned projects. ' +
10
+ 'Use this to understand how you are configured and what capabilities you have. ' +
11
+ 'Essential for self-reflection and improvement proposals.',
12
+ inputSchema: { type: 'object', properties: {} },
13
+ },
14
+ {
15
+ name: 'get_own_sessions',
16
+ description: 'List your own recent sessions. Returns session metadata including status, trigger type, and timestamps. ' +
17
+ 'Use this to review your recent activity for retrospective analysis.',
18
+ inputSchema: {
19
+ type: 'object',
20
+ properties: {
21
+ limit: { type: 'number', description: 'Max sessions to return (default 10)' },
22
+ offset: { type: 'number', description: 'Skip first N sessions (default 0)' },
23
+ },
24
+ },
25
+ },
26
+ {
27
+ name: 'list_memories',
28
+ description: 'List all your persistent memory entries. Memory persists across sessions and is scoped to you. ' +
29
+ 'Use this to recall observations, patterns, and notes from previous work.',
30
+ inputSchema: { type: 'object', properties: {} },
31
+ },
32
+ {
33
+ name: 'get_memory',
34
+ description: 'Get a specific memory entry by key. Returns the content and metadata for a single memory entry.',
35
+ inputSchema: {
36
+ type: 'object',
37
+ properties: {
38
+ key: { type: 'string', description: 'The memory key to retrieve' },
39
+ },
40
+ required: ['key'],
41
+ },
42
+ },
43
+ {
44
+ name: 'save_memory',
45
+ description: 'Save a persistent memory entry by key. Creates the entry if it does not exist, or updates it if it does. ' +
46
+ 'Use this to persist observations, learnings, and notes across sessions. ' +
47
+ 'To clear a memory entry, save it with empty content.',
48
+ inputSchema: {
49
+ type: 'object',
50
+ properties: {
51
+ key: {
52
+ type: 'string',
53
+ description: 'A unique key for this memory entry (e.g. "retrospective-notes", "recurring-issues", "session-learnings")',
54
+ },
55
+ content: {
56
+ type: 'string',
57
+ description: 'The content to persist. Use markdown for structured notes.',
58
+ },
59
+ },
60
+ required: ['key', 'content'],
61
+ },
62
+ },
63
+ ];
64
+ // ─── Zod schemas ───────────────────────────────────────────────────────────────
65
+ const GetOwnSessionsSchema = z.object({
66
+ limit: z.number().optional(),
67
+ offset: z.number().optional(),
68
+ });
69
+ const GetMemorySchema = z.object({
70
+ key: z.string(),
71
+ });
72
+ const SaveMemorySchema = z.object({
73
+ key: z.string(),
74
+ content: z.string(),
75
+ });
76
+ // ─── Handler ───────────────────────────────────────────────────────────────────
77
+ export async function handleAgentSelfTool(name, args, client) {
78
+ switch (name) {
79
+ case 'get_self': {
80
+ const self = await client.getSelf();
81
+ return { content: [{ type: 'text', text: text(self) }] };
82
+ }
83
+ case 'get_own_sessions': {
84
+ const parsed = GetOwnSessionsSchema.parse(args || {});
85
+ const sessions = await client.getOwnSessions(parsed);
86
+ return { content: [{ type: 'text', text: text(sessions) }] };
87
+ }
88
+ case 'list_memories': {
89
+ const memories = await client.listMemories();
90
+ if (memories.length === 0) {
91
+ return {
92
+ content: [
93
+ { type: 'text', text: 'No memory entries found. Use save_memory to create one.' },
94
+ ],
95
+ };
96
+ }
97
+ return { content: [{ type: 'text', text: text(memories) }] };
98
+ }
99
+ case 'get_memory': {
100
+ const parsed = GetMemorySchema.parse(args);
101
+ const memory = await client.getMemory(parsed.key);
102
+ if (!memory) {
103
+ return {
104
+ content: [{ type: 'text', text: `Memory entry "${parsed.key}" not found.` }],
105
+ };
106
+ }
107
+ return { content: [{ type: 'text', text: text(memory) }] };
108
+ }
109
+ case 'save_memory': {
110
+ const parsed = SaveMemorySchema.parse(args);
111
+ const memory = await client.saveMemory(parsed.key, parsed.content);
112
+ return {
113
+ content: [
114
+ {
115
+ type: 'text',
116
+ text: `Saved memory "${parsed.key}" (updated: ${memory.dateUpdated})`,
117
+ },
118
+ ],
119
+ };
120
+ }
121
+ default:
122
+ throw new Error(`Unknown agent self tool: ${name}`);
123
+ }
124
+ }
package/dist/client.js CHANGED
@@ -17,6 +17,13 @@ export class WolfpackClient {
17
17
  const sep = path.includes('?') ? '&' : '?';
18
18
  return `${path}${sep}teamSlug=${encodeURIComponent(slug)}`;
19
19
  }
20
+ /** Build a URL path with optional org_slug query parameter. */
21
+ withOrgSlug(path, orgSlug) {
22
+ if (!orgSlug)
23
+ return path;
24
+ const sep = path.includes('?') ? '&' : '?';
25
+ return `${path}${sep}org_slug=${encodeURIComponent(orgSlug)}`;
26
+ }
20
27
  /**
21
28
  * Fetch and cache the project slug by verifying it exists.
22
29
  * Uses the MCP team endpoint to validate the slug.
@@ -572,13 +579,18 @@ export class WolfpackClient {
572
579
  async getCapabilities() {
573
580
  return this.api.get('/capabilities');
574
581
  }
582
+ // ─── Organisations ──────────────────────────────────────────────────────────
583
+ async listOrganisations() {
584
+ const response = await this.api.get('/organisations');
585
+ return response.organisations;
586
+ }
575
587
  // ─── Agent Builder: Agent CRUD ─────────────────────────────────────────────
576
- async listAgents() {
577
- return this.api.get('/agents');
588
+ async listAgents(orgSlug) {
589
+ return this.api.get(this.withOrgSlug('/agents', orgSlug));
578
590
  }
579
- async getAgent(agentId) {
591
+ async getAgent(agentId, orgSlug) {
580
592
  try {
581
- return await this.api.get(`/agents/${agentId}`);
593
+ return await this.api.get(this.withOrgSlug(`/agents/${agentId}`, orgSlug));
582
594
  }
583
595
  catch (error) {
584
596
  if (error && typeof error === 'object' && 'status' in error && error.status === 404)
@@ -586,26 +598,26 @@ export class WolfpackClient {
586
598
  throw error;
587
599
  }
588
600
  }
589
- async createAgent(body) {
590
- return this.api.post('/agents', body);
601
+ async createAgent(body, orgSlug) {
602
+ return this.api.post(this.withOrgSlug('/agents', orgSlug), body);
591
603
  }
592
- async updateAgent(agentId, body) {
593
- return this.api.patch(`/agents/${agentId}`, body);
604
+ async updateAgent(agentId, body, orgSlug) {
605
+ return this.api.patch(this.withOrgSlug(`/agents/${agentId}`, orgSlug), body);
594
606
  }
595
607
  // ─── Agent Builder: Project Assignment ────────────────────────────────────
596
- async listAgentProjects(agentId) {
597
- return this.api.get(`/agents/${agentId}/projects`);
608
+ async listAgentProjects(agentId, orgSlug) {
609
+ return this.api.get(this.withOrgSlug(`/agents/${agentId}/projects`, orgSlug));
598
610
  }
599
- async assignAgentToProject(agentId, teamSlug) {
600
- return this.api.post(`/agents/${agentId}/projects/${encodeURIComponent(teamSlug)}`, {});
611
+ async assignAgentToProject(agentId, teamSlug, orgSlug) {
612
+ return this.api.post(this.withOrgSlug(`/agents/${agentId}/projects/${encodeURIComponent(teamSlug)}`, orgSlug), {});
601
613
  }
602
- async removeAgentFromProject(agentId, teamSlug) {
614
+ async removeAgentFromProject(agentId, teamSlug, orgSlug) {
603
615
  return this.api
604
- .delete(`/agents/${agentId}/projects/${encodeURIComponent(teamSlug)}`)
616
+ .delete(this.withOrgSlug(`/agents/${agentId}/projects/${encodeURIComponent(teamSlug)}`, orgSlug))
605
617
  .then(() => ({ success: true }));
606
618
  }
607
619
  // ─── Agent Builder: Sessions ───────────────────────────────────────────────
608
- async listAgentSessions(agentId, options) {
620
+ async listAgentSessions(agentId, options, orgSlug) {
609
621
  const params = new URLSearchParams();
610
622
  if (options?.status)
611
623
  params.append('status', options.status);
@@ -613,12 +625,14 @@ export class WolfpackClient {
613
625
  params.append('limit', options.limit.toString());
614
626
  if (options?.offset !== undefined)
615
627
  params.append('offset', options.offset.toString());
628
+ if (orgSlug)
629
+ params.append('org_slug', orgSlug);
616
630
  const q = params.toString();
617
631
  return this.api.get(`/agents/${agentId}/sessions${q ? `?${q}` : ''}`);
618
632
  }
619
- async getAgentSession(agentId, sessionId) {
633
+ async getAgentSession(agentId, sessionId, orgSlug) {
620
634
  try {
621
- return await this.api.get(`/agents/${agentId}/sessions/${sessionId}`);
635
+ return await this.api.get(this.withOrgSlug(`/agents/${agentId}/sessions/${sessionId}`, orgSlug));
622
636
  }
623
637
  catch (error) {
624
638
  if (error && typeof error === 'object' && 'status' in error && error.status === 404)
@@ -626,33 +640,36 @@ export class WolfpackClient {
626
640
  throw error;
627
641
  }
628
642
  }
629
- async getAgentSessionConversation(agentId, sessionId, options) {
643
+ async getAgentSessionConversation(agentId, sessionId, options, orgSlug) {
630
644
  const params = new URLSearchParams();
631
645
  if (options?.limit !== undefined)
632
646
  params.append('limit', options.limit.toString());
633
647
  if (options?.offset !== undefined)
634
648
  params.append('offset', options.offset.toString());
649
+ if (orgSlug)
650
+ params.append('org_slug', orgSlug);
635
651
  const q = params.toString();
636
652
  return this.api.get(`/agents/${agentId}/sessions/${sessionId}/conversation${q ? `?${q}` : ''}`);
637
653
  }
638
- async runAgent(agentId, prompt, teamSlug) {
639
- return this.api.post(`/agents/${agentId}/run`, { prompt, teamSlug });
640
- }
641
- async stopAgentSession(agentId, sessionId) {
642
- return this.api.post(`/agents/${agentId}/sessions/${sessionId}/stop`, {});
643
- }
644
- async resumeAgentSession(agentId, sessionId, prompt) {
645
- return this.api.post(`/agents/${agentId}/sessions/${sessionId}/resume`, {
654
+ async runAgent(agentId, prompt, teamSlug, orgSlug) {
655
+ return this.api.post(this.withOrgSlug(`/agents/${agentId}/run`, orgSlug), {
646
656
  prompt,
657
+ teamSlug,
647
658
  });
648
659
  }
660
+ async stopAgentSession(agentId, sessionId, orgSlug) {
661
+ return this.api.post(this.withOrgSlug(`/agents/${agentId}/sessions/${sessionId}/stop`, orgSlug), {});
662
+ }
663
+ async resumeAgentSession(agentId, sessionId, prompt, orgSlug) {
664
+ return this.api.post(this.withOrgSlug(`/agents/${agentId}/sessions/${sessionId}/resume`, orgSlug), { prompt });
665
+ }
649
666
  // ─── Agent Builder: Tasks ──────────────────────────────────────────────────
650
- async listAgentTasks(agentId) {
651
- return this.api.get(`/agents/${agentId}/tasks`);
667
+ async listAgentTasks(agentId, orgSlug) {
668
+ return this.api.get(this.withOrgSlug(`/agents/${agentId}/tasks`, orgSlug));
652
669
  }
653
- async getAgentTask(agentId, taskId) {
670
+ async getAgentTask(agentId, taskId, orgSlug) {
654
671
  try {
655
- return await this.api.get(`/agents/${agentId}/tasks/${taskId}`);
672
+ return await this.api.get(this.withOrgSlug(`/agents/${agentId}/tasks/${taskId}`, orgSlug));
656
673
  }
657
674
  catch (error) {
658
675
  if (error && typeof error === 'object' && 'status' in error && error.status === 404)
@@ -660,59 +677,69 @@ export class WolfpackClient {
660
677
  throw error;
661
678
  }
662
679
  }
663
- async createAgentTask(agentId, body) {
664
- return this.api.post(`/agents/${agentId}/tasks`, body);
680
+ async createAgentTask(agentId, body, orgSlug) {
681
+ return this.api.post(this.withOrgSlug(`/agents/${agentId}/tasks`, orgSlug), body);
665
682
  }
666
- async updateAgentTask(agentId, taskId, body) {
667
- return this.api.patch(`/agents/${agentId}/tasks/${taskId}`, body);
683
+ async updateAgentTask(agentId, taskId, body, orgSlug) {
684
+ return this.api.patch(this.withOrgSlug(`/agents/${agentId}/tasks/${taskId}`, orgSlug), body);
668
685
  }
669
- async runAgentTask(agentId, taskId, teamSlug) {
670
- return this.api.post(`/agents/${agentId}/tasks/${taskId}/run`, { teamSlug });
686
+ async runAgentTask(agentId, taskId, teamSlug, orgSlug) {
687
+ return this.api.post(this.withOrgSlug(`/agents/${agentId}/tasks/${taskId}/run`, orgSlug), { teamSlug });
671
688
  }
672
689
  // ─── Agent Builder: Queue ──────────────────────────────────────────────────
673
- async listAgentQueue(agentId, status) {
674
- const q = status ? `?status=${encodeURIComponent(status)}` : '';
675
- return this.api.get(`/agents/${agentId}/queue${q}`);
690
+ async listAgentQueue(agentId, status, orgSlug) {
691
+ const params = new URLSearchParams();
692
+ if (status)
693
+ params.append('status', status);
694
+ if (orgSlug)
695
+ params.append('org_slug', orgSlug);
696
+ const q = params.toString();
697
+ return this.api.get(`/agents/${agentId}/queue${q ? `?${q}` : ''}`);
676
698
  }
677
- async cancelQueueEntry(agentId, entryId) {
678
- return this.api.delete(`/agents/${agentId}/queue/${entryId}`).then(() => ({ success: true }));
699
+ async cancelQueueEntry(agentId, entryId, orgSlug) {
700
+ return this.api
701
+ .delete(this.withOrgSlug(`/agents/${agentId}/queue/${entryId}`, orgSlug))
702
+ .then(() => ({ success: true }));
679
703
  }
680
704
  // ─── Agent Builder: Secrets ────────────────────────────────────────────────
681
- async listAgentSecrets(agentId) {
682
- return this.api.get(`/agents/${agentId}/secrets`);
705
+ async listAgentSecrets(agentId, orgSlug) {
706
+ return this.api.get(this.withOrgSlug(`/agents/${agentId}/secrets`, orgSlug));
683
707
  }
684
- async setAgentSecret(agentId, name, value) {
685
- return this.api.post(`/agents/${agentId}/secrets`, { name, value });
708
+ async setAgentSecret(agentId, name, value, orgSlug) {
709
+ return this.api.post(this.withOrgSlug(`/agents/${agentId}/secrets`, orgSlug), { name, value });
686
710
  }
687
711
  // ─── Agent Builder: Skills (write) ────────────────────────────────────────
688
- async createSkill(body) {
689
- return this.api.post('/skills', body);
712
+ async createSkill(body, orgSlug) {
713
+ return this.api.post(this.withOrgSlug('/skills', orgSlug), body);
690
714
  }
691
- async updateSkill(skillId, body) {
692
- return this.api.patch(`/skills/${skillId}`, body);
715
+ async updateSkill(skillId, body, orgSlug) {
716
+ return this.api.patch(this.withOrgSlug(`/skills/${skillId}`, orgSlug), body);
693
717
  }
694
- async createSkillResource(skillId, body) {
695
- return this.api.post(`/skills/${skillId}/resources`, body);
718
+ async createSkillResource(skillId, body, orgSlug) {
719
+ return this.api.post(this.withOrgSlug(`/skills/${skillId}/resources`, orgSlug), body);
696
720
  }
697
- async updateSkillResource(skillId, resourceId, body) {
698
- return this.api.patch(`/skills/${skillId}/resources/${resourceId}`, body);
721
+ async updateSkillResource(skillId, resourceId, body, orgSlug) {
722
+ return this.api.patch(this.withOrgSlug(`/skills/${skillId}/resources/${resourceId}`, orgSlug), body);
699
723
  }
700
- async setAgentSkills(agentId, skillIds) {
701
- return this.api.post(`/skills/agent-assignments/${agentId}`, {
702
- skillIds,
703
- });
724
+ async setAgentSkills(agentId, skillIds, orgSlug) {
725
+ return this.api.post(this.withOrgSlug(`/skills/agent-assignments/${agentId}`, orgSlug), { skillIds });
704
726
  }
705
727
  // ─── Agent Builder: Skills (read) ──────────────────────────────────────────
706
728
  async listAgentSkills(agentId) {
707
729
  return this.api.get(`/skills/agent-profiles/${agentId}`);
708
730
  }
709
- async listOrgSkills() {
710
- return this.api.get('/agents/org-skills');
731
+ async listOrgSkills(orgSlug) {
732
+ return this.api.get(this.withOrgSlug('/agents/org-skills', orgSlug));
711
733
  }
712
- async getSkillDetail(name, agentId) {
734
+ async getSkillDetail(name, agentId, orgSlug) {
713
735
  try {
714
- const query = agentId ? `?agentProfileId=${agentId}` : '';
715
- return await this.api.get(`/agents/org-skills/${encodeURIComponent(name)}${query}`);
736
+ const params = new URLSearchParams();
737
+ if (agentId)
738
+ params.append('agentProfileId', agentId);
739
+ if (orgSlug)
740
+ params.append('org_slug', orgSlug);
741
+ const q = params.toString();
742
+ return await this.api.get(`/agents/org-skills/${encodeURIComponent(name)}${q ? `?${q}` : ''}`);
716
743
  }
717
744
  catch (error) {
718
745
  if (error && typeof error === 'object' && 'status' in error && error.status === 404)
@@ -721,11 +748,93 @@ export class WolfpackClient {
721
748
  }
722
749
  }
723
750
  // ─── Agent Builder: Discovery ──────────────────────────────────────────────
724
- async listAgentTemplates() {
725
- return this.api.get('/agent-builder/templates');
751
+ async listAgentTemplates(orgSlug) {
752
+ return this.api.get(this.withOrgSlug('/agent-builder/templates', orgSlug));
753
+ }
754
+ async listLlmModels(orgSlug) {
755
+ return this.api.get(this.withOrgSlug('/agent-builder/llm-models', orgSlug));
756
+ }
757
+ // ─── Procedures ──────────────────────────────────────────────────────────
758
+ async listProcedures(options) {
759
+ const params = new URLSearchParams();
760
+ if (options?.teamSlug)
761
+ params.append('teamSlug', options.teamSlug);
762
+ if (options?.search)
763
+ params.append('search', options.search);
764
+ if (options?.activeOnly)
765
+ params.append('activeOnly', 'true');
766
+ if (options?.limit !== undefined || options?.offset !== undefined) {
767
+ if (options?.limit)
768
+ params.append('limit', options.limit.toString());
769
+ if (options?.offset)
770
+ params.append('offset', options.offset.toString());
771
+ const query = params.toString();
772
+ const response = await this.api.get(`/procedures${query ? `?${query}` : ''}`);
773
+ if (!response || !Array.isArray(response.items)) {
774
+ throw new Error(`Invalid API response from /procedures: expected { items: [], total: number } but got ${JSON.stringify(response)}`);
775
+ }
776
+ return {
777
+ items: response.items,
778
+ total: response.total,
779
+ truncated: response.total > response.items.length,
780
+ };
781
+ }
782
+ return this.fetchAllPages('/procedures', params);
783
+ }
784
+ async getProcedure(procedureId, teamSlug) {
785
+ try {
786
+ const params = new URLSearchParams();
787
+ if (teamSlug)
788
+ params.append('teamSlug', teamSlug);
789
+ const query = params.toString();
790
+ return await this.api.get(`/procedures/${procedureId}${query ? `?${query}` : ''}`);
791
+ }
792
+ catch (error) {
793
+ if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
794
+ return null;
795
+ }
796
+ throw error;
797
+ }
798
+ }
799
+ async createProcedure(data) {
800
+ const { teamSlug, ...rest } = data;
801
+ return this.api.post('/procedures', { ...rest, teamSlug });
802
+ }
803
+ async updateProcedure(procedureId, data, teamSlug) {
804
+ return this.api.patch(this.withTeamSlug(`/procedures/${procedureId}`, teamSlug), data);
805
+ }
806
+ async deleteProcedure(procedureId, teamSlug) {
807
+ await this.api.delete(this.withTeamSlug(`/procedures/${procedureId}`, teamSlug));
808
+ return { success: true };
809
+ }
810
+ // ─── Agent Self-Introspection ──────────────────────────────────────────────
811
+ async getSelf() {
812
+ return this.api.get('/self');
813
+ }
814
+ async getOwnSessions(options) {
815
+ const params = new URLSearchParams();
816
+ if (options?.limit !== undefined)
817
+ params.append('limit', options.limit.toString());
818
+ if (options?.offset !== undefined)
819
+ params.append('offset', options.offset.toString());
820
+ const q = params.toString();
821
+ return this.api.get(`/self/sessions${q ? `?${q}` : ''}`);
822
+ }
823
+ async listMemories() {
824
+ return this.api.get('/self/memories');
825
+ }
826
+ async getMemory(key) {
827
+ try {
828
+ return await this.api.get(`/self/memories/${encodeURIComponent(key)}`);
829
+ }
830
+ catch (error) {
831
+ if (error && typeof error === 'object' && 'status' in error && error.status === 404)
832
+ return null;
833
+ throw error;
834
+ }
726
835
  }
727
- async listLlmModels() {
728
- return this.api.get('/agent-builder/llm-models');
836
+ async saveMemory(key, content) {
837
+ return this.api.put(`/self/memories/${encodeURIComponent(key)}`, { content });
729
838
  }
730
839
  close() {
731
840
  // No cleanup needed for API client
package/dist/config.js CHANGED
@@ -2,6 +2,7 @@ export const config = {
2
2
  apiUrl: process.env.WOLFPACK_API_URL || 'https://wolfpacks.work/api/mcp',
3
3
  apiKey: process.env.WOLFPACK_API_KEY,
4
4
  projectSlug: process.env.WOLFPACK_PROJECT_SLUG || process.env.WOLFPACK_TEAM_SLUG,
5
+ orgSlug: process.env.WOLFPACK_ORG_SLUG,
5
6
  };
6
7
  // Validate configuration on startup
7
8
  export function validateConfig() {
@@ -17,6 +18,9 @@ export function validateConfig() {
17
18
  process.exit(1);
18
19
  }
19
20
  console.error(`MCP Server connecting to: ${config.apiUrl}`);
21
+ if (config.orgSlug) {
22
+ console.error(`Organisation configured: ${config.orgSlug}`);
23
+ }
20
24
  if (config.projectSlug) {
21
25
  console.error(`Project configured: ${config.projectSlug}`);
22
26
  }
package/dist/index.js CHANGED
@@ -9,6 +9,8 @@ import { basename, extname, resolve } from 'path';
9
9
  import { WolfpackClient } from './client.js';
10
10
  import { validateConfig, config } from './config.js';
11
11
  import { AGENT_BUILDER_TOOLS, handleAgentBuilderTool } from './agentBuilderTools.js';
12
+ import { PROCEDURE_TOOLS, handleProcedureTool } from './procedureTools.js';
13
+ import { AGENT_SELF_TOOLS, handleAgentSelfTool } from './agentSelfTools.js';
12
14
  // Get current package version
13
15
  const require = createRequire(import.meta.url);
14
16
  const packageJson = require('../package.json');
@@ -46,8 +48,9 @@ async function checkForUpdates() {
46
48
  }
47
49
  // Cross-reference syntax for linking between content items in markdown fields
48
50
  const CONTENT_LINKING_HELP = 'CROSS-REFERENCES: In any markdown content, you can link to other items using these patterns: ' +
49
- '#123 or #w123 for work items, #i123 for issues, #r123 for initiatives/roadmap, ' +
50
- '#j123 for journal entries, #c123 for cases, #p123 for procedures. ' +
51
+ '#123, #w123, or #work-123 for work items (DEFAULT bare #N always means a work item), ' +
52
+ '#i123 or #issue-123 for issues, #r123 or #roadmap-123 for initiatives/roadmap, ' +
53
+ '#j123 or #journal-123 for journal entries, #c123 or #case-123 for cases, #p123 or #proc-123 for procedures. ' +
51
54
  'Use @username to mention team members (triggers notifications). ' +
52
55
  'Standard markdown links also work: [link text](/project/{slug}/work-items/123).';
53
56
  // Work Item schemas
@@ -643,7 +646,12 @@ class WolfpackMCPServer {
643
646
  '3) NEVER perform bulk actions across multiple projects - always work in one project at a time. ' +
644
647
  '4) If the user mentions a specific project, use that for all subsequent operations. ' +
645
648
  '5) If unclear which project to use, ASK the user before proceeding. ' +
646
- 'Returns project slugs, names, and types. Single-project users have their project auto-selected; multi-project users must specify project_slug in other tool calls.',
649
+ 'Returns project slugs, names, and types. Single-project users have their project auto-selected; multi-project users must specify project_slug in other tool calls. ' +
650
+ 'ID CONVENTION: A bare number like #1 or #42 ALWAYS refers to a WORK ITEM refId — use get_work_item. ' +
651
+ 'Other document types REQUIRE a prefix and are never bare numbers: ' +
652
+ '#i1 or #issue-1 for issues, #r1 or #roadmap-1 for roadmap/radar, ' +
653
+ '#j1 or #journal-1 for journal, #c1 or #case-1 for cases, #p1 or #proc-1 for procedures. ' +
654
+ 'Wiki pages are referenced by path (e.g. /docs/setup). There is no ambiguity: bare #N = work item.',
647
655
  inputSchema: {
648
656
  type: 'object',
649
657
  properties: {},
@@ -652,7 +660,8 @@ class WolfpackMCPServer {
652
660
  // Work Item tools
653
661
  {
654
662
  name: 'list_work_items',
655
- description: 'List work items (tasks/tickets) on the Kanban board or backlog. By default lists ALL items in the team, sorted by most recently updated. ' +
663
+ description: 'List work items (tasks/tickets) on the Kanban board or backlog. Work items are the PRIMARY entity bare #N references (e.g. "work on #1") always mean work items. ' +
664
+ 'By default lists ALL items in the team, sorted by most recently updated. ' +
656
665
  'Use assigned_to_id="me" to filter to only your assigned items. ' +
657
666
  'TERMINOLOGY: "board" and "kanban" are synonymous - both refer to the Kanban board of work items. ' +
658
667
  'The board has columns: "new" (to do), "doing" (in progress), "review" (pending review), "ready" (code done, awaiting deployment), "blocked", "completed" (deployed). ' +
@@ -717,7 +726,8 @@ class WolfpackMCPServer {
717
726
  },
718
727
  {
719
728
  name: 'get_work_item',
720
- description: 'Get a specific work item/task by reference number. Returns full details including description (markdown notes). ' +
729
+ description: 'Get a specific work item/task by reference number. This is the DEFAULT lookup when a user says "#1" or "work on #42" — bare #N always means a work item. ' +
730
+ 'Returns full details including description (markdown notes). ' +
721
731
  'Call this before updating to see current content. ' +
722
732
  'WORKFLOW: When asked to work on an item, check its status and follow the required state transitions ' +
723
733
  '(pending→pull first, new→doing, blocked/ready/completed/closed→new→doing, then review when done). ' +
@@ -1001,8 +1011,9 @@ class WolfpackMCPServer {
1001
1011
  name: 'list_issues',
1002
1012
  description: 'List issues from the Issue Tracker. Issues are a SEPARATE system from work items on the Kanban board. ' +
1003
1013
  'Issues track bugs, feature requests, and other reports that may or may not have associated work items. ' +
1014
+ 'Issues are referenced with the #i prefix (e.g. #i5). A bare #N (without prefix) is ALWAYS a work item, NOT an issue. ' +
1004
1015
  'IMPORTANT: If the user asks about "bugs" or "tasks" in the context of the "board", "kanban", or "backlog", use list_work_items instead - those are work items, not issues. ' +
1005
- 'Only use this tool when the user specifically asks about "issues", the "issue tracker", or is clearly referring to the issue tracking system. ' +
1016
+ 'Only use this tool when the user specifically asks about "issues", the "issue tracker", uses the #i prefix, or is clearly referring to the issue tracking system. ' +
1006
1017
  'Can filter by status, severity, and type.',
1007
1018
  inputSchema: {
1008
1019
  type: 'object',
@@ -1057,7 +1068,9 @@ class WolfpackMCPServer {
1057
1068
  },
1058
1069
  {
1059
1070
  name: 'get_issue',
1060
- description: 'Get a specific issue by reference number, including comment and attachment counts. ' +
1071
+ description: 'Get a specific issue by its PREFIXED reference #iN (e.g. #i5). ' +
1072
+ 'IMPORTANT: A bare #N (without prefix) is ALWAYS a work item, NOT an issue. Only use this tool when the user explicitly says "issue" or uses the #i prefix. ' +
1073
+ 'Returns full details including comment and attachment counts. ' +
1061
1074
  'IMAGES: Image references in the description (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
1062
1075
  inputSchema: {
1063
1076
  type: 'object',
@@ -1863,6 +1876,8 @@ class WolfpackMCPServer {
1863
1876
  required: ['discussion_id', 'content'],
1864
1877
  },
1865
1878
  },
1879
+ ...(this.capabilities.includes('procedures') ? PROCEDURE_TOOLS : []),
1880
+ ...(this.capabilities.includes('agent_self') ? AGENT_SELF_TOOLS : []),
1866
1881
  ...(this.capabilities.includes('agent_builder') ? AGENT_BUILDER_TOOLS : []),
1867
1882
  ],
1868
1883
  }));
@@ -2702,6 +2717,21 @@ class WolfpackMCPServer {
2702
2717
  };
2703
2718
  }
2704
2719
  default: {
2720
+ // Check procedure tools
2721
+ if (this.capabilities.includes('procedures')) {
2722
+ const procedureToolNames = PROCEDURE_TOOLS.map((t) => t.name);
2723
+ if (procedureToolNames.includes(name)) {
2724
+ return handleProcedureTool(name, args, this.client);
2725
+ }
2726
+ }
2727
+ // Check agent self tools
2728
+ if (this.capabilities.includes('agent_self')) {
2729
+ const selfToolNames = AGENT_SELF_TOOLS.map((t) => t.name);
2730
+ if (selfToolNames.includes(name)) {
2731
+ return handleAgentSelfTool(name, args, this.client);
2732
+ }
2733
+ }
2734
+ // Check agent builder tools
2705
2735
  if (this.capabilities.includes('agent_builder')) {
2706
2736
  return handleAgentBuilderTool(name, args, this.client);
2707
2737
  }