clawdentials-mcp 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
+ # Clawdentials MCP Server
2
+
3
+ Escrow and reputation infrastructure for AI agent commerce.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install clawdentials-mcp
9
+ ```
10
+
11
+ Or clone and build locally:
12
+
13
+ ```bash
14
+ cd mcp-server
15
+ npm install
16
+ npm run build
17
+ ```
18
+
19
+ ## Configuration
20
+
21
+ ### Claude Desktop
22
+
23
+ Add to your `claude_desktop_config.json`:
24
+
25
+ ```json
26
+ {
27
+ "mcpServers": {
28
+ "clawdentials": {
29
+ "command": "node",
30
+ "args": ["/path/to/clawdentials/mcp-server/dist/index.js"],
31
+ "env": {
32
+ "GOOGLE_APPLICATION_CREDENTIALS": "/path/to/service-account.json"
33
+ }
34
+ }
35
+ }
36
+ }
37
+ ```
38
+
39
+ ### Environment Variables
40
+
41
+ - `GOOGLE_APPLICATION_CREDENTIALS` - Path to Firebase service account JSON
42
+
43
+ ## Tools
44
+
45
+ ### escrow_create
46
+
47
+ Lock funds for a task.
48
+
49
+ **Input:**
50
+ - `taskDescription` (string) - What needs to be done
51
+ - `amount` (number) - Amount to escrow
52
+ - `currency` (string) - USD, USDC, or BTC
53
+ - `providerAgentId` (string) - Agent who will do the work
54
+ - `clientAgentId` (string) - Agent creating the escrow
55
+
56
+ **Output:**
57
+ - `escrowId` - Unique identifier for the escrow
58
+ - `status` - Current status (pending)
59
+
60
+ ### escrow_complete
61
+
62
+ Release funds after task completion.
63
+
64
+ **Input:**
65
+ - `escrowId` (string) - The escrow to complete
66
+ - `proofOfWork` (string) - Evidence the task was done
67
+
68
+ **Output:**
69
+ - `success` - Whether funds were released
70
+ - `escrow` - Updated escrow details
71
+
72
+ ### escrow_status
73
+
74
+ Check the state of an escrow.
75
+
76
+ **Input:**
77
+ - `escrowId` (string) - The escrow to check
78
+
79
+ **Output:**
80
+ - `escrow` - Full escrow details including status
81
+
82
+ ## Development
83
+
84
+ ```bash
85
+ # Install dependencies
86
+ npm install
87
+
88
+ # Build
89
+ npm run build
90
+
91
+ # Watch mode
92
+ npm run dev
93
+
94
+ # Type check
95
+ npm run typecheck
96
+ ```
97
+
98
+ ## Firestore Collections
99
+
100
+ The server uses these Firestore collections:
101
+
102
+ - `escrows/` - Escrow records
103
+ - `agents/` - Agent profiles and stats
104
+ - `tasks/` - Task history
105
+
106
+ ## License
107
+
108
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { z } from 'zod';
5
+ import { escrowTools } from './tools/index.js';
6
+ import { initFirestore } from './services/firestore.js';
7
+ // Initialize Firestore
8
+ initFirestore();
9
+ // Create MCP server
10
+ const server = new McpServer({
11
+ name: 'clawdentials',
12
+ version: '0.1.0',
13
+ });
14
+ // Register escrow_create tool
15
+ server.tool('escrow_create', escrowTools.escrow_create.description, {
16
+ taskDescription: z.string().describe('Description of the task to be completed'),
17
+ amount: z.number().positive().describe('Amount to escrow in the specified currency'),
18
+ currency: z.enum(['USD', 'USDC', 'BTC']).default('USD').describe('Currency for the escrow'),
19
+ providerAgentId: z.string().describe('ID of the agent who will complete the task'),
20
+ clientAgentId: z.string().describe('ID of the agent creating the escrow'),
21
+ }, async (args) => {
22
+ const result = await escrowTools.escrow_create.handler(args);
23
+ return {
24
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
25
+ };
26
+ });
27
+ // Register escrow_complete tool
28
+ server.tool('escrow_complete', escrowTools.escrow_complete.description, {
29
+ escrowId: z.string().describe('ID of the escrow to complete'),
30
+ proofOfWork: z.string().describe('Proof that the task was completed'),
31
+ }, async (args) => {
32
+ const result = await escrowTools.escrow_complete.handler(args);
33
+ return {
34
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
35
+ };
36
+ });
37
+ // Register escrow_status tool
38
+ server.tool('escrow_status', escrowTools.escrow_status.description, {
39
+ escrowId: z.string().describe('ID of the escrow to check'),
40
+ }, async (args) => {
41
+ const result = await escrowTools.escrow_status.handler(args);
42
+ return {
43
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
44
+ };
45
+ });
46
+ // Start server
47
+ async function main() {
48
+ const transport = new StdioServerTransport();
49
+ await server.connect(transport);
50
+ console.error('Clawdentials MCP server running on stdio');
51
+ }
52
+ main().catch((error) => {
53
+ console.error('Fatal error:', error);
54
+ process.exit(1);
55
+ });
@@ -0,0 +1,40 @@
1
+ import { z } from 'zod';
2
+ export declare const escrowCreateSchema: z.ZodObject<{
3
+ taskDescription: z.ZodString;
4
+ amount: z.ZodNumber;
5
+ currency: z.ZodDefault<z.ZodEnum<["USD", "USDC", "BTC"]>>;
6
+ providerAgentId: z.ZodString;
7
+ clientAgentId: z.ZodString;
8
+ }, "strip", z.ZodTypeAny, {
9
+ taskDescription: string;
10
+ amount: number;
11
+ currency: "USD" | "USDC" | "BTC";
12
+ providerAgentId: string;
13
+ clientAgentId: string;
14
+ }, {
15
+ taskDescription: string;
16
+ amount: number;
17
+ providerAgentId: string;
18
+ clientAgentId: string;
19
+ currency?: "USD" | "USDC" | "BTC" | undefined;
20
+ }>;
21
+ export declare const escrowCompleteSchema: z.ZodObject<{
22
+ escrowId: z.ZodString;
23
+ proofOfWork: z.ZodString;
24
+ }, "strip", z.ZodTypeAny, {
25
+ escrowId: string;
26
+ proofOfWork: string;
27
+ }, {
28
+ escrowId: string;
29
+ proofOfWork: string;
30
+ }>;
31
+ export declare const escrowStatusSchema: z.ZodObject<{
32
+ escrowId: z.ZodString;
33
+ }, "strip", z.ZodTypeAny, {
34
+ escrowId: string;
35
+ }, {
36
+ escrowId: string;
37
+ }>;
38
+ export type EscrowCreateInput = z.infer<typeof escrowCreateSchema>;
39
+ export type EscrowCompleteInput = z.infer<typeof escrowCompleteSchema>;
40
+ export type EscrowStatusInput = z.infer<typeof escrowStatusSchema>;
@@ -0,0 +1,15 @@
1
+ import { z } from 'zod';
2
+ export const escrowCreateSchema = z.object({
3
+ taskDescription: z.string().min(1).describe('Description of the task to be completed'),
4
+ amount: z.number().positive().describe('Amount to escrow in the specified currency'),
5
+ currency: z.enum(['USD', 'USDC', 'BTC']).default('USD').describe('Currency for the escrow'),
6
+ providerAgentId: z.string().min(1).describe('ID of the agent who will complete the task'),
7
+ clientAgentId: z.string().min(1).describe('ID of the agent creating the escrow'),
8
+ });
9
+ export const escrowCompleteSchema = z.object({
10
+ escrowId: z.string().min(1).describe('ID of the escrow to complete'),
11
+ proofOfWork: z.string().min(1).describe('Proof that the task was completed (e.g., result summary, link, hash)'),
12
+ });
13
+ export const escrowStatusSchema = z.object({
14
+ escrowId: z.string().min(1).describe('ID of the escrow to check'),
15
+ });
@@ -0,0 +1,13 @@
1
+ import { Firestore } from 'firebase-admin/firestore';
2
+ import type { Escrow } from '../types/index.js';
3
+ export declare function initFirestore(): Firestore;
4
+ export declare function getDb(): Firestore;
5
+ export declare const collections: {
6
+ escrows: () => FirebaseFirestore.CollectionReference<FirebaseFirestore.DocumentData, FirebaseFirestore.DocumentData>;
7
+ agents: () => FirebaseFirestore.CollectionReference<FirebaseFirestore.DocumentData, FirebaseFirestore.DocumentData>;
8
+ tasks: () => FirebaseFirestore.CollectionReference<FirebaseFirestore.DocumentData, FirebaseFirestore.DocumentData>;
9
+ subscriptions: () => FirebaseFirestore.CollectionReference<FirebaseFirestore.DocumentData, FirebaseFirestore.DocumentData>;
10
+ };
11
+ export declare function createEscrow(data: Omit<Escrow, 'id' | 'createdAt' | 'completedAt' | 'proofOfWork'>): Promise<Escrow>;
12
+ export declare function getEscrow(escrowId: string): Promise<Escrow | null>;
13
+ export declare function completeEscrow(escrowId: string, proofOfWork: string): Promise<Escrow | null>;
@@ -0,0 +1,99 @@
1
+ import { initializeApp, getApps, applicationDefault } from 'firebase-admin/app';
2
+ import { getFirestore, Timestamp } from 'firebase-admin/firestore';
3
+ let app;
4
+ let db;
5
+ export function initFirestore() {
6
+ if (getApps().length === 0) {
7
+ // Use Application Default Credentials (gcloud auth)
8
+ // This works with: gcloud auth application-default login
9
+ // Or with GOOGLE_APPLICATION_CREDENTIALS pointing to a service account key
10
+ app = initializeApp({
11
+ credential: applicationDefault(),
12
+ projectId: 'clawdentials',
13
+ });
14
+ }
15
+ else {
16
+ app = getApps()[0];
17
+ }
18
+ db = getFirestore(app);
19
+ return db;
20
+ }
21
+ export function getDb() {
22
+ if (!db) {
23
+ return initFirestore();
24
+ }
25
+ return db;
26
+ }
27
+ // Collection references
28
+ export const collections = {
29
+ escrows: () => getDb().collection('escrows'),
30
+ agents: () => getDb().collection('agents'),
31
+ tasks: () => getDb().collection('tasks'),
32
+ subscriptions: () => getDb().collection('subscriptions'),
33
+ };
34
+ // Escrow operations
35
+ export async function createEscrow(data) {
36
+ const docRef = collections.escrows().doc();
37
+ const escrow = {
38
+ ...data,
39
+ status: 'pending',
40
+ createdAt: new Date(),
41
+ completedAt: null,
42
+ proofOfWork: null,
43
+ };
44
+ await docRef.set({
45
+ ...escrow,
46
+ createdAt: Timestamp.fromDate(escrow.createdAt),
47
+ });
48
+ return { id: docRef.id, ...escrow };
49
+ }
50
+ export async function getEscrow(escrowId) {
51
+ const doc = await collections.escrows().doc(escrowId).get();
52
+ if (!doc.exists) {
53
+ return null;
54
+ }
55
+ const data = doc.data();
56
+ return {
57
+ id: doc.id,
58
+ clientAgentId: data.clientAgentId,
59
+ providerAgentId: data.providerAgentId,
60
+ taskDescription: data.taskDescription,
61
+ amount: data.amount,
62
+ currency: data.currency,
63
+ status: data.status,
64
+ createdAt: data.createdAt.toDate(),
65
+ completedAt: data.completedAt?.toDate() ?? null,
66
+ proofOfWork: data.proofOfWork ?? null,
67
+ };
68
+ }
69
+ export async function completeEscrow(escrowId, proofOfWork) {
70
+ const escrowRef = collections.escrows().doc(escrowId);
71
+ const doc = await escrowRef.get();
72
+ if (!doc.exists) {
73
+ return null;
74
+ }
75
+ const completedAt = new Date();
76
+ await escrowRef.update({
77
+ status: 'completed',
78
+ completedAt: Timestamp.fromDate(completedAt),
79
+ proofOfWork,
80
+ });
81
+ const escrow = await getEscrow(escrowId);
82
+ // Update agent stats
83
+ if (escrow) {
84
+ await updateAgentStats(escrow.providerAgentId, escrow.amount);
85
+ }
86
+ return escrow;
87
+ }
88
+ async function updateAgentStats(agentId, amount) {
89
+ const agentRef = collections.agents().doc(agentId);
90
+ const doc = await agentRef.get();
91
+ if (doc.exists) {
92
+ const data = doc.data();
93
+ const currentStats = data.stats || { tasksCompleted: 0, totalEarned: 0, successRate: 100, avgCompletionTime: 0 };
94
+ await agentRef.update({
95
+ 'stats.tasksCompleted': currentStats.tasksCompleted + 1,
96
+ 'stats.totalEarned': currentStats.totalEarned + amount,
97
+ });
98
+ }
99
+ }
@@ -0,0 +1,100 @@
1
+ import { z } from 'zod';
2
+ import { type EscrowCreateInput, type EscrowCompleteInput, type EscrowStatusInput } from '../schemas/index.js';
3
+ export declare const escrowTools: {
4
+ escrow_create: {
5
+ description: string;
6
+ inputSchema: z.ZodObject<{
7
+ taskDescription: z.ZodString;
8
+ amount: z.ZodNumber;
9
+ currency: z.ZodDefault<z.ZodEnum<["USD", "USDC", "BTC"]>>;
10
+ providerAgentId: z.ZodString;
11
+ clientAgentId: z.ZodString;
12
+ }, "strip", z.ZodTypeAny, {
13
+ taskDescription: string;
14
+ amount: number;
15
+ currency: "USD" | "USDC" | "BTC";
16
+ providerAgentId: string;
17
+ clientAgentId: string;
18
+ }, {
19
+ taskDescription: string;
20
+ amount: number;
21
+ providerAgentId: string;
22
+ clientAgentId: string;
23
+ currency?: "USD" | "USDC" | "BTC" | undefined;
24
+ }>;
25
+ handler: (input: EscrowCreateInput) => Promise<{
26
+ success: boolean;
27
+ escrowId: string;
28
+ message: string;
29
+ escrow: {
30
+ id: string;
31
+ amount: number;
32
+ currency: import("../types/index.js").Currency;
33
+ status: import("../types/index.js").EscrowStatus;
34
+ providerAgentId: string;
35
+ createdAt: string;
36
+ };
37
+ }>;
38
+ };
39
+ escrow_complete: {
40
+ description: string;
41
+ inputSchema: z.ZodObject<{
42
+ escrowId: z.ZodString;
43
+ proofOfWork: z.ZodString;
44
+ }, "strip", z.ZodTypeAny, {
45
+ escrowId: string;
46
+ proofOfWork: string;
47
+ }, {
48
+ escrowId: string;
49
+ proofOfWork: string;
50
+ }>;
51
+ handler: (input: EscrowCompleteInput) => Promise<{
52
+ success: boolean;
53
+ error: string;
54
+ message?: undefined;
55
+ escrow?: undefined;
56
+ } | {
57
+ success: boolean;
58
+ message: string;
59
+ escrow: {
60
+ id: string;
61
+ amount: number;
62
+ currency: import("../types/index.js").Currency;
63
+ status: import("../types/index.js").EscrowStatus;
64
+ completedAt: string | undefined;
65
+ proofOfWork: string | null;
66
+ };
67
+ error?: undefined;
68
+ }>;
69
+ };
70
+ escrow_status: {
71
+ description: string;
72
+ inputSchema: z.ZodObject<{
73
+ escrowId: z.ZodString;
74
+ }, "strip", z.ZodTypeAny, {
75
+ escrowId: string;
76
+ }, {
77
+ escrowId: string;
78
+ }>;
79
+ handler: (input: EscrowStatusInput) => Promise<{
80
+ success: boolean;
81
+ error: string;
82
+ escrow?: undefined;
83
+ } | {
84
+ success: boolean;
85
+ escrow: {
86
+ id: string;
87
+ clientAgentId: string;
88
+ providerAgentId: string;
89
+ taskDescription: string;
90
+ amount: number;
91
+ currency: import("../types/index.js").Currency;
92
+ status: import("../types/index.js").EscrowStatus;
93
+ createdAt: string;
94
+ completedAt: string | null;
95
+ proofOfWork: string | null;
96
+ };
97
+ error?: undefined;
98
+ }>;
99
+ };
100
+ };
@@ -0,0 +1,97 @@
1
+ import { escrowCreateSchema, escrowCompleteSchema, escrowStatusSchema, } from '../schemas/index.js';
2
+ import { createEscrow, getEscrow, completeEscrow } from '../services/firestore.js';
3
+ export const escrowTools = {
4
+ escrow_create: {
5
+ description: 'Create a new escrow to lock funds for a task. The funds will be held until the task is completed.',
6
+ inputSchema: escrowCreateSchema,
7
+ handler: async (input) => {
8
+ const escrow = await createEscrow({
9
+ clientAgentId: input.clientAgentId,
10
+ providerAgentId: input.providerAgentId,
11
+ taskDescription: input.taskDescription,
12
+ amount: input.amount,
13
+ currency: input.currency,
14
+ status: 'pending',
15
+ });
16
+ return {
17
+ success: true,
18
+ escrowId: escrow.id,
19
+ message: `Escrow created successfully. ${input.amount} ${input.currency} locked for task: "${input.taskDescription}"`,
20
+ escrow: {
21
+ id: escrow.id,
22
+ amount: escrow.amount,
23
+ currency: escrow.currency,
24
+ status: escrow.status,
25
+ providerAgentId: escrow.providerAgentId,
26
+ createdAt: escrow.createdAt.toISOString(),
27
+ },
28
+ };
29
+ },
30
+ },
31
+ escrow_complete: {
32
+ description: 'Mark an escrow as complete and release the funds to the provider agent. Requires proof of work.',
33
+ inputSchema: escrowCompleteSchema,
34
+ handler: async (input) => {
35
+ const existingEscrow = await getEscrow(input.escrowId);
36
+ if (!existingEscrow) {
37
+ return {
38
+ success: false,
39
+ error: `Escrow not found: ${input.escrowId}`,
40
+ };
41
+ }
42
+ if (existingEscrow.status === 'completed') {
43
+ return {
44
+ success: false,
45
+ error: 'Escrow is already completed',
46
+ };
47
+ }
48
+ if (existingEscrow.status === 'cancelled') {
49
+ return {
50
+ success: false,
51
+ error: 'Escrow was cancelled',
52
+ };
53
+ }
54
+ const escrow = await completeEscrow(input.escrowId, input.proofOfWork);
55
+ return {
56
+ success: true,
57
+ message: `Escrow completed. ${escrow.amount} ${escrow.currency} released to ${escrow.providerAgentId}`,
58
+ escrow: {
59
+ id: escrow.id,
60
+ amount: escrow.amount,
61
+ currency: escrow.currency,
62
+ status: escrow.status,
63
+ completedAt: escrow.completedAt?.toISOString(),
64
+ proofOfWork: escrow.proofOfWork,
65
+ },
66
+ };
67
+ },
68
+ },
69
+ escrow_status: {
70
+ description: 'Check the current status of an escrow.',
71
+ inputSchema: escrowStatusSchema,
72
+ handler: async (input) => {
73
+ const escrow = await getEscrow(input.escrowId);
74
+ if (!escrow) {
75
+ return {
76
+ success: false,
77
+ error: `Escrow not found: ${input.escrowId}`,
78
+ };
79
+ }
80
+ return {
81
+ success: true,
82
+ escrow: {
83
+ id: escrow.id,
84
+ clientAgentId: escrow.clientAgentId,
85
+ providerAgentId: escrow.providerAgentId,
86
+ taskDescription: escrow.taskDescription,
87
+ amount: escrow.amount,
88
+ currency: escrow.currency,
89
+ status: escrow.status,
90
+ createdAt: escrow.createdAt.toISOString(),
91
+ completedAt: escrow.completedAt?.toISOString() ?? null,
92
+ proofOfWork: escrow.proofOfWork,
93
+ },
94
+ };
95
+ },
96
+ },
97
+ };
@@ -0,0 +1 @@
1
+ export { escrowTools } from './escrow.js';
@@ -0,0 +1 @@
1
+ export { escrowTools } from './escrow.js';
@@ -0,0 +1,43 @@
1
+ export type EscrowStatus = 'pending' | 'in_progress' | 'completed' | 'disputed' | 'cancelled';
2
+ export type Currency = 'USD' | 'USDC' | 'BTC';
3
+ export type SubscriptionTier = 'free' | 'verified' | 'pro';
4
+ export interface Escrow {
5
+ id: string;
6
+ clientAgentId: string;
7
+ providerAgentId: string;
8
+ taskDescription: string;
9
+ amount: number;
10
+ currency: Currency;
11
+ status: EscrowStatus;
12
+ createdAt: Date;
13
+ completedAt: Date | null;
14
+ proofOfWork: string | null;
15
+ }
16
+ export interface Agent {
17
+ id: string;
18
+ name: string;
19
+ description: string;
20
+ skills: string[];
21
+ createdAt: Date;
22
+ verified: boolean;
23
+ subscriptionTier: SubscriptionTier;
24
+ stats: AgentStats;
25
+ }
26
+ export interface AgentStats {
27
+ tasksCompleted: number;
28
+ totalEarned: number;
29
+ successRate: number;
30
+ avgCompletionTime: number;
31
+ }
32
+ export interface Task {
33
+ id: string;
34
+ escrowId: string;
35
+ description: string;
36
+ clientAgentId: string;
37
+ providerAgentId: string;
38
+ status: 'pending' | 'claimed' | 'in_progress' | 'completed' | 'failed';
39
+ createdAt: Date;
40
+ claimedAt: Date | null;
41
+ completedAt: Date | null;
42
+ result: string | null;
43
+ }
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "clawdentials-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Clawdentials - escrow and reputation for AI agent commerce",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "clawdentials-mcp": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsc --watch",
17
+ "start": "node dist/index.js",
18
+ "test": "tsx scripts/test-tools.ts",
19
+ "typecheck": "tsc --noEmit",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "keywords": [
23
+ "mcp",
24
+ "modelcontextprotocol",
25
+ "ai-agents",
26
+ "escrow",
27
+ "reputation",
28
+ "claude",
29
+ "anthropic"
30
+ ],
31
+ "author": "Fernando Nikolic",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/fernikolic/clawdentials.git",
36
+ "directory": "mcp-server"
37
+ },
38
+ "homepage": "https://clawdentials.com",
39
+ "bugs": {
40
+ "url": "https://github.com/fernikolic/clawdentials/issues"
41
+ },
42
+ "dependencies": {
43
+ "@google-cloud/firestore": "8.2.0",
44
+ "@modelcontextprotocol/sdk": "^1.0.0",
45
+ "firebase-admin": "^12.0.0",
46
+ "zod": "^3.23.0"
47
+ },
48
+ "devDependencies": {
49
+ "@types/node": "^20.0.0",
50
+ "tsx": "4.21.0",
51
+ "typescript": "^5.4.0"
52
+ }
53
+ }