Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
45ed7af
feat: add support for mcp resources
frontegg-david Nov 25, 2025
23f5a9e
feat: enhance resource documentation with static and function styles
frontegg-david Nov 25, 2025
b175516
feat: add resource module with fixtures and decorators
frontegg-david Nov 26, 2025
906f24c
feat: add resource module with fixtures and decorators
frontegg-david Nov 26, 2025
cfbc73c
feat: refine resource interfaces and enhance error handling
frontegg-david Nov 26, 2025
d794cc6
Merge branch 'main' into add-support-for-resources
frontegg-david Nov 26, 2025
9bcbaad
feat: enhance resource handling with AnyResourceRecord type and impro…
frontegg-david Nov 26, 2025
399bd64
feat: register resource flows in ResourceRegistry
frontegg-david Nov 26, 2025
d94cff0
feat: enhance resource handling with improved type definitions and lo…
frontegg-david Nov 26, 2025
8370531
feat: improve error handling and logging in resource management
frontegg-david Nov 26, 2025
f60d95f
feat: add support for prompts with new registry and flow implementations
frontegg-david Nov 26, 2025
77f1286
feat: update MCP integration for Codex home configuration and enhance…
frontegg-david Nov 26, 2025
4562952
enhance prompt and resource handling with improved type definitions a…
frontegg-david Nov 26, 2025
0ced899
Merge branch 'main' into add-support-for-prompts
frontegg-david Nov 26, 2025
9864586
feat: add MCP capabilities retrieval for prompts in registry and loca…
frontegg-david Nov 26, 2025
3d37227
feat: implement MCP specifications for prompts, resources, and tools …
frontegg-david Nov 26, 2025
0c81994
Merge branch 'main' into add-support-for-prompts
frontegg-david Nov 26, 2025
22c3272
feat: enhance prompt handling with improved type safety and error mes…
frontegg-david Nov 26, 2025
b5c0d27
feat: update execute method to return typed Promise<GetPromptResult> …
frontegg-david Nov 26, 2025
a52dc3e
fix: update authentication links in README for accurate documentation
frontegg-david Nov 26, 2025
b6b3989
feat(prompts): add categorize-expense and expense-report prompts for …
frontegg-david Nov 26, 2025
ca577a2
fix: update threshold value to use Number.MAX_SAFE_INTEGER and improv…
frontegg-david Nov 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 32 additions & 41 deletions .github/workflows/update-draft-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,50 +59,37 @@ jobs:
run: yarn install

# ========================================
# MCP Integration: Query Mintlify docs for context
# MCP Integration: Configure Mintlify docs MCP server
# ========================================
- name: Setup MCP server for enhanced context
- name: Prepare Codex home with MCP config
id: mcp
shell: bash
run: |
set -euo pipefail
mkdir -p .github/codex/mcp-context

echo "Setting up Mintlify MCP context..."

# Query Mintlify MCP for documentation best practices
cat > .github/codex/mcp-context/mintlify-guidelines.md <<'GUIDELINES'
# Mintlify Documentation Guidelines

## Structure
- Use clear, hierarchical organization
- Group related pages under common sections
- Keep navigation depth to 3 levels max

## Content
- Start with conceptual overview, then details
- Include code examples for all features
- Use callouts for important notes (Note, Warning, Tip)
- Keep paragraphs short and scannable

## Versioning
- Draft docs are for the next release
- Use current paths (no version prefix) in draft docs
- Draft content will be moved to live on release

## Code Blocks
- Specify language for syntax highlighting
- Include comments for complex examples
- Show both TypeScript and JavaScript when relevant

## Navigation (docs.json)
- Each version has its own groups array
- Use descriptive group names
- Add icons to enhance visual hierarchy
GUIDELINES

echo "✓ MCP context prepared"
echo "mcp_enabled=true" >> "$GITHUB_OUTPUT"
CODEX_HOME="${RUNNER_TEMP}/codex-home"
mkdir -p "$CODEX_HOME"

echo "Setting up Codex home with Mintlify MCP server..."

cat > "$CODEX_HOME/config.toml" << 'EOF'
[features]
# Enable the Rust MCP client (needed for HTTP/OAuth MCP support)
rmcp_client = true

# --- Mintlify Documentation Server ---
# Provides access to Mintlify documentation best practices
[mcp_servers.mintlify_docs]
url = "https://mintlify.com/docs/mcp"
# Read-only access to Mintlify documentation
http_headers = { "X-MCP-Readonly" = "true" }
startup_timeout_sec = 30
tool_timeout_sec = 60
EOF

echo "✓ Codex home configured with Mintlify MCP server"
echo "codex_home=${CODEX_HOME}" >> "$GITHUB_OUTPUT"
env:
RUNNER_TEMP: ${{ runner.temp }}

- name: Prepare diff context for Codex
id: ctx
Expand Down Expand Up @@ -173,11 +160,14 @@ jobs:
- Commit list (TSV): `.github/codex/prompts/commits.txt` # columns: sha<TAB>subject<TAB>body
- Next version: `.github/codex/prompts/version.txt` # e.g., 0.4.1
- Date (UTC, ISO): `.github/codex/prompts/date.txt` # e.g., 2025-11-22
- MCP Context Guidelines: `.github/codex/mcp-context/mintlify-guidelines.md`

MCP SERVER AVAILABLE:
- **mintlify_docs** - Mintlify documentation MCP server at `https://mintlify.com/docs/mcp`
Use this to query Mintlify best practices for documentation structure, MDX components, callouts, code blocks, and navigation.

DOCS LAYOUT

**IMPORTANT: Follow the MCP guidelines in `.github/codex/mcp-context/mintlify-guidelines.md`**
**IMPORTANT: Use the `mintlify_docs` MCP server to look up Mintlify documentation best practices when writing or updating docs.**

Folders:
- `docs/draft/docs/**`
Expand Down Expand Up @@ -373,6 +363,7 @@ jobs:
uses: openai/codex-action@v1
with:
openai-api-key: ${{ secrets.CODEX_OPENAI_KEY }}
codex-home: ${{ steps.mcp.outputs.codex_home }}
prompt-file: .github/codex/prompts/update-draft-docs.md
output-file: ${{ env.CODEX_OUT }}
model: "gpt-5.1-codex"
Expand Down
33 changes: 32 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,40 @@ export * from './errors';

## SDK Code Guidelines

### Type Safety Philosophy

FrontMCP is a TypeScript-first schema validation framework. All types should align with MCP protocol definitions.

#### MCP Response Types (DO NOT use `unknown` for protocol types)

- **Tools**: `execute()` returns `Promise<Out>` where `Out` is the typed output schema
- **Prompts**: `execute()` returns `Promise<GetPromptResult>` (MCP-defined type)
- **Resources**: `read()` returns `Promise<ReadResourceResult>` (MCP-defined type)

```typescript
// ✅ Good - strict MCP protocol types
abstract execute(args: Record<string, string>): Promise<GetPromptResult>;

// ❌ Bad - using unknown defeats TypeScript-first development
abstract execute(args: Record<string, string>): Promise<unknown>;
```

#### Validation Flow Pattern

1. `execute/read` methods return strictly typed MCP responses
2. `parseOutput/safeParseOutput` normalize various input shapes to the strict type
3. Flows finalize output using the entry's parse methods

```typescript
// In flow finalize stage:
const parseResult = prompt.safeParseOutput(rawOutput);
if (!parseResult.success) throw new InvalidOutputError();
this.respond(parseResult.data); // data is GetPromptResult
```

### Type System Patterns

**Use `unknown` instead of `any` for generic types:**
**Use `unknown` instead of `any` for generic type defaults (NOT for MCP protocol types):**

```typescript
// ✅ Good - explicit constraint with unknown default
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ See [LICENSE](./LICENSE).
[7]: https://docs.agentfront.dev/docs/servers/resources 'Resources - FrontMCP'
[8]: https://docs.agentfront.dev/docs/servers/prompts 'Prompts - FrontMCP'
[9]: https://docs.agentfront.dev/docs/guides/add-openapi-adapter 'Add OpenAPI Adapter - FrontMCP'
[10]: https://docs.agentfront.dev/docs/servers/authentication/overview 'Authentication - FrontMCP'
[11]: https://docs.agentfront.dev/docs/servers/authentication/remote 'Remote OAuth - FrontMCP'
[12]: https://docs.agentfront.dev/docs/servers/authentication/local 'Local OAuth - FrontMCP'
[10]: https://docs.agentfront.dev/docs/authentication/overview 'Authentication - FrontMCP'
[11]: https://docs.agentfront.dev/docs/authentication/remote 'Remote OAuth - FrontMCP'
[12]: https://docs.agentfront.dev/docs/authentication/local 'Local OAuth - FrontMCP'
[13]: https://docs.agentfront.dev/docs/deployment/production-build 'Production Build - FrontMCP'
10 changes: 9 additions & 1 deletion apps/demo/src/apps/expenses/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import AddTool from './tools/add.tool';
import AuthorizationPlugin from './plugins/authorization.plugin';
import { CachePlugin } from '@frontmcp/plugins';

// Prompts
import { ExpenseReportPrompt, CategorizeExpensePrompt } from './prompts';

// Resources
import { ExpensePolicyResource, ExpenseByIdResource, ExpenseCategoriesResource } from './resources';

@App({
id: 'expense',
name: 'Expense MCP app',
Expand All @@ -29,6 +35,8 @@ import { CachePlugin } from '@frontmcp/plugins';
},
}),
],
tools: [AddTool, CreateExpenseTool, GetExpenseTool]
tools: [AddTool, CreateExpenseTool, GetExpenseTool],
prompts: [ExpenseReportPrompt, CategorizeExpensePrompt],
resources: [ExpensePolicyResource, ExpenseByIdResource, ExpenseCategoriesResource],
})
export default class ExpenseMcpApp {}
62 changes: 62 additions & 0 deletions apps/demo/src/apps/expenses/prompts/categorize-expense.prompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { prompt } from '@frontmcp/sdk';

/**
* Function-style prompt for categorizing expenses
*/
export default prompt({
name: 'categorize-expense',
description: 'Help categorize an expense based on its description and amount',
arguments: [
{
name: 'description',
description: 'Description of the expense',
required: true,
},
{
name: 'amount',
description: 'Amount of the expense',
required: true,
},
{
name: 'vendor',
description: 'Vendor or merchant name',
required: false,
},
],
})((args) => {
const { description, amount, vendor } = args ?? {};

const vendorInfo = vendor ? `\nVendor: ${vendor}` : '';

return {
description: 'Categorize an expense',
messages: [
{
role: 'user' as const,
content: {
type: 'text' as const,
text: `Please categorize the following expense:

Description: ${description}
Amount: $${amount}${vendorInfo}

Suggest the most appropriate category from:
- Travel
- Meals & Entertainment
- Office Supplies
- Software & Subscriptions
- Professional Services
- Marketing
- Equipment
- Utilities
- Other

Also provide:
1. Confidence level (High/Medium/Low)
2. Alternative category if applicable
3. Any compliance flags (e.g., requires receipt, needs approval)`,
},
},
],
};
});
52 changes: 52 additions & 0 deletions apps/demo/src/apps/expenses/prompts/expense-report.prompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Prompt, PromptContext } from '@frontmcp/sdk';

@Prompt({
name: 'expense-report',
description: 'Generate an expense report summary for a given time period',
arguments: [
{
name: 'startDate',
description: 'Start date for the report (YYYY-MM-DD)',
required: true,
},
{
name: 'endDate',
description: 'End date for the report (YYYY-MM-DD)',
required: true,
},
{
name: 'category',
description: 'Optional expense category filter',
required: false,
},
],
})
export default class ExpenseReportPrompt extends PromptContext {
async execute(args: Record<string, string>) {
const { startDate, endDate, category } = args;

const categoryFilter = category ? ` for category "${category}"` : '';

return {
description: `Expense report from ${startDate} to ${endDate}${categoryFilter}`,
messages: [
{
role: 'user' as const,
content: {
type: 'text' as const,
text: `Please generate an expense report summary for the period from ${startDate} to ${endDate}${categoryFilter}.

Include the following information:
1. Total expenses for the period
2. Breakdown by category
3. Top 5 largest expenses
4. Comparison with previous period (if available)
5. Any anomalies or unusual spending patterns

Format the report in a clear, professional manner suitable for management review.`,
},
},
],
};
}
}
2 changes: 2 additions & 0 deletions apps/demo/src/apps/expenses/prompts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as ExpenseReportPrompt } from './expense-report.prompt';
export { default as CategorizeExpensePrompt } from './categorize-expense.prompt';
50 changes: 50 additions & 0 deletions apps/demo/src/apps/expenses/resources/expense-by-id.resource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { ResourceTemplate, ResourceContext } from '@frontmcp/sdk';
import { ReadResourceResult } from '@modelcontextprotocol/sdk/types.js';

type ExpenseParams = {
expenseId: string;
};

@ResourceTemplate({
name: 'expense-by-id',
uriTemplate: 'expense://expenses/{expenseId}',
description: 'Get expense details by ID',
mimeType: 'application/json',
})
export default class ExpenseByIdResource extends ResourceContext<ExpenseParams> {
async execute(uri: string, params: ExpenseParams): Promise<ReadResourceResult> {
const { expenseId } = params;

// Mock expense data - in real app, would fetch from database
const expense = {
id: expenseId,
description: `Business expense #${expenseId}`,
amount: Math.floor(Math.random() * 500) + 50,
currency: 'USD',
category: 'Travel',
status: 'approved',
submittedBy: 'john.doe@company.com',
submittedAt: new Date().toISOString(),
approvedBy: 'manager@company.com',
approvedAt: new Date().toISOString(),
receipt: {
url: `https://receipts.company.com/${expenseId}.pdf`,
uploadedAt: new Date().toISOString(),
},
metadata: {
project: 'Q4-Marketing',
costCenter: 'CC-1001',
},
};

return {
contents: [
{
uri,
mimeType: 'application/json',
text: JSON.stringify(expense, null, 2),
},
],
};
}
}
Loading
Loading