@agent-tasks/mcp-server 0.1.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/README.md ADDED
@@ -0,0 +1,108 @@
1
+ # @agent-tasks/mcp-server
2
+
3
+ MCP server that exposes the [agent-tasks](https://agent-tasks.opentriologue.ai) API
4
+ as tools so MCP-capable clients (Claude Code, Cursor, Cline, triologue, …) can
5
+ drive the full task lifecycle without writing REST boilerplate.
6
+
7
+ It is a thin wrapper: all governance rules (confidence gates, preconditions,
8
+ review locks, audit trail) are enforced by the agent-tasks backend. The MCP
9
+ server just translates tool calls into authenticated HTTP requests.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ # once published
15
+ npx @agent-tasks/mcp-server
16
+
17
+ # or build from this workspace
18
+ npm run build --workspace=mcp-server
19
+ node mcp-server/dist/index.js
20
+ ```
21
+
22
+ ## Configuration
23
+
24
+ Two environment variables:
25
+
26
+ | Variable | Required | Default |
27
+ | ---------------------- | -------- | ---------------------------------------- |
28
+ | `AGENT_TASKS_TOKEN` | yes | — |
29
+ | `AGENT_TASKS_BASE_URL` | no | `https://agent-tasks.opentriologue.ai` |
30
+
31
+ Obtain a token from the agent-tasks UI under **Settings → Agent Tokens**.
32
+ The token scope determines which tools succeed at runtime; tools that require
33
+ missing scopes return an API error describing the missing scope.
34
+
35
+ ## Claude Code setup
36
+
37
+ Register globally for your user so the server is available in every project:
38
+
39
+ ```bash
40
+ claude mcp add agent-tasks \
41
+ --scope user \
42
+ --env AGENT_TASKS_TOKEN=atk_xxx \
43
+ -- npx -y @agent-tasks/mcp-server
44
+ ```
45
+
46
+ Drop `--scope user` if you want it project-local instead. See
47
+ `claude mcp add --help` for the full list of scopes and options.
48
+
49
+ ## Tools
50
+
51
+ | Tool | Wraps |
52
+ | -------------------- | -------------------------------------------- |
53
+ | `projects_list` | `GET /api/projects/available` |
54
+ | `tasks_list` | `GET /api/tasks/claimable` |
55
+ | `tasks_get` | `GET /api/tasks/:id` |
56
+ | `tasks_instructions` | `GET /api/tasks/:id/instructions` |
57
+ | `tasks_create` | `POST /api/projects/:projectId/tasks` |
58
+ | `tasks_claim` | `POST /api/tasks/:id/claim` |
59
+ | `tasks_release` | `POST /api/tasks/:id/release` |
60
+ | `tasks_transition` | `POST /api/tasks/:id/transition` |
61
+ | `tasks_update` | `PATCH /api/tasks/:id` |
62
+ | `tasks_comment` | `POST /api/tasks/:id/comments` |
63
+ | `signals_poll` | `GET /api/agent/signals` |
64
+ | `signals_ack` | `POST /api/agent/signals/:id/ack` |
65
+
66
+ All tools return the raw JSON response from the backend as a text block.
67
+
68
+ ## Transport
69
+
70
+ This package ships **stdio** only. It is the recommended path for
71
+ local Claude Code / Cursor / Cline integrations — one `npx` command,
72
+ no running server to maintain, no network hop.
73
+
74
+ ### Remote clients: use the backend's `/api/mcp` endpoint instead
75
+
76
+ Remote MCP clients that speak HTTP + JSON-RPC (e.g. Triologue's
77
+ `mcpBridge.ts`) cannot drive a stdio child process across a network
78
+ boundary. For those, the agent-tasks backend exposes the **same 12
79
+ tools** over HTTP at `POST /api/mcp`:
80
+
81
+ ```bash
82
+ # Example: discover tools on a remote gateway
83
+ curl -X POST https://agent-tasks.opentriologue.ai/api/mcp \
84
+ -H "Authorization: Bearer <agent_token>" \
85
+ -H "Content-Type: application/json" \
86
+ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
87
+ ```
88
+
89
+ - Stateless Streamable HTTP (no session ID, one round-trip per
90
+ request)
91
+ - Same Bearer auth as the rest of the agent-tasks REST API
92
+ - Same tools, same schemas, same governance — the HTTP handler
93
+ dispatches every tool call back through the same Hono app stack
94
+ the REST routes live on, so the code paths stay in sync with zero
95
+ duplication
96
+ - GET / DELETE on `/api/mcp` return 405 with `Allow: POST`
97
+
98
+ Pick stdio (this package) for local agents; pick `/api/mcp` for
99
+ remote / server-side consumers.
100
+
101
+ ## Development
102
+
103
+ ```bash
104
+ npm install
105
+ npm run dev --workspace=mcp-server # tsx watch
106
+ npm run build --workspace=mcp-server # tsc -> dist/
107
+ npm run typecheck --workspace=mcp-server
108
+ ```
@@ -0,0 +1,45 @@
1
+ export interface ClientConfig {
2
+ baseUrl: string;
3
+ token: string;
4
+ }
5
+ export declare class AgentTasksApiError extends Error {
6
+ status: number;
7
+ body: unknown;
8
+ constructor(status: number, body: unknown, message: string);
9
+ }
10
+ export declare class AgentTasksClient {
11
+ private readonly config;
12
+ constructor(config: ClientConfig);
13
+ private request;
14
+ listProjects(): Promise<unknown>;
15
+ listClaimableTasks(params?: {
16
+ limit?: number;
17
+ }): Promise<unknown>;
18
+ getTask(taskId: string): Promise<unknown>;
19
+ getTaskInstructions(taskId: string): Promise<unknown>;
20
+ createTask(projectId: string, input: {
21
+ title: string;
22
+ description?: string;
23
+ priority?: "LOW" | "MEDIUM" | "HIGH" | "CRITICAL";
24
+ workflowId?: string;
25
+ dueAt?: string;
26
+ externalRef?: string;
27
+ labels?: string[];
28
+ }): Promise<unknown>;
29
+ claimTask(taskId: string): Promise<unknown>;
30
+ releaseTask(taskId: string): Promise<unknown>;
31
+ transitionTask(taskId: string, input: {
32
+ status: string;
33
+ force?: boolean;
34
+ forceReason?: string;
35
+ }): Promise<unknown>;
36
+ updateTask(taskId: string, input: {
37
+ branchName?: string | null;
38
+ prUrl?: string | null;
39
+ prNumber?: number | null;
40
+ result?: string | null;
41
+ }): Promise<unknown>;
42
+ addTaskComment(taskId: string, content: string): Promise<unknown>;
43
+ pollSignals(): Promise<unknown>;
44
+ ackSignal(signalId: string): Promise<unknown>;
45
+ }
package/dist/client.js ADDED
@@ -0,0 +1,88 @@
1
+ export class AgentTasksApiError extends Error {
2
+ status;
3
+ body;
4
+ constructor(status, body, message) {
5
+ super(message);
6
+ this.status = status;
7
+ this.body = body;
8
+ this.name = "AgentTasksApiError";
9
+ }
10
+ }
11
+ export class AgentTasksClient {
12
+ config;
13
+ constructor(config) {
14
+ this.config = config;
15
+ }
16
+ async request(method, path, body) {
17
+ const url = `${this.config.baseUrl.replace(/\/$/, "")}${path}`;
18
+ const headers = {
19
+ Authorization: `Bearer ${this.config.token}`,
20
+ Accept: "application/json",
21
+ };
22
+ if (body !== undefined) {
23
+ headers["Content-Type"] = "application/json";
24
+ }
25
+ const res = await fetch(url, {
26
+ method,
27
+ headers,
28
+ body: body === undefined ? undefined : JSON.stringify(body),
29
+ });
30
+ const text = await res.text();
31
+ let parsed = undefined;
32
+ if (text.length > 0) {
33
+ try {
34
+ parsed = JSON.parse(text);
35
+ }
36
+ catch {
37
+ parsed = text;
38
+ }
39
+ }
40
+ if (!res.ok) {
41
+ const msg = (parsed && typeof parsed === "object" && "message" in parsed
42
+ ? String(parsed.message)
43
+ : undefined) ?? `${method} ${path} failed: ${res.status}`;
44
+ throw new AgentTasksApiError(res.status, parsed, msg);
45
+ }
46
+ return parsed;
47
+ }
48
+ listProjects() {
49
+ return this.request("GET", "/api/projects/available");
50
+ }
51
+ listClaimableTasks(params) {
52
+ const qs = params?.limit !== undefined ? `?limit=${params.limit}` : "";
53
+ return this.request("GET", `/api/tasks/claimable${qs}`);
54
+ }
55
+ getTask(taskId) {
56
+ return this.request("GET", `/api/tasks/${taskId}`);
57
+ }
58
+ getTaskInstructions(taskId) {
59
+ return this.request("GET", `/api/tasks/${taskId}/instructions`);
60
+ }
61
+ createTask(projectId, input) {
62
+ return this.request("POST", `/api/projects/${projectId}/tasks`, input);
63
+ }
64
+ claimTask(taskId) {
65
+ return this.request("POST", `/api/tasks/${taskId}/claim`);
66
+ }
67
+ releaseTask(taskId) {
68
+ return this.request("POST", `/api/tasks/${taskId}/release`);
69
+ }
70
+ transitionTask(taskId, input) {
71
+ return this.request("POST", `/api/tasks/${taskId}/transition`, input);
72
+ }
73
+ updateTask(taskId, input) {
74
+ return this.request("PATCH", `/api/tasks/${taskId}`, input);
75
+ }
76
+ addTaskComment(taskId, content) {
77
+ return this.request("POST", `/api/tasks/${taskId}/comments`, {
78
+ content,
79
+ });
80
+ }
81
+ pollSignals() {
82
+ return this.request("GET", "/api/agent/signals");
83
+ }
84
+ ackSignal(signalId) {
85
+ return this.request("POST", `/api/agent/signals/${signalId}/ack`);
86
+ }
87
+ }
88
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ import { runStdioServer, DEFAULT_BASE_URL } from "./server.js";
3
+ function resolveConfig() {
4
+ const token = process.env.AGENT_TASKS_TOKEN;
5
+ if (!token) {
6
+ throw new Error("AGENT_TASKS_TOKEN env var is required. Obtain a token from the agent-tasks UI under Settings → Agent Tokens.");
7
+ }
8
+ const baseUrl = process.env.AGENT_TASKS_BASE_URL ?? DEFAULT_BASE_URL;
9
+ return { token, baseUrl };
10
+ }
11
+ runStdioServer(resolveConfig()).catch((err) => {
12
+ // eslint-disable-next-line no-console
13
+ console.error("[agent-tasks-mcp] fatal:", err);
14
+ process.exit(1);
15
+ });
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/D,SAAS,aAAa;IACpB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,8GAA8G,CAC/G,CAAC;IACJ,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,gBAAgB,CAAC;IACrE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC5B,CAAC;AAED,cAAc,CAAC,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAC5C,sCAAsC;IACtC,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,GAAG,CAAC,CAAC;IAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type ClientConfig } from "./client.js";
3
+ export declare const DEFAULT_BASE_URL = "https://agent-tasks.opentriologue.ai";
4
+ export declare const SERVER_NAME = "agent-tasks-mcp";
5
+ export declare const SERVER_VERSION = "0.1.0";
6
+ export declare function createServer(config: ClientConfig): McpServer;
7
+ export declare function runStdioServer(config: ClientConfig): Promise<void>;
8
+ export { AgentTasksClient, type ClientConfig } from "./client.js";
9
+ export { buildTools } from "./tools.js";
package/dist/server.js ADDED
@@ -0,0 +1,51 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { AgentTasksClient } from "./client.js";
4
+ import { buildTools } from "./tools.js";
5
+ export const DEFAULT_BASE_URL = "https://agent-tasks.opentriologue.ai";
6
+ export const SERVER_NAME = "agent-tasks-mcp";
7
+ export const SERVER_VERSION = "0.1.0";
8
+ export function createServer(config) {
9
+ const client = new AgentTasksClient(config);
10
+ const tools = buildTools(client);
11
+ const server = new McpServer({
12
+ name: SERVER_NAME,
13
+ version: SERVER_VERSION,
14
+ });
15
+ for (const tool of tools) {
16
+ server.registerTool(tool.name, {
17
+ description: tool.description,
18
+ inputSchema: tool.inputShape,
19
+ }, async (args) => {
20
+ try {
21
+ const result = await tool.handler(args);
22
+ return {
23
+ content: [
24
+ {
25
+ type: "text",
26
+ text: typeof result === "string"
27
+ ? result
28
+ : JSON.stringify(result, null, 2),
29
+ },
30
+ ],
31
+ };
32
+ }
33
+ catch (err) {
34
+ const message = err instanceof Error ? err.message : String(err);
35
+ return {
36
+ isError: true,
37
+ content: [{ type: "text", text: message }],
38
+ };
39
+ }
40
+ });
41
+ }
42
+ return server;
43
+ }
44
+ export async function runStdioServer(config) {
45
+ const server = createServer(config);
46
+ const transport = new StdioServerTransport();
47
+ await server.connect(transport);
48
+ }
49
+ export { AgentTasksClient } from "./client.js";
50
+ export { buildTools } from "./tools.js";
51
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAqB,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,CAAC,MAAM,gBAAgB,GAAG,sCAAsC,CAAC;AACvE,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAC7C,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAEtC,MAAM,UAAU,YAAY,CAAC,MAAoB;IAC/C,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAEjC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,cAAc;KACxB,CAAC,CAAC;IAEH,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,CAAC,YAAY,CACjB,IAAI,CAAC,IAAI,EACT;YACE,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,UAAU;SAC7B,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;YACb,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAa,CAAC,CAAC;gBACjD,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EACF,OAAO,MAAM,KAAK,QAAQ;gCACxB,CAAC,CAAC,MAAM;gCACR,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;yBACtC;qBACF;iBACF,CAAC;YACJ,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACjE,OAAO;oBACL,OAAO,EAAE,IAAI;oBACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;iBAC3C,CAAC;YACJ,CAAC;QACH,CAAC,CACF,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAoB;IACvD,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,OAAO,EAAE,gBAAgB,EAAqB,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { z, ZodRawShape } from "zod";
2
+ import { AgentTasksClient } from "./client.js";
3
+ export interface ToolDefinition<Shape extends ZodRawShape = ZodRawShape> {
4
+ name: string;
5
+ description: string;
6
+ inputShape: Shape;
7
+ handler: (args: z.objectOutputType<Shape, z.ZodTypeAny>) => Promise<unknown>;
8
+ }
9
+ export declare function buildTools(client: AgentTasksClient): ToolDefinition[];
package/dist/tools.js ADDED
@@ -0,0 +1,132 @@
1
+ import { z } from "zod";
2
+ import { AgentTasksApiError } from "./client.js";
3
+ const transitionStatusEnum = z.enum([
4
+ "open",
5
+ "in_progress",
6
+ "review",
7
+ "done",
8
+ ]);
9
+ const priorityEnum = z.enum(["LOW", "MEDIUM", "HIGH", "CRITICAL"]);
10
+ const uuid = () => z.string().uuid();
11
+ async function wrap(fn) {
12
+ try {
13
+ return await fn();
14
+ }
15
+ catch (err) {
16
+ if (err instanceof AgentTasksApiError) {
17
+ const detail = err.body
18
+ ? ` — ${typeof err.body === "string" ? err.body : JSON.stringify(err.body)}`
19
+ : "";
20
+ throw new Error(`agent-tasks API ${err.status}: ${err.message}${detail}`);
21
+ }
22
+ throw err;
23
+ }
24
+ }
25
+ function def(d) {
26
+ return d;
27
+ }
28
+ export function buildTools(client) {
29
+ return [
30
+ def({
31
+ name: "projects_list",
32
+ description: "List all projects visible to the authenticated actor. Returns id, slug, name, and GitHub repo for each.",
33
+ inputShape: {},
34
+ handler: async () => wrap(() => client.listProjects()),
35
+ }),
36
+ def({
37
+ name: "tasks_list",
38
+ description: "List tasks that the authenticated actor may claim (status=open, not blocked, not already claimed). Supports an optional limit.",
39
+ inputShape: {
40
+ limit: z.number().int().positive().max(500).optional(),
41
+ },
42
+ handler: async ({ limit }) => wrap(() => client.listClaimableTasks({ limit })),
43
+ }),
44
+ def({
45
+ name: "tasks_get",
46
+ description: "Fetch a single task by id, including comments and dependencies.",
47
+ inputShape: { taskId: uuid() },
48
+ handler: async ({ taskId }) => wrap(() => client.getTask(taskId)),
49
+ }),
50
+ def({
51
+ name: "tasks_instructions",
52
+ description: "Fetch agent-facing instructions for a task: current state, allowed transitions, confidence score, required-field checklist, and updatable fields.",
53
+ inputShape: { taskId: uuid() },
54
+ handler: async ({ taskId }) => wrap(() => client.getTaskInstructions(taskId)),
55
+ }),
56
+ def({
57
+ name: "tasks_create",
58
+ description: "Create a new task in a project. Only title is required. Use externalRef as an idempotency key for bulk imports — the backend dedupes on (projectId, externalRef).",
59
+ inputShape: {
60
+ projectId: uuid(),
61
+ title: z.string().min(1).max(255),
62
+ description: z.string().optional(),
63
+ priority: priorityEnum.optional(),
64
+ workflowId: uuid().optional(),
65
+ dueAt: z.string().datetime().optional(),
66
+ externalRef: z.string().trim().min(1).max(255).optional(),
67
+ labels: z
68
+ .array(z.string().trim().min(1).max(100))
69
+ .max(20)
70
+ .optional(),
71
+ },
72
+ handler: async ({ projectId, ...input }) => wrap(() => client.createTask(projectId, input)),
73
+ }),
74
+ def({
75
+ name: "tasks_claim",
76
+ description: "Claim a task as the authenticated actor. Fails if the task is already claimed, blocked, or not in a claimable state.",
77
+ inputShape: { taskId: uuid() },
78
+ handler: async ({ taskId }) => wrap(() => client.claimTask(taskId)),
79
+ }),
80
+ def({
81
+ name: "tasks_release",
82
+ description: "Release a previously claimed task, returning it to the claimable pool.",
83
+ inputShape: { taskId: uuid() },
84
+ handler: async ({ taskId }) => wrap(() => client.releaseTask(taskId)),
85
+ }),
86
+ def({
87
+ name: "tasks_transition",
88
+ description: "Transition a task to a new status. Preconditions from the task's workflow (branchPresent, prMerged, ciGreen, …) are enforced server-side. Use force=true with a forceReason only when you have explicit authorization to bypass gates.",
89
+ inputShape: {
90
+ taskId: uuid(),
91
+ status: transitionStatusEnum,
92
+ force: z.boolean().optional(),
93
+ forceReason: z.string().max(500).optional(),
94
+ },
95
+ handler: async ({ taskId, ...input }) => wrap(() => client.transitionTask(taskId, input)),
96
+ }),
97
+ def({
98
+ name: "tasks_update",
99
+ description: "Update mutable fields on a task: branchName, prUrl, prNumber, result. Pass null to clear a field.",
100
+ inputShape: {
101
+ taskId: uuid(),
102
+ branchName: z.string().max(255).nullable().optional(),
103
+ prUrl: z.string().url().nullable().optional(),
104
+ prNumber: z.number().int().positive().nullable().optional(),
105
+ result: z.string().nullable().optional(),
106
+ },
107
+ handler: async ({ taskId, ...input }) => wrap(() => client.updateTask(taskId, input)),
108
+ }),
109
+ def({
110
+ name: "tasks_comment",
111
+ description: "Add a comment to a task. Useful for logging progress, asking human reviewers for clarification, or recording decisions.",
112
+ inputShape: {
113
+ taskId: uuid(),
114
+ content: z.string().min(1).max(5000),
115
+ },
116
+ handler: async ({ taskId, content }) => wrap(() => client.addTaskComment(taskId, content)),
117
+ }),
118
+ def({
119
+ name: "signals_poll",
120
+ description: "Poll the signal inbox for the authenticated agent. Signals represent state changes the agent should react to (task claimed, review requested, force-transition, …).",
121
+ inputShape: {},
122
+ handler: async () => wrap(() => client.pollSignals()),
123
+ }),
124
+ def({
125
+ name: "signals_ack",
126
+ description: "Acknowledge a signal by id. Acknowledged signals are removed from the inbox.",
127
+ inputShape: { signalId: uuid() },
128
+ handler: async ({ signalId }) => wrap(() => client.ackSignal(signalId)),
129
+ }),
130
+ ];
131
+ }
132
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@agent-tasks/mcp-server",
3
+ "version": "0.1.0",
4
+ "description": "MCP server exposing the agent-tasks API as tools for MCP-capable clients",
5
+ "homepage": "https://github.com/LanNguyenSi/agent-tasks/tree/master/mcp-server#readme",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/LanNguyenSi/agent-tasks.git",
9
+ "directory": "mcp-server"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/LanNguyenSi/agent-tasks/issues"
13
+ },
14
+ "license": "MIT",
15
+ "type": "module",
16
+ "bin": {
17
+ "agent-tasks-mcp": "./dist/index.js"
18
+ },
19
+ "main": "./dist/server.js",
20
+ "types": "./dist/server.d.ts",
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/server.d.ts",
24
+ "import": "./dist/server.js"
25
+ }
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "README.md"
30
+ ],
31
+ "publishConfig": {
32
+ "access": "public",
33
+ "provenance": true
34
+ },
35
+ "scripts": {
36
+ "build": "tsc",
37
+ "dev": "tsx watch src/index.ts",
38
+ "start": "node dist/index.js",
39
+ "test": "vitest run",
40
+ "typecheck": "tsc --noEmit"
41
+ },
42
+ "dependencies": {
43
+ "@modelcontextprotocol/sdk": "^1.29.0",
44
+ "zod": "^3.23.8"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^22.0.0",
48
+ "tsx": "^4.19.0",
49
+ "typescript": "^5.6.0",
50
+ "vitest": "^2.1.0"
51
+ },
52
+ "engines": {
53
+ "node": ">=22"
54
+ }
55
+ }