tascan-mcp 1.0.1 → 2.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.
Files changed (3) hide show
  1. package/README.md +180 -101
  2. package/index.js +199 -1
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -1,153 +1,232 @@
1
- # MCP Registry
1
+ # TaScan MCP Server
2
2
 
3
- The MCP registry provides MCP clients with a list of MCP servers, like an app store for MCP servers.
3
+ AI agent integration for [TaScan](https://tascan.io) — the closed-loop autonomous operations protocol. Manage projects, events, tasks, workers, QR codes, templates, completion reports, and AI-powered issue resolution through Claude, GitHub Copilot, or any MCP-compatible AI client.
4
4
 
5
- [**📤 Publish my MCP server**](docs/modelcontextprotocol-io/quickstart.mdx) | [**⚡️ Live API docs**](https://registry.modelcontextprotocol.io/docs) | [**👀 Ecosystem vision**](docs/design/ecosystem-vision.md) | 📖 **[Full documentation](./docs)**
5
+ **Scan. Task. Done.**
6
6
 
7
- ## Development Status
7
+ ## What is TaScan?
8
8
 
9
- **2025-10-24 update**: The Registry API has entered an **API freeze (v0.1)** 🎉. For the next month or more, the API will remain stable with no breaking changes, allowing integrators to confidently implement support. This freeze applies to v0.1 while development continues on v0. We'll use this period to validate the API in real-world integrations and gather feedback to shape v1 for general availability. Thank you to everyone for your contributions and patience—your involvement has been key to getting us here!
9
+ TaScan is a zero-download task assignment and verification platform for physical-world work. Workers scan a QR code, complete tasks with photo verification, and managers get real-time completion reports — no app download, no login, no training required.
10
10
 
11
- **2025-09-08 update**: The registry has launched in preview 🎉 ([announcement blog post](https://blog.modelcontextprotocol.io/posts/2025-09-08-mcp-registry-preview/)). While the system is now more stable, this is still a preview release and breaking changes or data resets may occur. A general availability (GA) release will follow later. We'd love your feedback in [GitHub discussions](https://github.com/modelcontextprotocol/registry/discussions/new?category=ideas) or in the [#registry-dev Discord](https://discord.com/channels/1358869848138059966/1369487942862504016) ([joining details here](https://modelcontextprotocol.io/community/communication)).
11
+ When something breaks, AI analyzes the issue, generates fix instructions, and dispatches them to the right worker — closing the loop autonomously in under 10 seconds.
12
12
 
13
- Current key maintainers:
14
- - **Adam Jones** (Anthropic) [@domdomegg](https://github.com/domdomegg)
15
- - **Tadas Antanavicius** (PulseMCP) [@tadasant](https://github.com/tadasant)
16
- - **Toby Padilla** (GitHub) [@toby](https://github.com/toby)
17
- - **Radoslav (Rado) Dimitrov** (Stacklok) [@rdimitrov](https://github.com/rdimitrov)
13
+ Industries: live events, construction, hospitality, warehousing, property management, healthcare, aviation, FEMA disaster response, and more.
18
14
 
19
- ## Contributing
15
+ **Patent Pending** — USPTO #63/995,189 & #63/996,023
20
16
 
21
- We use multiple channels for collaboration - see [modelcontextprotocol.io/community/communication](https://modelcontextprotocol.io/community/communication).
17
+ ## Quickest Start: Claude.ai / Claude Mobile
22
18
 
23
- Often (but not always) ideas flow through this pipeline:
19
+ No install required. Add TaScan as a custom connector in Claude:
24
20
 
25
- - **[Discord](https://modelcontextprotocol.io/community/communication)** - Real-time community discussions
26
- - **[Discussions](https://github.com/modelcontextprotocol/registry/discussions)** - Propose and discuss product/technical requirements
27
- - **[Issues](https://github.com/modelcontextprotocol/registry/issues)** - Track well-scoped technical work
28
- - **[Pull Requests](https://github.com/modelcontextprotocol/registry/pulls)** - Contribute work towards issues
21
+ 1. **Settings > Connectors > Add custom connector**
22
+ 2. Enter: `https://tascan-live-event.netlify.app/mcp`
23
+ 3. First time you use a tool, sign in with your TaScan email and password
29
24
 
30
- ### Quick start:
25
+ That's it. Works on claude.ai and Claude mobile. Same sign-in experience as GitHub, Netlify, and Supabase connectors.
31
26
 
32
- #### Pre-requisites
27
+ ---
33
28
 
34
- - **Docker**
35
- - **Go 1.24.x**
36
- - **ko** - Container image builder for Go ([installation instructions](https://ko.build/install/))
37
- - **golangci-lint v2.4.0**
38
-
39
- #### Running the server
29
+ ## Installation (Claude Desktop / Claude Code)
40
30
 
41
31
  ```bash
42
- # Start full development environment
43
- make dev-compose
32
+ npm install tascan-mcp
44
33
  ```
45
34
 
46
- This starts the registry at [`localhost:8080`](http://localhost:8080) with PostgreSQL. The database uses ephemeral storage and is reset each time you restart the containers, ensuring a clean state for development and testing.
35
+ Or run directly with npx:
47
36
 
48
- **Note:** The registry uses [ko](https://ko.build) to build container images. The `make dev-compose` command automatically builds the registry image with ko and loads it into your local Docker daemon before starting the services.
37
+ ```bash
38
+ npx tascan-mcp
39
+ ```
49
40
 
50
- By default, the registry seeds from the production API with a filtered subset of servers (to keep startup fast). This ensures your local environment mirrors production behavior and all seed data passes validation. For offline development you can seed from a file without validation with `MCP_REGISTRY_SEED_FROM=data/seed.json MCP_REGISTRY_ENABLE_REGISTRY_VALIDATION=false make dev-compose`.
41
+ ## Configuration
51
42
 
52
- The setup can be configured with environment variables in [docker-compose.yml](./docker-compose.yml) - see [.env.example](./.env.example) for a reference.
43
+ ### Environment Variables
53
44
 
54
- <details>
55
- <summary>Alternative: Running a pre-built Docker image</summary>
45
+ | Variable | Required | Description |
46
+ |----------|----------|-------------|
47
+ | `TASCAN_API_KEY` | Yes | Your TaScan API key (generate in Admin Portal > Team > API Keys) |
48
+ | `TASCAN_API_URL` | No | API base URL (default: `https://tascan-live-event.netlify.app/api/v1`) |
56
49
 
57
- Pre-built Docker images are automatically published to GitHub Container Registry:
50
+ ### Claude Desktop
58
51
 
59
- ```bash
60
- # Run latest stable release
61
- docker run -p 8080:8080 ghcr.io/modelcontextprotocol/registry:latest
52
+ Add to your Claude Desktop config file (`claude_desktop_config.json`):
62
53
 
63
- # Run latest from main branch (continuous deployment)
64
- docker run -p 8080:8080 ghcr.io/modelcontextprotocol/registry:main
54
+ ```json
55
+ {
56
+ "mcpServers": {
57
+ "tascan": {
58
+ "command": "npx",
59
+ "args": ["-y", "tascan-mcp"],
60
+ "env": {
61
+ "TASCAN_API_KEY": "your-api-key-here"
62
+ }
63
+ }
64
+ }
65
+ }
66
+ ```
65
67
 
66
- # Run specific release version
67
- docker run -p 8080:8080 ghcr.io/modelcontextprotocol/registry:v1.0.0
68
+ ### Claude Code
68
69
 
69
- # Run development build from main branch
70
- docker run -p 8080:8080 ghcr.io/modelcontextprotocol/registry:main-20250906-abc123d
70
+ ```bash
71
+ claude mcp add tascan -- npx -y tascan-mcp
71
72
  ```
72
73
 
73
- **Available tags:**
74
- - **Releases**: `latest`, `v1.0.0`, `v1.1.0`, etc.
75
- - **Continuous**: `main` (latest main branch build)
76
- - **Development**: `main-<date>-<sha>` (specific commit builds)
74
+ Then set your API key in the environment.
77
75
 
78
- </details>
76
+ ### Remote (claude.ai / Claude Mobile)
79
77
 
80
- #### Publishing a server
78
+ TaScan MCP is also available as a remote server — no install, no API key needed:
81
79
 
82
- To publish a server, we've built a simple CLI. You can use it with:
80
+ ```
81
+ https://tascan-live-event.netlify.app/mcp
82
+ ```
83
83
 
84
- ```bash
85
- # Build the latest CLI
86
- make publisher
84
+ Add as a custom connector in Claude (Settings > Connectors). When you first use a tool, you'll be redirected to sign in with your TaScan email and password — just like connecting GitHub or Netlify. OAuth 2.0 with PKCE handles everything automatically.
85
+
86
+ ## Tools (27)
87
+
88
+ ### Projects
89
+ | Tool | Description | Type |
90
+ |------|-------------|------|
91
+ | `tascan_list_projects` | List all projects in the organization | Read |
92
+ | `tascan_get_project` | Get details of a specific project | Read |
93
+ | `tascan_create_project` | Create a new project | Create |
94
+ | `tascan_update_project` | Update project name, location, status, dates | Update |
95
+ | `tascan_delete_project` | Delete a project and all its contents | Delete |
96
+
97
+ ### Events (Task Lists)
98
+ | Tool | Description | Type |
99
+ |------|-------------|------|
100
+ | `tascan_list_events` | List all events within a project | Read |
101
+ | `tascan_get_event` | Get event details including tasks | Read |
102
+ | `tascan_create_event` | Create a new event in a project | Create |
103
+ | `tascan_update_event` | Update event name, description, modes | Update |
104
+ | `tascan_delete_event` | Delete an event and all its tasks | Delete |
105
+
106
+ ### Tasks
107
+ | Tool | Description | Type |
108
+ |------|-------------|------|
109
+ | `tascan_list_tasks` | List all tasks in an event | Read |
110
+ | `tascan_get_task` | Get task details including completions | Read |
111
+ | `tascan_add_tasks` | Bulk-create tasks in an event | Create |
112
+ | `tascan_update_task` | Update task title, type, flags, order | Update |
113
+ | `tascan_delete_task` | Delete a task and its completions | Delete |
114
+
115
+ ### Workers
116
+ | Tool | Description | Type |
117
+ |------|-------------|------|
118
+ | `tascan_list_workers` | List all workers in the organization | Read |
119
+ | `tascan_create_worker` | Create a new worker profile | Create |
120
+ | `tascan_update_worker` | Update worker name, phone, email | Update |
121
+
122
+ ### Operations
123
+ | Tool | Description | Type |
124
+ |------|-------------|------|
125
+ | `tascan_generate_qr` | Generate a QR code for an event | Create |
126
+ | `tascan_apply_template` | Apply a pre-built template to an event | Create |
127
+ | `tascan_list_templates` | List available task templates | Read |
128
+ | `tascan_get_report` | Get completion report for an event | Read |
129
+
130
+ ### Closed-Loop Autonomous Operations (Patent Pending)
131
+ | Tool | Description | Type |
132
+ |------|-------------|------|
133
+ | `tascan_list_issues` | List field-reported issues with filtering by status, category, severity | Read |
134
+ | `tascan_analyze_issue` | AI classifies issue severity, identifies root cause, and scores urgency | AI |
135
+ | `tascan_recommend_fix` | AI generates ranked remediation tasks with step-by-step instructions | AI |
136
+ | `tascan_dispatch_instruction` | Multi-channel delivery of fix instructions to workers (SMS, push, QR) | Create |
137
+ | `tascan_auto_resolve` | Full closed loop in ONE call — issue in, AI analyzes, fix dispatched, loop closes | AI |
138
+
139
+ ## Usage Examples
140
+
141
+ ### Example 1: Set up a construction site inspection
87
142
 
88
- # Use it!
89
- ./bin/mcp-publisher --help
90
143
  ```
144
+ User: Create a construction project for the Downtown Tower site and set up a daily safety inspection with tasks for PPE check, fall protection, scaffolding inspection, and fire extinguisher check. Make all tasks safety checkpoints that require photos.
91
145
 
92
- See [the publisher guide](./docs/modelcontextprotocol-io/quickstart.mdx) for more details.
146
+ Claude will:
147
+ 1. Call tascan_create_project with name "Downtown Tower" and location "123 Main St"
148
+ 2. Call tascan_create_event with name "Daily Safety Inspection"
149
+ 3. Call tascan_add_tasks with 4 safety checkpoint tasks requiring photos
150
+ 4. Call tascan_generate_qr to create a scannable QR code for the foreman
151
+ ```
93
152
 
94
- #### Other commands
153
+ ### Example 2: AI-powered autonomous issue resolution
95
154
 
96
- ```bash
97
- # Run lint, unit tests and integration tests
98
- make check
99
155
  ```
156
+ User: Check if there are any open issues on the Marriott load-in and have TaScan fix them automatically.
100
157
 
101
- There are also a few more helpful commands for development. Run `make help` to learn more, or look in [Makefile](./Makefile).
158
+ Claude will:
159
+ 1. Call tascan_list_issues to find open issues
160
+ 2. Call tascan_auto_resolve for each issue — AI analyzes root cause, generates fix tasks, and dispatches instructions to the nearest qualified worker via SMS
161
+ 3. Report back with resolution status and confidence scores
162
+ ```
102
163
 
103
- <!--
104
- For Claude and other AI tools: Always prefer make targets over custom commands where possible.
105
- -->
164
+ ### Example 3: Use templates to quickly deploy an event
106
165
 
107
- ## Architecture
166
+ ```
167
+ User: We have a warehouse receiving shipment coming in tomorrow. Set up the standard receiving checklist.
168
+
169
+ Claude will:
170
+ 1. Call tascan_list_templates with category "logistics" to find available templates
171
+ 2. Call tascan_create_project for the warehouse
172
+ 3. Call tascan_create_event for the receiving session
173
+ 4. Call tascan_apply_template with the "warehouse-receiving" template slug
174
+ 5. Call tascan_generate_qr for the receiving dock crew
175
+ ```
108
176
 
109
- ### Project Structure
177
+ ### Example 4: Analyze and triage field issues
110
178
 
111
179
  ```
112
- ├── cmd/ # Application entry points
113
- │ └── publisher/ # Server publishing tool
114
- ├── data/ # Seed data
115
- ├── deploy/ # Deployment configuration (Pulumi)
116
- ├── docs/ # Documentation
117
- ├── internal/ # Private application code
118
- │ ├── api/ # HTTP handlers and routing
119
- │ ├── auth/ # Authentication (GitHub OAuth, JWT, namespace blocking)
120
- │ ├── config/ # Configuration management
121
- │ ├── database/ # Data persistence (PostgreSQL)
122
- │ ├── service/ # Business logic
123
- │ ├── telemetry/ # Metrics and monitoring
124
- │ └── validators/ # Input validation
125
- ├── pkg/ # Public packages
126
- │ ├── api/ # API types and structures
127
- │ │ └── v0/ # Version 0 API types
128
- │ └── model/ # Data models for server.json
129
- ├── scripts/ # Development and testing scripts
130
- ├── tests/ # Integration tests
131
- └── tools/ # CLI tools and utilities
132
- └── validate-*.sh # Schema validation tools
180
+ User: We have 5 open issues on the concert setup. Analyze them all and tell me which ones are most urgent.
181
+
182
+ Claude will:
183
+ 1. Call tascan_list_issues to get all open issues
184
+ 2. Call tascan_analyze_issue for each one — AI classifies severity, root cause probability, and urgency score
185
+ 3. Rank by urgency and recommend which to auto-resolve vs which need human attention
133
186
  ```
134
187
 
135
- ### Authentication
188
+ ## Task Types
189
+
190
+ Tasks support multiple response types:
191
+
192
+ | Type | Description |
193
+ |------|-------------|
194
+ | `checkbox` | Simple done/not-done (default) |
195
+ | `photo` | Requires photo upload to complete |
196
+ | `text` | Free-text response |
197
+ | `number` | Numeric response |
198
+ | `date` | Date selection |
199
+ | `choice` | Multiple choice selection |
200
+
201
+ Tasks can also be flagged as:
202
+ - **Safety checkpoints** (`is_safety_checkpoint: true`) — highlighted in red, cannot be skipped
203
+ - **Photo required** (`requires_photo: true`) — worker must attach a photo to complete
204
+
205
+ ## Getting an API Key
206
+
207
+ 1. Log in to the [TaScan Admin Portal](https://tascan-live-event.netlify.app)
208
+ 2. Navigate to **Team** in the sidebar
209
+ 3. Scroll to **API Keys**
210
+ 4. Click **Generate API Key**
211
+ 5. Copy the key (it's only shown once)
212
+ 6. Set it as `TASCAN_API_KEY` in your environment
213
+
214
+ API keys are scoped to your organization and support rate limiting (60 requests/minute).
215
+
216
+ ## Privacy Policy
217
+
218
+ TaScan collects and processes task completion data, worker information (name, phone, email), GPS coordinates (with consent), and photos uploaded during task completion. Data is stored securely in Supabase with row-level security policies. API access is authenticated and rate-limited.
136
219
 
137
- Publishing supports multiple authentication methods:
138
- - **GitHub OAuth** - For publishing by logging into GitHub
139
- - **GitHub OIDC** - For publishing from GitHub Actions
140
- - **DNS verification** - For proving ownership of a domain and its subdomains
141
- - **HTTP verification** - For proving ownership of a domain
220
+ For the full privacy policy, visit: https://tascan.io/faq.html
142
221
 
143
- The registry validates namespace ownership when publishing. E.g. to publish...:
144
- - `io.github.domdomegg/my-cool-mcp` you must login to GitHub as `domdomegg`, or be in a GitHub Action on domdomegg's repos
145
- - `me.adamjones/my-cool-mcp` you must prove ownership of `adamjones.me` via DNS or HTTP challenge
222
+ For data deletion requests or privacy inquiries, contact: Michael@TaScan.io
146
223
 
147
- ## Community Projects
224
+ ## Support
148
225
 
149
- Check out [community projects](docs/community-projects.md) to explore notable registry-related work created by the community.
226
+ - **Email:** Michael@TaScan.io
227
+ - **Website:** https://tascan.io
228
+ - **Issues:** https://github.com/snowbikemike/tascan-mcp/issues
150
229
 
151
- ## More documentation
230
+ ## License
152
231
 
153
- See the [documentation](./docs) for more details if your question has not been answered here!
232
+ MIT License - Copyright (c) 2026 Michael Edward Love II / Love Productions LLC
package/index.js CHANGED
@@ -46,7 +46,7 @@ async function apiCall(method, path, body) {
46
46
  // ─── Server Setup ──────────────────────────────────────────
47
47
  const server = new McpServer({
48
48
  name: 'tascan',
49
- version: '1.0.0'
49
+ version: '2.0.0'
50
50
  });
51
51
 
52
52
 
@@ -662,6 +662,204 @@ server.registerTool(
662
662
  );
663
663
 
664
664
 
665
+ // ─── Closed-Loop Autonomous Operations Protocol ───────────
666
+
667
+ // Tool 23: List Issues (discover issues for analysis)
668
+ server.registerTool(
669
+ 'tascan_list_issues',
670
+ {
671
+ title: 'List Issues',
672
+ description: 'List all issues for a task list (event). Returns open, acknowledged, and resolved issues. Use to discover issues for AI analysis via tascan_analyze_issue.',
673
+ inputSchema: {
674
+ list_id: z.string().describe('Task list (event) ID')
675
+ },
676
+ annotations: {
677
+ readOnlyHint: true,
678
+ destructiveHint: false
679
+ }
680
+ },
681
+ async ({ list_id }) => {
682
+ const result = await apiCall('GET', `/lists/${list_id}/issues`);
683
+ const issues = result.data;
684
+ if (!issues.length) return { content: [{ type: 'text', text: 'No issues reported for this task list.' }] };
685
+ let text = `${issues.length} issue(s) found:\n\n`;
686
+ issues.forEach((iss, i) => {
687
+ text += `${i+1}. [${iss.status.toUpperCase()}] ${iss.title}\n`;
688
+ text += ` ID: ${iss.id} | Type: ${iss.type} | Category: ${iss.category} | Severity: ${iss.severity || 'unset'}\n`;
689
+ if (iss.tasks) text += ` Task: ${iss.tasks.title}\n`;
690
+ text += ` Reported: ${iss.created_at}\n\n`;
691
+ });
692
+ return { content: [{ type: 'text', text }] };
693
+ }
694
+ );
695
+
696
+ // Tool 24: Analyze Issue (Step 1 of Closed-Loop — read issue with full context + optional server AI)
697
+ server.registerTool(
698
+ 'tascan_analyze_issue',
699
+ {
700
+ title: 'Analyze Issue',
701
+ description: 'Step 1 of the Closed-Loop Autonomous Operations Protocol. Returns full issue context including worker info, message thread, project history, and recent similar issues for AI reasoning. Supports optional server-side AI analysis via Anthropic API.',
702
+ inputSchema: {
703
+ issue_id: z.string().describe('Issue ID to analyze'),
704
+ server_side_ai: z.boolean().optional().describe('If true, server calls Anthropic API for analysis (default: false)')
705
+ },
706
+ annotations: {
707
+ readOnlyHint: false,
708
+ destructiveHint: false
709
+ }
710
+ },
711
+ async ({ issue_id, server_side_ai }) => {
712
+ if (server_side_ai) {
713
+ const result = await apiCall('POST', `/issues/${issue_id}/analyze`);
714
+ const d = result.data;
715
+ let text = `=== AI ANALYSIS (Server-Side) ===\n`;
716
+ text += `Issue: ${d.issue_title} (${d.issue_id})\nAnalyzed: ${d.analyzed_at}\n\n`;
717
+ text += JSON.stringify(d.analysis, null, 2);
718
+ return { content: [{ type: 'text', text }] };
719
+ }
720
+
721
+ const result = await apiCall('GET', `/issues/${issue_id}`);
722
+ const d = result.data;
723
+ let text = `=== ISSUE CONTEXT FOR ANALYSIS ===\n`;
724
+ text += `Issue: ${d.title}\n`;
725
+ text += `Type: ${d.type} | Category: ${d.category} | Severity: ${d.severity || 'unset'} | Status: ${d.status}\n`;
726
+ text += `Description: ${d.description || 'none'}\n`;
727
+ if (d.tasks) text += `Task: ${d.tasks.title} (${d.tasks.response_type || 'checkbox'})\nTask Description: ${d.tasks.description || 'none'}\n`;
728
+ if (d.worker) text += `Worker: ${d.worker.name} (ID: ${d.worker.id})\n`;
729
+ if (d.project) text += `Project: ${d.project.name} | Location: ${d.project.location || 'unknown'}\n`;
730
+ if (d.injury_data) text += `Injury Data: ${JSON.stringify(d.injury_data)}\n`;
731
+ text += `Reported: ${d.created_at}\n`;
732
+ if (d.ai_analysis) text += `\n--- PREVIOUS AI ANALYSIS ---\n${JSON.stringify(d.ai_analysis, null, 2)}\n`;
733
+ if (d.messages && d.messages.length) {
734
+ text += `\n--- Message Thread (${d.messages.length}) ---\n`;
735
+ d.messages.forEach(m => { text += `[${m.sender_type}/${m.sender_name}] ${m.message}\n`; });
736
+ }
737
+ if (d.recent_issues && d.recent_issues.length) {
738
+ text += `\n--- Recent Issues on Same Project (${d.recent_issues.length}) ---\n`;
739
+ d.recent_issues.forEach(ri => { text += `- [${ri.severity}/${ri.category}] ${(ri.description || '').substring(0, 80)} (${ri.status})\n`; });
740
+ }
741
+ return { content: [{ type: 'text', text }] };
742
+ }
743
+ );
744
+
745
+ // Tool 25: Recommend Fix (Step 2 — post recommendation + optional structured tasks)
746
+ server.registerTool(
747
+ 'tascan_recommend_fix',
748
+ {
749
+ title: 'Recommend Fix',
750
+ description: 'Step 2 of the Closed-Loop. Post AI recommendation to issue thread. Accepts optional structured_recommendation with task definitions for auto-dispatch. Persisted in AI audit trail.',
751
+ inputSchema: {
752
+ issue_id: z.string().describe('Issue ID to recommend a fix for'),
753
+ recommendation: z.string().describe('AI recommendation text (clear, actionable instructions)'),
754
+ structured_recommendation: z.any().optional().describe('Structured recommendation object with tasks for dispatch'),
755
+ ai_agent: z.string().optional().describe('AI agent name (default: TaScan AI)')
756
+ },
757
+ annotations: {
758
+ readOnlyHint: false,
759
+ destructiveHint: false
760
+ }
761
+ },
762
+ async ({ issue_id, recommendation, structured_recommendation, ai_agent }) => {
763
+ const body = { recommendation };
764
+ if (structured_recommendation) body.structured_recommendation = structured_recommendation;
765
+ if (ai_agent) body.ai_agent = ai_agent;
766
+ const result = await apiCall('POST', `/issues/${issue_id}/recommend`, body);
767
+ const d = result.data;
768
+ let text = `Recommendation posted to issue "${d.issue_title}":\n`;
769
+ text += `Project: ${d.project_name} | List: ${d.list_name}\n`;
770
+ text += `Message ID: ${d.message_id}\n\nRecommendation:\n${d.recommendation}`;
771
+ if (d.structured_recommendation?.tasks) {
772
+ text += `\n\nStructured Tasks (${d.structured_recommendation.tasks.length}):`;
773
+ d.structured_recommendation.tasks.forEach((t, i) => { text += `\n ${i+1}. ${t.title}`; });
774
+ }
775
+ return { content: [{ type: 'text', text }] };
776
+ }
777
+ );
778
+
779
+ // Tool 26: Dispatch Instruction (Step 3 — multi-channel delivery + task list creation)
780
+ server.registerTool(
781
+ 'tascan_dispatch_instruction',
782
+ {
783
+ title: 'Dispatch Instruction',
784
+ description: 'Step 3 of the Closed-Loop. Multi-channel dispatch: issue thread, in-app message, progress feed, SMS, and optional remediation task list. Closes the loop from AI analysis to physical worker execution.',
785
+ inputSchema: {
786
+ issue_id: z.string().describe('Issue ID'),
787
+ instruction: z.string().describe('Actionable instruction for the worker'),
788
+ worker_id: z.string().optional().describe('Target worker ID (defaults to issue reporter)'),
789
+ remediation_tasks: z.array(z.any()).optional().describe('Tasks to create as remediation task list'),
790
+ recommendation_summary: z.string().optional().describe('Summary for task list description'),
791
+ send_sms: z.boolean().optional().describe('Send SMS (default: true if phone on file)'),
792
+ ai_agent: z.string().optional().describe('AI agent name (default: TaScan AI)')
793
+ },
794
+ annotations: {
795
+ readOnlyHint: false,
796
+ destructiveHint: false
797
+ }
798
+ },
799
+ async ({ issue_id, instruction, worker_id, remediation_tasks, recommendation_summary, send_sms, ai_agent }) => {
800
+ const body = { instruction };
801
+ if (worker_id) body.worker_id = worker_id;
802
+ if (remediation_tasks) body.remediation_tasks = remediation_tasks;
803
+ if (recommendation_summary) body.recommendation_summary = recommendation_summary;
804
+ if (send_sms !== undefined) body.send_sms = send_sms;
805
+ if (ai_agent) body.ai_agent = ai_agent;
806
+ const result = await apiCall('POST', `/issues/${issue_id}/dispatch`, body);
807
+ const d = result.data;
808
+ let text = `Dispatched via ${d.channels.length} channels: ${d.channels.join(', ')}\n`;
809
+ text += `Worker: ${d.worker_id} | Issue: ${d.issue_id} (${d.issue_status})\n`;
810
+ text += `SMS: ${d.sms_status}\n`;
811
+ if (d.remediation_task_list_id) {
812
+ text += `Task List: ${d.remediation_task_list_id}\nWorker URL: ${d.worker_url}\nTasks: ${d.tasks_created}\n`;
813
+ }
814
+ text += `\nInstruction:\n${d.instruction}`;
815
+ return { content: [{ type: 'text', text }] };
816
+ }
817
+ );
818
+
819
+ // Tool 27: Auto-Resolve (Full Closed-Loop in one call — Patent Claim 7)
820
+ server.registerTool(
821
+ 'tascan_auto_resolve',
822
+ {
823
+ title: 'Auto-Resolve Issue',
824
+ description: 'FULL Closed-Loop Autonomous Operations Protocol in one call. Server-side AI analyzes issue, generates remediation tasks, creates task list, dispatches to worker via multi-channel delivery — all without human intervention. Patent Claim 7.',
825
+ inputSchema: {
826
+ issue_id: z.string().describe('Issue ID to auto-resolve')
827
+ },
828
+ annotations: {
829
+ readOnlyHint: false,
830
+ destructiveHint: false,
831
+ openWorldHint: true
832
+ }
833
+ },
834
+ async ({ issue_id }) => {
835
+ const result = await apiCall('POST', `/issues/${issue_id}/auto-resolve`);
836
+ const d = result.data;
837
+ let text = `=== CLOSED-LOOP AUTONOMOUS OPERATIONS PROTOCOL ===\n`;
838
+ text += `Issue: ${d.issue_id}\n\n`;
839
+ text += `--- ANALYSIS ---\n`;
840
+ text += `Summary: ${d.analysis?.summary || 'N/A'}\n`;
841
+ text += `Classification: ${d.analysis?.classification?.type || 'N/A'} (${d.analysis?.classification?.severity || 'N/A'})\n`;
842
+ text += `Urgency: ${d.analysis?.urgency_score || 'N/A'}/10\n`;
843
+ if (d.analysis?.root_cause_hypotheses?.length) {
844
+ d.analysis.root_cause_hypotheses.forEach((h, i) => {
845
+ text += ` ${i+1}. ${h.hypothesis} (${Math.round(h.confidence * 100)}%)\n`;
846
+ });
847
+ }
848
+ text += `\n--- RECOMMENDATION ---\n`;
849
+ text += `Fix: ${d.recommendation?.recommendation_summary || 'N/A'}\n`;
850
+ text += `Tasks: ${d.recommendation?.tasks?.length || 0}\n`;
851
+ text += `Duration: ${d.recommendation?.estimated_duration_minutes || 'N/A'} min\n`;
852
+ text += `\n--- DISPATCH ---\n`;
853
+ text += `Channels: ${d.dispatch?.channels?.join(', ') || 'none'}\n`;
854
+ text += `SMS: ${d.dispatch?.sms_status || 'N/A'}\n`;
855
+ if (d.dispatch?.worker_url) text += `Worker URL: ${d.dispatch.worker_url}\n`;
856
+ if (d.dispatch?.remediation_task_list_id) text += `Task List: ${d.dispatch.remediation_task_list_id}\n`;
857
+ text += `\nTimestamps: analyzed ${d.timestamps?.analyzed_at} | recommended ${d.timestamps?.recommended_at} | dispatched ${d.timestamps?.dispatched_at}`;
858
+ return { content: [{ type: 'text', text }] };
859
+ }
860
+ );
861
+
862
+
665
863
  // ─── Start Server ──────────────────────────────────────────
666
864
  async function main() {
667
865
  const transport = new StdioServerTransport();
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "tascan-mcp",
3
- "version": "1.0.1",
3
+ "version": "2.1.0",
4
4
  "mcpName": "io.github.snowbikemike/tascan-mcp",
5
- "description": "TaScan MCP Server — AI agent integration for the universal task protocol platform. Manage projects, events, tasks, workers, QR codes, templates, and reports. Scan. Task. Done.",
5
+ "description": "TaScan MCP Server — Closed-loop autonomous operations protocol. 27 tools for projects, tasks, workers, QR codes, AI issue analysis, and autonomous remediation dispatch. Patent pending. Scan. Task. Done.",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "bin": {