@offorte/mcp-server
Version:
Offorte MCP Server
853 lines (800 loc) • 27.4 kB
JavaScript
// src/server.ts
import { FastMCP } from "fastmcp";
// src/tools/context/initial-context-guard.ts
var initialContextSet = false;
function initialContextGuard(tool) {
if (tool.name === "get_initial_context") {
return {
...tool,
execute: async (args, context) => {
initialContextSet = true;
return tool.execute(args, context);
}
};
}
return {
...tool,
execute: async (args, context) => {
if (!initialContextSet) {
throw new Error("Initial context has not been set. You must call get_initial_context before using this tool.");
}
return tool.execute(args, context);
}
};
}
// src/tools/context/get-initial-context.ts
import { outdent } from "outdent";
// src/config/env.ts
import dotenv from "dotenv";
import { z } from "zod";
dotenv.config();
var ConfiguredSchema = z.object({
OFFORTE_ACCOUNT_NAME: z.string().describe("Offorte Account Name"),
OFFORTE_API_KEY: z.string().describe("Offorte API key")
});
var EnvSchema = z.object({
OFFORTE_API_HOST: z.string().optional().default("https://connect.offorte.com/api/v2/").describe("Offorte API host"),
TRANSPORT_TYPE: z.enum(["stdio", "sse"]).optional().default("stdio").describe("Transport type for MCP server")
}).merge(ConfiguredSchema);
var env = EnvSchema.safeParse(process.env);
if (!env.success) {
console.error("Invalid environment variables", env.error.format());
process.exit(1);
}
var config = env.data;
// src/config/offorte.ts
if (!env.success) {
throw new Error("Environment variables are not properly configured");
}
var config2 = {
accountName: env.data.OFFORTE_ACCOUNT_NAME,
apiUrl: `${env.data.OFFORTE_API_HOST}${env.data.OFFORTE_ACCOUNT_NAME}`,
apiKey: env.data.OFFORTE_API_KEY
};
// src/instructions.ts
var INSTRUCTIONS = `You are a helpful assistant integrated with Offorte Proposal Software via the Model Context Protocol (MCP).
IMPORTANT FIRST STEP:
- Always call get_initial_context tool first to initialize the session before using any other tools
- This is mandatory for all operations and will give you essential information about the current Offorte environment
WHAT YOU CAN DO
You can help users by:
- Answering questions about their Offorte account
- Retrieving proposal or contact data
- Creating and sending proposals to customers
OFFORTE BASICS
- A proposal is an online, interactive document that outlines a business offer to a customer
- Proposals are sent via email with a link and can be signed online
- A proposal can be signed online for approval by the contact
- A contact can be a person (individual) or an organisation
- An organisation may have multiple people
- A person without an organisation is treated as a private individual
CREATING PROPOSALS
- When creating a proposal, always ask for one required field at a time. Never list all required fields or IDs up front. Guide the user step-by-step, gathering each piece of information in sequence.
- Always gather proposal information step-by-step: ask for one field at a time, confirm, then proceed to the next. Do not present a summary or list of all required fields or IDs at once. This approach prevents overwhelming the user and ensures a smooth, guided experience.
- A proposal is created based on a proposal template, language text template, design template and a contact
- When an organisation contains multiple people, you need to ask the user which persons he/she wants to assign to the proposal
- A proposal template can contain custom fields which are used to insert content into the proposal
- If the selected proposal template has custom fields, go through all fields with the user and fill them in.
To create a proposal, you need:
1. Contact (organisation + person)
2. Proposal template
3. Language text template
4. Design template
Use:
\u2022 search_contact_organisation and search_contact_people to find contacts
\u2022 create_contact to create one if not found (ask first if user wants to use existing)
\u2022 get_proposal_templates, get_text_templates, and get_design_templates to fetch templates
SENDING PROPOSALS:
- After creating a proposal, you can send it to its assigned contacts using the send_proposal tool
- Use send_proposal to send it via: offorte (email sent by system) or self (user sends it manually)
- Use get_email_templates to fetch available templates
- Either use send_message_id or ask the user for a custom send_message
CREATING CONTACTS
- Always search for a contact before creating a new one, if found ask the user if it wants to use the existing contact
- Use the create_contact tool to create a new contact
- The full name and email address are the most important fields
- Only ask for optional fields if the user asks for it
WRITING TEXTS
- When writing proposal texts, use a professional yet conversational tone
- Focus on value proposition and benefits rather than just features
- Make content engaging, persuasive and customer-centric
- Include clear calls-to-action and next steps
- Highlight unique selling points and competitive advantages
- Use active voice and positive language
- Keep paragraphs concise and scannable
- Address potential objections proactively
- Maintain a balance between being informative and sales-oriented
- Use industry-specific terminology appropriately
- Include social proof, case studies, or testimonials when relevant
- Focus on ROI and business outcomes
- End with a strong closing that encourages action
- Avoid generic content - make each proposal feel tailored
RESPONSE FORMAT:
- When listing items, only mention the most relevant field per item, e.g. name, label, etc.
- Always use human understandable language and avoid technical jargon
- When a list of items is longer than 3 items, only mention the first 3 items and then say "and more"
- Never mention ID's, unless the user asks for it
- Keep your responses concise but thorough
- Confirm actions, give next steps, and avoid overexplaining
ACTION-FIRST APPROACH:
- When a user asks for something (e.g. create/send proposal), do it immediately
- After performing the action, provide a short confirmation, key details and logical next steps
ERROR HANDLING:
- If you encounter an error, clearly explain what went wrong
- Suggest how to fix or proceed
- Always validate required fields and contact existence
BEST PRACTICES:
- Be clear, concise, and direct
- Never introduce yourself or write long greetings
- Provide guidance only when needed
- Always focus on helping users achieve their goals quickly
- Never ask the user for optional fields unless they ask for it
You have access to powerful tools that can help you work with Offorte Proposal Software.
Start with get_initial_context and then use the appropriate tools based on the user's needs.
`;
// src/utils/schema.ts
import { z as z2 } from "zod";
var emptyObject = z2.object({});
var optionalId = z2.union([z2.number(), z2.null()]).optional();
var stringOrNumber = z2.union([z2.number(), z2.string()]);
// src/tools/context/get-initial-context.ts
var getInitialContextTool = {
name: "get_initial_context",
description: `IMPORTANT: This tool must be called before using any other tools. It will get usage instructions & Offorte context for this MCP server.`,
parameters: emptyObject,
annotations: {
title: "Get MCP Server Instructions",
openWorldHint: false
},
async execute() {
const currentDate = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US");
const context = outdent`
${INSTRUCTIONS}
Context for your Offorte instance:
<context>
Account Name: ${config2.accountName}
Date today: ${currentDate}
</content>
`;
return context;
}
};
// src/utils/requests.ts
import axios from "axios";
import { UserError } from "fastmcp";
function buildUrl(url) {
if (/^https?:\/\//i.test(url)) {
return url;
}
return `${config2.apiUrl.replace(/\/$/, "")}/${url.replace(/^\//, "")}`;
}
async function request({ url, method = "GET", data, params, headers = {} }) {
const conf = {
url: buildUrl(url),
method,
data,
params,
headers: {
Authorization: config2.apiKey,
Accept: "application/json",
...headers
}
};
try {
const response = await axios(conf);
return response.data;
} catch (err) {
const isAxiosError = axios.isAxiosError(err);
const errorsString = isAxiosError && err.response?.data?.errors ? ` | Errors: ${JSON.stringify(err.response.data.errors)}` : "";
throw new UserError(
`Request failed: ${err["message"] || "Unknown error"}${errorsString}`,
isAxiosError ? {
method,
url: conf.url,
status: err.response?.status,
statusText: err.response?.statusText,
data: err.response?.data,
code: err.code,
errors: err.response?.data?.errors
} : { err }
);
}
}
function get(url, options = {}) {
return request({ url, method: "GET", ...options });
}
function post(url, data, options = {}) {
return request({ url, method: "POST", data, ...options });
}
// src/schemas/favorites.ts
import { z as z4 } from "zod";
// src/schemas/shared.ts
import { z as z3 } from "zod";
var contactType = z3.enum(["organisation", "person"]);
var proposalStatus = z3.enum(["edit", "open", "won", "lost", "closed"]);
var customFieldSchema = z3.object({
label: z3.string(),
name: z3.string(),
required: z3.boolean(),
type: z3.enum(["text", "textarea", "html"])
}).passthrough();
var tagsSchema = z3.array(z3.union([z3.string(), z3.object({ id: z3.number(), name: z3.string() })]));
// src/schemas/favorites.ts
var proposalTemplateSchema = z4.object({
automations_set_id: optionalId,
custom_fields: z4.array(customFieldSchema).optional(),
design_template_id: optionalId,
id: z4.number(),
name: z4.string(),
text_template_id: optionalId
}).passthrough();
var proposalTemplatesSchema = z4.array(proposalTemplateSchema);
// src/utils/errors.ts
import { UserError as UserError2 } from "fastmcp";
var MESSAGES = {
invalidApiResponse: "The API response did not match the expected format."
};
var message = (type) => {
return `Error: ${MESSAGES[type]}`;
};
var throwApiInvalidResponseError = (error) => {
const msg = message("invalidApiResponse");
throw new UserError2(`${msg}: ${String(error)}`);
};
// src/tools/favorites/get-proposal-templates.ts
var getProposalTemplatesTool = {
name: "get_proposal_templates",
description: `Lists proposal templates which are used as starting points to create new proposals`,
parameters: emptyObject,
annotations: {
title: "Get Proposal Templates",
openWorldHint: true
},
async execute() {
const result = await get("/favorites/proposals");
const parsed = proposalTemplatesSchema.safeParse(result);
if (!parsed.success) {
throwApiInvalidResponseError(parsed.error);
}
return JSON.stringify(parsed.data);
}
};
// src/schemas/automations.ts
import { z as z5 } from "zod";
var automationSetSchema = z5.object({
id: z5.number(),
name: z5.string()
}).passthrough();
var automationSetsSchema = z5.array(automationSetSchema);
// src/tools/automations/get-automation-sets.ts
var getAutomationSetsTool = {
name: "get_automation_sets",
description: "Lists automation sets which are used as an optional input to create a new proposal",
parameters: emptyObject,
annotations: {
title: "Get Automation Sets",
openWorldHint: true
},
async execute() {
const result = await get("/automations/sets");
const parsed = automationSetsSchema.safeParse(result);
if (!parsed.success) {
throwApiInvalidResponseError(parsed.error);
}
return JSON.stringify(parsed.data);
}
};
// src/schemas/settings.ts
import { z as z6 } from "zod";
var designTemplateSchema = z6.object({
id: z6.number(),
name: z6.string()
}).passthrough();
var designTemplatesSchema = z6.array(designTemplateSchema);
var emailTemplateSchema = z6.object({
id: z6.number(),
name: z6.string()
}).passthrough();
var emailTemplatesSchema = z6.array(emailTemplateSchema);
var textTemplateSchema = z6.object({
id: z6.number(),
name: z6.string()
}).passthrough();
var textTemplatesSchema = z6.array(textTemplateSchema);
var tagSchema = z6.object({
id: z6.number(),
name: z6.string()
}).passthrough();
var tagsSchema2 = z6.array(tagSchema);
// src/tools/settings/get-design-templates.ts
var getDesignTemplatesTool = {
name: "get_design_templates",
description: "Lists available design templates which are used to create new proposals",
parameters: emptyObject,
annotations: {
title: "Get Design Templates",
openWorldHint: true
},
async execute() {
const result = await get("/settings/design-templates");
const parsed = designTemplatesSchema.safeParse(result);
if (!parsed.success) {
throwApiInvalidResponseError(parsed.error);
}
return JSON.stringify(parsed.data);
}
};
// src/tools/settings/get-email-templates.ts
var getEmailTemplatesTool = {
name: "get_email_templates",
description: "Lists available email templates which are used to send proposals",
parameters: emptyObject,
annotations: {
title: "Get Email Templates",
openWorldHint: true
},
async execute() {
const result = await get("/settings/email-templates");
const parsed = emailTemplatesSchema.safeParse(result);
if (!parsed.success) {
throwApiInvalidResponseError(parsed.error);
}
return JSON.stringify(parsed.data);
}
};
// src/tools/settings/get-text-templates.ts
var getTextTemplatesTool = {
name: "get_text_templates",
description: "Lists available language text templates which are used to create new proposals",
parameters: emptyObject,
annotations: {
title: "Get Language Text Templates",
openWorldHint: true
},
async execute() {
const result = await get("/settings/text-templates");
const parsed = textTemplatesSchema.safeParse(result);
if (!parsed.success) {
throwApiInvalidResponseError(parsed.error);
}
return JSON.stringify(parsed.data);
}
};
// src/schemas/account.ts
import { z as z7 } from "zod";
var accountUserSchema = z7.object({
id: z7.number(),
email: z7.string(),
firstname: z7.string(),
lastname: z7.string(),
phone: z7.string(),
jobtitle: z7.string(),
date_lastlogin: z7.string()
}).passthrough();
var accountUsersSchema = z7.array(accountUserSchema);
// src/tools/account/get-users.ts
var getAccountUsersTool = {
name: "get_account_users",
description: "Lists all account users for the current account",
parameters: emptyObject,
annotations: {
title: "Get Account Users",
openWorldHint: true
},
async execute() {
const result = await get("/account/users");
const parsed = accountUsersSchema.safeParse(result);
if (!parsed.success) {
throwApiInvalidResponseError(parsed.error);
}
return JSON.stringify(parsed.data);
}
};
// src/tools/contacts/get-contact-details.ts
import { z as z10 } from "zod";
// src/schemas/contacts.ts
import { z as z9 } from "zod";
// src/schemas/proposals.ts
import { z as z8 } from "zod";
var proposalListSchema = z8.object({
id: z8.number(),
name: z8.string(),
account_user_id: optionalId,
contact_id: optionalId,
contact_name: z8.string().optional(),
contact_person_fullname: z8.string().nullable().optional(),
contact_type: contactType.optional(),
date_created: z8.string(),
date_modified: z8.string().optional(),
date_viewed: z8.string().optional(),
date_won: z8.string().optional(),
directory_id: optionalId,
price_total: z8.string(),
proposal_nr: stringOrNumber,
status: proposalStatus,
total_price: z8.string().optional(),
total_price_override: z8.string().optional(),
version_id: z8.number()
}).passthrough();
var proposalsListSchema = z8.array(proposalListSchema);
var proposalDirectorySchema = z8.object({
id: z8.number(),
name: z8.string()
});
var proposalDirectoriesSchema = z8.object({
closed: z8.array(proposalDirectorySchema).optional(),
edit: z8.array(proposalDirectorySchema).optional(),
lost: z8.array(proposalDirectorySchema).optional(),
open: z8.array(proposalDirectorySchema).optional(),
won: z8.array(proposalDirectorySchema).optional()
});
var proposalContentRowSchema = z8.object({
content: z8.string(),
discount_type: z8.string().optional(),
discount_value: z8.number().optional(),
hide_price: z8.boolean().optional(),
hide_quantity: z8.boolean().optional(),
price: z8.number().optional(),
product_id: z8.number().optional(),
quantity: z8.number().optional(),
recurring_include_in_totals: z8.boolean().optional(),
recurring_type: z8.string().optional(),
selectable: z8.string().optional(),
sku: z8.union([z8.string(), z8.number()]).optional(),
type: z8.string(),
unique_id: z8.string().optional(),
user_quantity: z8.boolean().optional(),
user_selected: z8.boolean().optional(),
vat_percentage: z8.number().optional()
});
var proposalContentPricetableSchema = z8.object({
id: z8.string(),
rows: z8.array(proposalContentRowSchema)
});
var proposalContentSchema = z8.object({
pricetables: z8.array(proposalContentPricetableSchema)
});
var createProposalSchema = z8.object({
id: z8.number(),
version_id: z8.number()
});
var sendProposalReceiverSchema = z8.object({
email: z8.string(),
fullname: z8.string(),
id: z8.number(),
proposal_link: z8.string()
});
var sendProposalSchema = z8.object({
receivers: z8.array(sendProposalReceiverSchema)
});
// src/schemas/contacts.ts
var addressFields = {
city: z9.string().optional(),
country: z9.string().optional(),
state: z9.string().optional(),
street: z9.string().optional(),
zipcode: z9.string().optional()
};
var socialFields = {
facebook: z9.string().optional(),
instagram: z9.string(),
internet: z9.string(),
linkedin: z9.string(),
twitter: z9.string()
};
var contactFields = {
email: z9.string().optional(),
phone: z9.string().optional(),
mobile: z9.string().optional(),
fax: z9.string().optional()
};
var personFields = {
firstname: z9.string().optional(),
lastname: z9.string().optional(),
fullname: z9.string().optional(),
salutation: z9.string().optional(),
total_proposals: z9.number().optional()
};
var organisationFields = {
name: z9.string(),
coc_number: z9.string().optional(),
vat_number: z9.string().optional(),
account_user_id: optionalId,
account_user_name: z9.string().optional(),
date_created: z9.string(),
proposals_open: z9.number().optional(),
proposals_won: z9.number().optional(),
people: z9.array(z9.lazy(() => personSchema)).optional(),
type: contactType
};
var personSchema = z9.object({
id: z9.number(),
...addressFields,
...socialFields,
...contactFields,
...personFields
}).passthrough();
var organisationSchema = z9.object({
id: z9.number(),
...addressFields,
...socialFields,
...contactFields,
...organisationFields
}).passthrough();
var contactOrganisationsListSchema = z9.array(organisationSchema);
var personOrOrganisationSchema = z9.object({
id: z9.number(),
contact_id: optionalId,
type: contactType,
account_user_id: optionalId,
account_user_name: z9.string().optional(),
organisation: z9.string(),
date_created: z9.string(),
proposals_open: z9.number().optional(),
proposals_won: z9.number().optional(),
...addressFields,
...socialFields,
...contactFields,
firstname: z9.string(),
lastname: z9.string(),
fullname: z9.string(),
salutation: z9.string()
}).passthrough();
var contactPeopleListSchema = z9.array(personOrOrganisationSchema);
var contactDetailsSchema = z9.object({
id: z9.number(),
...addressFields,
...socialFields,
...contactFields,
...organisationFields,
people: z9.array(personSchema).optional(),
proposals: proposalsListSchema.optional(),
tags: tagsSchema2.optional()
}).passthrough();
var contactCreateSchema = z9.object({
type: contactType,
name: z9.string(),
street: z9.string().optional(),
zipcode: z9.string().optional(),
city: z9.string().optional(),
state: z9.string().optional(),
country: z9.string().optional(),
phone: z9.string().optional(),
email: z9.string().optional(),
internet: z9.string().optional(),
linkedin: z9.string().optional(),
facebook: z9.string().optional(),
twitter: z9.string().optional(),
instagram: z9.string().optional(),
coc_number: z9.string().optional(),
vat_number: z9.string().optional(),
tags: tagsSchema2.optional(),
firstname: z9.string().optional(),
lastname: z9.string().optional(),
salutation: z9.string().optional(),
mobile: z9.string().optional()
}).passthrough();
// src/tools/contacts/get-contact-details.ts
var parameters = z10.object({
contact_id: z10.string()
});
var getContactDetailsTool = {
name: "get_contact_details",
description: "Get all details for a contact by id",
parameters,
annotations: {
title: "Get Contact Details",
openWorldHint: true
},
async execute({ contact_id }) {
const result = await get(`/contacts/${contact_id}`);
const parsed = contactDetailsSchema.safeParse(result);
if (!parsed.success) {
throwApiInvalidResponseError(parsed.error);
}
return JSON.stringify(parsed.data);
}
};
// src/tools/contacts/search-contact-organisations.ts
import { z as z11 } from "zod";
var parameters2 = z11.object({
search: z11.string()
});
var searchContactOrganisationsTool = {
name: "search_contact_organisations",
description: "Search for organisations by name in the contacts",
parameters: parameters2,
annotations: {
title: "Search Contact Organisations",
openWorldHint: true
},
async execute({ search }) {
const result = await get(`/contacts/organisations/?query=${encodeURIComponent(search)}`);
const parsed = contactOrganisationsListSchema.safeParse(result);
if (!parsed.success) {
throwApiInvalidResponseError(parsed.error);
}
return JSON.stringify(parsed.data);
}
};
// src/tools/contacts/search-contact-people.ts
import { z as z12 } from "zod";
var parameters3 = z12.object({
search: z12.string()
});
var searchContactPeopleTool = {
name: "search_contact_people",
description: `Search for people by name in the contacts`,
parameters: parameters3,
annotations: {
title: "Search Contact People",
openWorldHint: true
},
async execute({ search }) {
const result = await get(`/contacts/people/?query=${encodeURIComponent(search)}`);
const parsed = contactPeopleListSchema.safeParse(result);
if (!parsed.success) {
throwApiInvalidResponseError(parsed.error);
}
return JSON.stringify(parsed.data);
}
};
// src/tools/contacts/create-contact.ts
var parameters4 = contactCreateSchema;
var createContactTool = {
name: "create_contact",
description: "Create a new contact (organisation or person/individual)",
parameters: parameters4,
annotations: {
title: "Create Contact",
openWorldHint: true
},
async execute(params) {
const parsed = contactCreateSchema.safeParse(params);
if (!parsed.success) {
throwApiInvalidResponseError(parsed.error);
}
const result = await post("/contacts/", parsed.data);
return JSON.stringify(result);
}
};
// src/tools/proposals/search-proposals.ts
import { z as z13 } from "zod";
var parameters5 = z13.object({
search: z13.string()
});
var searchProposalsTool = {
name: "search_proposals",
description: "Search for proposals by query",
parameters: parameters5,
annotations: {
title: "Search Proposals",
openWorldHint: true
},
async execute({ search }) {
const result = await get(`/proposals/open/?query=${encodeURIComponent(search)}`);
const parsed = proposalsListSchema.safeParse(result);
if (!parsed.success) {
throwApiInvalidResponseError(parsed.error);
}
return JSON.stringify(parsed.data);
}
};
// src/tools/proposals/get-proposal-directories.ts
var getProposalDirectoriesTool = {
name: "get_proposal_directories",
description: "Get all proposal directories grouped by status (edit, open, won, lost, closed)",
parameters: emptyObject,
annotations: {
title: "Get Proposal Directories",
openWorldHint: true
},
async execute() {
const result = await get("/proposal-directories/");
const parsed = proposalDirectoriesSchema.safeParse(result);
if (!parsed.success) {
throwApiInvalidResponseError(parsed.error);
}
return JSON.stringify(parsed.data);
}
};
// src/tools/proposals/create-proposal.ts
import { z as z14 } from "zod";
var parameters6 = z14.object({
account_user_id: z14.number().optional(),
contact_id: z14.number(),
contact_people: z14.array(z14.number()),
design_template_id: z14.number(),
name: z14.string(),
proposal_template_id: z14.number(),
text_template_id: z14.number(),
custom_fields: z14.array(z14.object({ name: z14.string(), value: z14.string() })).optional()
// automations_set_id: z.number().optional(),
// content: proposalContentSchema.optional(),
// directory_id: z.number().optional(),
// tags: z.array(z.union([z.string(), z.object({ id: z.number(), name: z.string() })])).optional(),
});
var createProposalTool = {
name: "create_proposal",
description: "Create a new proposal",
parameters: parameters6,
annotations: {
title: "Create Proposal",
openWorldHint: true
},
async execute(params) {
const result = await post("/proposals/", params);
const parsed = createProposalSchema.safeParse(result);
if (!parsed.success) {
throwApiInvalidResponseError(parsed.error);
}
return JSON.stringify(parsed.data);
}
};
// src/tools/proposals/send-proposal.ts
import { z as z15 } from "zod";
var parameters7 = z15.object({
proposal_id: z15.number(),
send_message_id: z15.number().optional(),
send_method: z15.enum(["offorte", "self"]).default("offorte").optional(),
send_message: z15.string().optional(),
password_reset: z15.boolean().optional()
});
var sendProposalTool = {
name: "send_proposal",
description: "Send a proposal to its assigned contacts",
parameters: parameters7,
annotations: {
title: "Send Proposal",
openWorldHint: true
},
async execute({ proposal_id, ...body }) {
const result = await post(`/proposals/${proposal_id}/send/`, body);
const parsed = sendProposalSchema.safeParse(result);
if (!parsed.success) {
throwApiInvalidResponseError(parsed.error);
}
return JSON.stringify(parsed.data);
}
};
// src/tools/register.ts
var tools = [
getInitialContextTool,
getAccountUsersTool,
getAutomationSetsTool,
getContactDetailsTool,
getDesignTemplatesTool,
getEmailTemplatesTool,
getProposalDirectoriesTool,
getProposalTemplatesTool,
getTextTemplatesTool,
searchContactOrganisationsTool,
searchContactPeopleTool,
searchProposalsTool,
createContactTool,
createProposalTool,
sendProposalTool
];
function registerTools({ server: server2 }) {
tools.map(initialContextGuard).forEach((tool) => server2.addTool(tool));
}
// src/server.ts
var { TRANSPORT_TYPE } = config;
var server = new FastMCP({
name: "Offorte Proposals",
version: process.env.npm_package_version || "0.0.0"
});
registerTools({ server });
if (TRANSPORT_TYPE === "sse") {
server.start({
transportType: "sse",
sse: {
endpoint: "/sse",
port: 3e3
}
});
} else {
server.start({ transportType: "stdio" });
}
//# sourceMappingURL=server.js.map