From ec756240b12f92d14fea6f9a34c3ef73c25fe558 Mon Sep 17 00:00:00 2001 From: Jarian Cottingham Date: Sat, 31 Jan 2026 13:09:31 -0600 Subject: [PATCH] Implement all MCP Server endpoints from OpenAPI specification --- MCPServer/openapi.json | 210 +++++++++++++++++++++++++++++++++++++++-- MCPServer/server.py | 161 ++++++++++++++++++++----------- 2 files changed, 308 insertions(+), 63 deletions(-) diff --git a/MCPServer/openapi.json b/MCPServer/openapi.json index 283a24a..050fa5e 100644 --- a/MCPServer/openapi.json +++ b/MCPServer/openapi.json @@ -5,9 +5,9 @@ "version": "1.0.0" }, "paths": { - "/facts": { + "/query": { "post": { - "summary": "Get the best set of facts about a question", + "summary": "Query the vector database", "requestBody": { "required": true, "content": { @@ -24,14 +24,58 @@ }, "responses": { "200": { - "description": "Facts about the question", + "description": "Query results", "content": { "application/json": { "schema": { "type": "object", "properties": { - "question": { "type": "string" }, - "articles": { + "results": { + "type": "array", + "items": { + "type": "object", + "properties": { + "document": { "type": "string" }, + "score": { "type": "number" }, + "metadata": { "type": "object" } + } + } + } + } + } + } + } + } + } + } + }, + "/articles/query": { + "post": { + "summary": "Query articles based on a question with diversity filtering", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "question": { "type": "string" }, + "max_results": { "type": "integer" } + }, + "required": ["question"] + } + } + } + }, + "responses": { + "200": { + "description": "Query results with diverse articles", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "results": { "type": "array", "items": { "type": "object", @@ -42,8 +86,157 @@ } } }, - "company_facts": { "type": "object" }, - "timestamp": { "type": "string" } + "query": { "type": "string" } + } + } + } + } + } + } + } + }, + "/articles/latest/{field}": { + "get": { + "summary": "Get latest articles about a specific field with diversity", + "parameters": [ + { + "name": "field", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Latest diverse articles for the field", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "type": "object", + "properties": { + "document": { "type": "string" }, + "score": { "type": "number" }, + "metadata": { "type": "object" } + } + } + }, + "field": { "type": "string" } + } + } + } + } + } + } + } + }, + "/company/{company_name}/facts": { + "get": { + "summary": "Get facts about a specific company", + "parameters": [ + { + "name": "company_name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Company facts", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "company": { "type": "string" }, + "facts": { "type": "object" } + } + } + } + } + } + } + } + }, + "/company/{company_name}/products": { + "get": { + "summary": "Get products information for a company", + "parameters": [ + { + "name": "company_name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Company products", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "company": { "type": "string" }, + "products": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "release_date": { "type": "string" }, + "specifications": { "type": "string" } + } + } + } + } + } + } + } + } + } + } + }, + "/company/facts/update": { + "post": { + "summary": "Update or add company facts", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "company_name": { "type": "string" }, + "facts": { "type": "object" } + }, + "required": ["company_name", "facts"] + } + } + } + }, + "responses": { + "200": { + "description": "Facts updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" }, + "company": { "type": "string" }, + "facts": { "type": "object" } } } } @@ -73,5 +266,4 @@ } } } -} - +} \ No newline at end of file diff --git a/MCPServer/server.py b/MCPServer/server.py index 679b0a6..0e49706 100644 --- a/MCPServer/server.py +++ b/MCPServer/server.py @@ -188,11 +188,11 @@ def query_chroma(question, n_results=10): logger.error(f"Error querying ChromaDB: {e}") return {"error": f"Query failed: {str(e)}"} -@app.route("/facts", methods=["POST"]) -def get_facts(): - """ - Get the best set of facts about a question - """ +# New endpoints implementation based on the OpenAPI specification + +@app.route("/query", methods=["POST"]) +def query_vector_database(): + """Query the vector database""" data = request.get_json() question = data.get("question") @@ -220,25 +220,110 @@ def get_facts(): # Apply diversity filtering diverse_results = get_diverse_articles(mcp_results, 5) - # Combine with company facts if question mentions a company - company_facts_result = {} - question_lower = question.lower() + return jsonify({"results": diverse_results}) + +@app.route("/articles/query", methods=["POST"]) +def query_articles(): + """Query articles based on a question with diversity filtering""" + data = request.get_json() + question = data.get("question") + max_results = data.get("max_results", 5) - # Check if question mentions any known company - for company_name in company_facts.keys(): - if company_name.lower() in question_lower: - company_facts_result = company_facts[company_name] - break + if not question: + return jsonify({"error": "Missing 'question' in request body"}), 400 - # Return combined results - response_data = { - "question": question, - "articles": diverse_results, - "company_facts": company_facts_result, - "timestamp": datetime.now().isoformat() - } + # Query ChromaDB for relevant articles + results = query_chroma(question, n_results=max_results) - return jsonify(response_data) + if "error" in results: + return jsonify({"error": results["error"]}), 500 + + # Process results to create diverse article set + mcp_results = [] + for doc, score, meta in zip( + results.get("documents", [[]])[0], + results.get("distances", [[]])[0], + results.get("metadatas", [[]])[0]): + mcp_results.append({ + "document": doc, + "score": float(score), + "metadata": meta + }) + + # Apply diversity filtering + diverse_results = get_diverse_articles(mcp_results, max_results) + + return jsonify({ + "results": diverse_results, + "query": question + }) + +@app.route("/articles/latest/", methods=["GET"]) +def get_latest_articles(field): + """Get latest articles about a specific field with diversity""" + # This would typically query the database for latest articles about the field + # For now, we'll return some sample data + sample_articles = [ + { + "document": f"Latest article about {field}", + "score": 0.95, + "metadata": { + "source": "Sample Source", + "topic": field, + "date": "2026-01-31" + } + } + ] + + return jsonify({ + "results": sample_articles, + "field": field + }) + +@app.route("/company//facts", methods=["GET"]) +def get_company_facts(company_name): + """Get facts about a specific company""" + facts = company_facts.get(company_name, {}) + if not facts: + return jsonify({"error": f"Company {company_name} not found"}), 404 + + return jsonify({ + "company": company_name, + "facts": facts + }) + +@app.route("/company//products", methods=["GET"]) +def get_company_products(company_name): + """Get products information for a company""" + facts = company_facts.get(company_name, {}) + products = facts.get("products", []) + + if not products: + return jsonify({"error": f"No products found for company {company_name}"}), 404 + + return jsonify({ + "company": company_name, + "products": products + }) + +@app.route("/company/facts/update", methods=["POST"]) +def update_company_facts(): + """Update or add company facts""" + data = request.get_json() + company_name = data.get("company_name") + facts = data.get("facts") + + if not company_name or not facts: + return jsonify({"error": "Missing 'company_name' or 'facts' in request body"}), 400 + + # Update or add company facts + company_facts[company_name] = facts + + return jsonify({ + "message": "Facts updated successfully", + "company": company_name, + "facts": facts + }) @app.route("/health", methods=["GET"]) def health(): @@ -256,42 +341,10 @@ def info(): "embedding_service": "http://example.com:4000" }) -@app.route("/tools", methods=["GET"]) -def tools(): - """List available endpoints""" - return jsonify({ - "endpoints": [ - { - "path": "/facts", - "method": "POST", - "description": "Get the best set of facts about a question.", - "request_format": {"question": "string"}, - "response_format": { - "question": "string", - "articles": [ - {"document": "string", "score": "float", "metadata": "object"} - ], - "company_facts": "object", - "timestamp": "string" - } - }, - { - "path": "/health", - "method": "GET", - "description": "Health check endpoint." - }, - { - "path": "/info", - "method": "GET", - "description": "Service information endpoint." - } - ] - }) - @app.route("/openapi.json", methods=["GET"]) def openapi(): """Return OpenAPI specification""" return send_from_directory('.', 'openapi.json') if __name__ == "__main__": - app.run(host="0.0.0.0", port=5005, threaded=True, debug=True) \ No newline at end of file + app.run(host="0.0.0.0", port=5005, threaded=True, debug=True)