Skip to content

WebMCP Contact Form Tool

Draft - awaiting review

The site has an impressum.md and datenschutz.md page, but currently lacks a structured contact form. Adding a WebMCP-enabled contact form serves two purposes: (1) provides a real contact mechanism, and (2) demonstrates WebMCP’s declarative API where HTML forms become agent-callable tools.

  • No simple way for agents to submit messages on behalf of users
  • Current contact method (email link) requires agent to hand off to user or external email service

Create a WebMCP-enabled contact form that agents can invoke to submit structured messages.

As an AI agent assisting a visitor, I want to submit a contact message on their behalf using the site’s form.

Acceptance Criteria:

  • Agent calls submit_contact_form(subject, message, email)
  • Form submits via standard HTTP POST
  • Agent receives confirmation of submission status
ID Requirement
FR-001 Declarative API via HTML form with WebMCP annotations
FR-002 Tool name: submit_contact_form (from form’s toolname attribute)
FR-003 Required fields: subject, message, email
FR-004 toolautosubmit attribute: agent triggers immediate submission
FR-005 Tool description ≤ 500 chars
FR-006 Return confirmation message on success
FR-007 Return error message on validation failure
<form
toolname="submit_contact_form"
tooldescription="Submit a contact message about this site or its projects. Agent submits on behalf of user."
toolautosubmit
method="POST"
action="/api/contact">
<label for="email">Your Email</label>
<input
type="email"
name="email"
id="email"
required
toolparamdescription="Contact email for reply">
<label for="subject">Subject</label>
<input
type="text"
name="subject"
id="subject"
required
toolparamdescription="Brief subject line">
<label for="message">Message</label>
<textarea
name="message"
id="message"
required
toolparamdescription="Your message content"
rows="4"></textarea>
<button type="submit">Send Message</button>
</form>
site/src/pages/api/contact.ts
export const POST = async ({ request }) => {
const body = await request.json();
const { email, subject, message } = body;
// Basic validation
if (!email || !subject || !message) {
return new Response(JSON.stringify({ error: "Missing required fields" }), {
status: 400,
headers: { "Content-Type": "application/json" }
});
}
// TODO: Implement actual sending (SMTP, webhook, etc.)
// For demo: log and return success
return new Response(JSON.stringify({
success: true,
message: "Message received. We'll get back to you soon."
}), {
status: 200,
headers: { "Content-Type": "application/json" }
});
};
const form = document.querySelector("form");
form.addEventListener("submit", async (e) => {
e.preventDefault();
if (e.agentInvoked) {
// Agent triggered submission
const data = Object.fromEntries(new FormData(e.target));
try {
const res = await fetch("/api/contact", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
});
const result = await res.json();
e.respondWith(Promise.resolve(result.message || "Message sent successfully"));
} catch (err) {
e.respondWith(Promise.reject(`Submission failed: ${err.message}`));
}
}
});
Trigger Behavior
Human submits Normal form flow with validation and UI feedback
Agent submits (e.agentInvoked) Silent POST, agent receives structured response
Risk Mitigation
Spam/abuse Rate limiting on API route, email validation
Prompt injection in message untrustedContentHint: true if exposing submitted messages to other tools
No backend yet Start with console.log/demo mode; add SMTP/webhook when ready
Test Scenario Expected
Human submit Fill form + click submit Form validates, shows confirmation
Agent submit Agent calls tool with valid data POST sent, agent receives confirmation
Invalid email Agent submits malformed email 400 response with error
Missing field Agent omits subject 400 response with error
  • Contact page needs to exist (create docs/contact.md with embedded form)
  • Astro API route needed at /api/contact