@askmesh/mcp 0.3.1 → 0.4.1

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/README.md CHANGED
@@ -62,11 +62,10 @@ One single tool `askmesh` — Claude understands natural language:
62
62
 
63
63
  ## Auto-responder
64
64
 
65
- Questions are answered automatically using 3 strategies (in order):
65
+ When a question arrives, your agent responds automatically:
66
66
 
67
- 1. **MCP Sampling** — asks your active Claude Code to respond (no extra config)
68
- 2. **Anthropic API** — reads your CLAUDE.md + memories, calls Claude API (requires `ANTHROPIC_API_KEY`)
69
- 3. **Manual** — question stays pending, respond via `askmesh(action:"pending")`
67
+ 1. **MCP Sampling** — asks your active Claude Code to respond using your CLAUDE.md, memories, and project context. Uses your existing Claude subscription — no API key needed.
68
+ 2. **Manual fallback** — if sampling unavailable, question stays pending. Respond via `askmesh(action:"pending")`.
70
69
 
71
70
  ## Environment variables
72
71
 
@@ -74,7 +73,6 @@ Questions are answered automatically using 3 strategies (in order):
74
73
  |---|---|---|
75
74
  | `ASKMESH_TOKEN` | Yes | Your agent API token from askmesh.dev |
76
75
  | `ASKMESH_URL` | No | API URL (default: `https://api.askmesh.dev`) |
77
- | `ANTHROPIC_API_KEY` | No | Enables auto-responses via Claude API when MCP sampling unavailable |
78
76
 
79
77
  ## How it works
80
78
 
@@ -7,5 +7,4 @@ export declare class AutoResponder {
7
7
  constructor(client: AskMeshClient);
8
8
  setServer(server: Server): void;
9
9
  handleRequest(request: IncomingRequest): Promise<void>;
10
- private callAnthropicAPI;
11
10
  }
@@ -11,8 +11,11 @@ export class AutoResponder {
11
11
  async handleRequest(request) {
12
12
  console.error(`[AskMesh] Question from @${request.fromUsername}: "${request.question}"`);
13
13
  // Strategy 1: MCP sampling — asks the active Claude Code to respond
14
+ // Uses the user's existing Claude subscription, no API key needed
14
15
  if (this.mcpServer) {
15
16
  try {
17
+ // Include local context in the sampling request
18
+ const context = readLocalContext();
16
19
  const result = (await this.mcpServer.request({
17
20
  method: 'sampling/createMessage',
18
21
  params: {
@@ -24,10 +27,15 @@ export class AutoResponder {
24
27
  text: [
25
28
  `A teammate @${request.fromUsername} is asking you a question via AskMesh.`,
26
29
  ``,
30
+ `Your project context:`,
31
+ context,
32
+ ``,
33
+ `---`,
34
+ ``,
27
35
  `Question: "${request.question}"`,
28
- request.context ? `\nContext: ${request.context}` : '',
36
+ request.context ? `\nAdditional context: ${request.context}` : '',
29
37
  ``,
30
- `Answer based on your knowledge of this project. Be concise and technical.`,
38
+ `Answer based on this project context. Be concise and technical.`,
31
39
  `Answer in the same language as the question.`,
32
40
  ].join('\n'),
33
41
  },
@@ -39,63 +47,15 @@ export class AutoResponder {
39
47
  const answer = result?.content?.text || result?.content?.[0]?.text;
40
48
  if (answer) {
41
49
  await this.client.answerRequest(request.id, answer);
42
- console.error(`[AskMesh] Responded to #${request.id} via MCP sampling`);
50
+ console.error(`[AskMesh] Responded to #${request.id} via Claude Code`);
43
51
  return;
44
52
  }
45
53
  }
46
54
  catch {
47
- console.error('[AskMesh] MCP sampling not available, trying API fallback...');
55
+ console.error('[AskMesh] MCP sampling not available');
48
56
  }
49
57
  }
50
- // Strategy 2: Direct Anthropic API with local context
51
- const apiKey = process.env.ANTHROPIC_API_KEY;
52
- if (apiKey) {
53
- try {
54
- const context = readLocalContext();
55
- const answer = await this.callAnthropicAPI(apiKey, request, context);
56
- if (answer) {
57
- await this.client.answerRequest(request.id, answer);
58
- console.error(`[AskMesh] Responded to #${request.id} via Anthropic API`);
59
- return;
60
- }
61
- }
62
- catch (err) {
63
- console.error('[AskMesh] Anthropic API failed:', err);
64
- }
65
- }
66
- // Strategy 3: Manual — question stays pending
67
- console.error(`[AskMesh] Question #${request.id} queued — use askmesh(action:"pending") to see and respond`);
68
- }
69
- async callAnthropicAPI(apiKey, request, context) {
70
- const response = await fetch('https://api.anthropic.com/v1/messages', {
71
- method: 'POST',
72
- headers: {
73
- 'x-api-key': apiKey,
74
- 'anthropic-version': '2023-06-01',
75
- 'content-type': 'application/json',
76
- },
77
- body: JSON.stringify({
78
- model: 'claude-sonnet-4-20250514',
79
- max_tokens: 2048,
80
- system: `You are an AI coding agent responding on behalf of a developer through AskMesh.
81
- You have access to the developer's project context below.
82
- Use this context to answer the question accurately and concisely.
83
- Reference specific files, conventions, or decisions from the context when relevant.
84
- If the context doesn't contain enough info, say so honestly.
85
- Answer in the same language as the question.
86
- Keep responses under 500 words unless more detail is needed.`,
87
- messages: [
88
- {
89
- role: 'user',
90
- content: `Project context:\n\n${context}\n\n---\n\nQuestion from @${request.fromUsername}:\n${request.question}${request.context ? `\n\nAdditional context: ${request.context}` : ''}`,
91
- },
92
- ],
93
- }),
94
- });
95
- if (!response.ok) {
96
- throw new Error(`Anthropic API ${response.status}: ${await response.text()}`);
97
- }
98
- const data = (await response.json());
99
- return data.content?.[0]?.text || null;
58
+ // Strategy 2: Manual question stays pending
59
+ console.error(`[AskMesh] Question #${request.id} queued — use askmesh(action:"pending") to respond`);
100
60
  }
101
61
  }
@@ -13,6 +13,17 @@ export declare class AskMeshClient {
13
13
  answer: string | null;
14
14
  question: string;
15
15
  }>;
16
+ getSentRequests(): Promise<{
17
+ requests: Array<{
18
+ id: number;
19
+ toUsername: string;
20
+ question: string;
21
+ status: string;
22
+ answer: string | null;
23
+ answeredAt: string | null;
24
+ createdAt: string;
25
+ }>;
26
+ }>;
16
27
  getPendingRequests(): Promise<{
17
28
  requests: Array<{
18
29
  id: number;
@@ -29,6 +29,14 @@ export class AskMeshClient {
29
29
  throw new Error(`getRequest failed: ${res.status}`);
30
30
  return res.json();
31
31
  }
32
+ async getSentRequests() {
33
+ const res = await fetch(`${this.baseUrl}/api/v1/requests/sent`, {
34
+ headers: this.headers(),
35
+ });
36
+ if (!res.ok)
37
+ throw new Error(`getSent failed: ${res.status}`);
38
+ return res.json();
39
+ }
32
40
  async getPendingRequests() {
33
41
  const res = await fetch(`${this.baseUrl}/api/v1/requests/pending`, {
34
42
  headers: this.headers(),
@@ -7,9 +7,10 @@ Actions:
7
7
  - "list" : liste les agents de tes teams et leur statut
8
8
  - "status" : vérifie si un agent est disponible
9
9
  - "pending" : voir les questions qu'on t'a posées
10
+ - "inbox" : voir les réponses aux questions que tu as envoyées
10
11
  - "answer" : répondre à une question en attente
11
12
  - "context" : partager ton contexte projet avec ta team`, {
12
- action: z.enum(['ask', 'list', 'status', 'pending', 'answer', 'context']).describe('Action à effectuer'),
13
+ action: z.enum(['ask', 'list', 'status', 'pending', 'inbox', 'answer', 'context']).describe('Action à effectuer'),
13
14
  username: z.string().optional().describe("Username de l'agent cible (pour ask/status)"),
14
15
  question: z.string().optional().describe('Question à poser (pour ask)'),
15
16
  requestId: z.number().optional().describe('ID de la requête (pour answer)'),
@@ -61,6 +62,19 @@ Actions:
61
62
  const lines = requests.map((r) => `#${r.id} — "${r.question}"`);
62
63
  return text(`Questions en attente:\n${lines.join('\n')}\n\nUtilise action "answer" avec requestId et message pour répondre.`);
63
64
  }
65
+ case 'inbox': {
66
+ const { requests } = await client.getSentRequests();
67
+ if (requests.length === 0)
68
+ return text('Aucune question envoyée.');
69
+ const lines = requests.map((r) => {
70
+ const status = r.status === 'answered' ? '✅' : '⏳';
71
+ let line = `${status} #${r.id} → @${r.toUsername}: "${r.question}"`;
72
+ if (r.answer)
73
+ line += `\n Réponse: ${r.answer}`;
74
+ return line;
75
+ });
76
+ return text(`Questions envoyées:\n\n${lines.join('\n\n')}`);
77
+ }
64
78
  case 'answer': {
65
79
  if (!requestId || !message) {
66
80
  return text("Paramètres requis : requestId et message");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askmesh/mcp",
3
- "version": "0.3.1",
3
+ "version": "0.4.1",
4
4
  "description": "AskMesh MCP server — connect your AI coding agent to your team's mesh network",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,7 +32,6 @@
32
32
  "homepage": "https://askmesh.dev",
33
33
  "license": "MIT",
34
34
  "dependencies": {
35
- "@anthropic-ai/sdk": "^0.80.0",
36
35
  "@modelcontextprotocol/sdk": "^1.0.0",
37
36
  "eventsource": "^2.0.2",
38
37
  "zod": "^4.3.6"