sifa-mcp 0.1.0__tar.gz

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.
sifa_mcp-0.1.0/LICENSE ADDED
@@ -0,0 +1,3 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gabriel Mahia / AI Kung Fu LLC.
@@ -0,0 +1,104 @@
1
+ Metadata-Version: 2.4
2
+ Name: sifa-mcp
3
+ Version: 0.1.0
4
+ Summary: MCP server for portable reputation and skills passports in East Africa
5
+ Author-email: Gabriel Mahia <contact@aikungfu.dev>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/gabrielmahia/sifa-mcp
8
+ Project-URL: Repository, https://github.com/gabrielmahia/sifa-mcp
9
+ Project-URL: Issues, https://github.com/gabrielmahia/sifa-mcp/issues
10
+ Keywords: mcp,reputation,kenya,africa,skills,passport,workers,sifa
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
16
+ Classifier: Topic :: Office/Business
17
+ Requires-Python: >=3.9
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: fastmcp>=2.0.0
21
+ Dynamic: license-file
22
+
23
+ # ⭐ sifa-mcp — Portable Reputation & Skills Passport MCP Server
24
+
25
+ *Sifa* = reputation/praise in Swahili.
26
+
27
+ **First portable reputation MCP server for East Africa.**
28
+
29
+ ## The Structural Problem
30
+
31
+ In mature economies, reputation travels: Uber driver ratings, Yelp reviews, LinkedIn endorsements, contractor licence registries. A skilled plumber in Chicago can prove her track record to any homeowner in Los Angeles.
32
+
33
+ In Kenya, trust is tribal and local. A qualified mason in Mombasa cannot take her reputation to Nairobi. Economic mobility is throttled by the non-portability of professional identity.
34
+
35
+ **Reputation portability is a coordination technology.** Without it, hiring defaults to personal networks, which excludes the most talented people outside existing networks.
36
+
37
+ ## Tools
38
+
39
+ | Tool | What it does |
40
+ |------|-------------|
41
+ | `create_worker_profile` | Create a portable reputation profile with skills, location, experience |
42
+ | `add_service_record` | Log a completed job with client details and rating |
43
+ | `get_reputation_profile` | Retrieve full profile with trust score for any requester type |
44
+ | `generate_reference` | Generate a formatted professional reference letter |
45
+ | `list_skill_categories` | Browse all NITA-aligned skill categories |
46
+ | `compare_workers` | Rank multiple workers by trust score and skill match |
47
+
48
+ ## Trust Score
49
+
50
+ Scored 0–100 across four signals:
51
+ - **Job volume** (up to 30 pts) — number of completed jobs
52
+ - **Average quality** (up to 35 pts) — client star ratings
53
+ - **Verified records** (up to 20 pts) — client-OTP-confirmed completions
54
+ - **Tenure** (up to 15 pts) — years of documented history
55
+
56
+ Tiers: `NEW` → `BUILDING` → `ESTABLISHED` → `TRUSTED`
57
+
58
+ ## Quick Start
59
+
60
+ ```bash
61
+ pip install sifa-mcp # coming soon to PyPI
62
+ sifa-mcp # starts on stdio
63
+ ```
64
+
65
+ ## Example
66
+
67
+ ```python
68
+ # Create a mason's portable profile
69
+ create_worker_profile(
70
+ full_name="James Mwangi",
71
+ phone="0712345678",
72
+ primary_skill="construction",
73
+ sub_skills="masonry,tiling,plastering",
74
+ location="Nairobi",
75
+ years_experience=8
76
+ )
77
+ # → SFA-A3F2B19C4E1D
78
+
79
+ # Log a completed job
80
+ add_service_record(
81
+ profile_id="SFA-A3F2B19C4E1D",
82
+ client_name="ABC Contractors",
83
+ client_phone="0722000000",
84
+ service_type="Kitchen tiling",
85
+ duration_days=5,
86
+ payment_kes=15000,
87
+ client_rating=5
88
+ )
89
+
90
+ # Generate a reference for a new job application
91
+ generate_reference(profile_id="SFA-A3F2B19C4E1D", reference_purpose="job_application")
92
+ ```
93
+
94
+ ## Research Basis
95
+
96
+ - IFC "The Value of Reputation" (2020)
97
+ - ILO Skills Recognition Framework (2023)
98
+ - World Bank "Mobile-Based Reputation Systems" (2021)
99
+ - Kenya NITA (National Industrial Training Authority) trade classifications
100
+
101
+ ⚠️ DEMO — Production requires Huduma Number / NIIMS integration for identity verification.
102
+
103
+ ---
104
+ *© 2026 Gabriel Mahia / AI Kung Fu LLC · MIT License*
@@ -0,0 +1,82 @@
1
+ # ⭐ sifa-mcp — Portable Reputation & Skills Passport MCP Server
2
+
3
+ *Sifa* = reputation/praise in Swahili.
4
+
5
+ **First portable reputation MCP server for East Africa.**
6
+
7
+ ## The Structural Problem
8
+
9
+ In mature economies, reputation travels: Uber driver ratings, Yelp reviews, LinkedIn endorsements, contractor licence registries. A skilled plumber in Chicago can prove her track record to any homeowner in Los Angeles.
10
+
11
+ In Kenya, trust is tribal and local. A qualified mason in Mombasa cannot take her reputation to Nairobi. Economic mobility is throttled by the non-portability of professional identity.
12
+
13
+ **Reputation portability is a coordination technology.** Without it, hiring defaults to personal networks, which excludes the most talented people outside existing networks.
14
+
15
+ ## Tools
16
+
17
+ | Tool | What it does |
18
+ |------|-------------|
19
+ | `create_worker_profile` | Create a portable reputation profile with skills, location, experience |
20
+ | `add_service_record` | Log a completed job with client details and rating |
21
+ | `get_reputation_profile` | Retrieve full profile with trust score for any requester type |
22
+ | `generate_reference` | Generate a formatted professional reference letter |
23
+ | `list_skill_categories` | Browse all NITA-aligned skill categories |
24
+ | `compare_workers` | Rank multiple workers by trust score and skill match |
25
+
26
+ ## Trust Score
27
+
28
+ Scored 0–100 across four signals:
29
+ - **Job volume** (up to 30 pts) — number of completed jobs
30
+ - **Average quality** (up to 35 pts) — client star ratings
31
+ - **Verified records** (up to 20 pts) — client-OTP-confirmed completions
32
+ - **Tenure** (up to 15 pts) — years of documented history
33
+
34
+ Tiers: `NEW` → `BUILDING` → `ESTABLISHED` → `TRUSTED`
35
+
36
+ ## Quick Start
37
+
38
+ ```bash
39
+ pip install sifa-mcp # coming soon to PyPI
40
+ sifa-mcp # starts on stdio
41
+ ```
42
+
43
+ ## Example
44
+
45
+ ```python
46
+ # Create a mason's portable profile
47
+ create_worker_profile(
48
+ full_name="James Mwangi",
49
+ phone="0712345678",
50
+ primary_skill="construction",
51
+ sub_skills="masonry,tiling,plastering",
52
+ location="Nairobi",
53
+ years_experience=8
54
+ )
55
+ # → SFA-A3F2B19C4E1D
56
+
57
+ # Log a completed job
58
+ add_service_record(
59
+ profile_id="SFA-A3F2B19C4E1D",
60
+ client_name="ABC Contractors",
61
+ client_phone="0722000000",
62
+ service_type="Kitchen tiling",
63
+ duration_days=5,
64
+ payment_kes=15000,
65
+ client_rating=5
66
+ )
67
+
68
+ # Generate a reference for a new job application
69
+ generate_reference(profile_id="SFA-A3F2B19C4E1D", reference_purpose="job_application")
70
+ ```
71
+
72
+ ## Research Basis
73
+
74
+ - IFC "The Value of Reputation" (2020)
75
+ - ILO Skills Recognition Framework (2023)
76
+ - World Bank "Mobile-Based Reputation Systems" (2021)
77
+ - Kenya NITA (National Industrial Training Authority) trade classifications
78
+
79
+ ⚠️ DEMO — Production requires Huduma Number / NIIMS integration for identity verification.
80
+
81
+ ---
82
+ *© 2026 Gabriel Mahia / AI Kung Fu LLC · MIT License*
@@ -0,0 +1,33 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "sifa-mcp"
7
+ version = "0.1.0"
8
+ description = "MCP server for portable reputation and skills passports in East Africa"
9
+ authors = [{name = "Gabriel Mahia", email = "contact@aikungfu.dev"}]
10
+ license = {text = "MIT"}
11
+ readme = "README.md"
12
+ requires-python = ">=3.9"
13
+ keywords = ["mcp", "reputation", "kenya", "africa", "skills", "passport", "workers", "sifa"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
20
+ "Topic :: Office/Business",
21
+ ]
22
+ dependencies = ["fastmcp>=2.0.0"]
23
+
24
+ [project.urls]
25
+ Homepage = "https://github.com/gabrielmahia/sifa-mcp"
26
+ Repository = "https://github.com/gabrielmahia/sifa-mcp"
27
+ Issues = "https://github.com/gabrielmahia/sifa-mcp/issues"
28
+
29
+ [project.scripts]
30
+ sifa-mcp = "sifa_mcp.main:main"
31
+
32
+ [tool.setuptools.packages.find]
33
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,2 @@
1
+ """sifa-mcp: Portable Reputation & Skills Passport MCP Server"""
2
+ __version__ = "0.1.0"
@@ -0,0 +1,423 @@
1
+ #!/usr/bin/env python3
2
+ # sifa-mcp — Portable Reputation & Skills Passport MCP Server
3
+ # © 2026 Gabriel Mahia / AI Kung Fu LLC — MIT License
4
+ #
5
+ # Sifa = reputation/praise in Swahili
6
+ #
7
+ # The structural problem: Trust in East Africa is tribal/family-based.
8
+ # A skilled mechanic in Mombasa cannot take her reputation to Nairobi.
9
+ # A qualified mason cannot prove his work history to a new contractor.
10
+ # Economic mobility is throttled by reputation portability.
11
+ #
12
+ # Western parallel: Yelp, Uber ratings, LinkedIn endorsements, Angie's List,
13
+ # Better Business Bureau, professional license registries.
14
+ # Research: IFC "The Value of Reputation" (2020), ILO Skills Recognition (2023)
15
+ # "Mobile-Based Reputation Systems" (World Bank, 2021)
16
+ #
17
+ # TRUST INTEGRITY: All profiles are DEMO/synthetic. No real identity verification.
18
+ # A production implementation requires integration with Huduma Number, NIIMS,
19
+ # or other Kenya DPI (Digital Public Infrastructure) identity systems.
20
+ # =============================================================================
21
+
22
+ from __future__ import annotations
23
+ import json
24
+ import datetime
25
+ import hashlib
26
+ from typing import Annotated
27
+ from fastmcp import FastMCP
28
+
29
+ mcp = FastMCP(
30
+ name="sifa-mcp",
31
+ instructions="""Portable reputation and skills passport MCP server for East Africa.
32
+ Provides tools to create worker profiles, record service history, generate
33
+ references, and calculate trust scores — enabling economic mobility for
34
+ informal workers.
35
+
36
+ IMPORTANT: All profiles are DEMO/synthetic. No real identity verification.
37
+ A production deployment requires integration with Kenya's Huduma Number
38
+ or NIIMS identity infrastructure.
39
+ """,
40
+ )
41
+
42
+ # In-memory profile store (demo — production uses persistent DB)
43
+ _PROFILES: dict[str, dict] = {}
44
+
45
+ SKILL_CATEGORIES = {
46
+ "construction": ["masonry", "plumbing", "electrical", "carpentry", "painting",
47
+ "roofing", "tiling", "welding", "concrete_work"],
48
+ "transport": ["boda_boda_riding", "tuk_tuk_driving", "truck_driving",
49
+ "taxi_driving", "logistics_coordination"],
50
+ "domestic": ["house_cleaning", "childcare", "cooking", "laundry",
51
+ "elder_care", "gardening"],
52
+ "tech": ["phone_repair", "computer_repair", "solar_installation",
53
+ "appliance_repair", "cctv_installation"],
54
+ "agriculture": ["crop_farming", "animal_husbandry", "irrigation",
55
+ "pest_control", "greenhouse_management"],
56
+ "food": ["catering", "baking", "butchery", "food_processing",
57
+ "market_vending"],
58
+ "health": ["community_health_worker", "pharmacy_assistant",
59
+ "lab_technician", "first_aid"],
60
+ "education": ["primary_tutoring", "secondary_tutoring", "vocational_training",
61
+ "adult_literacy"],
62
+ "business": ["bookkeeping", "inventory_management", "sales",
63
+ "customer_service", "procurement"],
64
+ }
65
+
66
+ def _profile_id(name: str, phone: str) -> str:
67
+ """Generate a deterministic, non-reversible profile ID."""
68
+ raw = f"{name.lower().strip()}:{phone.strip()}"
69
+ return "SFA-" + hashlib.sha256(raw.encode()).hexdigest()[:12].upper()
70
+
71
+ def _trust_score(profile: dict) -> dict:
72
+ """Calculate trust score from profile signals."""
73
+ jobs = profile.get("service_records", [])
74
+ verified = sum(1 for j in jobs if j.get("verified"))
75
+ avg_rating = (sum(j.get("rating", 0) for j in jobs) / len(jobs)) if jobs else 0
76
+ tenure_months = profile.get("tenure_months", 0)
77
+
78
+ # Score components (0-100)
79
+ volume_score = min(30, len(jobs) * 3) # Up to 30 pts for job count
80
+ quality_score = int(avg_rating / 5 * 35) # Up to 35 pts for avg rating
81
+ verified_score = min(20, verified * 5) # Up to 20 pts for verified jobs
82
+ tenure_score = min(15, tenure_months // 3) # Up to 15 pts for tenure
83
+
84
+ total = volume_score + quality_score + verified_score + tenure_score
85
+
86
+ tier = ("TRUSTED" if total >= 70 else
87
+ "ESTABLISHED" if total >= 45 else
88
+ "BUILDING" if total >= 20 else "NEW")
89
+
90
+ return {
91
+ "total_score": total,
92
+ "tier": tier,
93
+ "breakdown": {
94
+ "job_volume": volume_score,
95
+ "average_quality": quality_score,
96
+ "verified_records": verified_score,
97
+ "tenure": tenure_score,
98
+ },
99
+ "tier_description": {
100
+ "TRUSTED": "Strong, verifiable history. High confidence for new engagements.",
101
+ "ESTABLISHED": "Good track record. Suitable for most engagements.",
102
+ "BUILDING": "Growing history. Recommend starting with small jobs.",
103
+ "NEW": "Limited history. Ask for references and start with a trial job.",
104
+ }[tier],
105
+ }
106
+
107
+
108
+ @mcp.tool(
109
+ description=(
110
+ "Create a portable worker reputation profile. "
111
+ "Western parallel: LinkedIn profile creation, Angie's List contractor profile. "
112
+ "This is the 'economic passport' that travels with the worker. "
113
+ "DEMO — no real identity verification in this prototype."
114
+ ),
115
+ annotations={"readOnlyHint": False, "destructiveHint": False},
116
+ )
117
+ def create_worker_profile(
118
+ full_name: Annotated[str, "Worker's full name"],
119
+ phone: Annotated[str, "M-PESA phone number (used as identity anchor, not stored in plain text)"],
120
+ primary_skill: Annotated[str, "Primary skill category (see skill_categories tool)"],
121
+ sub_skills: Annotated[str, "Comma-separated list of specific skills (e.g., 'masonry,tiling,plastering')"],
122
+ location: Annotated[str, "Current base location (town or county)"],
123
+ years_experience: Annotated[int, "Years of experience in primary skill (0-40)"],
124
+ languages: Annotated[str, "Languages spoken (e.g., 'Swahili,English,Kikuyu')"] = "Swahili",
125
+ ) -> dict:
126
+ profile_id = _profile_id(full_name, phone)
127
+
128
+ profile = {
129
+ "profile_id": profile_id,
130
+ "name": full_name,
131
+ "phone_masked": phone[-4:].rjust(len(phone), "*"),
132
+ "primary_skill": primary_skill.lower(),
133
+ "sub_skills": [s.strip() for s in sub_skills.split(",")],
134
+ "location": location,
135
+ "years_experience": years_experience,
136
+ "languages": [l.strip() for l in languages.split(",")],
137
+ "created": datetime.date.today().isoformat(),
138
+ "service_records": [],
139
+ "tenure_months": max(0, years_experience * 12),
140
+ }
141
+
142
+ _PROFILES[profile_id] = profile
143
+
144
+ return {
145
+ "status": "OK",
146
+ "profile_id": profile_id,
147
+ "profile_summary": {
148
+ "name": full_name,
149
+ "primary_skill": primary_skill,
150
+ "location": location,
151
+ "experience_years": years_experience,
152
+ "trust_score": _trust_score(profile),
153
+ },
154
+ "next_steps": [
155
+ "Add service records with add_service_record to build trust score",
156
+ "Share your profile_id with clients so they can verify your history",
157
+ "After 5+ verified records, generate a reference with generate_reference",
158
+ ],
159
+ "share_text": (
160
+ f"My Sifa Profile: {profile_id} · {primary_skill} · {years_experience}yr exp · {location}"
161
+ ),
162
+ "note": "DEMO — No real identity verification. Production requires Huduma Number integration.",
163
+ "source": "sifa-mcp. Reference: IFC 'The Value of Reputation' (2020).",
164
+ }
165
+
166
+
167
+ @mcp.tool(
168
+ description=(
169
+ "Add a completed service record to a worker's profile. "
170
+ "Western parallel: Uber trip completion, Angie's List job review, "
171
+ "Upwork completed contract. Each record builds the reputation score. "
172
+ "DEMO — client verification is simulated."
173
+ ),
174
+ annotations={"readOnlyHint": False, "destructiveHint": False},
175
+ )
176
+ def add_service_record(
177
+ profile_id: Annotated[str, "Worker profile ID (SFA-XXXXXXXXXXXX format)"],
178
+ client_name: Annotated[str, "Client name (or business name)"],
179
+ client_phone: Annotated[str, "Client M-PESA number (for verification anchor)"],
180
+ service_type: Annotated[str, "Type of service performed"],
181
+ duration_days: Annotated[int, "Duration of the job in days"],
182
+ payment_kes: Annotated[int, "Amount paid in KES (0 if unpaid/pro bono)"],
183
+ client_rating: Annotated[int, "Client rating 1-5 stars"],
184
+ notes: Annotated[str, "Brief description of work done"] = "",
185
+ ) -> dict:
186
+ if profile_id not in _PROFILES:
187
+ return {"status": "NOT_FOUND",
188
+ "message": f"Profile {profile_id} not found. Create it first with create_worker_profile."}
189
+
190
+ if not 1 <= client_rating <= 5:
191
+ return {"status": "ERROR", "message": "Rating must be 1-5"}
192
+
193
+ record = {
194
+ "record_id": f"REC-{datetime.date.today().isoformat()}-{len(_PROFILES[profile_id]['service_records'])+1:03d}",
195
+ "date": datetime.date.today().isoformat(),
196
+ "service": service_type,
197
+ "client": client_name,
198
+ "client_phone_masked": client_phone[-4:].rjust(len(client_phone), "*"),
199
+ "duration_days": duration_days,
200
+ "payment_kes": payment_kes,
201
+ "rating": client_rating,
202
+ "notes": notes,
203
+ "verified": True, # In demo, all client-submitted records are marked verified
204
+ # Production: requires OTP confirmation from client phone
205
+ }
206
+
207
+ _PROFILES[profile_id]["service_records"].append(record)
208
+ new_score = _trust_score(_PROFILES[profile_id])
209
+
210
+ return {
211
+ "status": "OK",
212
+ "record_id": record["record_id"],
213
+ "profile_id": profile_id,
214
+ "new_trust_score": new_score,
215
+ "total_records": len(_PROFILES[profile_id]["service_records"]),
216
+ "verification_note": (
217
+ "DEMO: Record marked verified. In production, client receives an OTP "
218
+ "to confirm the job completion — prevents workers from fabricating history."
219
+ ),
220
+ "source": "sifa-mcp.",
221
+ }
222
+
223
+
224
+ @mcp.tool(
225
+ description=(
226
+ "Retrieve a worker's full reputation profile including trust score. "
227
+ "Western parallel: Checking a contractor's BBB rating or Upwork JSS. "
228
+ "DEMO data."
229
+ ),
230
+ annotations={"readOnlyHint": True},
231
+ )
232
+ def get_reputation_profile(
233
+ profile_id: Annotated[str, "Worker profile ID to retrieve"],
234
+ requester_context: Annotated[str, "Who is requesting (employer, SACCO, bank, NGO)"] = "employer",
235
+ ) -> dict:
236
+ if profile_id not in _PROFILES:
237
+ return {"status": "NOT_FOUND",
238
+ "message": "Profile not found. Worker may not have registered yet."}
239
+
240
+ profile = _PROFILES[profile_id]
241
+ score = _trust_score(profile)
242
+ records = profile.get("service_records", [])
243
+
244
+ return {
245
+ "status": "OK",
246
+ "profile": {
247
+ "profile_id": profile_id,
248
+ "name": profile["name"],
249
+ "primary_skill": profile["primary_skill"],
250
+ "skills": profile["sub_skills"],
251
+ "location": profile["location"],
252
+ "experience_years": profile["years_experience"],
253
+ "languages": profile["languages"],
254
+ "member_since": profile["created"],
255
+ },
256
+ "trust_score": score,
257
+ "service_history": {
258
+ "total_jobs": len(records),
259
+ "verified_jobs": sum(1 for r in records if r.get("verified")),
260
+ "average_rating": round(sum(r["rating"] for r in records) / len(records), 1) if records else 0,
261
+ "total_earned_kes": sum(r.get("payment_kes", 0) for r in records),
262
+ "recent_jobs": records[-3:] if records else [],
263
+ },
264
+ "recommendation_for_requester": {
265
+ "employer": f"{'Recommended' if score['tier'] in ('TRUSTED','ESTABLISHED') else 'Start with a trial job'}",
266
+ "SACCO": f"{'Eligible for member loan' if score['tier'] == 'TRUSTED' else 'Insufficient history for loan'}",
267
+ "bank": f"{'Consider for microfinance product' if score['total_score'] >= 60 else 'Insufficient reputation history'}",
268
+ "NGO": f"{'Strong candidate for programme participation' if score['total_score'] >= 30 else 'Emerging candidate'}",
269
+ }.get(requester_context, "Review profile and trust score manually."),
270
+ "note": "DEMO — Synthetic profile. Production requires Huduma Number verification.",
271
+ "source": "sifa-mcp.",
272
+ }
273
+
274
+
275
+ @mcp.tool(
276
+ description=(
277
+ "Generate a structured professional reference letter for a worker. "
278
+ "Western parallel: LinkedIn recommendation, employer reference letter. "
279
+ "Outputs a formatted reference that can be printed, shared as PDF, "
280
+ "or verified by QR code in production. DEMO."
281
+ ),
282
+ annotations={"readOnlyHint": True},
283
+ )
284
+ def generate_reference(
285
+ profile_id: Annotated[str, "Worker profile ID"],
286
+ reference_purpose: Annotated[str, "Purpose: job_application, loan_application, tenancy, SACCO_membership, NGO_programme"] = "job_application",
287
+ ) -> dict:
288
+ if profile_id not in _PROFILES:
289
+ return {"status": "NOT_FOUND", "message": "Profile not found."}
290
+
291
+ profile = _PROFILES[profile_id]
292
+ score = _trust_score(profile)
293
+ records = profile.get("service_records", [])
294
+ today = datetime.date.today().strftime("%B %d, %Y")
295
+ avg_rating = round(sum(r["rating"] for r in records) / len(records), 1) if records else 0
296
+ total_earned = sum(r.get("payment_kes", 0) for r in records)
297
+
298
+ reference_text = f"""SIFA REPUTATION REFERENCE
299
+ Issued: {today}
300
+ Profile ID: {profile_id}
301
+ Verification: sifa-mcp.africastack.io/{profile_id} [DEMO]
302
+
303
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
304
+
305
+ TO WHOM IT MAY CONCERN
306
+
307
+ This reference is issued on behalf of {profile["name"]}, whose portable
308
+ reputation profile ({profile_id}) has been verified by the Sifa network.
309
+
310
+ PROFESSIONAL SUMMARY
311
+ Name: {profile["name"]}
312
+ Primary Skill: {profile["primary_skill"].title()}
313
+ Skills: {", ".join(profile["sub_skills"])}
314
+ Experience: {profile["years_experience"]} years
315
+ Location: {profile["location"]}
316
+ Languages: {", ".join(profile["languages"])}
317
+
318
+ REPUTATION SUMMARY
319
+ Trust Tier: {score["tier"]}
320
+ Trust Score: {score["total_score"]}/100
321
+ Completed Jobs: {len(records)}
322
+ Verified Jobs: {sum(1 for r in records if r.get("verified"))}
323
+ Average Rating: {avg_rating}/5.0 stars
324
+ Total Earned: KES {total_earned:,}
325
+
326
+ ASSESSMENT
327
+ {profile["name"]} has demonstrated {score["tier_description"].lower()}
328
+
329
+ {"This reference is provided for: " + reference_purpose.replace("_", " ").title() + "."}
330
+
331
+ VERIFICATION
332
+ This profile can be independently verified at the QR code above or by
333
+ contacting the Sifa network at sifa-mcp.africastack.io [DEMO].
334
+
335
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
336
+ ⚠️ DEMO DOCUMENT — Synthetic for educational purposes.
337
+ Production version requires Huduma Number integration.
338
+ sifa-mcp · © 2026 Gabriel Mahia / AI Kung Fu LLC · MIT License
339
+ """
340
+
341
+ return {
342
+ "status": "OK",
343
+ "profile_id": profile_id,
344
+ "reference_purpose": reference_purpose,
345
+ "reference_text": reference_text,
346
+ "trust_score": score,
347
+ "note": "DEMO — Reference is illustrative only. Production version uses digital signatures and Huduma Number verification.",
348
+ "source": "sifa-mcp. Reference: ILO Skills Recognition Framework (2023).",
349
+ }
350
+
351
+
352
+ @mcp.tool(
353
+ description=(
354
+ "List all skill categories and subcategories available in the Sifa system. "
355
+ "Use this to see valid skill values for create_worker_profile."
356
+ ),
357
+ annotations={"readOnlyHint": True},
358
+ )
359
+ def list_skill_categories() -> dict:
360
+ return {
361
+ "status": "OK",
362
+ "categories": SKILL_CATEGORIES,
363
+ "total_skills": sum(len(v) for v in SKILL_CATEGORIES.values()),
364
+ "usage": "Pass the category name as primary_skill and specific skills as sub_skills in create_worker_profile",
365
+ "source": "sifa-mcp. Categories aligned with Kenya NITA (National Industrial Training Authority) trade classifications.",
366
+ }
367
+
368
+
369
+ @mcp.tool(
370
+ description=(
371
+ "Compare the reputation scores of multiple workers for a specific job. "
372
+ "Western parallel: Contractor comparison on Thumbtack, Bark, or Houzz. "
373
+ "DEMO data."
374
+ ),
375
+ annotations={"readOnlyHint": True},
376
+ )
377
+ def compare_workers(
378
+ profile_ids: Annotated[str, "Comma-separated list of profile IDs to compare"],
379
+ required_skill: Annotated[str, "Skill required for the job"] = "",
380
+ ) -> dict:
381
+ ids = [p.strip() for p in profile_ids.split(",")]
382
+ results = []
383
+ for pid in ids:
384
+ if pid in _PROFILES:
385
+ p = _PROFILES[pid]
386
+ s = _trust_score(p)
387
+ results.append({
388
+ "profile_id": pid,
389
+ "name": p["name"],
390
+ "primary_skill": p["primary_skill"],
391
+ "location": p["location"],
392
+ "trust_score": s["total_score"],
393
+ "trust_tier": s["tier"],
394
+ "total_jobs": len(p.get("service_records", [])),
395
+ "experience_years": p["years_experience"],
396
+ "skill_match": not required_skill or required_skill.lower() in [
397
+ sk.lower() for sk in p.get("sub_skills", [])] or
398
+ required_skill.lower() == p["primary_skill"].lower(),
399
+ })
400
+ else:
401
+ results.append({"profile_id": pid, "status": "NOT_FOUND"})
402
+
403
+ results_sorted = sorted(
404
+ [r for r in results if "trust_score" in r],
405
+ key=lambda x: (x.get("skill_match", False), x.get("trust_score", 0)),
406
+ reverse=True
407
+ )
408
+
409
+ return {
410
+ "status": "OK",
411
+ "required_skill": required_skill or "any",
412
+ "ranked_workers": results_sorted,
413
+ "recommendation": results_sorted[0] if results_sorted else None,
414
+ "note": "DEMO — Ranking based on synthetic trust scores. Production uses verified job history.",
415
+ "source": "sifa-mcp.",
416
+ }
417
+
418
+
419
+ def main():
420
+ mcp.run()
421
+
422
+ if __name__ == "__main__":
423
+ main()
@@ -0,0 +1,104 @@
1
+ Metadata-Version: 2.4
2
+ Name: sifa-mcp
3
+ Version: 0.1.0
4
+ Summary: MCP server for portable reputation and skills passports in East Africa
5
+ Author-email: Gabriel Mahia <contact@aikungfu.dev>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/gabrielmahia/sifa-mcp
8
+ Project-URL: Repository, https://github.com/gabrielmahia/sifa-mcp
9
+ Project-URL: Issues, https://github.com/gabrielmahia/sifa-mcp/issues
10
+ Keywords: mcp,reputation,kenya,africa,skills,passport,workers,sifa
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
16
+ Classifier: Topic :: Office/Business
17
+ Requires-Python: >=3.9
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: fastmcp>=2.0.0
21
+ Dynamic: license-file
22
+
23
+ # ⭐ sifa-mcp — Portable Reputation & Skills Passport MCP Server
24
+
25
+ *Sifa* = reputation/praise in Swahili.
26
+
27
+ **First portable reputation MCP server for East Africa.**
28
+
29
+ ## The Structural Problem
30
+
31
+ In mature economies, reputation travels: Uber driver ratings, Yelp reviews, LinkedIn endorsements, contractor licence registries. A skilled plumber in Chicago can prove her track record to any homeowner in Los Angeles.
32
+
33
+ In Kenya, trust is tribal and local. A qualified mason in Mombasa cannot take her reputation to Nairobi. Economic mobility is throttled by the non-portability of professional identity.
34
+
35
+ **Reputation portability is a coordination technology.** Without it, hiring defaults to personal networks, which excludes the most talented people outside existing networks.
36
+
37
+ ## Tools
38
+
39
+ | Tool | What it does |
40
+ |------|-------------|
41
+ | `create_worker_profile` | Create a portable reputation profile with skills, location, experience |
42
+ | `add_service_record` | Log a completed job with client details and rating |
43
+ | `get_reputation_profile` | Retrieve full profile with trust score for any requester type |
44
+ | `generate_reference` | Generate a formatted professional reference letter |
45
+ | `list_skill_categories` | Browse all NITA-aligned skill categories |
46
+ | `compare_workers` | Rank multiple workers by trust score and skill match |
47
+
48
+ ## Trust Score
49
+
50
+ Scored 0–100 across four signals:
51
+ - **Job volume** (up to 30 pts) — number of completed jobs
52
+ - **Average quality** (up to 35 pts) — client star ratings
53
+ - **Verified records** (up to 20 pts) — client-OTP-confirmed completions
54
+ - **Tenure** (up to 15 pts) — years of documented history
55
+
56
+ Tiers: `NEW` → `BUILDING` → `ESTABLISHED` → `TRUSTED`
57
+
58
+ ## Quick Start
59
+
60
+ ```bash
61
+ pip install sifa-mcp # coming soon to PyPI
62
+ sifa-mcp # starts on stdio
63
+ ```
64
+
65
+ ## Example
66
+
67
+ ```python
68
+ # Create a mason's portable profile
69
+ create_worker_profile(
70
+ full_name="James Mwangi",
71
+ phone="0712345678",
72
+ primary_skill="construction",
73
+ sub_skills="masonry,tiling,plastering",
74
+ location="Nairobi",
75
+ years_experience=8
76
+ )
77
+ # → SFA-A3F2B19C4E1D
78
+
79
+ # Log a completed job
80
+ add_service_record(
81
+ profile_id="SFA-A3F2B19C4E1D",
82
+ client_name="ABC Contractors",
83
+ client_phone="0722000000",
84
+ service_type="Kitchen tiling",
85
+ duration_days=5,
86
+ payment_kes=15000,
87
+ client_rating=5
88
+ )
89
+
90
+ # Generate a reference for a new job application
91
+ generate_reference(profile_id="SFA-A3F2B19C4E1D", reference_purpose="job_application")
92
+ ```
93
+
94
+ ## Research Basis
95
+
96
+ - IFC "The Value of Reputation" (2020)
97
+ - ILO Skills Recognition Framework (2023)
98
+ - World Bank "Mobile-Based Reputation Systems" (2021)
99
+ - Kenya NITA (National Industrial Training Authority) trade classifications
100
+
101
+ ⚠️ DEMO — Production requires Huduma Number / NIIMS integration for identity verification.
102
+
103
+ ---
104
+ *© 2026 Gabriel Mahia / AI Kung Fu LLC · MIT License*
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/sifa_mcp/__init__.py
5
+ src/sifa_mcp/main.py
6
+ src/sifa_mcp.egg-info/PKG-INFO
7
+ src/sifa_mcp.egg-info/SOURCES.txt
8
+ src/sifa_mcp.egg-info/dependency_links.txt
9
+ src/sifa_mcp.egg-info/entry_points.txt
10
+ src/sifa_mcp.egg-info/requires.txt
11
+ src/sifa_mcp.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ sifa-mcp = sifa_mcp.main:main
@@ -0,0 +1 @@
1
+ fastmcp>=2.0.0
@@ -0,0 +1 @@
1
+ sifa_mcp