new-site/mcp/src/tools/formation.ts
justin f8cd37ac8c Initial commit — Performance West telecom compliance platform
Includes: API (Express/TypeScript), Astro site, Python workers,
document generators, FCC compliance tools, Canada CRTC formation,
Ansible infrastructure, and deployment scripts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 06:54:22 -05:00

381 lines
17 KiB
TypeScript

/**
* Formation tools — the core business formation workflow.
*
* Tools:
* formation_guide — Interactive questionnaire → entity + state recommendation
* search_name — Check business name availability in a state
* create_formation_order — Place a complete formation order
* check_order_status — Check status of an existing order
*/
import { z } from "zod";
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { apiGet, apiPost } from "../client.js";
// Recommendation logic (mirrors the website formation guide)
interface Recommendation {
entity_type: string;
entity_reason: string;
state: string;
state_name: string;
state_reason: string;
cost_basic: number;
cost_complete: number;
annual_cost: number;
notes: string[];
}
const STATE_NAMES: Record<string, string> = {
AL:"Alabama",AK:"Alaska",AZ:"Arizona",AR:"Arkansas",CA:"California",CO:"Colorado",
CT:"Connecticut",DE:"Delaware",FL:"Florida",GA:"Georgia",HI:"Hawaii",ID:"Idaho",
IL:"Illinois",IN:"Indiana",IA:"Iowa",KS:"Kansas",KY:"Kentucky",LA:"Louisiana",
ME:"Maine",MD:"Maryland",MA:"Massachusetts",MI:"Michigan",MN:"Minnesota",
MS:"Mississippi",MO:"Missouri",MT:"Montana",NE:"Nebraska",NV:"Nevada",
NH:"New Hampshire",NJ:"New Jersey",NM:"New Mexico",NY:"New York",NC:"North Carolina",
ND:"North Dakota",OH:"Ohio",OK:"Oklahoma",OR:"Oregon",PA:"Pennsylvania",
RI:"Rhode Island",SC:"South Carolina",SD:"South Dakota",TN:"Tennessee",TX:"Texas",
UT:"Utah",VT:"Vermont",VA:"Virginia",WA:"Washington",WV:"West Virginia",
WI:"Wisconsin",WY:"Wyoming",DC:"District of Columbia",
};
const STATE_FEES: Record<string, { llc: number; corp: number; annual: number }> = {
WY:{llc:100,corp:100,annual:60},DE:{llc:110,corp:89,annual:300},NV:{llc:425,corp:725,annual:350},
TX:{llc:300,corp:300,annual:0},FL:{llc:125,corp:70,annual:139},CA:{llc:70,corp:100,annual:800},
CO:{llc:50,corp:50,annual:25},MT:{llc:35,corp:70,annual:20},NM:{llc:50,corp:125,annual:0},
OH:{llc:99,corp:99,annual:0},UT:{llc:59,corp:59,annual:18},MA:{llc:500,corp:275,annual:500},
NY:{llc:200,corp:125,annual:9},SD:{llc:150,corp:150,annual:55},TN:{llc:300,corp:100,annual:300},
};
function recommend(answers: {
situation: string;
tax_id: string;
owners: string;
revenue: string;
operations: string;
home_state: string;
priorities: string[];
}): Recommendation {
let entity = "LLC";
let entityReason = "";
let state = "WY";
let stateReason = "";
const notes: string[] = [];
const p = answers.priorities || [];
// Entity type
if (answers.owners === "investors") {
entity = "C-Corporation";
entityReason = "C-Corporations are standard for raising investment capital. Investors expect the familiar stock structure.";
} else if (answers.revenue === "over_500k" && answers.owners === "single") {
entity = "LLC with S-Corp election";
entityReason = "At your revenue level, an S-Corp election saves significant self-employment taxes while keeping LLC flexibility.";
} else if (answers.revenue === "100k_500k") {
entity = "LLC (consider S-Corp later)";
entityReason = "An LLC provides liability protection and pass-through taxation. Consider S-Corp election as revenue grows.";
} else {
entity = "LLC";
entityReason = "An LLC provides personal liability protection, pass-through taxation, and flexible management. Best choice for most small businesses.";
}
// State
if (answers.owners === "investors") {
state = "DE";
stateReason = "Delaware's Court of Chancery and established corporate law make it standard for investor-backed companies.";
} else if (p.includes("privacy") && p.includes("no_income_tax")) {
state = "WY";
stateReason = "Wyoming: no income tax, strongest privacy (no public member disclosure), excellent asset protection, low cost.";
} else if (p.includes("low_cost") && answers.home_state) {
const hf = STATE_FEES[answers.home_state];
if (hf && hf.llc >= 175) {
state = "WY";
stateReason = `Your home state (${STATE_NAMES[answers.home_state]}) charges $${hf.llc} for LLC formation. Wyoming ($100) + foreign qualification is more cost-effective plus you get privacy and no income tax.`;
} else {
state = answers.home_state;
stateReason = `${STATE_NAMES[answers.home_state]} has reasonable formation costs. Forming in your home state avoids foreign qualification fees.`;
}
} else if (answers.home_state === "TX") {
state = p.includes("privacy") ? "WY" : "TX";
stateReason = state === "WY"
? "Wyoming adds privacy protections over Texas. Foreign qualification in TX is a one-time $750 fee."
: "Texas: no income tax, large economy, fast processing. No franchise tax unless revenue exceeds $2.47M.";
} else if (answers.home_state === "FL") {
state = p.includes("privacy") ? "WY" : "FL";
stateReason = state === "WY"
? "Wyoming adds privacy over Florida. FL foreign qualification is only $125 one-time."
: "Florida: no personal income tax. Corporate income tax only applies to C-Corps, not LLCs/S-Corps.";
} else if (answers.operations === "single_state" && answers.home_state) {
state = answers.home_state;
stateReason = `Operating in one state — forming in your home state (${STATE_NAMES[answers.home_state]}) avoids foreign qualification.`;
} else {
state = "WY";
stateReason = "Wyoming: no income tax, no franchise tax, strong privacy, excellent asset protection, fast processing, low cost.";
}
const sf = STATE_FEES[state] || { llc: 100, corp: 100, annual: 60 };
const isLLC = !entity.includes("C-Corp");
const stateFee = isLLC ? sf.llc : sf.corp;
return {
entity_type: entity,
entity_reason: entityReason,
state,
state_name: STATE_NAMES[state] || state,
state_reason: stateReason,
cost_basic: stateFee + 179,
cost_complete: stateFee + 399,
annual_cost: sf.annual,
notes,
};
}
export function registerFormationTools(server: McpServer): void {
// ── Formation Guide ──────────────────────────────────────────────
server.registerTool(
"formation_guide",
{
title: "Business Formation Guide",
description:
"Interactive questionnaire that recommends the best entity type (LLC, Corporation, S-Corp) " +
"and formation state based on the user's situation. Provide answers to get a personalized recommendation. " +
"Performance West offers business formation in all 50 US states from $179 (basic) or $399 (complete).",
inputSchema: {
situation: z.enum(["new_business", "restructure", "holding", "ecommerce"])
.describe("Business situation: new_business, restructure, holding, or ecommerce"),
tax_id: z.enum(["us_ssn", "has_itin", "needs_itin"])
.describe("Tax ID status: us_ssn (US citizen with SSN), has_itin (foreign with ITIN), needs_itin (foreign without ITIN)"),
owners: z.enum(["single", "multi", "investors"])
.describe("Number of owners: single, multi (multiple partners), or investors (raising VC/angel)"),
revenue: z.enum(["under_100k", "100k_500k", "over_500k"])
.describe("Expected annual revenue range"),
operations: z.enum(["single_state", "multi_state", "online_only"])
.describe("Where the business will operate"),
home_state: z.string().length(2)
.describe("Two-letter state code where the owner lives (e.g., TX, CA, FL)"),
priorities: z.array(z.enum(["low_cost", "privacy", "no_income_tax", "asset_protection", "corp_law", "simplicity"]))
.describe("What matters most (select all that apply)"),
},
},
async (args) => {
if (args.tax_id === "needs_itin") {
return {
content: [{
type: "text" as const,
text: JSON.stringify({
recommendation: "ITIN Required First",
message: "To form a US business and obtain an EIN, you need either an SSN or ITIN. " +
"Visit the IRS Acceptance Agent Program to find an authorized agent in your country: " +
"https://www.irs.gov/individuals/international-taxpayers/acceptance-agent-program",
next_step: "Once you have your ITIN, come back to form your business.",
performancewest_url: "https://performancewest.net/tools/formation-guide",
}, null, 2),
}],
};
}
const rec = recommend(args);
return {
content: [{
type: "text" as const,
text: JSON.stringify({
recommendation: {
entity_type: rec.entity_type,
entity_reason: rec.entity_reason,
formation_state: rec.state,
formation_state_name: rec.state_name,
state_reason: rec.state_reason,
estimated_cost_basic: `$${rec.cost_basic}`,
estimated_cost_complete: `$${rec.cost_complete}`,
annual_ongoing_cost: `$${rec.annual_cost}/year`,
notes: rec.notes,
},
pricing: {
basic: "$179 — Formation filing only",
complete: "$399 — Formation + EIN ($49) + Operating Agreement ($99) + 1st year Registered Agent ($99, $49 WY)",
},
next_steps: [
`Search for name availability in ${rec.state_name} using the search_name tool`,
"Place your order using the create_formation_order tool",
"Or visit https://performancewest.net/order/formation",
],
}, null, 2),
}],
};
},
);
// ── Name Search ──────────────────────────────────────────────────
server.registerTool(
"search_name",
{
title: "Search Business Name Availability",
description:
"Check if a business name is available in a specific US state. " +
"Returns availability status and similar existing names.",
inputSchema: {
state: z.string().length(2).describe("Two-letter state code (e.g., WY, DE, TX)"),
name: z.string().min(2).describe("Desired business name (e.g., 'Acme Holdings LLC')"),
},
},
async ({ state, name }) => {
const res = await apiGet<{ state_code: string; name: string; available: boolean | null; message: string; similar_names: string[] }>(
`/api/v1/states/${state.toUpperCase()}/name-search`,
{ name },
);
if (!res.ok) {
return { content: [{ type: "text" as const, text: `Name search failed: ${JSON.stringify(res.data)}` }], isError: true };
}
return {
content: [{
type: "text" as const,
text: JSON.stringify({
state: res.data.state_code,
name: res.data.name,
available: res.data.available,
message: res.data.message,
similar_names: res.data.similar_names,
next_step: res.data.available
? "Name is available! Use create_formation_order to place your order."
: "Name is taken. Try a different name.",
}, null, 2),
}],
};
},
);
// ── Create Formation Order ───────────────────────────────────────
server.registerTool(
"create_formation_order",
{
title: "Create Business Formation Order",
description:
"Place a complete business formation order. Creates an LLC, Corporation, or S-Corp in any US state. " +
"Basic tier: $179 (formation only). Complete tier: $399 (includes EIN + Operating Agreement + 1st year Registered Agent). " +
"State filing fees are additional and vary by state.",
inputSchema: {
customer_name: z.string().min(2).describe("Full name of the person placing the order"),
customer_email: z.string().email().describe("Email address for order confirmations and document delivery"),
customer_phone: z.string().optional().describe("Phone number (optional)"),
state_code: z.string().length(2).describe("Two-letter state code for formation (e.g., WY, DE, TX)"),
entity_type: z.enum(["llc", "corporation", "s_corp"]).describe("Entity type to form"),
entity_name: z.string().min(3).describe("Desired entity name (e.g., 'Acme Holdings LLC')"),
entity_name_alt: z.string().optional().describe("Backup name if primary is unavailable"),
management_type: z.enum(["member_managed", "manager_managed"]).optional()
.describe("LLC management type (default: member_managed)"),
principal_address: z.string().describe("Principal business address (street)"),
principal_city: z.string().describe("City"),
principal_state: z.string().length(2).describe("State code"),
principal_zip: z.string().describe("ZIP code"),
members: z.array(z.object({
name: z.string(),
address: z.string(),
city: z.string(),
state: z.string(),
zip: z.string(),
title: z.string().optional(),
ownership_pct: z.number().optional(),
})).min(1).describe("At least one member/officer with name, address, and ownership %"),
tier: z.enum(["basic", "complete"]).default("basic")
.describe("Pricing tier: basic ($179) or complete ($399 with EIN + OA + RA)"),
discount_code: z.string().optional().describe("Discount or referral code (optional)"),
},
},
async (args) => {
const isComplete = args.tier === "complete";
const serviceFee = isComplete ? 39900 : 17900;
const sf = STATE_FEES[args.state_code.toUpperCase()] || { llc: 100, corp: 100 };
const stateFee = (args.entity_type === "corporation" ? sf.corp : sf.llc) * 100;
const payload = {
customer_name: args.customer_name,
customer_email: args.customer_email,
customer_phone: args.customer_phone,
state_code: args.state_code.toUpperCase(),
entity_type: args.entity_type,
entity_name: args.entity_name,
entity_name_alt: args.entity_name_alt,
management_type: args.management_type || "member_managed",
principal_address: args.principal_address,
principal_city: args.principal_city,
principal_state: args.principal_state,
principal_zip: args.principal_zip,
members: args.members,
include_ra_service: isComplete,
include_ein: isComplete,
include_operating_agreement: isComplete,
expedited: false,
state_fee_cents: stateFee,
service_fee_cents: serviceFee,
expedited_fee_cents: 0,
total_cents: stateFee + serviceFee,
discount_code: args.discount_code,
tier: args.tier,
};
const res = await apiPost<{ success: boolean; order_number?: string; message?: string; error?: string; discount_applied?: unknown }>(
"/api/v1/formations",
payload,
);
if (!res.ok || !res.data.success) {
return {
content: [{ type: "text" as const, text: `Order failed: ${res.data.error || JSON.stringify(res.data)}` }],
isError: true,
};
}
return {
content: [{
type: "text" as const,
text: JSON.stringify({
success: true,
order_number: res.data.order_number,
message: res.data.message,
discount_applied: res.data.discount_applied,
next_steps: [
`Order ${res.data.order_number} has been placed.`,
`An email will be sent to ${args.customer_email} with a link to set up a portal account and track progress.`,
"Formation typically takes 1-5 business days depending on the state.",
`Use check_order_status with order number "${res.data.order_number}" to track progress.`,
],
portal_url: "https://performancewest.net/portal",
}, null, 2),
}],
};
},
);
// ── Check Order Status ───────────────────────────────────────────
server.registerTool(
"check_order_status",
{
title: "Check Formation Order Status",
description: "Check the current status of a business formation order by order number.",
inputSchema: {
order_number: z.string().describe("Order number (e.g., PW-2026-A1B2C3)"),
},
},
async ({ order_number }) => {
const res = await apiGet<{ order?: Record<string, unknown>; error?: string }>(
`/api/v1/formations/${encodeURIComponent(order_number)}`,
);
if (!res.ok) {
return {
content: [{ type: "text" as const, text: `Order not found: ${res.data.error || "Unknown error"}` }],
isError: true,
};
}
return {
content: [{
type: "text" as const,
text: JSON.stringify(res.data.order, null, 2),
}],
};
},
);
}